Browse Source

Adds animated node transforms for animation importing.
Fixes sequence timing variables.

OTHGMars 6 years ago
parent
commit
17a2e416ed

+ 123 - 2
Engine/source/ts/assimp/assimpAppNode.cpp

@@ -31,6 +31,8 @@
 #include <assimp/postprocess.h>
 #include <assimp/types.h>
 
+aiAnimation* AssimpAppNode::sActiveSequence = NULL;
+
 AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* node, AssimpAppNode* parent)
 :  mInvertMeshes(false),
    mLastTransformTime(TSShapeLoader::DefaultTime - 1),
@@ -94,12 +96,131 @@ MatrixF AssimpAppNode::getTransform(F32 time)
       //mLastTransform.scale(ColladaUtils::getOptions().unit);
    }
 
-   mLastTransform.mul(mNodeTransform);
+   // If this node is animated in the active sequence, fetch the animated transform
+   if (sActiveSequence)
+   {
+      MatrixF mat(true);
+      getAnimatedTransform(mat, time, sActiveSequence);
+      mLastTransform.mul(mat);
+   }
+   else
+      mLastTransform.mul(mNodeTransform);
+   
    mLastTransformTime = time;
-
    return mLastTransform;
 }
 
+void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq)
+{
+   // Find the channel for this node
+   for (U32 i = 0; i < animSeq->mNumChannels; ++i)
+   {
+      if (strcmp(mName, animSeq->mChannels[i]->mNodeName.C_Str()) == 0)
+      {
+         aiNodeAnim *nodeAnim = animSeq->mChannels[i];
+         Point3F trans(Point3F::Zero);
+         Point3F scale(Point3F::One);
+         QuatF rot;
+         rot.identity();
+
+         // Transform
+         if (nodeAnim->mNumPositionKeys == 1)
+            trans.set(nodeAnim->mPositionKeys[0].mValue.x, nodeAnim->mPositionKeys[0].mValue.y, nodeAnim->mPositionKeys[0].mValue.z);
+         else
+         {
+            Point3F curPos, lastPos;
+            F32 lastT = 0.0;
+            for (U32 key = 0; key < nodeAnim->mNumPositionKeys; ++key)
+            {
+               F32 curT = (F32)nodeAnim->mPositionKeys[key].mTime;
+               curPos.set(nodeAnim->mPositionKeys[key].mValue.x, nodeAnim->mPositionKeys[key].mValue.y, nodeAnim->mPositionKeys[key].mValue.z);
+               if (curT > t)
+               {
+                  F32 factor = (t - lastT) / (curT - lastT);
+                  trans.interpolate(lastPos, curPos, factor);
+                  break;
+               }
+               else if ((curT == t) || (key == nodeAnim->mNumPositionKeys - 1))
+               {
+                  trans = curPos;
+                  break;
+               }
+
+               lastT = curT;
+               lastPos = curPos;
+            }
+         }
+
+         // Rotation
+         if (nodeAnim->mNumRotationKeys == 1)
+            rot.set(nodeAnim->mRotationKeys[0].mValue.x, nodeAnim->mRotationKeys[0].mValue.y,
+               nodeAnim->mRotationKeys[0].mValue.z, nodeAnim->mRotationKeys[0].mValue.w);
+         else
+         {
+            QuatF curRot, lastRot;
+            F32 lastT = 0.0;
+            for (U32 key = 0; key < nodeAnim->mNumRotationKeys; ++key)
+            {
+               F32 curT = (F32)nodeAnim->mRotationKeys[key].mTime;
+               curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y,
+                  nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w);
+               if (curT > t)
+               {
+                  F32 factor = (t - lastT) / (curT - lastT);
+                  rot.interpolate(lastRot, curRot, factor);
+                  break;
+               }
+               else if ((curT == t) || (key == nodeAnim->mNumRotationKeys - 1))
+               {
+                  rot = curRot;
+                  break;
+               }
+
+               lastT = curT;
+               lastRot = curRot;
+            }
+         }
+
+         // Scale
+         if (nodeAnim->mNumScalingKeys == 1)
+            scale.set(nodeAnim->mScalingKeys[0].mValue.x, nodeAnim->mScalingKeys[0].mValue.y, nodeAnim->mScalingKeys[0].mValue.z);
+         else
+         {
+            Point3F curScale, lastScale;
+            F32 lastT = 0.0;
+            for (U32 key = 0; key < nodeAnim->mNumScalingKeys; ++key)
+            {
+               F32 curT = (F32)nodeAnim->mScalingKeys[key].mTime;
+               curScale.set(nodeAnim->mScalingKeys[key].mValue.x, nodeAnim->mScalingKeys[key].mValue.y, nodeAnim->mScalingKeys[key].mValue.z);
+               if (curT > t)
+               {
+                  F32 factor = (t - lastT) / (curT - lastT);
+                  scale.interpolate(lastScale, curScale, factor);
+                  break;
+               }
+               else if ((curT == t) || (key == nodeAnim->mNumScalingKeys - 1))
+               {
+                  scale = curScale;
+                  break;
+               }
+
+               lastT = curT;
+               lastScale = curScale;
+            }
+         }
+
+         rot.setMatrix(&mat);
+         mat.inverse();
+         mat.setPosition(trans);
+         mat.scale(scale);
+         return;
+      }
+   }
+
+   // Node not found in the animation channels
+   mat = mNodeTransform;
+}
+
 bool AssimpAppNode::animatesTransform(const AppSequence* appSeq)
 {
    return false;

+ 4 - 0
Engine/source/ts/assimp/assimpAppNode.h

@@ -36,6 +36,7 @@
 #ifndef AI_TYPES_H_INC
 #include <assimp/types.h>
 #endif
+#include <assimp/scene.h>
 
 class AssimpAppNode : public AppNode
 {
@@ -43,6 +44,7 @@ class AssimpAppNode : public AppNode
    friend class AssimpAppMesh;
 
    MatrixF getTransform(F32 time);
+   void getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq);
    void buildMeshList();
    void buildChildList();
 
@@ -67,6 +69,8 @@ public:
       //
    }
 
