Milkshape 3D Model Animation
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:
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.
I've been trying to make this work for quite a while...
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've been trying to make this work for quite a while...
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...
Sorry about the huge amount of source...
I have an xcode project that I could e-mail. I don't have a website to upload it, though...
I have an xcode project that I could e-mail. I don't have a website to upload it, though...
dropbox, cloudapp, etc.
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| milkshape modeler for the mac? | ghettotek | 14 | 6,543 |
Mar 6, 2003 06:14 PM Last Post: ghettotek |
|

