nel-all
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [Nel] animation problem


From: Martin Schlingmann
Subject: RE: [Nel] animation problem
Date: Fri, 20 Feb 2004 09:38:16 -0000

Hi Andy.

Don’t know if this helps, but I successfully (except for landscapes… argh.. rbank has been bad to me) built a engine using the Nel libraries.

I build an AnimationMgr, a singleton based on the snowb. code for handling of all the animations.

A collegue of me also wrote a more advanced manager (gesturemgr) on top of this one, that one handles all transitions etc. Like if you are in one idle position and want to for example attack. You could just say “attack” to the manager and all transitions on_the_floor_idling -> transition_to_fight_idle -> transition_to_fight -> fight.. etc

 

What I do is:

Have my own map with a struct that I use for lookups (ec “idle”) where I store information and a pointer to the actual animation in the playlist.
Then I have an CAnim class that represents a current ongoing animation, the animation insance.

These reside in an animationqueue in the gameobject’s CPosdata object, if they have one.

 

The animation and their information I load from xml files, I have a system where I am using the network lib to distribute classes, objects and stuff as xml files.

So you could tell the server… “please create an object of id 101 at this position” and if you are allowed It will be created and the information distributed to all clients. Etc…

In the code below however, I just add two animations in the initialize method.

 

What we never got worked out in our heads was how to blend stuff… ie run two animations on the skeleton at the same time. For example walking and waving you hand at the same time. And also reversing the animations.

 

Here’s some code anyway…

 

**** H FILE ***

class CAnimationMgr : public Singleton <CAnimationMgr>

{

public:

                      CAnimationMgr();

                      virtual ~CAnimationMgr();

 

                      uint32 addToAnimationSet (uint32 id, std::string name, std::string file, bool loop);

                      void deleteAnimation(CGameObject* obj);

                      void initialize ();

                      void buildAnimationSet ();

                      void release();

 

                      uint32 update (NLMISC::TTime last_time,NLMISC::TTime new_time);

 

                      void playAnimation(CGameObject* obj, uint32 id, bool force);

 

                      SAnim* getAnim (std::string name,bool needAssert);

                      SAnim* getAnim (uint32 Id,bool needAssert);

 

                      NL3D::UAnimationSet* getAnimationSet () { return pAnimationSet; }

                      NL3D::UPlayListManager* getPlayListManager () { return pPlayListManager; }

                      std::map<uint32,SAnim*>* getAnimMap () {  return &_AnimMap; }

 

private:

                      void computeAnimation(CGameObject* obj, uint32 id);

                      void createAnimation(CGameObject* obj);

                      void updateAnimation(CGameObject* obj, NLMISC::TTime new_time);

 

                      NL3D::CAnimationTime                                _TransitionTime;

                      std::map<uint32,SAnim*>                            _AnimMap;

 

                      NL3D::UAnimationSet*                                pAnimationSet;

