# md2's and interpolation

This topic is 4914 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I found this for md2 animations, and I'm currently assuming that fps is the frames per second that the animation should be played at. I'm trying to get it to work, but with no avail.
struct MD2Animation{
unsigned int begin;
unsigned int end;
unsigned int fps;
};

MD2Animation MD2AnimationList[20] ={
{   0,  39,  9 },   // STAND
{  40,  45, 10 },   // RUN
{  46,  53, 10 },   // ATTACK
{  54,  57,  7 },   // PAIN_A
{  58,  61,  7 },   // PAIN_B
{  62,  65,  7 },   // PAIN_C
{  66,  71,  7 },   // JUMP
{  72,  83,  7 },   // FLIP
{  84,  94,  7 },   // SALUTE
{  95, 111, 10 },   // FALLBACK
{ 112, 122,  7 },   // WAVE
{ 123, 134,  6 },   // POINT
{ 135, 153, 10 },   // CROUCH_STAND
{ 154, 159,  7 },   // CROUCH_WALK
{ 160, 168, 10 },   // CROUCH_ATTACK
{ 196, 172,  7 },   // CROUCH_PAIN
{ 173, 177,  5 },   // CROUCH_DEATH
{ 178, 183,  7 },   // DEATH_FALLBACK
{ 184, 189,  7 },   // DEATH_FALLFORWARD
{ 190, 197,  7 },   // DEATH_FALLBACKSLOW
};

enum MD2AnimationState{
MD2_ANIM_STAND = 0,
MD2_ANIM_RUN,
MD2_ANIM_ATTACK,
MD2_ANIM_PAIN_A,
MD2_ANIM_PAIN_B,
MD2_ANIM_PAIN_C,
MD2_ANIM_JUMP,
MD2_ANIM_FLIP,
MD2_ANIM_SALUTE,
MD2_ANIM_FALLBACK,
MD2_ANIM_WAVE,
MD2_ANIM_POINT,
MD2_ANIM_CROUCH_STAND,
MD2_ANIM_CROUCH_WALK,
MD2_ANIM_CROUCH_ATTACK,
MD2_ANIM_CROUCH_PAIN,
MD2_ANIM_CROUCH_DEATH,
MD2_ANIM_DEATH_FALLBACK,
MD2_ANIM_DEATH_FALLFORWARD,
MD2_ANIM_DEATH_FALLBACKSLOW,

NUM_OF_ANIM
};


This is a little snip of code that I'm using to calculate the amount to interpolate every frame by to play the animation at the right speed.
// calculate the percentage for advance through the frames depending
// on the animation data and the frames-per-second for each anim
float p = (float)( MD2AnimationList[m_animState].fps /
(float)( MD2AnimationList[m_animState].end - MD2AnimationList[m_animState].begin) );

I'm for some animation's I'm getting a value of almost 1 or greater, which doesn't really work very well. Is there a better way to do this? Or are md2 animations supposed to be interpolated at a constant rate?

##### Share on other sites
I'm a little lost as to how you are iterating through your keyframes. The third column is the fps, as you already know. So in STAND, if 1000 / 9 ( =~ 111) ticks have expired, then you proceed to the next frame. In RUN, if 100 ticks have expired, you move on to the next frame.

(end - begin) / fps = time the animation will run for
fps / (end - begin) = one divided by the time the animation will run for

I don't think that the equation is helping much, unless I've misunderstood your intention.

