关于 turntable
turntable 是用于制作 360 度产品展示视频的 Blender 技能,并从用户选定的正面角度开始。它涵盖相机设置、灯光、渲染和视频编码。
主要功能
- 01360 度相机环绕
- 02从四个角度选择正面
- 03设置相机架与灯光
- 04渲染透明背景
- 05用 ffmpeg 编码 PNG 序列
适用场景
- 01制作旋转产品展示视频
- 02渲染透明背景的产品视频
- 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:已安装,用于视频编码
参数
| 参数 | 默认值 | 描述 |
|---|---|---|
duration | 5 | 视频时长,单位为秒 |
fps | 24 | 每秒帧数 |
camera_distance | 4.5 | 与物体中心的距离 |
camera_height | 2.0 | 摄像机高于物体的高度 |
camera_lens | 50 | 焦距,单位为 mm |
transparent_bg | true | 透明背景 |
output_format | mov | mov(带 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