六六の魔法世界

注册

Maya技能 - 技术分享 - 2022年8月29日

[Maya] 冻结已经蒙皮的骨骼

[Maya] 冻结已经蒙皮的骨骼

在maya里调节骨骼位置,设定骨骼方向时,经常会出现这样的警告提示:

// Warning: line 0: Skipping joint1: It has non-zero rotations.

原因就是在设定骨骼方向时,骨骼的旋转不能是0以外的数值。

  • 如果是没有影响蒙皮的骨骼的话,可以使用maya默认的冻结变换先把骨骼的变换清零再重新设定骨骼的方向。但如果是影响蒙皮的骨骼的话,在冻结的时候会出现另外一个错误提示:
// Error: line 1: Freeze Transform or Reset Transform was not applied because node joint1 is a joint and has skin attached.

这种情况下就只能手动冻结骨骼的变换信息了。和transform节点不同,joint节点在冻结旋转之后,旋转方向不会消失,而是会存储在joint orient里面。

Joint orient就像是在这个骨骼和他的父节点的骨骼之间夹着的一个transform节点,用来存储这个骨骼本身的朝向。 整个关系可以浅显的理解为:
父节点骨骼
↓(旋转A)
子节点骨骼joint orient
↓(旋转B)
子节点骨骼旋转

手动冻结旋转的目标就是把旋转A和旋转B相加为一个旋转,并把它设定为骨骼的joint orient,再把骨骼的旋转设为0。像这样:
父节点骨骼
↓(旋转Σ = 旋转A+旋转B)
子节点骨骼joint orient
↓(旋转C = 0)
子节点骨骼旋转

在骨骼的joint orient都是0的情况下,可以把骨骼的rotate x,y,z分别手动复制到joint orient的x,y,z里,再把rotate x,y,z都设为0。这样手动冻结旋转就完成了。在joint orient不是0的情况下,由于joint orient是父节点骨骼坐标下的信息,rotate是在joint orient坐标下的旋转信息,这两个坐标不一样的旋转单纯相加的话,骨骼会朝向不同的方向,造成这个骨骼的子节点出现在其他的位置上,以及蒙皮的模型出现变形。

要想正确计算旋转A和旋转B的叠加涉及到一些矩阵运算,但也可以灵活利用maya的xform命令里的坐标flag让maya替我们算这个旋转叠加。具体步骤是:
1. 求出当前骨骼在世界坐标下的旋转
2. 把骨骼的joint orient清零,清零后骨骼的方向会暂时发生变化
3. 把之前求得的世界坐标下的旋转以物体坐标设为骨骼的旋转
4. 把骨骼的旋转复制给joint orient
5. 把骨骼旋转清零
写成python脚本的话如下:

import maya.cmds as cmds
def freezeJntRot():
    slct = cmds.ls( sl = 1, type = 'joint' )
    for jnt in slct:
        rot = cmds.xform( jnt, q = 1, worldSpace = 1, rotation = 1 )
        cmds.setAttr( jnt + '.jointOrient', 0, 0, 0, type = 'double3' )
        cmds.xform( jnt, worldSpace = 1, rotation = rot )
        newRot = cmds.xform( jnt, q = 1, objectSpace = 1, rotation = 1 )
        cmds.setAttr( jnt + '.jointOrient', newRot[0], newRot[1], newRot[2], type = 'double3' )
        cmds.setAttr( jnt + '.rotate', 0, 0, 0, type = 'double3' )
freezeJntRot()

这样就可以在不影响子节点和蒙皮模型的情况下冻结已经蒙皮的骨骼的旋转了。

“本文转载自tong si