c++ - 如何计算 COLLADA 文件的父子 union 变换?

标签 c++ opengl matrix collada skeletal-animation

尝试实现索具:

  • 使用 Blender 创建了一个简单的操纵蛇测试并导出了一个 COLLADA 文件。
  • 我已经正确加载了顶点位置、权重和关节 ID。
  • 我已经为每个骨骼加载了骨架关节层次结构和这些变换(我加载了将所有浮点数转换为浮点数 [16] 的矩阵,然后我使用 glm::make_mat4(tmpFloatArray),然后我转置它,不确定是否这是正确的方法):
  •     <visual_scene id="Scene" name="Scene">
          <node id="Armature" name="Armature" type="NODE">
            <matrix sid="transform">1 0 0 0 0 0 1 0 0 -1 0 0 0 0 0 1</matrix>
            <node id="Armature_Bone" name="Bone" sid="Bone" type="JOINT">
              <matrix sid="transform">0.3299372 0.944003 -1.78814e-7 0 -4.76837e-7 0 -1 0 -0.944003 0.3299374 3.8743e-7 0 0 0 0 1</matrix>
              <node id="Armature_Bone_001" name="Bone.001" sid="Bone_001" type="JOINT">
                <matrix sid="transform">0.886344 -0.4630275 3.31894e-7 2.98023e-8 0.4630274 0.886344 -1.86307e-7 1.239941 -2.07907e-7 3.18808e-7 1 -2.84217e-14 0 0 0 1</matrix>
                <node id="Armature_Bone_002" name="Bone.002" sid="Bone_002" type="JOINT">
                  <matrix sid="transform">0.9669114 0.2551119 -1.83038e-7 -1.19209e-7 -0.2551119 0.9669115 1.29195e-7 1.219687 2.09941e-7 -7.82246e-8 1 0 0 0 0 1</matrix>
                  <node id="Armature_Bone_003" name="Bone.003" sid="Bone_003" type="JOINT">
                    <matrix sid="transform">0.8538353 0.5205433 1.0139e-7 -1.19209e-7 -0.5205433 0.8538353 2.4693e-7 1.815649 4.19671e-8 -2.63615e-7 1 5.68434e-14 0 0 0 1</matrix>
    
    现在,如果我将每个骨骼的矩阵设置为 glm::mat4(1),我会得到:
    Screenshot
    但是,如果我尝试乘以关节父变换,就像在 Thin Matrix rigging tutorial 中一样,我会得到非常奇怪的结果:
    void SkelManager::setTposeTransforms(std::vector<Joint>& _reference)
    {
        for (int child = 0; child < _reference.size(); child++)
        {
            if (_reference[child].parent == -1)
            {
                //_reference[child].tPose = glm::mat4(1);
                _reference[child].tPose = _reference[child].transform;
            }
            for (int parent = 0; parent < _reference.size(); parent++)
            if (_reference[child].parent == parent)
            {
                //_reference[child].tPose = glm::mat4(1);
                _reference[child].tPose = _reference[parent].tPose * _reference[child].transform;
            }
        }
    }
    
    Result of the above code
    请帮忙,我已经坚持了几个星期,但我没有成功,无论我多么努力地搜索网络,我都找不到任何有用的东西,关于我可能做错了什么的任何想法?

    最佳答案

    I use glm::make_mat4(tmpFloatArray), and then I transpose it, not sure if this is the correct way):


    请参阅 COLLADA 规范中关于矩阵的说明:

    Matrices in COLLADA are column matrices in the mathematical sense. These matrices are written in row- major order to aid the human reader. See the example.


    所以是的,你需要转置它。
    加载 COLLADA 的骨骼动画并不难。跟着这些步骤:
    进口方:
  • 加载所有关节节点层次结构,将关节变换与父节点相乘,直到根节点,就像对普通/其他节点(场景图)所做的那样。当每一帧的变换都改变时,最好做乘法...
  • 加载 Controller ->皮肤带有 的元素 union 编号 年代,重量 ... 还有 bind_shape_matrix INV_BIND_MATRIX
  • 加载动画对象[s] 以动画关节
  • 加载实例 Controller ,它存储 Material 和 <骨架> 指示关节层次结构的根节点在哪里的元素。这很重要,因为您需要从该元素开始解析 SID,而不是整个文档或场景中的顶部节点...

  • 渲染面:
  • 如果需要,为每个帧准备所有关节变换。与他们的 parent 相乘 union 变换
  • 为每个关节创建此矩阵:FinalJointTrans4x4 = JointTransform * InvBindPose * BindShapeMatrix union 转换 是与 parent 相乘的变换...
    绑定(bind)姿势 (或 InvBindMatrix)是您从 skin->joints->INV_BIND_MATRIX 为每个关节读取的变换
    绑定(bind)形状矩阵 是您从 skin->bind_shape_matrix 读取的变换
  • 将这些 FinalJointTrans4x4 矩阵和权重发送到着色器(统一的缓冲区可以很好地存储矩阵)
  • 在着色器中使用这些信息,渲染它。

  • 也许(来自 http://github.com/recp/gk ):
    ...
    mat4 skinMat;
        
    skinMat = uJoints[JOINTS.x] * WEIGHTS.x
            + uJoints[JOINTS.y] * WEIGHTS.y
            + uJoints[JOINTS.z] * WEIGHTS.z
            + uJoints[JOINTS.w] * WEIGHTS.w;
        
    pos4  = skinMat * pos4;
    norm4 = skinMat * norm4;
    
    ...
    
    #ifdef JOINT_COUNT
      gl_Position = VP * pos4;
    #else
      gl_Position = MVP * pos4;
    #endif
    ...
    
    我可能会忘记提及其他细节(稍后我可能会编辑答案),但这必须有很大帮助。
    PS:有一个名为 AssetKit ( http://github.com/recp/assetkit ) 的库,如果您愿意,可以使用它来加载 COLLADA 文件。

    关于c++ - 如何计算 COLLADA 文件的父子 union 变换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62971356/

    相关文章:

    c++ - 有没有办法将 C++ 数据类型作为变量返回?

    c++ - 重复计算的性能

    opengl - 使用 GPU 着色器错误进行失真校正

    c++ - 如何将未知大小的二维数组传递给函数

    python - 将矩阵保存为图像,恢复后不做任何更改

    matlab - 具有随机变量条目的矩阵的合适数据结构是什么?

    c++ - 基于 pthread_mutex 的进程间通信不起作用

    c++ - Qt中如何通知MySql Server关闭

    java - opengl 模具似乎没有效果

    opengl - MSAA 中的 GL_SAMPLE_ALPHA_TO_COVERAGE