# Looping animation problem

## Recommended Posts

belfegor    2834

I was reading "Skinned Mesh Character Animation with Direct3D 9.0c" pdf book by Frank Luna, wich is mostly about animating with D3DX animation classes.
But in it there was also an example of general function for bone interpolation between key frames, witch i took to experiment with (i have ommited scaling factor since i dont need that):

void AnimationController::interpolateKeys(std::size_t k0Inx, std::size_t k1Inx, std::size_t boneInx, D3DXMATRIX& L)

{

const auto& vKeyFrames  = vAnimations[currAnimInx]->getKeyFrames();

const float currAnimLen = vAnimations[currAnimInx]->getLength();

const auto& k0          = vKeyFrames[boneInx][k0Inx];

const auto& k1          = vKeyFrames[boneInx][k1Inx];

// Transform to [0, 1]

float t        = currTime;

float t0       = k0.time;

float t1       = k1.time;

if(k1Inx == 0)

{

t1 = currAnimLen;

}

float lerpTime = (t - t0) / (t1 - t0);

// Compute interpolated RST-values.

D3DXVECTOR3 lerpedT;

D3DXQUATERNION lerpedR;

D3DXVec3Lerp(&lerpedT, &k0.T, &k1.T, lerpTime);

D3DXQuaternionSlerp(&lerpedR, &k0.R, &k1.R, lerpTime);

// Build and return the interpolated local

// transformation matrix for this bone.

D3DXMATRIX T, R;

D3DXMatrixTranslation(&T, lerpedT.x, lerpedT.y, lerpedT.z);

D3DXMatrixRotationQuaternion(&R, &lerpedR);

L = R * T;

assert(!(t > t1));

assert(!(t < t0));

}

void AnimationController::interpolateBone(std::size_t boneInx, D3DXMATRIX& L)

{

std::size_t numKeys      = vAnimations[currAnimInx]->getNumKeys();

std::size_t secondKeyInx = currKeyFrameInx + 1;

if(secondKeyInx >= numKeys)

{

secondKeyInx = 0u;

}

interpolateKeys(currKeyFrameInx, secondKeyInx, boneInx, L);

}

So i write 3ds max exporter plugin using igame interface classes to export skinned data needed for my own animation structure.
This is my update function witch i call every frame:

void AnimationController::update(float dt)

{

const float currAnimLen = vAnimations[currAnimInx]->getLength();

currTime += dt;

// force time into corect range

while(currTime > currAnimLen)

{

currTime -= currAnimLen;

}

// Find first key index

const auto& vKeys   = vAnimations[currAnimInx]->getKeyFrames();

std::size_t numKeys = vAnimations[currAnimInx]->getNumKeys();

currKeyFrameInx = numKeys;

for(std::size_t i = 0; i < numKeys; ++i)

{

float ct = vKeys[0][i+1].time;

if(ct > currTime)

{

currKeyFrameInx = i;

break;

}

}

}

// and call it in my skinned mesh

void SkinnedMesh::update(float dt)

{

animCtrl->update(dt);

for(std::size_t i = 0; i < vBones.size(); ++i)

{

animCtrl->interpolateBone(i, vBones[i].localMat);

}

combineTransforms();

for(std::size_t i = 0; i < vBones.size(); ++i)

{

const auto& vPoseMat = animCtrl->getPoseMat();

vFinalTransforms[i] = vPoseMat[i] * vBones[i].combMat;

}

}

The problem is when it is about at the end frames my character have strange glitch/"sudden jerky movement". I made a video so you can better se what is the problem:

When i play animation in modeling editor, then it loops corectly.

Please comment my code if you see something wrong.

##### Share on other sites
for(std::size_t i = 0; i < numKeys; ++i)

{

float ct = vKeys[0][i+1].time;



That looks dodgy... what if i == numKeys - 1, you access vKeys array beyond the end....

##### Share on other sites
belfegor    2834

I have tried this also:

currKeyFrameInx     = 0u;
for(std::size_t i = (numKeys - 1); --i;)
{
float ct = vKeys[0][i].time;
if(ct < currTime)
{
currKeyFrameInx = i;
break;
}
}


But for some reason it isn't in range and it asserts:

assert(!(t > t1));


since t must be t0 < t < t1.

Any tip how should i find correct index for key.

EDIT:

I have 23 keyframes (in one second), this is the keys time (they are in seconds):

EDIT2:

Actually i made a mistake, it should be:

for(std::size_t i = numKeys; --i;)

{

float ct = vKeys[0][i].time;

if(ct < currTime)

{

currKeyFrameInx = i;

break;

}

}


Now it looks correct. Need to refresh my memory how for loop works.