Torque3D Documentation / _generateds / assimpAppNode.cpp

assimpAppNode.cpp

Engine/source/ts/assimp/assimpAppNode.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "ts/loader/appSequence.h"
 26#include "ts/assimp/assimpAppNode.h"
 27#include "ts/assimp/assimpAppMesh.h"
 28
 29// assimp include files. 
 30#include <assimp/cimport.h>
 31#include <assimp/scene.h>
 32#include <assimp/postprocess.h>
 33#include <assimp/types.h>
 34
 35aiAnimation* AssimpAppNode::sActiveSequence = NULL;
 36F32 AssimpAppNode::sTimeMultiplier = 1.0f;
 37
 38AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* node, AssimpAppNode* parent)
 39:  mInvertMeshes(false),
 40   mLastTransformTime(TSShapeLoader::DefaultTime - 1),
 41   mDefaultTransformValid(false)
 42{
 43   mScene = scene;
 44   mNode = node;
 45   appParent = parent;
 46
 47   mName = dStrdup(mNode->mName.C_Str());
 48   if ( dStrlen(mName) == 0 )
 49   {
 50      const char* defaultName = "null";
 51      mName = dStrdup(defaultName);
 52   }
 53
 54   mParentName = dStrdup(parent ? parent->getName() : "ROOT");
 55   assimpToTorqueMat(node->mTransformation, mNodeTransform);
 56   Con::printf("[ASSIMP] Node Created: %s, Parent: %s", mName, mParentName);
 57}
 58
 59// Get all child nodes
 60void AssimpAppNode::buildChildList()
 61{
 62   if (!mNode)
 63   {
 64      mNode = mScene->mRootNode;
 65   }
 66
 67   for (U32 n = 0; n < mNode->mNumChildren; ++n) {
 68      mChildNodes.push_back(new AssimpAppNode(mScene, mNode->mChildren[n], this));
 69   }
 70}
 71
 72// Get all geometry attached to this node
 73void AssimpAppNode::buildMeshList()
 74{
 75   for (U32 n = 0; n < mNode->mNumMeshes; ++n)
 76   {
 77      const struct aiMesh* mesh = mScene->mMeshes[mNode->mMeshes[n]];
 78      mMeshes.push_back(new AssimpAppMesh(mesh, this));
 79   }
 80}
 81
 82MatrixF AssimpAppNode::getTransform(F32 time)
 83{
 84   // Check if we can use the last computed transform
 85   if (time == mLastTransformTime)
 86      return mLastTransform;
 87
 88   if (appParent) {
 89      // Get parent node's transform
 90      mLastTransform = appParent->getTransform(time);
 91   }
 92   else {
 93      // no parent (ie. root level) => scale by global shape <unit>
 94      mLastTransform.identity();
 95      mLastTransform.scale(ColladaUtils::getOptions().unit * ColladaUtils::getOptions().formatScaleFactor);
 96      if (!isBounds())
 97         convertMat(mLastTransform);
 98   }
 99
100   // If this node is animated in the active sequence, fetch the animated transform
101   MatrixF mat(true);
102   if (sActiveSequence)
103      getAnimatedTransform(mat, time, sActiveSequence);
104   else
105      mat = mNodeTransform;
106
107   // Remove node scaling?
108   Point3F nodeScale = mat.getScale();
109   if (nodeScale != Point3F::One && appParent && ColladaUtils::getOptions().ignoreNodeScale)
110   {
111      nodeScale.x = nodeScale.x ? (1.0f / nodeScale.x) : 0;
112      nodeScale.y = nodeScale.y ? (1.0f / nodeScale.y) : 0;
113      nodeScale.z = nodeScale.z ? (1.0f / nodeScale.z) : 0;
114      mat.scale(nodeScale);
115   }
116
117   mLastTransform.mul(mat);
118
119   mLastTransformTime = time;
120   return mLastTransform;
121}
122
123void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq)
124{
125   // Find the channel for this node
126   for (U32 i = 0; i < animSeq->mNumChannels; ++i)
127   {
128      if (strcmp(mName, animSeq->mChannels[i]->mNodeName.C_Str()) == 0)
129      {
130         aiNodeAnim *nodeAnim = animSeq->mChannels[i];
131         Point3F trans(Point3F::Zero);
132         Point3F scale(Point3F::One);
133         QuatF rot;
134         rot.identity();
135
136         // Transform
137         if (nodeAnim->mNumPositionKeys == 1)
138            trans.set(nodeAnim->mPositionKeys[0].mValue.x, nodeAnim->mPositionKeys[0].mValue.y, nodeAnim->mPositionKeys[0].mValue.z);
139         else
140         {
141            Point3F curPos, lastPos;
142            F32 lastT = 0.0;
143            for (U32 key = 0; key < nodeAnim->mNumPositionKeys; ++key)
144            {
145               F32 curT = sTimeMultiplier * (F32)nodeAnim->mPositionKeys[key].mTime;
146               curPos.set(nodeAnim->mPositionKeys[key].mValue.x, nodeAnim->mPositionKeys[key].mValue.y, nodeAnim->mPositionKeys[key].mValue.z);
147               if ((curT > t) && (key > 0))
148               {
149                  F32 factor = (t - lastT) / (curT - lastT);
150                  trans.interpolate(lastPos, curPos, factor);
151                  break;
152               }
153               else if ((curT >= t) || (key == nodeAnim->mNumPositionKeys - 1))
154               {
155                  trans = curPos;
156                  break;
157               }
158
159               lastT = curT;
160               lastPos = curPos;
161            }
162         }
163
164         // Rotation
165         if (nodeAnim->mNumRotationKeys == 1)
166            rot.set(nodeAnim->mRotationKeys[0].mValue.x, nodeAnim->mRotationKeys[0].mValue.y,
167               nodeAnim->mRotationKeys[0].mValue.z, nodeAnim->mRotationKeys[0].mValue.w);
168         else
169         {
170            QuatF curRot, lastRot;
171            F32 lastT = 0.0;
172            for (U32 key = 0; key < nodeAnim->mNumRotationKeys; ++key)
173            {
174               F32 curT = sTimeMultiplier * (F32)nodeAnim->mRotationKeys[key].mTime;
175               curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y,
176                  nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w);
177               if ((curT > t) && (key > 0))
178               {
179                  F32 factor = (t - lastT) / (curT - lastT);
180                  rot.interpolate(lastRot, curRot, factor);
181                  break;
182               }
183               else if ((curT >= t) || (key == nodeAnim->mNumRotationKeys - 1))
184               {
185                  rot = curRot;
186                  break;
187               }
188
189               lastT = curT;
190               lastRot = curRot;
191            }
192         }
193
194         // Scale
195         if (nodeAnim->mNumScalingKeys == 1)
196            scale.set(nodeAnim->mScalingKeys[0].mValue.x, nodeAnim->mScalingKeys[0].mValue.y, nodeAnim->mScalingKeys[0].mValue.z);
197         else
198         {
199            Point3F curScale, lastScale;
200            F32 lastT = 0.0;
201            for (U32 key = 0; key < nodeAnim->mNumScalingKeys; ++key)
202            {
203               F32 curT = sTimeMultiplier * (F32)nodeAnim->mScalingKeys[key].mTime;
204               curScale.set(nodeAnim->mScalingKeys[key].mValue.x, nodeAnim->mScalingKeys[key].mValue.y, nodeAnim->mScalingKeys[key].mValue.z);
205               if ((curT > t) && (key > 0))
206               {
207                  F32 factor = (t - lastT) / (curT - lastT);
208                  scale.interpolate(lastScale, curScale, factor);
209                  break;
210               }
211               else if ((curT >= t) || (key == nodeAnim->mNumScalingKeys - 1))
212               {
213                  scale = curScale;
214                  break;
215               }
216
217               lastT = curT;
218               lastScale = curScale;
219            }
220         }
221
222         rot.setMatrix(&mat);
223         mat.inverse();
224         mat.setPosition(trans);
225         mat.scale(scale);
226         return;
227      }
228   }
229
230   // Node not found in the animation channels
231   mat = mNodeTransform;
232}
233
234bool AssimpAppNode::animatesTransform(const AppSequence* appSeq)
235{
236   return false;
237}
238
239/// Get the world transform of the node at the specified time
240MatrixF AssimpAppNode::getNodeTransform(F32 time)
241{
242   // Avoid re-computing the default transform if possible
243   if (mDefaultTransformValid && time == TSShapeLoader::DefaultTime)
244   {
245      return mDefaultNodeTransform;
246   }
247   else
248   {
249      MatrixF nodeTransform = getTransform(time);
250
251      // Check for inverted node coordinate spaces => can happen when modelers
252      // use the 'mirror' tool in their 3d app. Shows up as negative <scale>
253      // transforms in the collada model.
254      if (m_matF_determinant(nodeTransform) < 0.0f)
255      {
256         // Mark this node as inverted so we can mirror mesh geometry, then
257         // de-invert the transform matrix
258         mInvertMeshes = true;
259         nodeTransform.scale(Point3F(1, 1, -1));
260      }
261
262      // Cache the default transform
263      if (time == TSShapeLoader::DefaultTime)
264      {
265         mDefaultTransformValid = true;
266         mDefaultNodeTransform = nodeTransform;
267      }
268
269      return nodeTransform;
270   }
271}
272
273void AssimpAppNode::assimpToTorqueMat(const aiMatrix4x4& inAssimpMat, MatrixF& outMat)
274{
275   outMat.setRow(0, Point4F((F32)inAssimpMat.a1, (F32)inAssimpMat.a2,
276      (F32)inAssimpMat.a3, (F32)inAssimpMat.a4));
277
278   outMat.setRow(1, Point4F((F32)inAssimpMat.b1, (F32)inAssimpMat.b2,
279      (F32)inAssimpMat.b3, (F32)inAssimpMat.b4));
280
281   outMat.setRow(2, Point4F((F32)inAssimpMat.c1, (F32)inAssimpMat.c2,
282      (F32)inAssimpMat.c3, (F32)inAssimpMat.c4));
283
284   outMat.setRow(3, Point4F((F32)inAssimpMat.d1, (F32)inAssimpMat.d2,
285      (F32)inAssimpMat.d3, (F32)inAssimpMat.d4));
286}
287
288void AssimpAppNode::convertMat(MatrixF& outMat)
289{
290   MatrixF rot(true);
291
292   switch (ColladaUtils::getOptions().upAxis)
293   {
294   case UPAXISTYPE_X_UP:
295      // rotate 90 around Y-axis, then 90 around Z-axis
296      rot(0, 0) = 0.0f;  rot(1, 0) = 1.0f;
297      rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
298      rot(0, 2) = 1.0f; rot(2, 2) = 0.0f;
299
300      // pre-multiply the transform by the rotation matrix
301      outMat.mulL(rot);
302      break;
303
304   case UPAXISTYPE_Y_UP:
305      // rotate 180 around Y-axis, then 90 around X-axis
306      rot(0, 0) = -1.0f;
307      rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
308      rot(1, 2) = 1.0f; rot(2, 2) = 0.0f;
309
310      // pre-multiply the transform by the rotation matrix
311      outMat.mulL(rot);
312      break;
313
314   case UPAXISTYPE_Z_UP:
315   default:
316      // nothing to do
317      break;
318   }
319}
320
321aiNode* AssimpAppNode::findChildNodeByName(const char* nodeName, aiNode* rootNode)
322{
323   aiNode* retNode = NULL;
324   if (strcmp(nodeName, rootNode->mName.C_Str()) == 0)
325      return rootNode;
326
327   for (U32 i = 0; i < rootNode->mNumChildren; ++i)
328   {
329      retNode = findChildNodeByName(nodeName, rootNode->mChildren[i]);
330      if (retNode)
331         return retNode;
332   }
333   return nullptr;
334}
335