2

Trying to implement rigging:

  • Created a simple rigged snake test with Blender and exported a COLLADA file.
  • I've loaded vertex positions, weights and joint IDs correctly.
  • I've loaded the Skeleton joint hierarchy and these transforms for each bone (I load matrices taking all the floats into a float[16], and then I use glm::make_mat4(tmpFloatArray), and then I transpose it, not sure if this is the correct way):
    <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>

Now if I set each bone's matrix to glm::mat4(1), I get this:

Screenshot

But if I try to multiply by a joints parent transform, like in the Thin Matrix rigging tutorial, I get very weird results:

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

Please help, I've been stuck on this for a couple weeks and I've had no success, and no matter how hard I search the web I can't find anything that works, any ideas on what I could be doing wrong?

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56

1 Answers1

1

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

See COLLADA spec's about matrix:

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.

so yes, you need to transpose it.

It is not so hard to load COLLADA's skeleton animations. Follow these steps:

Importer side:

  1. Load all joint node hierarchy, multiply joint transform with parent until root node as you do for normal/other nodes (scene graph). It is better to do multiplication when transforms are changed for each frame...
  2. Load Controller->Skin element with joint IDs, weights... also bind_shape_matrix and INV_BIND_MATRIX
  3. Load Animation object[s] to animate joints
  4. Load instance_controller, it stores material and <skeleton> element which indicates where is the root node for joint hierarchy. It is important because you need to start resolve SID from that element not entire document or top nodes in scene...

Render side:

  1. Prepare all joint transforms for each frame if needed. Multiply joint transforms with their parents

  2. Create this matrix for each joints:

    FinalJointTrans4x4 = JointTransform * InvBindPose * BindShapeMatrix

    JointTransform is the transform that multiplied with parents...

    InvBindPose (or InvBindMatrix) is the transform you read from skin->joints->INV_BIND_MATRIX for each joints

    BindShapeMatrix is the transform that you read from skin->bind_shape_matrix

  3. Send these FinalJointTrans4x4 matrices and weights to shader (a uniform buffer would be good to store matrices)

  4. Use these information in the shader, render it.

Maybe (from 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
...

There may other details that I may forgot to mention (I may edit the answer later) but this must help a lot.

PS: There is a library called AssetKit (http://github.com/recp/assetkit) you can use it to load COLLADA files if you like.

recp
  • 383
  • 1
  • 2
  • 14
  • Thank you so much for answering! I'm trying to do things slowly, for now, I'm looking to get the default pose, I'm guessing that I need to get a matrix for each joint with no rotation or translation but with an offset, right? when I transform transform one of the joint matrices, the children move with it correctly, but it rotates on a wrong point. Also can't find the INV_BIND_MATRIX, and no matter how many times I read it, I don't get it because of all these new terms. But thanks so so much for the answer! If you could specify how to calculate the offset, I think I can manage the rest .Thx!. – Franc Pujolar Jul 20 '20 at 13:13
  • You must be able to find `INV_BIND_MATRIX` as ``. It is needed because you need to transform your mesh to bone's space from object space. Then if you transform bones/joints then mesh will follow that. Follow the steps above and create `FinalJointTrans4x4` matrix as I mentioned – recp Jul 20 '20 at 16:26
  • A tutorial you could follow http://www.wazim.com/Collada_Tutorial_1.htm – recp Jul 20 '20 at 16:27
  • recp, I read the tutorial you said in 100% detail, and now it sort of works better but still not 100% well, if you have a minute, could you explain this as if I was a monkey, like: in the initialization, take this from the collada file and multiply it by this other thing of the collada file, then in the update do this and this, please, it would help so much, i've been stuck here for so long :(((( and this stuf is known by a very small ammount of people – Franc Pujolar Jul 20 '20 at 18:36