MD2 Animation

Started by
5 comments, last by Deston 18 years, 1 month ago
Hi I am currently trying to animate a MD2 file in directX. I have it working but the animation is choppy. Could anyone help? Here is the code for the linear interpolation.

m_Anim.fOldTime = m_Anim.fCurrTime;

m_Anim.fCurrTime += fTime;

if (m_Anim.fCurrTime > (1.0 / m_Anim.nFPS))
{
	m_Anim.nCurrFrame = m_Anim.nNextFrame;
	m_Anim.nNextFrame++;

	if (m_Anim.nNextFrame > m_Anim.nEnd)
		m_Anim.nNextFrame = m_Anim.nNextFrame;

	m_Anim.fInterpol = 0;
	m_Anim.fCurrTime = 0;
}

if (m_Anim.nCurrFrame > (m_Anim.nEnd))
	m_Anim.nCurrFrame = m_Anim.nStart;

if (m_Anim.nCurrFrame < m_Anim.nStart)
	m_Anim.nCurrFrame = m_Anim.nStart;

if (m_Anim.nNextFrame > (m_Anim.nEnd))
	m_Anim.nNextFrame = m_Anim.nStart;

if (m_Anim.nNextFrame < m_Anim.nStart)
	m_Anim.nNextFrame = m_Anim.nStart;

m_Anim.fInterpol += m_Anim.nFPS * (m_Anim.fCurrTime - m_Anim.fOldTime);

if (m_Anim.fInterpol > 1.0f)
	m_Anim.fInterpol = 1.0f;
else if (m_Anim.fInterpol < 0.0f)
	m_Anim.fInterpol = 0.0f;

for (i = 0; i < (m_nNumTris * 3); i++)
{
	m_pVerts .x = m_pMesh [m_Anim.nCurrFrame].pVerts .x + ((m_pMesh [m_Anim.nNextFrame].pVerts .x - m_pMesh [m_Anim.nCurrFrame].pVerts .x) * m_Anim.fInterpol);
	m_pVerts .y = m_pMesh [m_Anim.nCurrFrame].pVerts .y + ((m_pMesh [m_Anim.nNextFrame].pVerts .y - m_pMesh [m_Anim.nCurrFrame].pVerts .y) * m_Anim.fInterpol);
	m_pVerts .z = m_pMesh [m_Anim.nCurrFrame].pVerts .z + ((m_pMesh [m_Anim.nNextFrame].pVerts .z - m_pMesh [m_Anim.nCurrFrame].pVerts .z) * m_Anim.fInterpol);
}

Thanks in advance!
Advertisement
Hi! I haven´t analyzed the whole source but what´s the following line supposed to do?

if (m_Anim.nNextFrame > m_Anim.nEnd)		m_Anim.nNextFrame = m_Anim.nNextFrame;


--Nacho


As far as I can tell, it's choppy because m_Anim.fInterpol is always set to 1.0f or 0.0f so you're never actually interpolating between the frames, you're just going from one frame to the next.

I think if m_Anim.fInterpol < 0.0f, you want to use the value of m_Anim.fInterpol as it is, not set it to zero. That way you'll actually interpolate between the current frame and the next frame.

If m_Anim.fInterpol is > 1.0f, then I think that means enough time has elapsed since the last frame was computed that m_Anim.nCurrFrame and m_Anim.nNextFrame should both refer to the NEXT frame in the animation set (ie, skip a frame). Although, the way you have it set up, it might mean something else.

What is m_Anim.nFPS? Is it more or less a constant? Or does it change?
Ignacio Liverotti :
Thanks for that, it doesn't influence the code, so I removed it. No change in the chopppyness.

Deston :
Why do you say that the interpolation value is always 1 or 0?

If fInterpol is < 0, it must be 0 because i would be extrapolation instead of interpolating. For interpolation, you must have a value between 1 and 0.
Also if fInterpol is > 1, i already change the value of the current frame when fCurrTime > (1/nFPS).


nFPS is defined in this code, for each anim, the proper value is loaded.