                      NL3D::UPlayListManager*                            pPlayListManager;

 

*** CPP FILE ***

#include "AnimationMgr.h"

 

#include "SceneMgr.h"

#include "common.h"

 

using namespace NLMISC;

using namespace NL3D;

using namespace std;

 

CAnimationMgr::CAnimationMgr()

{

                      // Amount of time for the transistion between 2 animations

                      _TransitionTime = 0.25f;

}

 

CAnimationMgr::~CAnimationMgr()

{

}

 

//Make sure the gesture manager has loaded it's animations before this is called

void CAnimationMgr::initialize()

{

                      //Create animation set

                      pAnimationSet = g_SceneMgr.getScene ()->createAnimationSet();

 

                      //Load animations

                      //...

                      addToAnimationSet (1,"idle","GH_Idle.anim",true);

                      addToAnimationSet (2,"walk","GH_Walk.anim",true);

 

}

 

void CAnimationMgr::release()

{

                      //Delete and remove all SAnim struct in map

                      map<uint32,SAnim*>::iterator next = _AnimMap.begin();

                      while (next != _AnimMap.end()) {

                                            SAnim* anim = (*next).second;

                                            map<uint32,SAnim*>::iterator curr = next++;

                                            _AnimMap.erase (curr);

                                            delete anim;

                      }

 

                      g_SceneMgr.getScene ()->deletePlayListManager (pPlayListManager);

}

 

uint32 CAnimationMgr::addToAnimationSet (uint32 id, std::string name, std::string file, bool loop)

{

                      //Create new struct and add to animationset

                      SAnim* anim = new SAnim;

                      anim->Id = id;

                      anim->Loop = loop;

                      anim->Name = name;

                      anim->File = file;

                      anim->AnimId = pAnimationSet->addAnimation (anim->File.c_str(), anim->Name.c_str());

                      anim->Animation = pAnimationSet->getAnimation (anim->AnimId);

                      //Add to map

                      _AnimMap.insert (make_pair (anim->Id, anim));

 

                      return anim->AnimId;

}

 

SAnim* CAnimationMgr::getAnim (std::string name,bool needAssert)

{

                      //This is slow! Iterating through all objects... if this is used a lot.. make a cache map for the strings

 

                      map<uint32,SAnim*>::iterator next = _AnimMap.begin();

                      while (next != _AnimMap.end()) {

                                            SAnim* anim = (*next).second;

                                            if (name.compare (anim->Name) == 0) {

                                                                 return anim;

                                            }

                                            next++;

                      }

                      if (needAssert) {

                                            nlerror ("AnimationMgr->getAnim: animation with name:%s not found", name.c_str());

                      }

                      return NULL;

}

 

SAnim* CAnimationMgr::getAnim (uint32 id,bool needAssert)

{

                      map<uint32,SAnim*>::iterator found = _AnimMap.find (id);

                      if (found == _AnimMap.end ()) {

                                            if (needAssert) {

                                                                 nlerror ("AnimationMgr->getAnim: animation with id:%u not found", id);

                                            }

                                            return NULL;

                      }

                      return (*found).second;

}

 

void CAnimationMgr::buildAnimationSet ()

{

                      pAnimationSet->build ();

                      pPlayListManager = g_SceneMgr.getScene ()->createPlayListManager ();

}

 

uint32 CAnimationMgr::update (TTime last_time,TTime new_time)

{

                      //Update all GameObject animations

                      map<uint32,CGameObject*>* objmap = g_GameObjectMgr.getGameObjects ();

                      map<uint32,CGameObject*>::iterator next = objmap->begin();

                      while (next != objmap->end())

                      {

                                            CGameObject* obj = (*next).second;

                                            if (obj->getAnimData () != NULL) { //Check if object has animation object

                                                                 updateAnimation (obj, new_time);

                                            }

                                            next++;

                      }

                      // compute new animation position depending of the current time

                      pPlayListManager->animate (float(new_time)/1000.0f);

 

                      return 1;

}

 

void CAnimationMgr::computeAnimation (CGameObject* obj, uint32 id)

{

                      //Get the animationId from Id

                      SAnim* anim = getAnim (id,true);

 

                      // Get the current time

                      double currentTime = double (CTime::getLocalTime ())/1000.0f;

 

                      // Find the new slot for the full animation (0 or 1)

                      uint newSlot = obj->getAnimData ()->getNextEmptySlot();

                      uint oldSlot = 1 - obj->getAnimData ()->getNextEmptySlot();

                      obj->getAnimData ()->setNextEmptySlot (1 - obj->getAnimData ()->getNextEmptySlot());

 

                      UPlayList::TWrapMode wrapMode;

 

                      if (anim->Loop == true) {

                                            wrapMode = UPlayList::Repeat;

                      }

                      else {

                                            wrapMode = UPlayList::Clamp;

                      }

                     

                      obj->getAnimData ()->getPlayList ()->setAnimation (newSlot, anim->AnimId);

                      obj->getAnimData ()->getPlayList ()->setTimeOrigin (newSlot, currentTime);

                      obj->getAnimData ()->getPlayList ()->setWeightSmoothness (newSlot, 1.0f);

                      obj->getAnimData ()->getPlayList ()->setWrapMode (newSlot, wrapMode);

 

                      double OldStartTime, OldEndTime;

                      double NewStartTime, NewEndTime;

 

                      // Get the starting time of the old animation slot

                      obj->getAnimData ()->getPlayList() ->getStartWeight (oldSlot, OldStartTime);

                     

                      // Compute the time delta between start of the old animation and now

                      double dt = currentTime - OldStartTime;

 

                      // Compute the new transition value depending of the current time

                      if (dt > _TransitionTime) {

                                            dt = _TransitionTime;

                      }

 

                      OldStartTime = currentTime - (_TransitionTime - dt);

                      OldEndTime = currentTime + dt;

                                           

                      NewStartTime = currentTime;

                      NewEndTime = currentTime + dt;

 

                      // Set new weights on the old and the new animation slot

                      obj->getAnimData ()->getPlayList() ->setStartWeight (oldSlot, 1.0f, OldStartTime);

                      obj->getAnimData ()->getPlayList() ->setEndWeight (oldSlot, 0.0f, OldEndTime);

 

                      obj->getAnimData ()->getPlayList() ->setStartWeight (newSlot, 0.0f, NewStartTime);

                      obj->getAnimData ()->getPlayList() ->setEndWeight (newSlot, 1.0f, OldEndTime);

 

                      // Keep in mind what is the last animation id we set

                      obj->getAnimData ()->setStartAnimationTime ((float)currentTime);

 

}

 

 

void CAnimationMgr::playAnimation (CGameObject* obj, uint32 id, bool force)

{

                      // Get the current time

                      CAnimationTime currentTime = CAnimationTime(CTime::getLocalTime ())/1000.0f;

 

                      // Can't do animation without skeleton

                      if (obj->getModelData ()->getSkeleton() == NULL) {

                                            return;

                      }

 

                      // If the first time we play an animation, create the animation class

                      if (obj->getAnimData ()->getPlayList() == NULL) {

                                            nlinfo ("AnimationMgr->playAnimation: first animation for object %u... creating playlist etc", obj->getId());

                                            createAnimation (obj);

                      }

 

                      if (force || obj->getAnimData ()->getAnimQueue()->empty())

                      {

                                            computeAnimation (obj, id);

                                           

                                            // clear the animation queue

                                            nlinfo ("clearing animation queue");

                                            while (!obj->getAnimData ()->getAnimQueue()->empty()) {

                                                                 obj->getAnimData ()->getAnimQueue()->pop ();

                                            }

                      }

 

                      obj->getAnimData ()->getAnimQueue()->push (id);

}

 

void CAnimationMgr::createAnimation (CGameObject* obj)

{

                      nlassert (obj->getModelData ()->getMesh() != NULL && obj->getModelData ()->getSkeleton() != NULL && pAnimationSet != NULL);

 

                      obj->getAnimData ()->setPlayList (pPlayListManager->createPlayList (pAnimationSet));

                      obj->getAnimData ()->getPlayList()->registerTransform (obj->getModelData ()->getMesh());

                      obj->getAnimData ()->getPlayList()->registerTransform (obj->getModelData ()->getSkeleton());

}

 

void CAnimationMgr::deleteAnimation (CGameObject* obj)

{

                      if (obj->getAnimData ()->getPlayList() == NULL)

                                            return;

 

                      pPlayListManager->deletePlayList (obj->getAnimData ()->getPlayList());

                      obj->getAnimData ()->setPlayList (NULL);

}

 

void CAnimationMgr::updateAnimation(CGameObject* obj, TTime new_time)

{

 

                      if (obj->getAnimData ()->getAnimQueue()->size() > 0) {

                                            SAnim* anim = getAnim (obj->getAnimData ()->getAnimQueue()->front (),true);

                                            if (!(anim->Loop == true) && (float)(new_time/1000.0f) >= obj->getAnimData ()->getStartAnimationTime() + anim->Animation->getEndTime () - _TransitionTime/2)

                                            {

                                                                 // remove the current anim

                                                                 obj->getAnimData ()->getAnimQueue()->pop ();

 

                                                                 if (obj->getAnimData ()->getAnimQueue()->empty ()) {

                                                                                       return;

                                                                 }

                                                                 uint32 newAnim = obj->getAnimData ()->getAnimQueue()->front ();

                                                                 computeAnimation (obj, newAnim);

                                            }

                      }

}

 

*** END OF CPP FILE ****

 

*** THE GAMEOBJECT H ILE ***

public:

