assimpAppNode.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "ts/loader/appSequence.h"
  24. #include "ts/assimp/assimpAppNode.h"
  25. #include "ts/assimp/assimpAppMesh.h"
  26. #if !defined(TORQUE_DISABLE_MEMORY_MANAGER)
  27. #ifdef new
  28. #undef new
  29. #endif
  30. #endif
  31. // assimp include files.
  32. #include <assimp/cimport.h>
  33. #include <assimp/scene.h>
  34. #include <assimp/postprocess.h>
  35. #include <assimp/types.h>
  36. #if !defined(TORQUE_DISABLE_MEMORY_MANAGER)
  37. # define _new new(__FILE__, __LINE__)
  38. # define new _new
  39. #endif
  40. aiAnimation* AssimpAppNode::sActiveSequence = NULL;
  41. F32 AssimpAppNode::sTimeMultiplier = 1.0f;
  42. AssimpAppNode::AssimpAppNode(const aiScene* scene, const aiNode* node, AssimpAppNode* parentNode)
  43. : mScene(scene),
  44. mNode(node ? node : scene->mRootNode),
  45. mInvertMeshes(false),
  46. mLastTransformTime(TSShapeLoader::DefaultTime - 1),
  47. mDefaultTransformValid(false)
  48. {
  49. appParent = parentNode;
  50. // Initialize node and parent names.
  51. mName = dStrdup(mNode->mName.C_Str());
  52. if ( dStrlen(mName) == 0 )
  53. {
  54. const char* defaultName = "null";
  55. mName = dStrdup(defaultName);
  56. }
  57. mParentName = dStrdup(parentNode ? parentNode->mName : "ROOT");
  58. // Convert transformation matrix
  59. assimpToTorqueMat(node->mTransformation, mNodeTransform);
  60. Con::printf("[ASSIMP] Node Created: %s, Parent: %s", mName, mParentName);
  61. }
  62. MatrixF AssimpAppNode::getTransform(F32 time)
  63. {
  64. // Check if we can use the last computed transform
  65. if (time == mLastTransformTime)
  66. {
  67. return mLastTransform;
  68. }
  69. if (appParent) {
  70. // Get parent node's transform
  71. mLastTransform = appParent->getTransform(time);
  72. }
  73. else {
  74. // no parent (ie. root level) => scale by global shape <unit>
  75. mLastTransform.identity();
  76. mLastTransform.scale(ColladaUtils::getOptions().unit * ColladaUtils::getOptions().formatScaleFactor);
  77. if (!isBounds())
  78. {
  79. MatrixF axisFix = ColladaUtils::getOptions().axisCorrectionMat;
  80. mLastTransform.mulL(axisFix);
  81. }
  82. }
  83. // If this node is animated in the active sequence, fetch the animated transform
  84. MatrixF mat(true);
  85. if (sActiveSequence)
  86. getAnimatedTransform(mat, time, sActiveSequence);
  87. else
  88. mat = mNodeTransform;
  89. // Remove node scaling?
  90. Point3F nodeScale = mat.getScale();
  91. if (nodeScale != Point3F::One && appParent && ColladaUtils::getOptions().ignoreNodeScale)
  92. {
  93. nodeScale.x = nodeScale.x ? (1.0f / nodeScale.x) : 0;
  94. nodeScale.y = nodeScale.y ? (1.0f / nodeScale.y) : 0;
  95. nodeScale.z = nodeScale.z ? (1.0f / nodeScale.z) : 0;
  96. mat.scale(nodeScale);
  97. }
  98. mLastTransform.mul(mat);
  99. mLastTransformTime = time;
  100. return mLastTransform;
  101. }
  102. void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq)
  103. {
  104. // Convert time `t` (in seconds) to a frame index
  105. const F32 frameTime = (t * animSeq->mTicksPerSecond + 0.5f) + 1.0f;
  106. // Loop through animation channels to find the matching node
  107. for (U32 k = 0; k < animSeq->mNumChannels; ++k)
  108. {
  109. const aiNodeAnim* nodeAnim = animSeq->mChannels[k];
  110. if (dStrcmp(mName, nodeAnim->mNodeName.C_Str()) != 0)
  111. continue;
  112. Point3F translation(Point3F::Zero);
  113. QuatF rotation(QuatF::Identity);
  114. Point3F scale(Point3F::One);
  115. // Interpolate Translation Keys
  116. if (nodeAnim->mNumPositionKeys > 0)
  117. {
  118. translation = interpolateVectorKey(nodeAnim->mPositionKeys, nodeAnim->mNumPositionKeys, frameTime);
  119. }
  120. // Interpolate Rotation Keys
  121. if (nodeAnim->mNumRotationKeys > 0)
  122. {
  123. rotation = interpolateQuaternionKey(nodeAnim->mRotationKeys, nodeAnim->mNumRotationKeys, frameTime);
  124. }
  125. // Interpolate Scaling Keys
  126. if (nodeAnim->mNumScalingKeys > 0)
  127. {
  128. scale = interpolateVectorKey(nodeAnim->mScalingKeys, nodeAnim->mNumScalingKeys, frameTime);
  129. }
  130. // Apply the interpolated transform components to the matrix
  131. rotation.setMatrix(&mat);
  132. mat.inverse();
  133. mat.setPosition(translation);
  134. mat.scale(scale);
  135. return; // Exit after processing the matching node
  136. }
  137. // Default to the static node transformation if no animation data is found
  138. mat = mNodeTransform;
  139. }
  140. Point3F AssimpAppNode::interpolateVectorKey(const aiVectorKey* keys, U32 numKeys, F32 frameTime)
  141. {
  142. if (numKeys == 1) // Single keyframe: use it directly
  143. return Point3F(keys[0].mValue.x, keys[0].mValue.y, keys[0].mValue.z);
  144. // Clamp frameTime to the bounds of the keyframes
  145. if (frameTime <= keys[0].mTime) {
  146. // Before the first keyframe, return the first key
  147. return Point3F(keys[0].mValue.x, keys[0].mValue.y, keys[0].mValue.z);
  148. }
  149. if (frameTime >= keys[numKeys - 1].mTime) {
  150. // After the last keyframe, return the last key
  151. return Point3F(keys[numKeys - 1].mValue.x, keys[numKeys - 1].mValue.y, keys[numKeys - 1].mValue.z);
  152. }
  153. // Interpolate between the two nearest keyframes
  154. for (U32 i = 1; i < numKeys; ++i)
  155. {
  156. if (frameTime < keys[i].mTime)
  157. {
  158. Assimp::Interpolator<aiVectorKey> interp;
  159. const aiVectorKey& next = keys[i];
  160. const aiVectorKey& prev = keys[i - 1];
  161. const F32 factor = (frameTime - keys[i - 1].mTime) / (keys[i].mTime - keys[i - 1].mTime);
  162. aiVector3D out;
  163. interp(out, prev, next, factor);
  164. return Point3F(out.x, out.y, out.z);
  165. }
  166. }
  167. // Default to the last keyframe
  168. return Point3F(keys[numKeys - 1].mValue.x, keys[numKeys - 1].mValue.y, keys[numKeys - 1].mValue.z);
  169. }
  170. QuatF AssimpAppNode::interpolateQuaternionKey(const aiQuatKey* keys, U32 numKeys, F32 frameTime)
  171. {
  172. if (numKeys == 1) // Single keyframe: use it directly
  173. return QuatF(keys[0].mValue.x, keys[0].mValue.y, keys[0].mValue.z, keys[0].mValue.w);
  174. // Clamp frameTime to the bounds of the keyframes
  175. if (frameTime <= keys[0].mTime) {
  176. // Before the first keyframe, return the first key
  177. return QuatF(keys[0].mValue.x, keys[0].mValue.y, keys[0].mValue.z, keys[0].mValue.w);
  178. }
  179. if (frameTime >= keys[numKeys - 1].mTime) {
  180. // After the last keyframe, return the last key
  181. return QuatF(keys[numKeys - 1].mValue.x, keys[numKeys - 1].mValue.y, keys[numKeys - 1].mValue.z, keys[numKeys - 1].mValue.w);
  182. }
  183. for (U32 i = 1; i < numKeys; ++i)
  184. {
  185. if (frameTime < keys[i].mTime)
  186. {
  187. const F32 factor = (frameTime - keys[i - 1].mTime) / (keys[i].mTime - keys[i - 1].mTime);
  188. QuatF start(keys[i - 1].mValue.x, keys[i - 1].mValue.y, keys[i - 1].mValue.z, keys[i - 1].mValue.w);
  189. QuatF end(keys[i].mValue.x, keys[i].mValue.y, keys[i].mValue.z, keys[i].mValue.w);
  190. QuatF result;
  191. result.interpolate(start, end, factor);
  192. return result;
  193. }
  194. }
  195. // Default to the last keyframe
  196. return QuatF(keys[numKeys - 1].mValue.x, keys[numKeys - 1].mValue.y, keys[numKeys - 1].mValue.z, keys[numKeys - 1].mValue.w);
  197. }
  198. bool AssimpAppNode::animatesTransform(const AppSequence* appSeq)
  199. {
  200. return false;
  201. }
  202. /// Get the world transform of the node at the specified time
  203. MatrixF AssimpAppNode::getNodeTransform(F32 time)
  204. {
  205. // Avoid re-computing the default transform if possible
  206. if (mDefaultTransformValid && time == TSShapeLoader::DefaultTime)
  207. {
  208. return mDefaultNodeTransform;
  209. }
  210. else
  211. {
  212. MatrixF nodeTransform = getTransform(time);
  213. // Check for inverted node coordinate spaces => can happen when modelers
  214. // use the 'mirror' tool in their 3d app. Shows up as negative <scale>
  215. // transforms in the collada model.
  216. if (m_matF_determinant(nodeTransform) < 0.0f)
  217. {
  218. // Mark this node as inverted so we can mirror mesh geometry, then
  219. // de-invert the transform matrix
  220. mInvertMeshes = true;
  221. nodeTransform.scale(Point3F(1, 1, -1));
  222. }
  223. // Cache the default transform
  224. if (time == TSShapeLoader::DefaultTime)
  225. {
  226. mDefaultTransformValid = true;
  227. mDefaultNodeTransform = nodeTransform;
  228. }
  229. return nodeTransform;
  230. }
  231. }
  232. void AssimpAppNode::assimpToTorqueMat(const aiMatrix4x4& inAssimpMat, MatrixF& outMat)
  233. {
  234. outMat.setRow(0, Point4F((F32)inAssimpMat.a1, (F32)inAssimpMat.a2,
  235. (F32)inAssimpMat.a3, (F32)inAssimpMat.a4));
  236. outMat.setRow(1, Point4F((F32)inAssimpMat.b1, (F32)inAssimpMat.b2,
  237. (F32)inAssimpMat.b3, (F32)inAssimpMat.b4));
  238. outMat.setRow(2, Point4F((F32)inAssimpMat.c1, (F32)inAssimpMat.c2,
  239. (F32)inAssimpMat.c3, (F32)inAssimpMat.c4));
  240. outMat.setRow(3, Point4F((F32)inAssimpMat.d1, (F32)inAssimpMat.d2,
  241. (F32)inAssimpMat.d3, (F32)inAssimpMat.d4));
  242. }
  243. aiNode* AssimpAppNode::findChildNodeByName(const char* nodeName, aiNode* rootNode)
  244. {
  245. aiNode* retNode = NULL;
  246. if (strcmp(nodeName, rootNode->mName.C_Str()) == 0)
  247. return rootNode;
  248. for (U32 i = 0; i < rootNode->mNumChildren; ++i)
  249. {
  250. retNode = findChildNodeByName(nodeName, rootNode->mChildren[i]);
  251. if (retNode)
  252. return retNode;
  253. }
  254. return nullptr;
  255. }
  256. void AssimpAppNode::addChild(AssimpAppNode* child)
  257. {
  258. mChildNodes.push_back(child);
  259. }
  260. void AssimpAppNode::addMesh(AssimpAppMesh* child)
  261. {
  262. mMeshes.push_back(child);
  263. }
  264. void AssimpAppNode::buildMeshList()
  265. {
  266. for (U32 i = 0; i < mNode->mNumMeshes; i++)
  267. {
  268. U32 meshIdx = mNode->mMeshes[i];
  269. const aiMesh* mesh = mScene->mMeshes[meshIdx];
  270. AssimpAppMesh* curMesh = new AssimpAppMesh(mesh, this);
  271. mMeshes.push_back(curMesh);
  272. }
  273. }
  274. void AssimpAppNode::buildChildList()
  275. {
  276. for (U32 i = 0; i < mNode->mNumChildren; i++)
  277. {
  278. const aiNode* node = mNode->mChildren[i];
  279. mChildNodes.push_back(new AssimpAppNode(mScene, node, this));
  280. }
  281. }