Jump to content
  • Advertisement
Sign in to follow this  
DavidJr

Skeletal Skinning With Quaternion (OpenGL)

This topic is 1114 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
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!