Sign in to follow this  
Heelp

OpenGL Exported animation from Blender to my game is kind of distorted.(+gif)

Recommended Posts

Guys, I animated some FPS arms model in Blender 2.77, because I need it for my game. But when I load it into my game using the Assimp Library, it is messed up.

 

(click on picture)

[attachment=33095:fpshandsmessedup.gif]

 

Some say it is because of Blender's vertex weight issues, others say that it doesn't export to collada properly. And I can't use .fbx because assimp has a really bad support for it. Guys, any suggestions are welcome. I spent 20+ hours on this, and if I figure out the reason why this happens maybe I can find a way to fix it.

 

The interesting thing is that when I use open3mod which is the assimp model viewer, there aren't distortions, but when I use assimp library in openGL to load the model, it loads really bad, and models from the internet are working fine that's why my guess is that the problem is in Blender, not in my code, I don't why this happens, really.

Edited by codeBoggs

Share this post


Link to post
Share on other sites

If you want some people here to help you, provide more information, as for example:

 

* what is the format of your export ?

* maybe a link to this file ?

* any code maybe ?

 

Also, if this works fine with the assimp model viewer, then it certainly means that there is a bug somewhere in your code. Compare both your code and the one in the assimp loader.

Share this post


Link to post
Share on other sites
what is the format of your export ?

 

collada export

 

 

 

maybe a link to this file ?

 

http://xenosmashgames.com/wp-content/uploads/2014/08/rigNoPose.blend_.zip

 

 

 

any code maybe ?

 

 

All the code for the animation loading is maybe more than 1000 lines, that's why I won't post it here, but I do all the loading using assimp and other animated models I download from the internet work perfectly fine, so it can't be the code ( it's mostly from tutorials ). pretty sure it's blender's fault but I don't know exactly what the reason for this is.

Edited by codeBoggs

Share this post


Link to post
Share on other sites

_Silence_, you were right. My code was the problem. There is a problem in the blender collada exporter which is connected with blender's vertex weight stuff, because the rig seems messed up, but that distortion I have that starts from the finger is because of my code here.

I tried to optimize this:

const aiNodeAnim* Model::FindNodeAnim(const aiAnimation* pAnimation, const string NodeName)
{
    for (uint i = 0 ; i < pAnimation->mNumChannels ; i++)   //Go through all animation channels stored by assimp
    {
        const aiNodeAnim* pNodeAnim = pAnimation->mChannels[i];    //Get the name of the current animation channel

        if (string(pNodeAnim->mNodeName.data) == NodeName)  //Check if the nodeName is the same with the channel name
        {
            return pNodeAnim; //If it's the same, return the channel
        }
    }

    return NULL;
}

This code finds the proper animation based on the node's name. The big problem with this code is that it searches for the same animations hundreds of time per second and it does very expensive string comparisons and this lowers my fps brutally. But when I use this code, the above animations works perfectly fine although the fps is slow.

 

But my idea was to store everything in a map container and just use it, instead of comparing strings all the time.

 

That's why I changed the code to this:

const aiNodeAnim* Model::FindNodeAnim( const aiAnimation* pAnimation, const string NodeName )
{
    uint numChannels = pAnimation->mNumChannels;

    if( nodeAnimMapping.size() < numChannels ) //If the map contains less elements than the number of channels in the model, then fill the map
    {
        for ( uint i = 0 ; i < numChannels ; i ++ )
        {
            const aiNodeAnim* pNodeAnim = pAnimation->mChannels[i];

            if ( string( pNodeAnim->mNodeName.data ) == NodeName )
            {
                if( nodeAnimMapping.find( NodeName ) == nodeAnimMapping.end() ) //If the name is not in the map, add it
                {
                    nodeAnimMapping[ NodeName ] = i;
                }
                return pNodeAnim;
            }
        }
        nodeAnimMapping[ NodeName ] = numChannels + 10; //Else just put random number that I won't need and return NULL
        return NULL;
    }
    else
    {
        int nodeIndex = nodeAnimMapping[ NodeName ];
        if( nodeIndex < numChannels ) // If the map container is full
        {
            const aiNodeAnim* pNodeAnim = pAnimation->mChannels[ nodeIndex ]; //Find the animation from the map container
            return pNodeAnim;
        }
        else if( nodeIndex > numChannels )
        {
            return NULL;
        }
    }
}

This code is a big optimization, and it works for most models, but not for this one I showed in the .gif. This means there is something wrong with this code, but I don't know what is it.

Share this post


Link to post
Share on other sites

If the original code is working, go back to the original code. The original code is solid code; just stop calling it over and over again.

 

You should be running this in a game loop that draws one frame buffer per loop.

 

I haven't used Assimp yet, but I have written a program that takes animation data for the standard Humanoid Armature in Blender and plays it back as a stick figure. And my program allowed you to select which animation you wanted to play back from the file. So, I'm sure Assimp is doing basically the same thing.

 

But you don't want this code to run every frame. You want this function to be called when it's time to move to a new animation. That's probably once, and then again when you want to play a different animation, not every frame. This is the "change the animation" code, not the "play the animation" code. Depending on how many animations the file contained, this could be a fairly expensive look-up. Just the fact that it is string based makes it a bit of an ugly lookup. But calling animations by name is easier than by number. All you are trying to do here is to get a pointer to the correct animation by supplying the animation's name; you need that once - not in a loop. So, use something to trigger this call when needed.

 

If there is only one animation in the file, you may not even need a loop here and can just pick the first one.

 

But I would probably stick with this. If you call this in your Update() for your game loop when a button is pressed or when some other event occurs signaling a different animation than you'll only run this code once in a blue moon. My program had a switch statement so that if you pressed the right arrow it selected the next animation and if you hit the left arrow it went to the previous animation.

 

But the code is returning a pointer to an animation. This is just allowing you to select which animation you want since an animation file can contain an infinite number of animations in one file. Usually the animator names the animations and so selecting them by name is pretty natural. Or at least that's what I assume by looking at the code. I imagine what Assimp is calling a channel is a single animation. Then each channel/animation contains a series of key frames. Then you have to provide the animation between the key frames.

 

The fact that it returns a pointer to an animation is the "efficiency". Look the pointer up when you need to change to a new animation since looking it up by name is the easiest way to do this. But then store the pointer and don't ask for it again until you need a different animation. Looking the animation up by pointer should be pretty efficient.

 

For those who don't know, the key frames are just poses of the armature (bones that control the model) with a specific frame number. So, if you have 90 frames in the animation and want to run the animation at 30 frames per second, the animation will last 3 seconds. And you may only get 7 key frames. Each key frame will have a frame number it needs to occur at. So for example, you may have the first one on the very first frame and then the second one on the 13th frame and the third on the 27th frame. All those frames in between you need to provide the poses for. So, between the first frame and the 13th frame - for example - you do a weighted average using SLERP to morph the pose of the first key frame into the pose of the 13th frame.

Edited by BBeck

Share this post


Link to post
Share on other sites

Guys, thanks a lot for the help. I'm kind of self-taught on this animations stuff and there is always something I don't know. But there's always someone else who knows it.  ^_^

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