0
\$\begingroup\$

Everything is almost ready 😣. I do not understand what the problem is.

The animation works, but some vertices are not where they should be.

enter image description here

I am using an SMD file from Half Life. I found that these vertices have a parent bone at index 2. "Bip01 Pelvis" This bone is in the right place - at the height of the pelvis.

version 1
nodes
  0 "Bip01"  -1
  1 "Bip01 Footsteps"   0
  2 "Bip01 Pelvis"   0
  3 "Bip01 L Leg"   2
  4 "Bip01 L Leg1"   3

Here is my code:

Animation:

// void modelUpdate()...
Mat4 TranslationM;
TranslationM[3] = objJoint.m_position;
TranslationM[3].w = 1.f;

Mat4 RotationM;
RotationM.setRotation(objJoint.m_rotation);

Mat4 NodeTransformation = TranslationM * RotationM;

if (mdlJoint->m_parentIndex != -1)
{
    objJoint.m_globalTransformation =
        m_joints[mdlJoint->m_parentIndex].m_globalTransformation
        * NodeTransformation;
}
else
{
    objJoint.m_globalTransformation = NodeTransformation;
}

objJoint.m_finalTransformation = objJoint.m_globalTransformation * mdlJoint->m_matrixOffset;

objJoint.m_finalTransformation - matrix for shader

Here how I read bind pose:

Mat4 R;                 
SMDAngleMatrix(v3f(nt.m_rotation.y, nt.m_rotation.z, nt.m_rotation.x), R);

Mat4 T;
T[3] = nt.m_position;
T[3].w = 1.f;

joint->m_matrixBind = T * R;
                    
if(node.m_parentID != -1)
{
    joint->m_matrixBind = object->m_mdl->m_joints[node.m_parentID]->m_matrixBind * joint->m_matrixBind;
}
joint->m_matrixOffset = joint->m_matrixBind;
joint->m_matrixOffset.invert();

I have no experience with skeletal animation. Perhaps someone has encountered a similar problem and knows the solution.

UPDATE

I disabled animation (for testing)

Mat4 NodeTransformation = mdlJoint->m_matrixBindNoParent;

if (mdlJoint->m_parentIndex != -1)
{
    objJoint.m_globalTransformation =
        m_joints[mdlJoint->m_parentIndex].m_globalTransformation
        * NodeTransformation;
}
else
{
    objJoint.m_globalTransformation = NodeTransformation;
}

objJoint.m_finalTransformation = objJoint.m_globalTransformation * mdlJoint->m_matrixOffset;

maybe problem with m_matrixOffset

How I create matrix from Tait–Bryan angles (ZYX)

// up / down
#define PITCH   0
// left / right
#define YAW     1
// fall over
#define ROLL    2 
void SMDAngleMatrix(v3f& angles, Mat4& matrix)
{
    float       angle;
    float       sr, sp, sy, cr, cp, cy;

    angle = angles[YAW];// *(math::PI * 2 / 360);
    sy = sin(angle);
    cy = cos(angle);
    angle = angles[PITCH];// * (math::PI * 2 / 360);
    sp = sin(angle);
    cp = cos(angle);
    angle = angles[ROLL];// * (math::PI * 2 / 360);
    sr = sin(angle);
    cr = cos(angle);

    // matrix = (YAW * PITCH) * ROLL
    matrix[0][0] = cp*cy;
    matrix[0][1] = cp*sy;
    matrix[0][2] = -sp;
    matrix[1][0] = sr*sp*cy + cr*-sy;
    matrix[1][1] = sr*sp*sy + cr*cy;
    matrix[1][2] = sr*cp;
    matrix[2][0] = (cr*sp*cy + -sr*-sy);
    matrix[2][1] = (cr*sp*sy + -sr*cy);
    matrix[2][2] = cr*cp;
    matrix[0][3] = 0.0;
    matrix[1][3] = 0.0;
    matrix[2][3] = 0.0;
}

OpenGL shader:

"void main(){\n"
    "   mat4 BoneTransform = Bones[inputBones.x] * inputWeights.x;\n"
    "   BoneTransform     += Bones[inputBones.y] * inputWeights.y;\n"
    "   BoneTransform     += Bones[inputBones.z] * inputWeights.z;\n"
    "   BoneTransform     += Bones[inputBones.w] * inputWeights.w;\n"
    "   vec4 vertexPosition = BoneTransform * vec4(inputPosition.xyz,1.0f);\n"
    "   gl_Position = WVP * vertexPosition;\n"
    "   texCoord.x = inputTexCoord.x;\n"
    "   texCoord.y = inputTexCoord.y;\n"
"}\n";

My matrices:

class Mat4{
    ....
    vec4 m_data[4];
}

Where m_data[3] - position;

That's all I have.

I will try to use quaternions instead of function SMDAngleMatrix...no same result...

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

This article helped me: https://veeenu.github.io/blog/implementing-skeletal-animation/

But, in my case, I needed to make some additional actions

Mat4 localMatrix = T * R;

if (node.m_parentID == -1)
{
    joint->m_matrixWorld = localMatrix;
}
else
{
    joint->m_matrixWorld =
        object->m_mdl->m_joints[node.m_parentID]->m_matrixWorld *
        localMatrix;
}

joint->m_matrixBindInverse = joint->m_matrixWorld;
joint->m_matrixBindInverse.invert();
joint->m_matrixOffset = joint->m_matrixBindInverse * joint->m_matrixWorld;
joint->m_matrixOffset.invert();   // invert here

And final shader matrix:

Mat4 NodeTransformation = TranslationM * RotationM;

if (mdlJoint->m_parentIndex != -1)
{
    objJoint.m_globalTransformation =
        m_joints[mdlJoint->m_parentIndex].m_globalTransformation
        * NodeTransformation;
}
else
{
    objJoint.m_globalTransformation = NodeTransformation;
}

objJoint.m_finalTransformation = 
                     
    objJoint.m_globalTransformation *  mdlJoint->m_matrixOffset *  mdlJoint->m_matrixBindInverse;

Result:

enter image description here

Perhaps someone will write a more complete answer. My question is why do I need 2 inverted matrices? What do I need to do to have only one?

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .