Sign in to follow this  
belfegor

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:

 

http://www.youtube.com/watch?v=HoUODy0r0RI

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.

Share this post


Link to post
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):

 

key-time.jpg

 

key-time2.jpg

 

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. sad.png

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