将非层次变换应用于层次骨架? [英] apply non-hierarchial transforms to hierarchial skeleton?

查看:36
本文介绍了将非层次变换应用于层次骨架?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Blender3D,但答案可能不是 API 独有的.

I use Blender3D, but the answer might not API-exclusive.

我有一些矩阵需要分配给 PoseBones.当没有骨骼层次(父母)时,生成的姿势看起来很好,当有时就乱七八糟.

I have some matrices I need to assign to PoseBones. The resulting pose looks fine when there is no bone hierarchy (parenting) and messed up when there is.

我在此处上传了一个档案,其中包含装配模型、文本动画导入器和测试动画文件的混合示例:http://www.2shared.com/file/5qUjmnIs/sample_files.html
通过选择一个骨架并在sba"文件上运行导入器来导入动画.对两个骨架都执行此操作.

I've uploaded an archive with sample blend of the rigged models, text animation importer and a test animation file here: http://www.2shared.com/file/5qUjmnIs/sample_files.html
Import the animation by selecting an Armature and running the importer on "sba" file. Do this for both Armatures.

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

This is how I assign the poses in the real (complex) importer:

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

如果我进入编辑模式,选择所有骨骼并按 Alt+P 取消父级,则姿势再次看起来不错.

If I go to edit mode, select all bones and press Alt+P to undo parenting, the Pose looks fine again.

API 文档说 PoseBone.matrix 位于对象空间"中,但从这些测试中我似乎很清楚它们与父骨骼相关.

The API documentation says the PoseBone.matrix is in "object space", but it seems clear to me from these tests that they are relative to parent bones.

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

Final 4x4 matrix after constraints and drivers are applied (object space)

我尝试做这样的事情:

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

但看起来更糟.尝试了操作顺序,但一切都没有运气.

But it looks worse. Experimented with order of operations, no luck with all.

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

For the record, in the old 2.4 API this worked like a charm:

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 参考链接:

Link to 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

推荐答案

'object space' 可能确实意味着相对于父骨骼.您可以通过乘以父变换矩阵的逆矩阵来从全局转换为局部.您可能还会发现您需要乘以所有父逆变换的串联:乘以 B1 * inverse(B0) 和 B2 * (inverse(B1) * inverse(B0)).

'object space' probably does mean relative to the parent bone. You can convert from global to local by multiplying times the inverse of the parent transform's matrix. You may also find that you'll want to multiply by the concatenation of all parent inverse transforms: multiply B1 * inverse(B0), and B2 * (inverse(B1) * inverse(B0)).

这是一些执行类似操作的示例代码(在 Panda3D 中,而不是 Blender,但总体思路相同).我们从 3 个具有全局位置和旋转值的骨骼开始,将它们放在一起,然后将全局坐标转换为正确的局部矩阵.

Here's some example code that does something similar (in Panda3D, not Blender, but same general idea). We start off with 3 bones with global position and rotation values, parent them together, and convert the global coordinates into the correct local matrices.

    # 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)

这篇关于将非层次变换应用于层次骨架?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