Ogre skeleton Animation

Source: Internet
Author: User
Http://www.cnblogs.com/gameprogram/archive/2011/11/22/2259127.html ogre skeleton Animation

I. Basic Framework

Let's take a look at the basic ogre animation framework:

Http://blog.csdn.net/leonwei/article/details/5819248

Ii. animation control

The basic animation control of ogre is very simple. The operation for setting an animation is as follows:

// Set idle animationmAnimationState = ent->getAnimationState( "Idle" ); mAnimationState->setLoop( true );mAnimationState->setEnabled( true );
Copy code

(The above Code comes from intermediate tutorial1-Ogre wiki) gets the animationstate pointer from an entity object, and then sets some attributes that need to be called at each frame (in framelistener ):

mAnimationState->addTime( evt.timeSinceLastFrame );

Input the time of each frame so that the animation starts to work.

Iii. Loading animation resources

1. Loading skeleton

You can use skeletonmanager to load the skeleton file.

SkeletonPtr skel = SkeletonManager::getSingleton().load("jaiqua.skeleton", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
Copy code

This load is the virtual function load of ResourceManager inherited by skeletonmanager.

 ResourcePtr ResourceManager::load(const String& name,         const String& group, bool isManual, ManualResourceLoader* loader,         const NameValuePairList* loadParams)    {        ResourcePtr r = createOrRetrieve(name,group,isManual,loader,loadParams).first;        // ensure loaded        r->load();        return r;    }
Copy code

Create a resource in it, skeleton is here, and call its load function.

This load function is inherited from the Resource class. All resources in ogre inherit from this class, such as material and mesh.

 void Resource::load(bool background){...    if (old==LOADSTATE_UNLOADED)                prepareImpl();       preLoadImpl();       old = LOADSTATE_PREPARED;       if (mGroup == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)       {             // Derive resource group             changeGroupOwnership(             ResourceGroupManager::getSingleton()             .findGroupContainingResource(mName));       }       loadImpl();       postLoadImpl();...}
Copy code

The main logic for loading resources here is loadimpl (). This is a pure virtual function, which is implemented by sub-classes. What we read now is skeleton, therefore, loadimpl () in the skeleton class is used ().

void Skeleton::loadImpl(void){    SkeletonSerializer serializer;    LogManager::getSingleton().stream()        << "Skeleton: Loading " << mName;    DataStreamPtr stream =         ResourceGroupManager::getSingleton().openResource(        mName, mGroup, true, this);    serializer.importSkeleton(stream, this);    // Load any linked skeletons    LinkedSkeletonAnimSourceList::iterator i;    for (i = mLinkedSkeletonAnimSourceList.begin();         i != mLinkedSkeletonAnimSourceList.end(); ++i)    {        i->pSkeleton = SkeletonManager::getSingleton().load(            i->skeletonName, mGroup);    }}
Copy code

This function mainly involves two things: 1. Use skeletonserializer to parse the file data stream and save it to the current skeleton instance; 2. Load all related skeleton instances (in. <animationlinks> label of the skeleton file ).

Animation information is stored in the "animationlist manimationslist" member variable of skeleton. The animation information can be obtained based on the animation name.

SkeletonPtr skel = SkeletonManager::getSingleton().load("Jaiqua.skeleton",            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);Animation* anim = skel->getAnimation("Sneak");
Copy code


Here is the difference between skeleton and skeletoninstance. skeletoninstance inherits skeleton and stores a pointer to skeleton. You can open the header file of skeletoninstance and see a brief description in English.

/** A SkeletonInstance is a single instance of a Skeleton used by a world object.    @remarks        The difference between a Skeleton and a SkeletonInstance is that the        Skeleton is the 'master' version much like Mesh is a 'master' version of        Entity. Many SkeletonInstance objects can be based on a single Skeleton,         and are copies of it when created. Any changes made to this are not        reflected in the master copy. The exception is animations; these are        shared on the Skeleton itself and may not be modified here.    */
Copy code

Simple translation:

A skeletoninstance class is a single skeleton instance. Skeleton is a host, just as a mesh can have multiple entity instances. One skeleton can have many skeletoninstances. Each skeletoninstance copies the skeleton information. Changes to some information in the skeletoninstance do not affect the information in the skeleton, however, modifications to the animation will affect the animation in skeleton, because the animation information is shared.

The most typical advantage here is that you can dynamically add things, such as weapons and equipment, to the bones.

2. Mesh Loading
Skeleton is loaded separately. How does mesh know which skeleton is his? If you use the XML converter to convert the. Mesh file to XML, you can see that there is <skeletonlink name = "jaiqua. Skeleton"/>

So he will load it when loading the mesh.

Now let's take a look at the mesh loading steps .. This loading can really confuse people ..

First, let's look at the call point:

Entity* ent = mSceneMgr->createEntity("jaiQua", "jaiqua.mesh");

Jump:

Entity* SceneManager::createEntity(                                   const String& entityName,                                   const String& meshName ){    // delegate to factory implementation    NameValuePairList params;    params["mesh"] = meshName;    return static_cast<Entity*>(        createMovableObject(entityName, EntityFactory::FACTORY_TYPE_NAME,             &params));}
Copy code

Production method:

MovableObject* SceneManager::createMovableObject(const String& name,     const String& typeName, const NameValuePairList* params){...    MovableObjectFactory* factory =         Root::getSingleton().getMovableObjectFactory(typeName);    MovableObject* newObj = factory->createInstance(name, this, params);...}
Copy code

Call factory method:

MovableObject* MovableObjectFactory::createInstance(        const String& name, SceneManager* manager,         const NameValuePairList* params){    MovableObject* m = createInstanceImpl(name, params);    m->_notifyCreator(this);    m->_notifyManager(manager);    return m;}
Copy code
Createinstanceimpl () is a pure virtual function implemented by different sub-classes. Here, the entity method is called.
MovableObject* EntityFactory::createInstanceImpl( const String& name,                                                 const NameValuePairList* params){    // must have mesh parameter    MeshPtr pMesh;    if (params != 0)    {        NameValuePairList::const_iterator ni = params->find("mesh");        if (ni != params->end())        {            // Get mesh (load if required)            pMesh = MeshManager::getSingleton().load(                ni->second,                // autodetect group location                ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME );        }    }    if (pMesh.isNull())    {        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,            "'mesh' parameter required when constructing an Entity.",            "EntityFactory::createInstance");    }    return OGRE_NEW Entity(name, pMesh);}
Copy code
The load function is also called to load mesh resources.
The loading process is similar to skeleton, so let's focus on the following:
After several jumps .. Call to meshserializerimpl: importmesh
void MeshSerializerImpl::importMesh(DataStreamPtr& stream, Mesh* pMesh, MeshSerializerListener *listener){    // Determine endianness (must be the first thing we do!)    determineEndianness(stream);    // Check header    readFileHeader(stream);    unsigned short streamID;    while(!stream->eof())    {        streamID = readChunk(stream);        switch (streamID)        {        case M_MESH:            readMesh(stream, pMesh, listener);            break;        }    }}
Copy code
Follow up:
Usage: readmesh ()-case when: =, meshserializerimpl: readskeletonlink (); =, mesh: setskeletonname (); =, mskeleton = skeletonmanager: getsingleton (). load (skelname, mgroup); -- get the skeleton pointer
Mskeleton is the pointer to the skeleton stored in the mesh.
In this way, the corresponding skeleton can be obtained from entity.
SkeletonInstance* skelIns = ent->getSkeleton();
 
3. animation set

The animation class object is "an animation sequence". All types of animation sequences are managed by this class. It manages three types of track lists: nodeanimationtrack, numericanimationtrack, and vertexanimationtrack.

In layman's terms, an animation is composed of the animation tracks of all its parts. For example, a human animation is composed of the trajectory of his head and limbs.

Animationstate is an animation state management class. You can set the animation weight inside and set whether or not the animation is enabled and whether the animation is in a loop state.

Animationstateset is a set of all animationstates.

In the constructor of entity, if the mesh contains a skeleton animation or vertex animation, an animationstateset object will be created and "mesh-> _ initanimationstate (manimationstate);" will be called );".

void Entity::_initialise(bool forceReinitialise){...// Is mesh skeletally animated?    if (mMesh->hasSkeleton() && !mMesh->getSkeleton().isNull())    {        mSkeletonInstance = OGRE_NEW SkeletonInstance(mMesh->getSkeleton());        mSkeletonInstance->load();    }// Initialise the AnimationState, if Mesh has animation    if (hasSkeleton())    {        mFrameBonesLastUpdated = OGRE_NEW_T(unsigned long, MEMCATEGORY_ANIMATION)(std::numeric_limits<unsigned long>::max());        mNumBoneMatrices = mSkeletonInstance->getNumBones();        mBoneMatrices = static_cast<Matrix4*>(OGRE_MALLOC_SIMD(sizeof(Matrix4) * mNumBoneMatrices, MEMCATEGORY_ANIMATION));    }    if (hasSkeleton() || hasVertexAnimation())    {        mAnimationState = OGRE_NEW AnimationStateSet();        mMesh->_initAnimationState(mAnimationState);        prepareTempBlendBuffers();    }...}
Copy code
You can see that skeletoninstance is used in entity, rather than directly using the skeleton of mesh.
 
4. animation update

The main operation is in the "Void entity: updateanimation (void)" function.

= "Entity: cachebonematrices
= "SKELETON: setanimationstate
This function first calls "skeleton: reset", finds the corresponding animation for each enabled animation state, and then calls Animation: Apply () to calculate the status of each bone.

 

TIPS:

1. Copy an animation

Animation * copyanim = skel-> createanimation ("oldsneak", anim-> getlength ());
* Copyanim = * (anim-> clone ("oldsneak "));
Ent-> refreshavailableanimationstate ();

Remember to use refresh, or you cannot find it.

2. Add an animation:

Skeletoninstance * skelins = ent-> getskeleton ();
Skelins-> addjavasskeletonanimationsource ("XX. Skeleton ");

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.