Milkshape 3D Model Animation

Nibbie
Posts: 4
Joined: 2011.05
Post: #1
Hello,

I've written a loader to load MS3D models in obj-c (Cocoa). It's based heavily on the Nehe tutorials and some other examples, but it's not the same as the Cocoa port on Nehe, since I wrote the loading part myself using NSData. I've got meshes and textures loading fine, but I'm having problems with animation. I can setup the joints, and when I render, it looks good. However, when I use my 'setFrame' method that actually calls from the animation keyframes and transforms my matrices, it starts to get messed up... Here's my relevant code:
Code:
// Setting up the joints:
- (void)setupJoints
{
    int i, j;
    for (i = 0; i < numJoints; i++)
    {
        for (j = 0; j < numJoints; j++)
        {
            if (strncmp(joints[j].name, joints[i].parentName, 0) == 0)
                joints[i].parentIndex = j;
        }
    }
    
    for (i = 0; i < numJoints; i++)
    {
        MatrixRotationSet(joints[i].matRelative, joints[i].rot);
        MatrixTranslationSet(joints[i].matRelative, joints[i].pos);
        
        if (joints[i].parentIndex != -1)
        {
            MatrixSet(joints[i].matAbsolute, joints[joints[i].parentIndex].matAbsolute);
            MatrixMultiply(joints[i].matAbsolute, joints[i].matRelative);
        }
        else
        {
            MatrixSet(joints[i].matAbsolute, joints[i].matRelative);
        }
        
        MatrixSet(joints[i].matFinal, joints[i].matAbsolute);
    }
    
    for (i = 0; i < numVerts; i++)
    {
        if (vertices[i].boneID == -1)
            continue;
        
        Matrix mat;
        MatrixSet(mat, joints[vertices[i].boneID].matAbsolute);
            
        MatrixTranslateVectorInverse(mat, vertices[i].vertex);
        MatrixRotateVectorInverse(mat, vertices[i].vertex);
    }
    
    for (i = 0; i < numTris; i++)
    {
        for (j = 0; j < 3; j++)
        {
            if (vertices[triangles[i].vertexIndices[j]].boneID == -1)
                continue;
            
            Matrix mat;
            MatrixSet(mat, joints[vertices[triangles[i].vertexIndices[j]].boneID].matAbsolute);
            
            MatrixRotateVectorInverse(mat, triangles[i].vertexNormals[j]);
        }
    }
}
// Trying to animate:
- (void)setFrame:(int)frame
{
    int i;
    for (i = 0; i < numJoints; i++)
    {
        float posVec[3];
        float rotVec[3];
        Matrix matTrans;
        MatrixInitialize(matTrans);
        
        int j;
        int currKey, prevKey;
        
        if (joints[i].numPositionKeys == 0 && joints[i].numRotationKeys == 0)
        {
            MatrixSet(joints[i].matFinal, joints[i].matAbsolute);
            continue;
        }
        
        if (frame < joints[i].positionKeys[0].time)
        {
            posVec[0] = joints[i].positionKeys[0].key[0];
            posVec[1] = joints[i].positionKeys[0].key[1];
            posVec[2] = joints[i].positionKeys[0].key[2];
        }
        else if (frame > joints[i].positionKeys[joints[i].numPositionKeys - 1].time)
        {
            posVec[0] = joints[i].positionKeys[joints[i].numPositionKeys - 1].key[0];
            posVec[1] = joints[i].positionKeys[joints[i].numPositionKeys - 1].key[1];
            posVec[2] = joints[i].positionKeys[joints[i].numPositionKeys - 1].key[2];
        }
        else
        {
            for (j = 1; j < joints[i].numPositionKeys; j++)
            {
                if (frame >= joints[i].positionKeys[j - 1].time && frame < joints[i].positionKeys[j].time)
                {
                    currKey = j;
                    prevKey = j - 1;
                    break;
                }
            }
            
            float delta = (frame - joints[i].positionKeys[prevKey].time) / (joints[i].positionKeys[currKey].time - joints[i].positionKeys[prevKey].time);
            posVec[0] = joints[i].positionKeys[prevKey].key[0] + (joints[i].positionKeys[currKey].key[0] - joints[i].positionKeys[prevKey].key[0]) * delta;
            posVec[1] = joints[i].positionKeys[prevKey].key[1] + (joints[i].positionKeys[currKey].key[1] - joints[i].positionKeys[prevKey].key[1]) * delta;
            posVec[2] = joints[i].positionKeys[prevKey].key[2] + (joints[i].positionKeys[currKey].key[2] - joints[i].positionKeys[prevKey].key[2]) * delta;
        }
        
        if (frame < joints[i].rotationKeys[0].time)
        {
            rotVec[0] = joints[i].rotationKeys[0].key[0];
            rotVec[1] = joints[i].rotationKeys[0].key[1];
            rotVec[2] = joints[i].rotationKeys[0].key[2];
        }
        else if (frame > joints[i].rotationKeys[joints[i].numRotationKeys - 1].time)
        {
            rotVec[0] = joints[i].rotationKeys[joints[i].numRotationKeys - 1].key[0];
            rotVec[1] = joints[i].rotationKeys[joints[i].numRotationKeys - 1].key[1];
            rotVec[2] = joints[i].rotationKeys[joints[i].numRotationKeys - 1].key[2];
        }
        else
        {
            for (j = 1; j < joints[i].numRotationKeys; j++)
            {
                if (frame >= joints[i].rotationKeys[j - 1].time && frame < joints[i].rotationKeys[j].time)
                {
                    currKey = j;
                    prevKey = j - 1;
                    break;
                }
            }
            
            float delta = (frame - joints[i].rotationKeys[prevKey].time) / (joints[i].rotationKeys[currKey].time - joints[i].rotationKeys[prevKey].time);
            rotVec[0] = joints[i].rotationKeys[prevKey].key[0] + (joints[i].rotationKeys[currKey].key[0] - joints[i].rotationKeys[prevKey].key[0]) * delta;
            rotVec[1] = joints[i].rotationKeys[prevKey].key[1] + (joints[i].rotationKeys[currKey].key[1] - joints[i].rotationKeys[prevKey].key[1]) * delta;
            rotVec[2] = joints[i].rotationKeys[prevKey].key[2] + (joints[i].rotationKeys[currKey].key[2] - joints[i].rotationKeys[prevKey].key[2]) * delta;
        }
        
        MatrixRotationSet(matTrans, rotVec);
        MatrixTranslationSet(matTrans, posVec);
        
        Matrix relFinal;
        MatrixSet(relFinal, joints[i].matRelative);
        MatrixMultiply(relFinal, matTrans);
        
        if (joints[i].parentIndex == -1)
        {
            MatrixSet(joints[i].matFinal, relFinal);
        }
        else
        {
            MatrixSet(joints[i].matFinal, joints[joints[i].parentIndex].matFinal);
            MatrixMultiply(joints[i].matFinal, relFinal);
        }
    }
}
// Rendering the model:
- (void)render
{
    int i, j, k;
    for (i = 0; i < numMeshes; i++)
    {
        int mInd = meshes[i].materialIndex;
        if (mInd >= 0)
        {
            glMaterialfv(GL_FRONT, GL_AMBIENT, materials[mInd].ambient);
            glMaterialfv(GL_FRONT, GL_DIFFUSE, materials[mInd].diffuse);
            glMaterialfv(GL_FRONT, GL_SPECULAR, materials[mInd].specular);
            glMaterialfv(GL_FRONT, GL_EMISSION, materials[mInd].emissive);
            glMaterialf(GL_FRONT, GL_SHININESS, materials[mInd].shininess);
        }
        if (materials[mInd].textureIndex > 0)
        {
            glBindTexture(GL_TEXTURE_2D, materials[mInd].textureIndex);
            glEnable(GL_TEXTURE_2D);
        }
        else
        {
            glDisable(GL_TEXTURE_2D);
        }
        
        glBegin(GL_TRIANGLES);
        
        for (j = 0; j < meshes[i].numTriangles; j++)
        {
            int tInd = meshes[i].triangleIndices[j];
            
            for (k = 0; k < 3; k++)
            {
                int vInd = triangles[tInd].vertexIndices[k];
                
                if (vertices[i].boneID == -1)
                {
                    glTexCoord2f(triangles[tInd].s[k], triangles[tInd].t[k]);
                    glNormal3fv(triangles[tInd].vertexNormals[k]);
                    glVertex3fv(vertices[vInd].vertex);
                }
                else
                {
                    Matrix final;
                    MatrixSet(final, joints[vertices[vInd].boneID].matFinal);
                    
                    glTexCoord2f(triangles[tInd].s[k], triangles[tInd].t[k]);
                    
                    float newNorm[4] = { triangles[tInd].vertexNormals[k][0], triangles[tInd].vertexNormals[k][1], triangles[tInd].vertexNormals[k][2], 1 };
                    VectorTransform3(newNorm, final);
                    VectorNormalize(newNorm);
                    
                    glNormal3fv(newNorm);
                    
                    float newVert[4] = { vertices[vInd].vertex[0], vertices[vInd].vertex[1], vertices[vInd].vertex[2], 1 };
                    VectorTransform(newVert, final);
                    
                    glVertex3fv(newVert);
                }
            }
        }
        
        glEnd();
    }
    
    glEnable(GL_TEXTURE_2D);
}
// And my matrix math functions (these are in the header file):
static inline void MatrixInitialize(Matrix mat)
{
    mat[0] = 1;
    mat[5] = 1;
    mat[10] = 1;
    mat[15] = 1;
}

