【转载】在 Blender 中使用 Python 生成角色动画(一)

639 阅读4分钟

原文链接

在 blender 中使用 python 生成角色动画(一)| 包包凯

正文

初衷

在一些具体使用场景上,我们希望能够 根据不同的语音,自动生成对应的卡通角色动画,以节省大量的 3D 动画师的工作,故通过脚本生成动画是必要的技术。

为什么选用 Blender

轻巧、免费、够用,另外 Python 平时也用的多。

整体流程

整体流程如下:

本文对应 输入部分 不做过多描述,仅对 动画生成渲染部分 进行说明。即假设目前已经有包含输入信息,包括:

  • 语音:一般为 TTS 生成的语音
  • 断句时间点:即语音中每一句话的起始时间点
  • 语句情绪:即语音中每句话对应的情绪
  • 嘴型:即和时间线对齐的嘴型参数,用于指导嘴型动画

动画生成

使用的模型

使用的模型如下,其中眼睛和嘴部包含了 BlendShape ,眼睛可以上下左右移动,嘴巴可以上下张合和左右扩展。

由于卡通角色比较简单,所以骨骼也做了大幅简化。

  • 演示模型

该模型 保存了动作在动作库(Blender3.0 的新功能),如下所示包含了两个动作:standhappy,后面会使用。

  • Blender 动作库

Python 控制

以下说明没有按照以上流程图的步骤来进行,而是按照类别的不同进行说明,具体每个步骤如何生成在此不进行赘述。

动画生成包含以下部分:

  • BPY 控制的内容

1. BPY 控制形态键

# shape_keys -> key_blocks
shapekey = bpy.data.shape_keys.get("Key_eye")   # 找到对应的形态键组
key_block = shapekey.key_blocks.get("eye_look_right")  # 一个组中可能有多个 key
key_block.value = x # 对形态键赋值
key_block.keyframe_insert(data_path="value", frame=frame_id) # 插入关键帧

形态键组 可以在大纲视图中查到:

  • 形态键组 image.png

对应的 形态键 为(建模时做的):

  • 形态键 image.png

如本项目中,对于眼睛,随机插入关键帧使其有随机的小幅度移动;对于嘴,则根据口型来控制其张合和扩展。生成的动画摄影表如下:

  • 形态键的动画摄影表

2. BPY 控制骨骼移动旋转

# pose -> bones -> rotation_euler
ob = bpy.data.objects['armature']
head=ob.pose.bones['head']
head.rotation_mode = 'XYZ'   # 旋转有不同的模式,这里采用的是 XYZ 的模式
head.rotation_euler.rotate_axis("X", x)
head.rotation_euler.rotate_axis("Y", y)
head.rotation_euler.rotate_axis("Z", z)
head.keyframe_insert(data_path="rotation_euler" ,frame=frame_id)  # 将旋转角度信息插入关键帧

和控制 形态键 类似,只是操作对象和参数不同,这里对头部和身体做随机的转动,生成的 动画摄影表 如下:

  • 单个骨骼的动画摄影表

3. BPY 使用姿态库资源

由于有很多复杂的 动作,不可能都在代码里面控制一根根骨骼来实现,故在 Blender 中可以先制作 一批固定的动作,然后直接将其 应用到姿态后,再(针对 位置旋转插入关键帧 即可。

ob = bpy.data.objects['armature']

# 将 happy 姿态插入第 1 帧
act = bpy.data.actions.get("happy")
ob.pose.apply_pose_from_action(act)

for bone in ob.pose.bones:
    bone.keyframe_insert(data_path="rotation_euler", frame=1)
    bone.keyframe_insert(data_path="location", frame=1)
    
# 将 stand 姿态插入第 10 帧
act = bpy.data.actions.get("stand")
ob.pose.apply_pose_from_action(act)

for bone in ob.pose.bones:
    bone.keyframe_insert(data_path="rotation_euler", frame=10)
    bone.keyframe_insert(data_path="location", frame=10)

PS: 这里有一点需要 注意 的是,旋转有 四元数 形式或者 XYZ 形式,这个是不互通的,即

  • 如果姿态库的姿态是在 四元数 形式做的话,设置的变量就是 data_path = "rotation_quaternion"
  • 如果是 XYZ 形式的话就是 data_path = "rotation_euler"

更加灵活的动作控制可以参考 【转载】在 Blender 中使用 Python 生成角色动画(二)- NLA 非线性动画 ,即它可以单独控制某个动作在时间线的位置,也就是说可以将动作保存(动作编辑器),继而加入到对应实体的对应 动画轨道 上(NLA

后台渲染

1. 在 Blender 中预设渲染属性

实际上渲染属性,如帧率、分辨率等都 可以使用 Python 脚本来控制,不过这里就直接在 Blender 里面设置了。

image.png

2. 后台渲染

由于后续需要支持自动化生成,故 命令行的方式 进行后台渲染是必要的。Blender 可以很方便的支持后台渲染:

CHCP 65001  
blender -b xxx.blend -P xxx.py -a

在输出目录可以看到结果。

最终效果

以下效果仅验证 BPY 控制,未针对断句等进行处理。

后续工作

后面还会研究如何通过脚本生成动画

90379556-bb02-11ec-ab97-e24cfd1fdd7b-v4_t10000011-wend7D50Se 00_00_00-00_00_30.gif