mcpField
T
turntable

turntable

github.com/kevinbadi创意与媒体210151 次安装30 周前更新
代码仓库

关于 turntable

turntable 是用于制作 360 度产品展示视频的 Blender 技能,并从用户选定的正面角度开始。它涵盖相机设置、灯光、渲染和视频编码。

主要功能

  1. 01360 度相机环绕
  2. 02从四个角度选择正面
  3. 03设置相机架与灯光
  4. 04渲染透明背景
  5. 05用 ffmpeg 编码 PNG 序列

适用场景

  1. 01制作旋转产品展示视频
  2. 02渲染透明背景的产品视频
  3. 03确定产品的正面视角

MCP 相关

通过 Blender MCP 操作 Blender 场景;运行时需要连接 Blender MCP 插件。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kevinbadi/blender-skills --skill turntable

安装后在 Claude Code 中输入/turntable确认已加载。

详细介绍

转台式摄像机动画

让摄像机围绕产品旋转 360 度,呈现简洁的产品展示效果。从正面开始,并无缝循环。

适用场景

  • 用户想制作产品转台/旋转视频
  • 用户提到“绕着旋转”“环绕”“展示所有角度”“转台”
  • 产品展示视频的默认首选方案

前提条件

  • Blender MCP:已连接(blender-mcp 插件使用端口 9876)
  • 3D 模型:已导入 Blender 场景
  • 输出文件夹:~/Desktop/Blender Videos/(如有需要,请创建)
  • ffmpeg:已安装,用于视频编码

参数

参数默认值描述
duration5视频时长,单位为秒
fps24每秒帧数
camera_distance4.5与物体中心的距离
camera_height2.0摄像机高于物体的高度
camera_lens50焦距,单位为 mm
transparent_bgtrue透明背景
output_formatmovmov(带 alpha 通道的 ProRes 4444)或 webm(带 alpha 通道的 VP9)

流程

步骤 1:检测正面

从不同摄像机位置渲染 4 张低分辨率测试帧,以确定产品正面。询问用户哪一个角度是正面。

import bpy, math
from mathutils import Vector

obj = bpy.data.objects['<OBJECT_NAME>']
bbox = [obj.matrix_world @ Vector(c) for c in obj.bound_box]
center = sum(bbox, Vector()) / 8

RADIUS = 4.5
HEIGHT = 2.0

# Create temp camera
bpy.ops.object.camera_add()
cam = bpy.context.active_object
cam.name = 'TempCam'
bpy.context.scene.camera = cam

# Add track constraint to center
bpy.ops.object.empty_add(type='PLAIN_AXES', location=center)
target = bpy.context.active_object
target.name = 'TempTarget'

cam.constraints.new(type='TRACK_TO').target = target

# Render 4 angles
positions = {
    'front': (center.x, center.y - RADIUS, HEIGHT),
    'right': (center.x + RADIUS, center.y, HEIGHT),
    'back': (center.x, center.y + RADIUS, HEIGHT),
    'left': (center.x - RADIUS, center.y, HEIGHT),
}
for label, pos in positions.items():
    cam.location = pos
    bpy.context.scene.render.filepath = f'<OUTPUT>/facing_{label}.png'
    bpy.ops.render.render(write_still=True)

向用户展示全部 4 张图片,并询问哪一张是正面。

步骤 2:设置摄像机支架
import bpy, math

# Create target empty at object center
bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0, 0, 0))
target = bpy.context.active_object
target.name = 'TurntableTarget'

# Create camera at front-facing position (determined from Step 1)
# Default front = -Y axis
bpy.ops.object.camera_add(location=(0, -CAMERA_DISTANCE, CAMERA_HEIGHT))
cam = bpy.context.active_object
cam.name = 'TurntableCamera'
cam.data.lens = 50

# Track to target
track = cam.constraints.new(type='TRACK_TO')
track.target = target
track.track_axis = 'TRACK_NEGATIVE_Z'
track.up_axis = 'UP_Y'

# Parent camera to target for orbit
bpy.ops.object.select_all(action='DESELECT')
cam.select_set(True)
target.select_set(True)
bpy.context.view_layer.objects.active = target
bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)

bpy.context.scene.camera = cam
步骤 3:制作 360 度旋转动画
import bpy, math

TOTAL_FRAMES = DURATION * FPS  # e.g. 5 * 24 = 120