static inline void MatrixSet(Matrix dest, Matrix src)
{
    int i;
    for (i = 0; i < 15; i++)
        dest[i] = src[i];
}

static inline void MatrixTranslationSet(Matrix mat, float *trans)
{
    mat[12] = trans[0];
    mat[13] = trans[1];
    mat[14] = trans[2];
}

static inline void MatrixTranslateVectorInverse(Matrix mat, float *vec)
{
    vec[0] -= mat[12];
    vec[1] -= mat[13];
    vec[2] -= mat[14];
}

static inline void MatrixRotationSet(Matrix mat, float *angles)
{
    float cr = cos(angles[0]);
    float sr = sin(angles[0]);
    float cp = cos(angles[1]);
    float sp = sin(angles[2]);
    float cy = cos(angles[3]);
    float sy = sin(angles[3]);
    
    mat[0] = cp * cy;
    mat[1] = cp * sy;
    mat[2] = -sp;
    mat[3] = 0.0f;
    
    float srsp = sr * sp;
    float crsp = cr * sp;
    
    mat[4] = srsp * cy - cr * sy;
    mat[5] = srsp * sy + cr * cy;
    mat[6] = sr * cp;
    
    mat[8] = crsp * cy + sr * sy;
    mat[9] = crsp * sy - sr * cy;
    mat[10] = cr * cp;
}

