【教程】口型速切控制器(脚本分享)

相信很多动画绑定师都有做过用控制器来控制 blendshape。在涉及到多个口型 blendshape 的时候,尤其是 AEIOU 这种同类口型时,经常就是其中一个拉到 1,另外几个拉到 0,K 的数量多了就不免有些繁琐。于是我想了个办法用一个控制器来控制多个同类口型。

首先确定一下最终效果:我想要中间的控制器回到圆心时,所有的 blendshape 为 0,当控制器从中心移动到某个字母上时,那个字母对应的 blendshape 为 1,其余为 0。当控制器从一个字母移动到另一个字母时,这两个 blendshape 之间也会混合。

一个控制器控制多个BlendShape
我这里使用 blender 来实现,并配合 python 来做一些批处理工作。后文我将用 blender 里的 shapekey 来称呼 blendshape。
前置知识:
Blender 基础知识
驱动器使用经验
一点点 Python 基础
向量和三角函数相关数学基础
1、准备一个带有 shapekey 的模型;
2、创建控制器(可根据自己的情况自定义):

1)创建一个圆环作为整个控制器的父级;
2)创建一个任意形状的物体作为主要控制器,并将其作为圆环的子级(无反向),置于圆环的原点;

3)创建一个名叫 DriverSources 的集合,将主要控制器添加到该集合中;(提示:在控制器的“物体”选项卡中的“集合”折叠栏中操作)
4)根据实际情况创建多个 3D 文字物体,一一对应要控制的 shapekey ,并作为圆环的子级(无反向),均匀排列到圆环上;

5)创建一个名叫 DriverTargets 的集合,将所有 3D 文字添加到该集合中;

3、编写 Python 脚本:
1)切换到 Scripting 界面,新建文本;
2)复制我的提供的脚本添加到文本编辑器;

3)在大纲视图展开 shapekey 物体数据块下的网格数据块,查看 shapekey 数据块的名称,并将该名称赋给脚本第 7 行的 shape_key 变量


4)在左边的控制台输入:
targets = bpy.data.collections["DriverTargets"].objects
for obj in targets:
print(obj.name)
敲两下回车运行脚本,根据打印出来的结果(即 DriverTargets 集合里所有物体的名称),在脚本第 8 行的数组里“按顺序”一一填入对应的 shapekey 名称(不是物体名称);

5)点击运行脚本按钮;
至此应该出效果了。

import bpy # 引入Blender的Python模块
import math # 引入数学模块
import mathutils # 引入数学实用工具模块
# 获取DriverTargets和DriverSources集合下的物体列表
targets = bpy.data.collections["DriverTargets"].objects
sources = bpy.data.collections["DriverSources"].objects
# 获取ShapeKey名称和其所包含的KeyBlocks列表
shape_key = ""
key_blocks = []
# 自定义驱动器函数
def drive_shape(index):
d = min(sources[0].location.length / targets[index].location.length, 1.0)
a = sources[0].location.normalized()
b = targets[index].location.normalized()
angle = a.dot(b)
angle = min(max(angle,-1.0),1.0)
angle = math.asin(angle)/math.pi*2
angle = (angle-1.0)/4*len(targets)+1.0
angle = angle*d
return angle
# 将自定义函数添加到驱动器命名空间
bpy.app.driver_namespace["drive_shape"] = drive_shape
# 对于每个Key
for i in range(len(key_blocks)):
# 清除旧有的驱动器,并添加新的驱动器
bpy.data.shape_keys[shape_key].key_blocks[key_blocks[i]].driver_remove("value")
fc = bpy.data.shape_keys[shape_key].key_blocks[key_blocks[i]].driver_add("value")
# 添加变量
var1 = fc.driver.variables.new()
var1.name = "src_scale"
var1.type = "SINGLE_PROP"
var1.targets[0].id = sources[0]
var1.targets[0].data_path = "scale[0]"
# 书写表达式
fc.driver.expression = "drive_shape(%d)" % i