前言
最近劲爆羊工具盒免费了,因此我怀着高兴的心情去挖掘里面众多工具的功能。
动画师那边刚好需要一个披风动态模拟关键帧的功能,而工具盒里面内置了 动画飘带工具 刚好解决了需求。 链接
这个飘带工具原本需要花费一丢丢的钱的,但是可爱的羊神完全免费了。
使用了一段时间之后,发现工具的性能有很严重的问题。
一个短小精悍的20-30帧动画都需要处理个几分钟甚至十几分钟。
我翻开源码看了下,原来是个mel脚本,于是就开始着手工具的优化
当前测试 | 动画演示
制作了一个简单的控制器动画,可以理解为 手臂的 FK 控制器。
就是个简单的举高高动作。
上面是我将插件最后一步烘焙到控制器的操作去掉。
然后打开debug模式生成中间 locator 效果。
可以看到插件会根据选择的控制器生成层级骨骼,然后再生成辅助的locator将骨架变成柔软过渡的效果。
最后我代码去掉的部分就是骨架动画约束到控制器上然后 烘焙关键帧。
原理分析
生成层级骨架
根据选择的控制器顺序,生成骨架,并且将骨架的朝向调整好.
然后复制最后一个关节。
然后执行move -r -ls -wd 2 0 0 ;
命令,再整理骨骼的朝向。
这样骨骼就会沿着上一根骨骼的旋转方向的 X 轴进行偏移。
最初我不太理解为什么是拿上一根骨骼的X轴方向偏移。
执行代码应该沿着红色轴方向移动才是。
结果却出乎意料了。
原来当我选中 X 通道的时候看到的移动方向才知道原来是继承上一根骨骼的方向。
这样运动就可以确保骨架偏移在正确的朝向上。
约束骨架 | 烘焙关键帧
将选择控制器约束骨架,并且将约束关系转成关键帧关系
层级关系如下图
生成辅助 locator
下面进入 for 循环遍历生成运动效果
生成 offset locator ,位置偏移取决于 scale 属性
生成 IK locator ,位置和控制器保持一致
后续让控制器保持偏移对locator进行父子约束并将运动烘焙为关键帧。
然后生成一个 wind locator 到 offset_loc 上
关键帧处理
这里抽出其中一个 offset locator 进行讲解
上面烘焙玩的关键帧如上图
后续需要对旋转的关键帧进行欧拉过滤
然后根据 softness 属性对关键帧曲线进行偏移,这里往右偏移了 3 帧。(注意 IK locator 不处理旋转)
然后将偏移之后的初始帧选上,继而将这一帧挪动回初始位置上。
下面是处理后的动画演示↓↓↓ (注意 IK 的旋转没有处理完全根随控制器旋转角度的)
生成骨架 locator
在骨架层级下生成相关的 locator
由于这里没有关键帧偏移的关系,这些locator会和之前的locator产生3帧的时间差
约束处理
将 wind locator 和 second locator 添加父子约束,当前两者的位置是完全重合的。
然后将 second locator 添加 目标约束 到 aim_grp 上 ,确保层级里面的 first locator 指向 second locator
透过层级关系可以看到因为 offset locator 可以控制到 first locator 的朝向
后续就是将 second locator 约束 first locator 的 x 旋转轴
然后将 first locator 约束到 result locator 上
最后输出的 result locator 大概就是指向 second locator 效果的运动
然后将 result locator 的运动烘焙成关键帧
out locator 超神操作
好了现在要将 result locator 的保持偏移约束到 新生成在原点的 out locator 上
相信大家看到这里一定会很困惑,我擦这是什么鬼操作,能生成出柔软的关键帧吗?!
我当时也完全不理解。
直到我将最后一行超神代码输进去之后明白其中的奥妙。
将 out locator 约束到之前的骨骼层级上。
震惊了吧,这行代码怎么就可以让效果这么好。
其实我上面演示的大部分效果都是错误的,因为我忘记了这个操作是在循环里面。
因此最后一行的操作会影响到后面每次循环生成 locator 的位置的
虽然是错误的结果,但是我自己摸索也是这么摸石头过河过来了(:з」∠)
视频录制
总结教训
一开始挖掘插件的效率极低,因为不知道mel代码的执行效果,只能注释运行、注释运行重复来查看效果。
后面看懂了一部分之后就开始讲mel语句转换成 python 加深理解,结果还产生了非常多的 BUG 浪费时间。
后来才发现原来工具有 Debug 模式,可以保留生成过程中的中间节点。
研究这些中间节点的作用才逐渐明白这一个工具的运行原理。
结果搞这个小插件花了 两天时间,实在不值得(:з」∠)
后续
录制视频的过程中发现了 VScode Debug 其实并不太友好,于是我打算开发一个 Maya Python Debugger 来解决这个问题。
因此这篇文章暂时拖更了,等 Debugger 开发好之后再进一步剖析。