Sign in to follow this  
cppcdr

MD2 Animation

Recommended Posts

cppcdr    168
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 [i].x = m_pMesh [m_Anim.nCurrFrame].pVerts [i].x + ((m_pMesh [m_Anim.nNextFrame].pVerts [i].x - m_pMesh [m_Anim.nCurrFrame].pVerts [i].x) * m_Anim.fInterpol);
	m_pVerts [i].y = m_pMesh [m_Anim.nCurrFrame].pVerts [i].y + ((m_pMesh [m_Anim.nNextFrame].pVerts [i].y - m_pMesh [m_Anim.nCurrFrame].pVerts [i].y) * m_Anim.fInterpol);
	m_pVerts [i].z = m_pMesh [m_Anim.nCurrFrame].pVerts [i].z + ((m_pMesh [m_Anim.nNextFrame].pVerts [i].z - m_pMesh [m_Anim.nCurrFrame].pVerts [i].z) * m_Anim.fInterpol);
}

Thanks in advance!

Share this post


Link to post
Share on other sites
Nacho    205
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


Share this post


Link to post
Share on other sites
Deston    162
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?

Share this post


Link to post
Share on other sites
cppcdr    168
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.

Share this post


Link to post
Share on other sites
Deston    162
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?

Share this post


Link to post
Share on other sites
cppcdr    168
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 [i].x = m_pMesh [m_Anim.nCurrFrame].pVerts [i].x + ((m_pMesh [m_Anim.nNextFrame].pVerts [i].x - m_pMesh [m_Anim.nCurrFrame].pVerts [i].x) * m_Anim.fInterpol);
m_pVerts [i].y = m_pMesh [m_Anim.nCurrFrame].pVerts [i].y + ((m_pMesh [m_Anim.nNextFrame].pVerts [i].y - m_pMesh [m_Anim.nCurrFrame].pVerts [i].y) * m_Anim.fInterpol);
m_pVerts [i].z = m_pMesh [m_Anim.nCurrFrame].pVerts [i].z + ((m_pMesh [m_Anim.nNextFrame].pVerts [i].z - m_pMesh [m_Anim.nCurrFrame].pVerts [i].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!

Share this post


Link to post
Share on other sites
Deston    162
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. ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this