+   static aiAnimation* sActiveSequence;
+
    //-----------------------------------------------------------------------
    const char *getName() { return mName; }
    const char *getParentName() { return mParentName; }

+ 53 - 11
Engine/source/ts/assimp/assimpAppSequence.cpp

@@ -10,29 +10,72 @@
 #include "console/persistenceManager.h"
 #include "ts/assimp/assimpAppMaterial.h"
 #include "ts/assimp/assimpAppSequence.h"
+#include "ts/assimp/assimpAppNode.h"
 
 AssimpAppSequence::AssimpAppSequence(aiAnimation *a) :
+   seqStart(0.0f),
    mAnim(a)
 {
-   fps = mAnim->mTicksPerSecond;
+   // From: http://sir-kimmi.de/assimp/lib_html/data.html#anims
+   // An aiAnimation has a duration. The duration as well as all time stamps are given in ticks.
+   // To get the correct timing, all time stamp thus have to be divided by aiAnimation::mTicksPerSecond.
+   // Beware, though, that certain combinations of file format and exporter don't always store this
+   // information in the exported file. In this case, mTicksPerSecond is set to 0 to indicate the lack of knowledge.
+   fps = (mAnim->mTicksPerSecond > 0) ? mAnim->mTicksPerSecond : 30.0f;
+
+   F32 maxEndTime = 0;
+   F32 minFrameTime = 1000.0f;
+   // Detect the frame rate (minimum time between keyframes) and max sequence time
+   for (U32 i = 0; i < mAnim->mNumChannels; ++i)
+   {
+      aiNodeAnim *nodeAnim = mAnim->mChannels[i];
+      if (nodeAnim->mNumPositionKeys)
+         maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mPositionKeys[nodeAnim->mNumPositionKeys-1].mTime);
+      if (nodeAnim->mNumRotationKeys)
+         maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mRotationKeys[nodeAnim->mNumRotationKeys-1].mTime);
+      if (nodeAnim->mNumScalingKeys)
+         maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mScalingKeys[nodeAnim->mNumScalingKeys-1].mTime);
+
+      for (U32 key = 1; key < nodeAnim->mNumPositionKeys; ++key)
+      {
+         F32 deltaT = nodeAnim->mPositionKeys[key].mTime - nodeAnim->mPositionKeys[key-1].mTime;
+         minFrameTime = getMin(minFrameTime, deltaT);
+      }
+      for (U32 key = 1; key < nodeAnim->mNumRotationKeys; ++key)
+      {
+         F32 deltaT = nodeAnim->mRotationKeys[key].mTime - nodeAnim->mRotationKeys[key-1].mTime;
+         minFrameTime = getMin(minFrameTime, deltaT);
+      }
+      for (U32 key = 1; key < nodeAnim->mNumScalingKeys; ++key)
+      {
+         F32 deltaT = nodeAnim->mScalingKeys[key].mTime - nodeAnim->mScalingKeys[key-1].mTime;
+         minFrameTime = getMin(minFrameTime, deltaT);
+      }
+   }
+
+   fps = (minFrameTime > 0.0f) ? 1.0f / minFrameTime : fps;
+   fps = mClamp(fps, TSShapeLoader::MinFrameRate, TSShapeLoader::MaxFrameRate);
+   seqEnd = maxEndTime;
 }
 
 AssimpAppSequence::~AssimpAppSequence()
 {
 }
 
-F32 AssimpAppSequence::getStart() const 
-{ 
-   return 0.0f; 
-}
-F32 AssimpAppSequence::getEnd() const 
-{ 
-   return (F32)mAnim->mDuration / fps; 
+void AssimpAppSequence::setActive(bool active)
+{
+   if (active)
+      AssimpAppNode::sActiveSequence = mAnim;
+   else
+   {
+      if (AssimpAppNode::sActiveSequence == mAnim)
+         AssimpAppNode::sActiveSequence = NULL;
+   }
 }
 
 U32 AssimpAppSequence::getFlags() const 
 { 
-   return TSShape::Blend; 
+   return TSShape::Blend;
 }
 F32 AssimpAppSequence::getPriority() const 
 { 
@@ -41,5 +84,4 @@ F32 AssimpAppSequence::getPriority() const
 F32 AssimpAppSequence::getBlendRefTime() const 
 { 
    return -1.0f; 
-}
-
+}

+ 7 - 4
Engine/source/ts/assimp/assimpAppSequence.h

@@ -22,6 +22,9 @@
 
 class AssimpAppSequence : public AppSequence
 {
+   F32      seqStart;
+   F32      seqEnd;
+
 public:
 
    AssimpAppSequence(aiAnimation *a);
@@ -29,18 +32,18 @@ public:
 
    aiAnimation *mAnim;
 
-   virtual void setActive(bool active) { }
+   virtual void setActive(bool active);
 
    virtual S32 getNumTriggers() const { return 0; }
    virtual void getTrigger(S32 index, TSShape::Trigger& trigger) const { trigger.state = 0; }
 
    virtual const char* getName() const { return mAnim->mName.C_Str(); }
 
-   virtual F32 getStart() const;
-   virtual F32 getEnd() const;
+   F32 getStart() const { return seqStart; }
+   F32 getEnd() const { return seqEnd; }
+   void setEnd(F32 end) { seqEnd = end; }
 
    virtual U32 getFlags() const;
    virtual F32 getPriority() const;
    virtual F32 getBlendRefTime() const;
-
 };