Jump to content
  • Advertisement
Sign in to follow this  

Skeletal Skinning With Quaternion (OpenGL)

This topic is 963 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I've been struggling with this for a month. I did skeletal animation in deprecated way and I wanna move on with Shader, how to do this with shader?

The skeleton has 3 axis angles (x,y,z) and 3 positions, here is the way I did:

1. Built joint transformation matrices

2. Get the rotation between 2 axis rotations & positions

3. Set those rotations to matrix and store the positions in matrix

4. SLERP the quaternion

5. Convert the slerp output quaternion to Matrix 4x4

6. Multiply the matrix with pre built joint transformation matrix

7. Multiply the child matrix with parent matrix


The problems when I convert these to shader are, instead of sending the bone matrices to shader, I convert the multiplied child & parent matrix to quaternion and send it to shader and convert them again to matrix in GPU then multiply it with the vertices & weight. However, to get the vertices going, I have to send the pre built matrices which I don't want to. Is there any method to transform the vertex without sending the pre built transformation matrices? What is the correct step of interpolating the joints? I don't want to send matrices but quaternion instead.


Thank you.

for (int i = 0; i < pMesh[mesh].VertNum; ++i)
        memcpy(pOut[i].Pos, pMesh[mesh].pVertex[i].Pos, sizeof (Vertex));

        float tmp[3], vert[3];
        // mGlobalSkeleton & mGlobal must have to be sent to the GPU too in order to make the vertices work
        VectorITransform(pMesh[mesh].pVertex[i].Pos, pAnim.pBones[pMesh[mesh].pVertex[i].BoneID].mGlobalSkeleton, tmp);
        VectorTransform(tmp, pAnim.pBones[pMesh[mesh].pVertex[i].BoneID].mGlobal, vert);

        pOut[i].Pos[0] = vert[0] * 1.0;
        pOut[i].Pos[1] = vert[1] * 1.0;
        pOut[i].Pos[2] = vert[2] * 1.0;

Here is my shader:

#version 400 compatibility

in vec3 vPosition;
in vec2 vTexCoord;
in vec3 vNormal;
in ivec4 vIndex;

uniform mat2x4 mQuat[100];

mat4 Quaternion_ToMatrix(in mat2x4 mIn)
    float sqw = mIn[0][0]*mIn[0][0];
    float sqx = mIn[0][1]*mIn[0][1];
    float sqy = mIn[0][2]*mIn[0][2];
    float sqz = mIn[0][3]*mIn[0][3];

    // invs (inverse square length) is only required if quaternion is not already normalised
    float fInv = 1.0 / (sqx + sqy + sqz + sqw);
    mat4x4 mOut;
    mOut[0][0] = (sqx - sqy - sqz + sqw) * fInv; // since sqw + sqx + sqy + sqz =1/invs*invs
    mOut[1][1] = (-sqx + sqy - sqz + sqw) * fInv;
    mOut[2][2] = (-sqx - sqy + sqz + sqw) * fInv;

    mOut[1][0] = 2.0 * (mIn[0][1]*mIn[0][2] + mIn[0][3]*mIn[0][0]) * fInv;
    mOut[0][1] = 2.0 * (mIn[0][1]*mIn[0][2] - mIn[0][3]*mIn[0][0]) * fInv;

    mOut[2][0] = 2.0 * (mIn[0][1]*mIn[0][3] - mIn[0][2]*mIn[0][0]) * fInv;
    mOut[0][2] = 2.0 * (mIn[0][1]*mIn[0][3] + mIn[0][2]*mIn[0][0]) * fInv;
    mOut[2][1] = 2.0 * (mIn[0][2]*mIn[0][3] + mIn[0][1]*mIn[0][0]) * fInv;
    mOut[1][2] = 2.0 * (mIn[0][2]*mIn[0][3] - mIn[0][1]*mIn[0][0]) * fInv;
    mOut[3][0] = 0.0;
    mOut[3][1] = 0.0;
    mOut[3][2] = 0.0;
    mOut[0][3] = mIn[1][0];
    mOut[1][3] = mIn[1][1];
    mOut[2][3] = mIn[1][2];
    mOut[3][3] = mIn[1][3];
    return mOut;
mat2x4 mTemp;
void main()
    mat4 mMat = Quaternion_ToMatrix(mQuat[vIndex.x]);
    vec4 vVertex = mMat * vec4(vPosition, 1.0);
    gl_Position = gl_ModelViewProjectionMatrix * vVertex;

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!