                      CGameObject ();

                      CGameObject (std::string xml);

                      virtual ~CGameObject();

 

                      uint32 createFromClass (std::string xml);

 

                      void setId (uint32 id) { _Id = id; }

                      uint32 getId () { return _Id; }

 

                      void setClassId (uint32 id) { _ClassId = id; }

                      uint32 getClassId () { return _ClassId; }

 

                      void setName (std::string name) { _Name = name; };

                      std::string getName () { return _Name; }

 

                      void setLastUpdate (NLMISC::TTime time) { _LastUpdate = time; }

                      NLMISC::TTime getLastUpdate () { return _LastUpdate; }

 

                      void setPosData (CPosData* obj) { pPosData = obj; }

                      CPosData* getPosData () { return pPosData; }

 

                      void setModelData (CModelData* obj) { pModelData = obj; }

                      CModelData* getModelData () { return pModelData; }

 

                      void setAnimData (CAnimData* obj) { pAnimData = obj; }

                      CAnimData* getAnimData () { return pAnimData; }

 

                      CStateHandler* getStateHandler ();

 

                      std::string toXml ();

 

private:

                      uint32                                                         _Id;

                      uint32                                                         _ClassId;

                      std::string                             _Name;

 

                      NLMISC::TTime                     _LastUpdate;

 

