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.localMat);
}
combineTransforms();
for(std::size_t i = 0; i < vBones.size(); ++i)
{
const auto& vPoseMat = animCtrl->getPoseMat();
vFinalTransforms = vPoseMat * vBones.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.
Thank you for your time.