Advertisement

Skeletal Skinning With Quaternion (OpenGL)

Started by November 28, 2015 02:04 PM
-1 comments, last by DavidJr 9 years, 2 months ago

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;
}

This topic is closed to new replies.

Advertisement