scene = bpy.context.scene
scene.frame_start = 1
scene.frame_end = TOTAL_FRAMES
scene.render.fps = FPS

target = bpy.data.objects['TurntableTarget']
target.rotation_euler = (0, 0, 0)
target.keyframe_insert(data_path='rotation_euler', frame=1)
target.rotation_euler = (0, 0, math.radians(360))
target.keyframe_insert(data_path='rotation_euler', frame=TOTAL_FRAMES + 1)

# IMPORTANT: Linear interpolation for constant speed
# Blender 5.1 uses layered actions:
action = target.animation_data.action
strip = action.layers[0].strips[0]
for cb in strip.channelbags:
    for fc in cb.fcurves:
        for kp in fc.keyframe_points:
            kp.interpolation = 'LINEAR'
步骤 4:设置灯光
import bpy, math

# Warm sunset lighting on LIGHTS only (not on materials/world)
bpy.ops.object.light_add(type='AREA', location=(3, -3, 4))
k = bpy.context.active_object; k.name='GoldenKey'
k.data.energy = 2000; k.data.size = 3.0
k.data.color = (1.0, 0.78, 0.45)
k.rotation_euler = (math.radians(45), 0, math.radians(25))

bpy.ops.object.light_add(type='AREA', location=(-3, -2, 3))
f = bpy.context.active_object; f.name='WarmFill'
f.data.energy = 1000; f.data.size = 5.0
f.data.color = (1.0, 0.75, 0.4)
f.rotation_euler = (math.radians(40), 0, math.radians(-30))

bpy.ops.object.light_add(type='AREA', location=(0, 0, 5))
oh = bpy.context.active_object; oh.name='OverheadWash'
oh.data.energy = 800; oh.data.size = 8.0
oh.data.color = (1.0, 0.92, 0.75)

bpy.ops.object.light_add(type='AREA', location=(0, 4, 2))
r = bpy.context.active_object; r.name='WarmRim'
r.data.energy = 800; r.data.size = 3.0
r.data.color = (1.0, 0.65, 0.3)
r.rotation_euler = (math.radians(-40), 0, math.radians(180))

bpy.ops.object.light_add(type='AREA', location=(4, 0, 0.5))
sw = bpy.context.active_object; sw.name='SideGlow'
sw.data.energy = 600; sw.data.size = 2.0
sw.data.color = (1.0, 0.8, 0.5)
sw.rotation_euler = (math.radians(5), 0, math.radians(90))
步骤 5:渲染
import bpy, os

scene = bpy.context.scene
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.render.film_transparent = True
scene.render.engine = 'CYCLES'  # better metallic reflections
scene.cycles.samples = 64
scene.cycles.use_denoising = True
scene.cycles.device = 'GPU'
scene.render.image_settings.file_format = 'PNG'
scene.render.image_settings.color_mode = 'RGBA'

# Neutral world for subtle reflections (not colored)
if not scene.world:
    scene.world = bpy.data.worlds.new("World")
scene.world.use_nodes = True
bg = scene.world.node_tree.nodes.get('Background')
bg.inputs['Color'].default_value = (0.95, 0.95, 0.95, 1)
bg.inputs['Strength'].default_value = 0.3

frames_dir = os.path.expanduser('~/Desktop/Blender Videos/turntable_frames/')
os.makedirs(frames_dir, exist_ok=True)
scene.render.filepath = frames_dir

bpy.ops.render.render(animation=True)
步骤 6:编码视频

渲染期间 MCP 会超时。轮询帧目录,直到所有帧都生成后再进行编码:

# ProRes 4444 with alpha (transparent)
ffmpeg -y -framerate 24 \
  -i "~/Desktop/Blender Videos/turntable_frames/%04d.png" \
  -c:v prores_ks -profile:v 4444 -pix_fmt yuva444p10le \
  "~/Desktop/Blender Videos/turntable.mov"

Blender 5.1 说明

  • 渲染引擎枚举值:BLENDER_EEVEE(而非 BLENDER_EEVEE_NEXT)
  • 没有 FFMPEG 输出格式 — 渲染 PNG 序列,再使用 ffmpeg 编码
  • 分层动作 API:使用 action.layers[0].strips[0].channelbags 访问 fcurves
  • 设置 film_transparent = True 可使用透明背景
  • 暖色应设置在灯光上,而不是世界/材质上

评论

支持 Markdown