将非分层变换应用于分层骨架?

时间:2012-07-30 13:17:02

标签: animation 3d matrix blender blender-2.61

我使用的是Blender3D,但答案可能不是API独占的。

我有一些我需要分配给PoseBones的矩阵。当没有骨骼层次结构(父母教养)时,结果姿势看起来很好,当有骨骼层次结构时,它会搞砸。 enter image description here

我上传了一个存档,其中包含绑定模型,文本动画导入器和测试动画文件的示例混合: http://www.2shared.com/file/5qUjmnIs/sample_files.html
通过选择Armature并在“sba”文件上运行导入器来导入动画。 为两个Armatures都这样做。

这就是我在真实(复杂)导入器中分配姿势的方法:

matrix_bases = ... # matrix from file
animation_matrix = matrix_basis * pose.bones['mybone'].matrix.copy()
pose.bones[bonename].matrix = animation_matrix

如果我进入编辑模式,选择所有骨骼并按Alt + P撤消育儿,Pose再次显示正常。

API文档说PoseBone.matrix位于“对象空间”,但我从这些测试中可以清楚地看出它们与父骨骼相关。

  

应用约束和驱动程序后的最终4x4矩阵(对象   空间)

我尝试过这样的事情:

matrix_basis = ... # matrix from file
animation_matrix = matrix_basis * (pose.bones['mybone'].matrix.copy()  * pose.bones[bonename].bone.parent.matrix_local.copy().inverted())
pose.bones[bonename].matrix = animation_matrix

但看起来更糟。通过操作顺序进行实验,没有运气。

为了记录,在旧的2.4 API中,这就像一个魅力:

matrix_basis = ... # matrix from file
animation_matrix = armature.bones['mybone'].matrix['ARMATURESPACE'].copy() * matrix_basis
pose.bones[bonename].poseMatrix = animation_matrix

pose.update()

链接到Blender API ref:

http://www.blender.org/documentation/blender_python_api_2_63_17/bpy.types.BlendData.html#bpy.types.BlendData

http://www.blender.org/documentation/blender_python_api_2_63_17/bpy.types.PoseBone.html#bpy.types.PoseBone

1 个答案:

答案 0 :(得分:0)

'对象空间'可能意味着相对于父骨骼。您可以通过乘以父变换矩阵的倒数来从全局转换为局部。您可能还会发现,您希望乘以所有父逆变换的串联:乘以B1 *逆(B0)和B2 *(逆(B1)*逆(B0))。

这是一些做类似事情的示例代码(在Panda3D中,不是Blender,但是一般的想法)。我们从3个具有全局位置和旋转值的骨骼开始,将它们组合在一起,并将全局坐标转换为正确的局部矩阵。

    # Load three boxes ('bones'), give them global position and rotation
    # each is 3 units long, at a 30 degree angle.  

    self.bone1=loader.loadModel("box.egg")
    self.bone1.reparentTo(render)

    self.bone2=loader.loadModel("box.egg")
    self.bone2.reparentTo(self.bone1)

    self.bone3=loader.loadModel("box.egg")
    self.bone3.reparentTo(self.bone2)

    ''' 
    equivalent code, in local coordinates
    self.bone1.setPos(0,0,0)
    self.bone1.setHpr(0,0,30)

    self.bone2.setPos(0,0,3)
    self.bone2.setHpr(0,0,30)

    self.bone3.setPos(0,0,3)
    self.bone3.setHpr(0,0,30)
    '''

    # give each a global rotation value

    R1=Mat4()
    R1.setRotateMat(30,Vec3(0,1,0))

    R2=Mat4()
    R2.setRotateMat(60,Vec3(0,1,0))

    R3=Mat4()
    R3.setRotateMat(90,Vec3(0,1,0))

    # set global translation values

    T1=Mat4()

    # position of bone 2 in global coords
    T2 = Mat4.translateMat(1.271,0,2.606) 

    # position of bone 3 in global coords
    T3 = Mat4.translateMat(3.782,0,4.036) 

    # set the matrix for bone 1
    M1 = R1 * T1
    self.bone1.setMat(M1)

    # get inverse of matrix of parent
    I1 = Mat4()
    I1.invertFrom (M1)

    # multiply bone2 matrix times inverse of parent

    M2 = R2 * T2
    M2 = M2 * I1

    self.bone2.setMat(M2)

    # get inverse of parent for next bone 

    I2 = Mat4()
    I2.invertFrom(M2)

    M3 = R3 * T3
    # notice that M3 * I2 isn't enough - needs to be M3 * (I1 * I2)
    M3 =  M3 * (I1 * I2)

    self.bone3.setMat(M3)