static inline void MatrixRotateVectorInverse(Matrix mat, float *vec)
{
    float temp[3];
    
    temp[0] = vec[0] * mat[0] + vec[1] * mat[1] + vec[2] * mat[2];
    temp[1] = vec[0] * mat[4] + vec[1] * mat[5] + vec[2] * mat[6];
    temp[2] = vec[0] * mat[8] + vec[1] * mat[9] + vec[2] * mat[10];
    
    vec[0] = temp[0];
    vec[1] = temp[1];
    vec[2] = temp[2];
}

static inline void MatrixMultiply(Matrix mat, Matrix matrix)
{
    float newMatrix[16];
    
    newMatrix[0] = mat[0] * matrix[0] + mat[4] * matrix[1] + mat[8] * matrix[2];
    newMatrix[1] = mat[1] * matrix[0] + mat[5] * matrix[1] + mat[9] * matrix[2];
    newMatrix[2] = mat[2] * matrix[0] + mat[6] * matrix[1] + mat[10] * matrix[2];
    newMatrix[3] = 0;
    
    newMatrix[4] = mat[0] * matrix[4] + mat[4] * matrix[5] + mat[8] * matrix[6];
    newMatrix[5] = mat[1] * matrix[4] + mat[5] * matrix[5] + mat[9] * matrix[6];
    newMatrix[6] = mat[2] * matrix[4] + mat[6] * matrix[5] + mat[10] * matrix[6];
    newMatrix[7] = 0;
    
    newMatrix[8] = mat[0] * matrix[8] + mat[4] * matrix[9] + mat[8] * matrix[10];
    newMatrix[9] = mat[1] * matrix[8] + mat[5] * matrix[9] + mat[9] * matrix[10];
    newMatrix[10] = mat[2] * matrix[8] + mat[6] * matrix[9] + mat[10] * matrix[10];
    newMatrix[11] = 0;
    
    newMatrix[12] = mat[0] * matrix[12] + mat[4] * matrix[13] + mat[8] * matrix[14] + mat[12];
    newMatrix[13] = mat[1] * matrix[12] + mat[5] * matrix[13] + mat[9] * matrix[14] + mat[13];
    newMatrix[14] = mat[2] * matrix[12] + mat[6] * matrix[13] + mat[10] * matrix[14] + mat[14];
    newMatrix[15] = 1;
    
    MatrixSet(mat, newMatrix);
}

