这几天把物理模拟框架移植到maya之中了。
maya编程有一点比较关键,就是要让自己的程序逻辑适应maya的节点求值机制。在物理模拟中,往往需要进行时间积分,对此我的解决办法是,写一个节点rigSimulator,存放模拟的状态数据(例如: 位置、速度、加速度、过去模拟的结果),再写一个mel命令rigSimulate,让指定的节点进行求值。模拟的主循环是一个mel 脚本,伪代码如下
int $t = 0; for ($t = $begTime; $t < $begTime + $length; $t++) { // 设置当前时间 currentTime $t; // 对指定节点执行计算,结果存在节点内部 int $res = `rigSimulate -step -name $nodeName`; if($res == 0) break; }
节点的属性如下:
Rigged Mesh为受到参数控制的网格
Mesh Transform为网格变换矩阵
Rig Parameter为控制网格变形的参数,是一个数组
节点的属性编辑器面板如下:
用法是先设置好物理参数,点Initialize,然后设置模拟的长度,点Simulate开始模拟,模拟过程中可以按ESC退出。
前两个参数控制四面体网格化的精细程度。
Young Modulus 为杨氏模量,与模型硬度有关。
Nu是不用轴向变形的影响程度。
Density是密度。
Step Time为每步的时间间隔,初始设置为1/24秒。
节点进行模拟时,需要获得给定参数下的网格形状。具体的做法是先设置Rig Parameter,然后读取Rigged Mesh,此时Maya便会对节点求值,返回一个被参数控制的网格。
模拟后的结果存在节点内部,一旦节点的draw函数被调用,节点会首先根据当前帧查找对应的模拟结果,再显示出来。
下图显示一个体网格化之后的圆柱体。
我给这个圆柱体加了一个平移动画,以及一个弯曲变形器。希望做出圆柱体移动的时候弯曲的效果。
节点求值网络如下:
这个是原来节点的动画
这个是模拟之后的动画。
最后说一点,就是模拟过程中按ESC退出功能的实现。这个功能虽然不是核心功能,但是却对程序调试带来方便。下面贴出代码:
global proc execSimulator(string $nodeName) { // 获取模拟长度 int $length = `intSliderGrp -query -value simLengthSlider`; // 设置进度条属性, -isInterruptable 表示能用ESC终止 global string $gMainProgressBar; // 这个全局变量由Maya定义,表示界面左下角的进度条 progressBar -edit -beginProgress -isInterruptable true -status "Simulating... " -maxValue $length $gMainProgressBar; int $begTime = `currentTime -q`; int $t; for ($t = $begTime; $t < $begTime + $length; $t++) { // 若发现ESC被按下,中止模拟 if(`progressBar -query -isCancelled $gMainProgressBar`) break; progressBar -edit -step 1 $gMainProgressBar; // 否则继续模拟 currentTime $t; // 移动时间滑块到下一帧 int $res = `rigSimulate -step -name $nodeName`; // 执行模拟命令 if($res == 0) break; } // 模拟结束,不再显示进度条,同时鼠标指针回复正常 progressBar -edit -endProgress $gMainProgressBar; }
估计有人会说“你这个只用Maya也能做到啊”,没错,而且这个插件现在还不完善。
其实,下一步还有功能要实现,例如给某些自由参数一些指导,而不是让它们完全自由。我把代码移植到maya的目的是在实现这些下一步的功能时,有个方便调试的平台(其中一个好处就是,不用自己实现maya的各种变形器)。
当前的问题,以及下一步的改进有如下几点:
1. 发现多个控制参数的时候模拟结果存在问题。不知道是不是雅可比矩阵的导数算错了的缘故。下一步需要检查。
2. 不能处理有洞的网格,估计自相交的也不行。
3. 暂时只支持corotational模型,不支持其他本构模型,例如NeoHookean。
4. 没有使用BFGS算法。
5. Rig Space Physics文中提及的硬度控制、反向运动学没有实现。
6. 把模拟出来的参数转成动画曲线,这一步估计用mel可以完成。
接下来几天可能要转向Python、Lua学习了。等这两个任务搞定了,再接着完成这些改进,到时候可以考虑尝试在maya用python编程。