剪裁角色动画
由部件骨架构建的角色的配方:身体、头部、两段式手臂,以及绘制在头部画布上的面部叠加层(嘴型和眨眼)。它们将在构建步骤中被插入 montagent 的循环中;如果尚未加载 montagent,请先加载。如果短片中有角色要说一句话,请在规划之前先打开 角色短片结构。
骨架必须提供的内容
请先阅读骨架的描述。你需要每个部件的:图像、尺寸、枢轴点(部件旋转的关节,在原始绘图中的点)、父级,以及部件从前到后的绘制顺序。还需要一张将语音视位 ID 映射到嘴型的表格。每个部件的图像必须经过内边距处理,使其枢轴点恰好位于画布的正中心。面部叠加层共享头部画布的位置和枢轴点。
如果需求只提供了一个单独的画稿,没有部件或枢轴点,你无法盲目切割骨架。请告知用户,并要求提供预切割好的骨架。
烘焙骨架
Montagent 没有层级关系,一个元素也无法更改其图像。因此,角色需要被烘焙:内置脚本会在每一绘制的帧中,根据父级计算出每个部件的屏幕位置和旋转,并将每个嘴型和眨眼作为独立元素写入,在其持续时间范围内应用头部的变换。请不要自己编写此过程。
python3 scripts/bake_rig.py <project> <rig> <spec> 会打印项目,并为每个部件添加一个轨道。使用 --help 运行可查看规范说明:角色站立位置、命名姿态、姿态之间的移动、摆动、跳跃、语音及其视位文件,以及眨眼。每次对规范进行更改后,请重新运行该脚本。它只会替换它写入的轨道。请将规范文件放在项目旁边:它就是角色的真正源文件。
阅读它的报告。 报告会列出它合并的每一个嘴部时间段、每个子级与其父级在每一绘制的帧之间的最大间隙,以及需要关注的时间点:每次移动的到达时刻和每个关节的极端角度。位置是整数像素,因此大约 1.5 像素以内的间隙是舍入误差,会被圆形关节隐藏。更大的间隙意味着骨架的枢轴点有误。
validate 会在角色保持的每个姿态上报告 R-EASE-INERT,并在嘴部和眨眼轨道的时间段之间报告 N-TRACK-GAP。两者都是预期的(请参阅问题排查指南)。
烘焙结果如下所示:每个部件以其枢轴点为中心,仅在移动处有关键帧,每个嘴部或眨眼元素在其时间段内复制头部的变换。
{
"frame": {"width": 640, "height": 360}, "fps": 30, "background": "#2E3440", "duration": 2000, "output": "out/baked.mp4",
"tracks": [
{"name": "set", "layer": 0, "elements": [
{"id": "set", "type": "image", "start": 0, "end": 2000, "source": "media/still.png", "x": 0, "y": 0, "origin": "top-left", "width": 640, "height": 360, "fit": "literal"}
]},
{"name": "puppet-torso", "layer": 10, "elements": [
{"id": "puppet-torso", "type": "image", "start": 0, "end": 2000, "source": "rig/parts/torso.png", "x": 320, "y": 330, "origin": "center", "fit": "literal", "width": 80, "height": 280}
]},
{"name": "puppet-head", "layer": 12, "elements": [
{"id": "puppet-head", "type": "image", "start": 0, "end": 2000, "source": "rig/parts/head.png", "x": 320, "y": 190, "origin": "center", "fit": "literal", "width": 90, "height": 160, "rotation": [{"t": 0, "v": 0}, {"t": 500, "v": 6.0, "ease": "linear"}, {"t": 1000, "v": 0.0, "ease": "linear"}]}
]},
{"name": "puppet-mouth", "layer": 13, "elements": [
{"id": "puppet-mouth-0", "type": "image", "start": 400, "end": 700, "source": "rig/parts/mouth_open.png", "x": 320, "y": 190, "origin": "center", "fit": "literal", "width": 24, "height": 60, "rotation": [{"t": 400, "v": 4.8}, {"t": 500, "v": 6.0, "ease": "linear"}, {"t": 666, "v": 4.0, "ease": "linear"}]}
]}
]
}
配方
每个配方只提供起始范围,而非最终答案。每个都以检查步骤结束:加载 montagent-craft,然后在继续之前查看步骤指定的位置。
角度以相对于其父级的绘制的静止姿态为基准,正角在屏幕上顺时针旋转。因此,观众右侧的手臂随着负角抬起,而观众左侧的手臂随着正角抬起。
将角色放置在场景中
- 背景: 一个全帧的场景图像,
origin设置为top-left,位于 (0, 0),尺寸与帧相同,放在最低层。请明确设置origin。 - 脚踩在地板上: 骨架的根部(身体,以脚为枢轴点)放置在地板与墙壁阴影线交汇处,或稍稍靠前一些。在一个高度为 1080 的场景中,地板的顶部边缘通常位于画面高度的 80–85% 处,因此将脚放在该线下方 5–10% 的位置。
- 尺寸: 角色高度为帧高度的 55–75%,由规范的缩放比例(每绘制像素对应的帧像素)设定。测量可见的角色,而不是带有内边距的绘图:绘图高度乘以缩放比例会高估尺寸。
- 放置: 若场景中有道具或卡片,角色应偏置于其对面的位置,约三分之一处;若为单独站立,则居中放置。
- 检查: 在静止时刻使用
frame命令,检查脚是否稳稳踩在地板上,既没有悬空也没有陷入地板,并且头部至少距离帧顶部 5%。
入场:轻跳入场
- 跳跃: 2–3 次,每次 300–450 毫秒,逐渐降低:第一次跳跃高度为角色高度的 8–12%,最后一次为 4–6%。水平移动覆盖相同的跨度,使用
ease-out缓出,以使最后一次跳跃轻柔落地。 - 姿态: 跳跃时手臂放下。在某一绘制帧上落地,并保持 150–300 毫秒后再做第一个手势。
- 时间: 在语音开始前完成跳跃,并至少留出 200 毫秒的余量。
- 检查: 在入场段使用
frame --from --to --keyframes命令。检查脚在每个落地时刻是否接触地板,并且没有部件拖后或超前于身体。
手势
手势是一个命名姿态,以及进入和离开该姿态的移动。为每个移动设置一个准备时间(规范的 in 参数),使得姿态在开始动作前能够保持住。
- 放下手臂: 从手臂伸出的静止姿态开始,将每个上臂向身体方向转动 40–55°,前臂再额外转动 5–15°。
- 挥手: 上臂从静止位置向外侧抬起 40–50°,前臂再向上抬起 25–35°。前臂以肘部为支点,左右摆动 15–20°,周期为 350–450 毫秒,至少进行 2 次完整摆动(800 毫秒或更长)。抬得更高会导致手在摆动到内侧极限时位于头部后方:头部会绘制在手臂上方。
- 指向某物: 上臂几乎水平地指向目标(从手臂伸出并下垂的静止位置向上抬 10–25°),前臂几乎伸直(与水平线夹角在 20° 以内),使手对准目标的近边缘。在提到该目标的词出现前 1–3 帧到达。
- 欢呼: 两个上臂向上抬起 40–50°,前臂再向上抬起 20–30°。如果弯曲得更多,手会在超调峰值时藏在头后面。
- 移动: 在 250–400 毫秒内完成。使用贝塞尔曲线
[0.34, 1.56, 0.64, 1]实现超调效果到达姿态,并使用ease-in-out缓动回到静止姿态。对于随动效果,在上臂到达后 2–4 帧,添加一个只控制前臂的次要移动。 - 永不冻结: 头部在重读单词上倾斜 2–5°,作为一次短暂摆动或在 250–400 毫秒内往返移动。如果一个角色在超过 1.5 秒内没有任何移动地保持姿态,看起来会像静止图像。
- 检查: 对于每个手势,在烘焙报告列出的该关节极端角度的时间点使用
frame --at命令。检查手是否远离头部和帧边缘,并且姿态在无声状态下也能被识别为相应手势。然后,在抬起幅度最大的姿态下,以真实比例在肩部和肘部使用frame --crop命令,检查是否存在间隙或松动的部件。
根据视位进行唇形同步
烘焙过程会根据语音的视位文件写入嘴部。每个视位 ID 通过骨架的表格映射到一个嘴型,静默状态对应鸟喙或闭合的嘴唇,不叠加任何图案。在规范中指定语音元素和视位文件。嘴部随后会跟随该元素的开始时间和源范围,因此移动语音并重新烘焙即可保持同步。
- 最短形状: 2 帧。烘焙会将更短的形状合并到其前面的形状中,并报告每一次合并。在一个 6 秒的句子中出现十几次合并是正常的。
- 提前量: 0 毫秒。如果在渲染时感觉嘴部动作偏慢,可以提前一帧(30 fps 下为 33 毫秒),且不要超过一帧。
- 时间: 探测语音文件。当语音文件时长与视位文件的声明时长不一致时,以探测结果为准。
- 检查: 在三个口头单词的中间位置使用
query --at命令,检查每个时刻是否只有一个嘴部元素处于激活状态。然后,在最长的停顿中间以及句子结束后使用query --at命令,检查是否没有任何嘴部元素处于激活状态。
眨眼
- 时长: 3 帧(30 fps 下为 100 毫秒),最多 4 帧。
- 节奏: 每 2–4 秒一次,不规律,绝不要踩在节拍上。在某个大幅度移动落地后进行一次眨眼,在语音停顿期间进行一次。在任何 8 秒内至少眨眼 2 次。
- 避免: 不要在某个手势到达的同一帧进行眨眼,以免掩盖到达动作。
- 检查: 在一次眨眼的中间帧使用
frame --at命令,检查闭眼图像是否完全贴合头部,并符合头部的倾斜角度。