struct MD2Anim{	char *chName;	int nStart;	int nEnd;	int nFPS;};MD2Anim MD2AnimList [21] = {	{"Stand", 0, 39, 9,},				// STAND	{"Run", 40, 45, 10},				// RUN	{"Attack", 46, 53, 10},				// ATTACK	{"Pain_A", 54, 57, 7},				// PAIN_A	{"Pain_B", 58, 61, 7},				// PAIN_B	{"Pain_C", 62, 65, 7},				// PAIN_C	{"Jump", 66, 71, 7},				// JUMP	{"Flip", 72, 83, 7},				// FLIP	{"Salute", 84, 94, 7},				// SALUTE	{"Fallback", 95, 111, 10},			// FALLBACK	{"Wave", 112, 122, 7},				// WAVE	{"Point", 123, 134, 6},				// POINT	{"Crouch_Stand", 135, 153, 10},		// CROUCH_STAND	{"Crouch_Walk", 154, 159, 7},		// CROUCH_WALK	{"Crouch_Attack", 160, 168, 10},	// CROUCH_ATTACK	{"Crouch_Pain", 169, 172, 7},		// CROUCH_PAIN	{"Crouch_Death", 173, 177, 5},		// CROUCH_DEATH	{"Death_FallBack", 178, 183, 7},	// DEATH_FALLBACK	{"Death_FallForeward", 184, 189, 7},// DEATH_FALLFORWARD	{"Death_FallBackSlow", 190, 197, 7},// DEATH_FALLBACKSLOW	{"Boom", 198, 198, 5},				// BOOM};


While the values for nFPS change between diffrent anims, the value when I loop the anim stays the same.
Quote:Original post by cppcdr
Deston :
Why do you say that the interpolation value is always 1 or 0?

If fInterpol is < 0, it must be 0 because i would be extrapolation instead of interpolating. For interpolation, you must have a value between 1 and 0.
Also if fInterpol is > 1, i already change the value of the current frame when fCurrTime > (1/nFPS).


Haha, yeah, never mind. I was a dolt and misread the code. :)

Okay, here's try #2. This looks suspect to me (hopefully I've looked at this more carefully now...):

m_Anim.fOldTime = m_Anim.fCurrTime;m_Anim.fCurrTime += fTime;if( ... ){    m_Anim.fInterpol = 0;    m_Anim.fCurrTime = 0;}m_Anim.fInterpol += m_Anim.nFPS * (m_Anim.fCurrTime - m_Anim.fOldTime);


CurrTime is growing right? OldTime takes it's value each frame, but after a while CurrTime and Interpol get reset to zero. So OldTime will be a bigger number than CurrTime.

pos * (smallerNumber - biggerNumber) = pos * neg = neg


Then Interpol gets clamped to 0.

Failing that, have you tried loading the model in another program (like the MD2 viewer from Chumbalum Soft) to see if the choppiness is in the animation itself?
I solved it!
Thanks for the replies!

Here is how I did it:
m_Anim.fInterpol += fTime / (1.0f / (float) m_Anim.nFPS);if (m_Anim.fInterpol > 1.0f){	m_Anim.nCurrFrame = m_Anim.nNextFrame;	m_Anim.nNextFrame++;	m_Anim.fInterpol = 0.0f;}else if (m_Anim.fInterpol < 0.0f)	m_Anim.fInterpol = 0.0f;if (m_Anim.nCurrFrame > (m_Anim.nEnd))	m_Anim.nCurrFrame = m_Anim.nStart;if (m_Anim.nCurrFrame < m_Anim.nStart)	m_Anim.nCurrFrame = m_Anim.nStart;if (m_Anim.nNextFrame > (m_Anim.nEnd))	m_Anim.nNextFrame = m_Anim.nStart;if (m_Anim.nNextFrame < m_Anim.nStart)	m_Anim.nNextFrame = m_Anim.nStart;for (i = 0; i < (m_nNumTris * 3); i++){	m_pVerts .x = m_pMesh [m_Anim.nCurrFrame].pVerts .x + ((m_pMesh [m_Anim.nNextFrame].pVerts .x - m_pMesh [m_Anim.nCurrFrame].pVerts .x) * m_Anim.fInterpol);	m_pVerts .y = m_pMesh [m_Anim.nCurrFrame].pVerts .y + ((m_pMesh [m_Anim.nNextFrame].pVerts .y - m_pMesh [m_Anim.nCurrFrame].pVerts .y) * m_Anim.fInterpol);	m_pVerts .z = m_pMesh [m_Anim.nCurrFrame].pVerts .z + ((m_pMesh [m_Anim.nNextFrame].pVerts .z - m_pMesh [m_Anim.nCurrFrame].pVerts .z) * m_Anim.fInterpol);}

fTime is the time elapsed since the last call to this function.
This way, the interpolation makes the frame change (thanks to Deston for that).

Thanks again for everything!
Cool. Congrats! And thanks for posting your final solution - hopefully it'll be of help to someone else. :)

Your animation code is a lot cleaner than the code I wrote in my MD2 class. ;)

This topic is closed to new replies.

Advertisement