                      CModelData*                         pModelData;

                      //CMind*                                                     pMind;

                      CAnimData*                          pAnimData;

                      CPosData*                            pPosData;

                      CStateHandler*                     pStateHandler;

*** END OF GAMEOBJECT H****

 

*** THE ANIMDATA H FILE ***

 

class CAnimData 

{

public:

                      CAnimData();

                      virtual ~CAnimData();

 

                      void release ();

 

                      void setNextEmptySlot (uint32 value);

                      uint getNextEmptySlot ();

 

                      NL3D::UPlayList* getPlayList ();

                      void setPlayList (NL3D::UPlayList* playlist);

 

                      void setStartAnimationTime (float time);

                      NL3D::CAnimationTime& getStartAnimationTime ();

 

                      std::queue<uint32>* getAnimQueue ();

 

private:

                      NL3D::UPlayList*                                                              pPlayList;

                      uint32                                                                                                                          _NextEmptySlot;

                      std::queue<uint32>                                                           _AnimQueue;

                      NL3D::CAnimationTime                                _StartAnimationTime;

};

*** END OF ANIMDATA FILE ***

 

-----Original Message-----
From: address@hidden [mailto:address@hidden On Behalf Of Andi 'Debug' Allen
Sent: den 20 februari 2004
03:47
To: Developer's list for the NeL platform
Subject: Re: [Nel] animation problem

 

hey cyril

 

hate to be a pain old chap

 

but this

 

- Evaluate the current animation time (ie where the animation must by played)

- Get the matrix of the root bone from the current animation (evalute the "pos" and the "rotquat" tracks and build a matrix)

- Translate the matrix with your snaped world position (if need be, rotate it)

- Set the final skeleton world matrix. (Skeleton->setMatrix (finalRootBoneWorldMatrix))

 

ive looked at the animation system and trying to get my head around it

 

how do i do this could you shoot me a quick example if thats ok

 

in my head im thinking

 

animationset of animations

playlists of animations from animation set

each entity has a playlist

 

i need to iterate entities

then get their playlist

then it gets fuzzy...

 

how do i get the current animation time per entity per animation

 

how do i evaluate the pos and rotquat tracks via that i assume which is gained via  getTrackByName

 

this i would of done like this

 

NL3D::UAnimation *testAnimation = CAnimationManager::instance().AnimationSet->getAnimation(0);
NL3D::UTrack *testTrack = testAnimation->getTrackByName("pos");

 

but if we are adjusting each entity via its own playlist? i think im just a little confused as of how

to proceed

 

then how do i use that id to get the

 

 

----- Original Message -----

Sent: Thursday, February 19, 2004 4:46 PM

Subject: Re: [Nel] animation problem

 

Ok,

 

In the previous mail, i tried to solve the bad skinning problem. :-)

For the bad position problem here is the point :

I assume that you move the creature skeleton with a code like:

 

Skeleton->setPos (LastSnapedOnTheGroundPosition);

 

It works with the GNU because it is not skinned to a skeleton and the GNU local origine is 1 meter under the object. So the GNU floats perfectly.

 

In the case of a skeleton, setPos() sets the world position of the root bone. (here, it is "Bip01"). The root bone is snap on the landscape and your creature is half into the ground. It is the animation that will give the delta Z position above the ground.

 

In Ryzom, we make the following things:

 

- Evaluate the next world position of the creature

- Snap it on the ground

- Evaluate the current animation time (ie where the animation must by played)

- Get the matrix of the root bone from the current animation (evalute the "pos" and the "rotquat" tracks and build a matrix)

- Translate the matrix with your snaped world position (if need be, rotate it)

- Set the final skeleton world matrix. (Skeleton->setMatrix (finalRootBoneWorldMatrix))

 

If you have animated your creature with its feet snaped on z=0, the "pos" track should return a decent Z value (>0, in fact the same than in 3dsmax).

 

I hope this helps.

 

Hld.

----- Original Message -----

Sent: Thursday, February 19, 2004 4:34 PM

Subject: Re: [Nel] animation problem

 

ok if the shape and skeleton are in the same position

no matter where that is they appear half underground

and (facing forwards in max ) appear facing left in game

even tho GNU is facing right way and happily floating above the

ground

 

 

 

----- Original Message -----

Sent: Thursday, February 19, 2004 3:06 PM

Subject: Re: [Nel] animation problem

 

moving the shape without the physique modifier

then pasting the physique modifier back on worked

 

i am about 0.0001" off but it doesnt notice visually

which i can cope with

 

strange tho if i clicked VIEW SCENE in 3ds max it

animated fine its only when i export that the shapes

position comes into play.

 

wouldnt it be a good idea to have a node option

that took its worldspace position instead of object space?

 

 

 

----- Original Message -----

Sent: Thursday, February 19, 2004 2:47 PM

Subject: Re: [Nel] animation problem

 

hi cyril :)

 

