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, ¶ms));}
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 ");