Advertisement

Skeletal animation trouble...

Started by April 09, 2003 11:46 AM
8 comments, last by James Trotter 21 years, 10 months ago
I''m trying to implement skeletal animation, but it isn''t working like it should. Please help! Anyway the problem is that the vertices are all screwed up, and I don''t know quite what''s wrong. It is animating it''s just not drawing the vertices in the right places! I''ve looked over the source 3 times already and can''t see that anything is wrong! Here''s a screenshot of the model in my program: here And here''s a screesnhot of the real model: here And the source... here''s my rendering code:
  
void CModel::Draw() {													// Render the model

	unsigned char IsTexEnabled = glIsEnabled(GL_TEXTURE_2D);			// Get this so we don''t mess up the state after drawing the model


	for (int i = 0; i < numMeshes; i++) {								// Loop through all the meshes in the modelW

		int materialIndex = mesh[i].MaterialIndex;						// Fetch the material index

		if (materialIndex >= 0) {										// If there is a material index

			glMaterialfv(GL_FRONT, GL_AMBIENT, materials[materialIndex].ambient);		// Set the ambient material property

			glMaterialfv(GL_FRONT, GL_DIFFUSE, materials[materialIndex].diffuse);		// Set the diffuse material property

			glMaterialfv(GL_FRONT, GL_SPECULAR, materials[materialIndex].specular);		// Set the specular material property

			glMaterialfv(GL_FRONT, GL_EMISSION, materials[materialIndex].emissive);		// Set the emissive material property

			glMaterialf(GL_FRONT, GL_SHININESS, materials[materialIndex].shininess);	// And the shininess property


			if (materials[materialIndex].texID > 0) {					// If there is a texture for this material

				glBindTexture(GL_TEXTURE_2D, materials[materialIndex].texID);	// Bind the texture

				glEnable(GL_TEXTURE_2D);								// And enable texture mapping

			} else glDisable(GL_TEXTURE_2D);							// If there was no texture, we disable texturing

		} else															// If there were no materials

			glDisable(GL_TEXTURE_2D);									// Disable texturing


		glBegin(GL_TRIANGLES);											// Begin rendering this models triangles

		for (int j = 0; j < mesh[i].numTriangles; j++) {				// Loop through the triangles in the mesh

			int triIndex = mesh[i].TriIndices[j];						// Fetch the triangle index

			const Triangle* tempTri = &tri[triIndex];					// Fetch a temporary triangle


			for (int k = 0; k < 3; k++) {
				int index = tempTri->VertexIndex[k];					// Get the index to the vertex


				if (vertex[index].boneID == -1) {						// If it belongs to the root joint

					glNormal3fv(tri[index].VertexNormals[k].v);			// Set the normal for this vertex

					glTexCoord2f(tri[index].s[k], tri[index].t[k]);		// Set the texture coordinate for this vertex

					glVertex3fv(vertex[index].position.v);				// And pass the vertex to OpenGL


				} else {												// If it belongs to another joint

					const Matrix& final = joints[vertex[index].boneID].final;	// Get the final matrix


					Vector3D newNormal(tempTri->VertexNormals[k]);		// Need to get the normal

					newNormal.transform3(final);						// So it can get transformed

					newNormal.normalize();								// Then normalize it

					glNormal3fv(newNormal.v);							// Set the normal


					glTexCoord2f(tempTri->s[k], tempTri->t[k]);			// Set the texture coordinate for this vertex

					Vector3D newVertex(vertex[index].position);
					newVertex.transform(final);							// Transform the vertex

					glVertex3fv(newVertex.v);							// Pass it to OpenGL

				}
			}
		}
		glEnd();														// End the triangles

	}
	if (IsTexEnabled)													// If it was enabled before we started rendering

		glEnable(GL_TEXTURE_2D);										// Restore the state

	else glDisable(GL_TEXTURE_2D);										// If it wasn''t we disable it again

}
  
and heres my animation code:
  