if i disable the physique modifier he drops back to 0,0,0

so that maybe the issue...

 

ill try moving him and let you know how it goes :)

 

incidentally do you know how to resize an object in 3ds

i cant seem to do more than rescale its world space interpretation

 

 

----- Original Message -----

Sent: Thursday, February 19, 2004 10:23 AM

Subject: Re: [Nel] animation problem

 

Oops, forget the previous message..

 

Hi Andi,

 

> after loading into our game i notice that after adding the skeleton our monster is half under the floor

> and facing the wrong way...

 

This is a classic issue, in max, when you create your biped, it looks at the -Y axis to face the front view.

 

> same issue his tail went crazy and im sure he enjoyed it but was pretty unbecomming even for a horny little monster

 

Can you check this points before we go further:

 

    The skin shape vertices are exported in world space (it's a special case). At run time, vertices are moved back in bone local space using the inverted "figure mode" bone world matrix and then transformed in word space using the "current" bone world matrix. It means that :

    - whatever you may change on your skeleton (position, posture, orientation, size) you have to reexport the skin model.

    - you have to be sure that your skin shape, with physique modifier disabled, matchs the skeleton in figure mode.

    - the skin shape and the skeleton have to be exported in figure mode.

 

I hope your monster will get back on form :-)

 

Hld.


_______________________________________________
Nel mailing list
address@hidden
http://mail.nongnu.org/mailman/listinfo/nel-all


_______________________________________________
Nel mailing list
address@hidden
http://mail.nongnu.org/mailman/listinfo/nel-all


_______________________________________________
Nel mailing list
address@hidden
http://mail.nongnu.org/mailman/listinfo/nel-all


_______________________________________________
Nel mailing list
address@hidden
http://mail.nongnu.org/mailman/listinfo/nel-all


_______________________________________________
Nel mailing list
address@hidden
http://mail.nongnu.org/mailman/listinfo/nel-all


reply via email to

[Prev in Thread] Current Thread [Next in Thread]