原文链接
在 blender 中使用 python 生成角色动画(二)- nla 非线性动画| 包包凯
正文
初衷
在上一期中介绍了如果通过 Python 自动化的在 Blender 中实现 关键帧的插入,如果只是简单的控制单独的几个变量的话,已经够用了。
但是如果是这样一个场景,希望在某个时间段让角色跳个舞,那需 要控制的骨骼数量过多,而且由于无法即时可视化,用 Python 来一一控制的可能性几乎为 0。
所以我们可以把这一段舞蹈动作预先在 Blender 工程中通过 动作编辑器 将其保存为一个动作,后面单独控制这个动作在时间线的位置即可。而 把动作加入时间线 就需要用到 NLA 非线性动画。
实现
1. 动作编辑器
动作编辑器的使用和普通的关键帧动画使用 没有区别,只是 记得要更改动作名称,并且完成一个动作后,要将其 保存 到动作堆栈中。
- 动作编辑器
2. 非线性动画
非线性动画界面如下所示:
- NLA 非线性动画界面
可以看到,每个实体(object
)有一条 单独的轨道,轨道上面的圆点是前面在 动作编辑器 / 时间线 中添加的关键帧,这些关键帧一般在 NLA 中不会做修改。
完成了前面的动作存放后,可以在 NLA 界面中看到存放的动作,位于轨道 [Action Stash]
上。
我们要实现的脚本功能类似 NLA 。
3. 控制 NLA 的 Python 脚本
该脚本的作用:将 指定动作 添加到 对应实体 的 指定动画轨道 的 特定时间段 上
import bpy
def add_action_to_nla(obj_name, track_name, action_name, frame_num):
# 在 NLA 中,按照 object 进行分组,如果是控制骨骼动作,故先获取到 `骨骼实体`,对其进行插入轨道 (nla_tracks) 操作
ob = bpy.data.objects[obj_name] # !!!关键语句
# action 是已经做好的动作,在 `动作编辑器` 中制作完成后,存放到非线性动画堆栈中但暂时不启用,而是等待被调用
action = bpy.data.actions[action_name] # !!!关键语句
if action is not None:
# 1. 新建轨道:如果已经有同名轨道的话,就不新建
has_track = False
if track_name in ob.animation_data.nla_tracks.keys():
track1 = ob.animation_data.nla_tracks[track_name]
else:
track1 = ob.animation_data.nla_tracks.new() # !!!关键语句
track1.name = track_name
# 2. 冲突判断:由于同一个轨道上面,多个动作不能重叠,
# 如果要做 `动作混合`,可以新建一个轨道,这里不需要动作混合,如果有重叠,就直接返回错误
for act_ani in track1.strips:
exist_act = act_ani
action_len = action.frame_range[1] - action.frame_range[0]
action_start = frame_num
action_end = int(action_start + action_len)
if action_start in range(int(exist_act.frame_start), int(exist_act.frame_end)) or \
action_end in range(int(exist_act.frame_start), int(exist_act.frame_end)) or \
int(exist_act.frame_start) in range(action_start, action_end) or \
int(exist_act.frame_end) in range(action_start, action_end):
return False
# 3. 将动作加入到 NLA 中的对应轨道的对应时间段
track1.strips.new(action.name, frame_num, action) # !!!关键语句
return True
else:
return False
if __name__ == "__main__":
# 测试
print(add_action_to_nla("armature", "my_track", "user_action", 1))
# print(add_action_to_nla("armature", "[Action Stash]", "user_animation", 1))
运行后可以看到动作已经被加入到 my_track
轨道上面,可在渲染时生效了。