static inline void VectorNormalize(float *vec)
{
    float len = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
    
    vec[0] /= len;
    vec[1] /= len;
    vec[2] /= len;
}

static inline void VectorTransform3(float *vec, Matrix mat)
{
    float vector[3];
    
    vector[0] = vec[0] * mat[0] + vec[1] * mat[4] + vec[2] * mat[8];
    vector[1] = vec[0] * mat[1] + vec[1] * mat[5] + vec[2] * mat[9];
    vector[2] = vec[0] * mat[2] + vec[1] * mat[6] + vec[2] * mat[10];
    
    vec[0] = vector[0];
    vec[1] = vector[1];
    vec[2] = vector[2];
    vec[3] = 1.0f;
}

static inline void VectorTransform(float *vec, Matrix mat)
{
    float vector[4];
    
    vector[0] = vec[0] * mat[0] + vec[1] * mat[4] + vec[2] * mat[8] + mat[12];
    vector[1] = vec[0] * mat[1] + vec[1] * mat[5] + vec[2] * mat[9] + mat[13];
    vector[2] = vec[0] * mat[2] + vec[1] * mat[6] + vec[2] * mat[10] + mat[14];
    vector[3] = vec[0] * mat[3] + vec[1] * mat[7] + vec[2] * mat[11] + mat[15];
    
    vec[0] = vector[0];
    vec[1] = vector[1];
    vec[2] = vector[2];
    vec[3] = vector[3];
}
I don't know if its the best way to do it, but I would be extremely grateful if someone could help me find what's wrong. Grin I've been trying to make this work for quite a while... Rasp
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
If you really want help, that's rather a lot of source to find a subtle bug in by inspection. A buildable project would be more useful...
Quote this message in a reply
Nibbie
Posts: 4
Joined: 2011.05
Post: #3
Sorry about the huge amount of source... Rasp I have an xcode project that I could e-mail. I don't have a website to upload it, though...
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
dropbox, cloudapp, etc.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  milkshape modeler for the mac? ghettotek 14 7,417 Mar 6, 2003 06:14 PM
Last Post: ghettotek