##### Share on other sites
/** * Set an animation for the md2 model based on the animation state. * \param state The state of the model to be animated. */void animate(MD2AnimationState state){	// if the state is invalid	if( !(state >= 0 && state < NUM_OF_ANIM) ){		util::Message::print("CAnimatedMeshMD2::animate: invalid animation state.");		return;		// return without starting the animation	}	m_animState = state;	// change the animation state	// start the animation	animate(MD2AnimationList[m_animState].begin, MD2AnimationList[m_animState].end);}/** * Set the animation for the MD2 model. * \param start_frame Set the starting frame for the animation * \param end_frame Set the end frame for the animation */void animate(unsigned int start_frame, unsigned int end_frame){	// if the parameters are valid	if( start_frame < m_numFrames  &&  end_frame < m_numFrames){		// if we don't want any animation		if( start_frame == end_frame ){			m_startFrame = start_frame;			m_endFrame = end_frame;			m_interpol = 0.0f;			// We don't assign currentFrame here because we might be going from			// animating to not animation, so we'll use m_currentFrame as the difference.			// Eg. startFrame and endFrame could be 50, so we want to display frame 50 with			// no animation. If we're going from frame 70, then currentFrame will still be 70,			// but if currentFrame is equal to startFrame and endFrame, then we don't have to			// reassign the vertices, we can just stop interpolation.			return;		}		m_startFrame = start_frame;	// set the start frame of the animation		m_currentFrame = start_frame;	// set the start frame of the animation		m_endFrame = end_frame;		// set the end frame of the animation		m_interpol = 0.0f;			// set current interpolation to 0	}	else		util::Message::print("CAnimatedMeshMD2::animate: invalid start and/or end frame.");}/** * Updates the animation of the model. * Constructs the vertices between the two keyframes and * stores them in m_displayVertexList. * \param percent The percent to interpolate by (the percentage to advance through each frame, each * interpolation call). The percentage is a decimal point: 0.25 for 25% */void updateInterpolation(float percent = 0.01f){	util::CVector3d v1;					// current frame point values	util::CVector3d v2;					// next frame point values	scene::CVertex3d vertex;			// temporarily holds an interpolated vertex	// If the start and end frames are the same, then that means that	// we don't want any animation.	if( m_startFrame == m_endFrame ){		// if we don't want animation, we have to assign the right vertices for the frame		if( m_displayVertexList.getSize() != m_numVertices ){			m_displayVertexList.clear();			m_displayVertexList.resize(m_numVertices);	// size array		}					// Maybe we're already on the frame we want, so we don't have to reassign		// all the vertices in the model.		if( m_currentFrame != m_startFrame ){			// reassign all the vertices in the model			m_currentFrame = m_startFrame;			for(int i=0; i < m_numVertices; i++)				m_displayVertexList =  m_vertexList[(m_currentFrame*m_numVertices) + i];		}					return;	}	// copy the required vertices into the array	m_displayVertexList.clear();	m_displayVertexList.reserve( m_numVertices );	// If interpolation of a whole frame was done, increment the current frame and next frame.	// Note:: this wraps around again to the beginning of the whole animation.	if (m_interpol >= 1.0f){		m_interpol = 0.0f;	// set interpolation to 0			m_currentFrame++;	// start at next frame		if (m_currentFrame >= m_endFrame)			m_currentFrame = m_startFrame;	// wrap around to the start		m_nextFrame = m_currentFrame + 1;	// assign the next frame to interpolate to		if (m_nextFrame >= m_endFrame || m_nextFrame >= m_numFrames)			m_nextFrame = m_startFrame;		// wrap around to the start	}	// update the interpolation for each vertex	for(int i = 0; i < m_numVertices; i++){		// get the points of each frame to interpolate between		v1 = m_vertexList[(m_currentFrame*m_numVertices) + i].point;		v2 = m_vertexList[(m_nextFrame*m_numVertices) + i].point;		// store first interpolated vertex of triangle		vertex.point.x = v1.x + m_interpol * (v2.x - v1.x);		vertex.point.y = v1.y + m_interpol * (v2.y - v1.y);		vertex.point.z = v1.z + m_interpol * (v2.z - v1.z);		// render properly textured triangle		m_displayVertexList.push_back(vertex);	}	m_interpol += percent;  // increase percentage of interpolation between frames}/** * Render the model using indexed triangle lists. */void render(){	if(m_texture)		m_texture->apply();	// apply the texture	// if the animation state is NOT correct for the currentFrame	if( !(m_currentFrame >= MD2AnimationList[m_animState].begin &&		m_currentFrame < MD2AnimationList[m_animState].end) ){		// set the animation state correctly for the currentFrame of animation		for(int i=0; i < NUM_OF_ANIM; i++)			if( m_currentFrame >= MD2AnimationList.begin && m_currentFrame < MD2AnimationList.end ){				m_animState = (MD2AnimationState) i;				break;			}	}	// calculate the percentage for advance through the frames depending	// on the animation data and the frames-per-second for each anim	float p = (float)( MD2AnimationList[m_animState].fps / 			  (float)( MD2AnimationList[m_animState].end - MD2AnimationList[m_animState].begin) );	// update the animation	updateInterpolation(p);	// draw the indexed triangle list	m_sceneManager->getVideoDriver()->drawIndexedTriangleList(			m_displayVertexList.getPtr(), m_displayVertexList.getSize(),			m_displayIndexList.getPtr(), m_displayIndexList.getSize() );	ISceneGraphNode::render();	// render all the children}

Basically, the 'updateInterpolation' function generally takes care of changing the current frame, and I'm just using the fps inside the 'render' function to calculate the percentage I have to interpolate by this frame (next frame) to keep the proper fps for the animation.

##### Share on other sites
I appear to have lost all my MD2 stuff. :( Regardless, I believe this is what you're getting at. The FPS value in the MD2 data is just for your convenience - code 1000 ticks (one second) / fps to determine the length of each frame. For each animation the length of each frame is constant (although as you've noticed some animations use more FPS or less, depending).

Step 1. Find the time relative to the current frame.Step 1b. If we're greater than the length of this frame, move to the next. Go back to Step 1.Step 2. Say we're 40 ticks into a frame that's 100 ticks long. That's 40%Step 3. vertices = current_frame.vertices * 0.4 + next_frame.vertices * 0.6

Hope that helps.

• 10
• 13
• 57
• 11
• 84