void CModel::Animate() {											// Animate the model

	float time = timer->GetTime();									// Get the current time


	if (time > totalTime) {											// If the entire animation has been played

		restart();												// Reset the animation

			time = 0;
						// If not, play the last part of the animation

	} 

	for (int i = 0; i < numJoints; i++) {							// Loop through the joints

		float trans[3];												// Translation vector

		Matrix transform;
		int frame;													// The current frame

		Joint *joint = &joints[i];									// Get the joint


		if (joint->numRotationKeyframes == 0 && joint->numTranslationKeyframes == 0) {	// If there are no keyframes

			joint->final = joint->absolute;							// The final matrix is equal to the absolute matrix

			continue;												// Go to next joint

		}

		frame = joint->CurrentTranslationKeyframe;					// Get the current translation frame


		// While this is not the last frame, and the time of the frame has not gone past the current time

		while (frame < joint->numTranslationKeyframes && joint->TranslationKeyframes[frame].time < time) {
			frame++;												// Go to the next frame

		}

		joint->CurrentTranslationKeyframe = frame;					// Set the current frame


		if (frame == 0)												// If it is the first frame

			memcpy(trans, joint->TranslationKeyframes[0].parameter, sizeof (float) * 3);
		else if (frame == joint->numTranslationKeyframes)			// If it is the last frame

			memcpy(trans, joint->TranslationKeyframes[frame - 1].parameter, sizeof(float) * 3);
		else {														// If it is one of the frames between

			if (frame < 0)											// Limit the frame to

				frame = 0;											// 0 - numTranslationKeyframes

			if (frame > joint->numTranslationKeyframes)
				frame = joint->numTranslationKeyframes;

			const CModel::Keyframe& curFrame = joint->TranslationKeyframes[frame];		// Get the current

			const CModel::Keyframe& prevFrame = joint->TranslationKeyframes[frame - 1];	// And previous frames


			float timeDelta = curFrame.time - prevFrame.time;					// And get the elapsed time

			float interpolation = (float)((time - prevFrame.time) / timeDelta);	// And get the percent of interpolation between the frames


			trans[0] = prevFrame.parameter[0] + (curFrame.parameter[0] - prevFrame.parameter[0]) * interpolation;
			trans[1] = prevFrame.parameter[1] + (curFrame.parameter[1] - prevFrame.parameter[1]) * interpolation;
			trans[2] = prevFrame.parameter[2] + (curFrame.parameter[2] - prevFrame.parameter[2]) * interpolation; 
		}

		frame = joint->CurrentRotationKeyframe;							// Get the current rotation keyframe


		// While this is not the last frame, and the time of the frame has not gone past the current time

		while (frame < joint->numRotationKeyframes && joint->RotationKeyframes[frame].time < time) {
			frame++;													// Go to the next frame

		}
		joint->CurrentRotationKeyframe = frame;							// Set the current frame


		if (frame == 0)													// If it is the first frame

			transform.setRotationRadians(joint->RotationKeyframes[0].parameter);
		else if (frame == joint->numRotationKeyframes)					// If it is the last frame

			transform.setRotationRadians(joint->RotationKeyframes[frame - 1].parameter);
		else {															// If it is one of the frames between

			if (frame < 0)												// Limit the frame to

				frame = 0;												// 0 - numRotationKeyframes

			if (frame > joint->numRotationKeyframes)
				frame = joint->numRotationKeyframes;

			const CModel::Keyframe& curFrame = joint->RotationKeyframes[frame];			// Get the current

			const CModel::Keyframe& prevFrame = joint->RotationKeyframes[frame - 1];	// And previous frames


			float timeDelta = curFrame.time - prevFrame.time;					// And get the elapsed time

			float interpolation = (float)((time - prevFrame.time) / timeDelta);	// And get the percent of interpolation between the frames


			if (interpolation <= 0)										// Limit the interpolation

				interpolation = 0;										// Between zero and one

			if (interpolation >= 1)
				interpolation = 1;

			// Use quaternions for rotation

			Quaternion qPrev(prevFrame.parameter);						// Get quaternions from the

			Quaternion qCur(curFrame.parameter);						// Previous and current frame

			Quaternion qFinal(qPrev, qCur, interpolation);				// And calculate the final rotation

			transform.setRotationQuaternion(qFinal);					// Then apply the final rotation to the matrix

		}
		transform.setTranslation(trans);								// Apply the translation to the matrix


		Matrix relativeFinal(joint->relative);							// And get the relative final matrix

		relativeFinal.postMultiply(transform);							// And post-multiply it by the transformation matrix


		if (joint->parent == -1)										// If there is no parent joint

			joint->final = relativeFinal;								// Then the final matrix of this joint is the relative final matrix

		else {															// If this is not the root

			joint->final = joints[joint->parent].final;					// Then the final matrix of this joint is the final matrix of the parent joint

			joint->final.postMultiply(relativeFinal);					// Multiplied by the relative final matrix

		}
	}
}
  
plz help!!
*ahem* plz, I need help solving this problem, but no one seems to be very eager in posting....
Advertisement
quote:
Original post by James Trotter
*ahem* plz, I need help solving this problem, but no one seems to be very eager in posting....

It's a tough thing to write.

I assume (since you're using the bert model) that you're basing your work off of this:
http://rsn.gamedev.net/tutorials/ms3danim.asp

If not, it was just a guess. If you look at his source (as it's a good sample for reading MS3D files), you'll notice that after he loads everything he calls a method, "void Model::setupJoints()". What you'll notice is that he's inverse transforming/rotating/etc all of the joints to find out their initial possitions. If you take a look at the MS3D file format documentation, you see why:

// Mesh Transformation://// 0. Build the transformation matrices from the rotation and position// 1. Multiply the vertices by the inverse of local reference matrix (lmatrix0)// 2. Then translate the result by (lmatrix0 * keyFramesTrans)// 3. Then multiply the result by (lmatrix0 * keyFramesRot)//// For normals skip step 2.//  

I hope this helps.

- sighuh?

[edited by - redragon on April 11, 2003 12:27:29 PM]
- sighuh?
quote:
Original post by James Trotter
*ahem*

excuse you.
- sighuh?
lol, thank you very much! I was reading the rsn ms3danim tutorial, and so I am using the bert model, like you said.

I expected it to be tough when I started, but it all seemed to go okay, and now this very annoying bug that pops up out of nowhere, and has hidden itself very well in the code =(.

I''ve gone through the code time, and time again, like I said last.

I am calling the setupJoints() function where it inverse rotates and translates all the joints...

I''ll look at that function some more...

And THANK YOU VERY MUCH FOR POSTING!!
I feel like such a fool...

It was indeed like you said, redragon, something was wrong when setting up the joints... It wasn''t the setupJoints() function, but the inverseRotateVect, and inverseTranslateVect functions weren''t returning a value...

I fixed that and it looks alright now, but it''s still not rotating the joints during the animation....

thanks again redragon!!!!!!!!

Advertisement
The quaternion rotation wasn''t working 100%, so I''m just rotating the matrix the ordinary way.

I''ll try to get it fixed...
Never call yourself a fool. It''s tough stuff, skeletal animations can be tricky. I certainly know it took me a while to get my MS3D viewer working correctly. Plus it''s fun to figure out why stuff isn''t working...

Good luck with Quaternions. I''ve tried that several ways, and still like how my matrix based operations work...though typically the user isn''t THAT close to the models, so I don''t find that doing SLERP/etc. is very helpful.

- sighuh?
- sighuh?
Yes, they were tricky, but now I''m going to try something even more tricky... MY own model file format!
Good luck

Once you get a base for the format working - vertices, faces and uv coords, it gets pretty easy.

This topic is closed to new replies.

Advertisement