assimpAppNode.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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. // assimp include files.
  27. #include <assimp/cimport.h>
  28. #include <assimp/scene.h>
  29. #include <assimp/postprocess.h>
  30. #include <assimp/types.h>
  31. aiAnimation* AssimpAppNode::sActiveSequence = NULL;
  32. F32 AssimpAppNode::sTimeMultiplier = 1.0f;
  33. AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* node, AssimpAppNode* parent)
  34. : mInvertMeshes(false),
  35. mLastTransformTime(TSShapeLoader::DefaultTime - 1),
  36. mDefaultTransformValid(false)
  37. {
  38. mScene = scene;
  39. mNode = node;
  40. appParent = parent;
  41. mName = dStrdup(mNode->mName.C_Str());
  42. if ( dStrlen(mName) == 0 )
  43. {
  44. const char* defaultName = "null";
  45. mName = dStrdup(defaultName);
  46. }
  47. mParentName = dStrdup(parent ? parent->getName() : "ROOT");
  48. assimpToTorqueMat(node->mTransformation, mNodeTransform);
  49. Con::printf("[ASSIMP] Node Created: %s, Parent: %s", mName, mParentName);
  50. }
  51. // Get all child nodes
  52. void AssimpAppNode::buildChildList()
  53. {
  54. if (!mNode)
  55. {
  56. mNode = mScene->mRootNode;
  57. }
  58. for (U32 n = 0; n < mNode->mNumChildren; ++n) {
  59. mChildNodes.push_back(new AssimpAppNode(mScene, mNode->mChildren[n], this));
  60. }
  61. }
  62. // Get all geometry attached to this node
  63. void AssimpAppNode::buildMeshList()
  64. {
  65. for (U32 n = 0; n < mNode->mNumMeshes; ++n)
  66. {
  67. const struct aiMesh* mesh = mScene->mMeshes[mNode->mMeshes[n]];
  68. mMeshes.push_back(new AssimpAppMesh(mesh, this));
  69. }
  70. }
  71. MatrixF AssimpAppNode::getTransform(F32 time)
  72. {
  73. // Check if we can use the last computed transform
  74. if (time == mLastTransformTime)
  75. return mLastTransform;
  76. if (appParent) {
  77. // Get parent node's transform
  78. mLastTransform = appParent->getTransform(time);
  79. }
  80. else {
  81. // no parent (ie. root level) => scale by global shape <unit>
  82. mLastTransform.identity();
  83. mLastTransform.scale(ColladaUtils::getOptions().unit * ColladaUtils::getOptions().formatScaleFactor);
  84. if (!isBounds())
  85. convertMat(mLastTransform);
  86. }
  87. // If this node is animated in the active sequence, fetch the animated transform
  88. MatrixF mat(true);
  89. if (sActiveSequence)
  90. getAnimatedTransform(mat, time, sActiveSequence);
  91. else
  92. mat = mNodeTransform;
  93. // Remove node scaling?
  94. Point3F nodeScale = mat.getScale();
  95. if (nodeScale != Point3F::One && appParent && ColladaUtils::getOptions().ignoreNodeScale)
  96. {
  97. nodeScale.x = nodeScale.x ? (1.0f / nodeScale.x) : 0;
  98. nodeScale.y = nodeScale.y ? (1.0f / nodeScale.y) : 0;
  99. nodeScale.z = nodeScale.z ? (1.0f / nodeScale.z) : 0;
  100. mat.scale(nodeScale);
  101. }
  102. mLastTransform.mul(mat);
  103. mLastTransformTime = time;
  104. return mLastTransform;
  105. }
  106. void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq)
  107. {
  108. // Find the channel for this node
  109. for (U32 k = 0; k < animSeq->mNumChannels; ++k)
  110. {
  111. if (dStrcmp(mName, animSeq->mChannels[k]->mNodeName.C_Str()) == 0)
  112. {
  113. aiNodeAnim *nodeAnim = animSeq->mChannels[k];
  114. Point3F trans(Point3F::Zero);
  115. Point3F scale(Point3F::One);
  116. QuatF rot;
  117. rot.identity();
  118. // T is in seconds, convert to frames.
  119. F32 frame = t * animSeq->mTicksPerSecond;
  120. // interpolate scaling.
  121. if (nodeAnim->mNumScalingKeys > 1) {
  122. U32 scaleIndex = 0;
  123. for (U32 i = 0; i < nodeAnim->mNumScalingKeys-1; i++)
  124. {
  125. if (frame < nodeAnim->mScalingKeys[i + 1].mTime) {
  126. scaleIndex = i;
  127. break;
  128. }
  129. }
  130. const Point3F& scalingStart = Point3F( nodeAnim->mScalingKeys[scaleIndex].mValue.x,
  131. nodeAnim->mScalingKeys[scaleIndex].mValue.y,
  132. nodeAnim->mScalingKeys[scaleIndex].mValue.z);
  133. const Point3F& scalingEnd = Point3F(nodeAnim->mScalingKeys[scaleIndex + 1].mValue.x,
  134. nodeAnim->mScalingKeys[scaleIndex + 1].mValue.y,
  135. nodeAnim->mScalingKeys[scaleIndex + 1].mValue.z);
  136. F32 deltaTime = nodeAnim->mScalingKeys[scaleIndex + 1].mTime - nodeAnim->mScalingKeys[scaleIndex].mTime;
  137. F32 factor = (frame - nodeAnim->mScalingKeys[scaleIndex].mTime) / deltaTime;
  138. scale = scalingStart + factor * (scalingEnd - scalingStart);
  139. }
  140. else
  141. {
  142. scale.set( nodeAnim->mScalingKeys[0].mValue.x,
  143. nodeAnim->mScalingKeys[0].mValue.y,
  144. nodeAnim->mScalingKeys[0].mValue.z);
  145. }
  146. // interpolate rotation.
  147. if (nodeAnim->mNumRotationKeys > 1) {
  148. U32 rotationIndex = 0;
  149. for (U32 i = 0; i < nodeAnim->mNumRotationKeys - 1; i++)
  150. {
  151. if (frame < nodeAnim->mRotationKeys[i + 1].mTime) {
  152. rotationIndex = i;
  153. break;
  154. }
  155. }
  156. const QuatF& rotStart = QuatF(nodeAnim->mRotationKeys[rotationIndex].mValue.x,
  157. nodeAnim->mRotationKeys[rotationIndex].mValue.y,
  158. nodeAnim->mRotationKeys[rotationIndex].mValue.z,
  159. nodeAnim->mRotationKeys[rotationIndex].mValue.w);
  160. const QuatF& rotEnd = QuatF(nodeAnim->mRotationKeys[rotationIndex + 1].mValue.x,
  161. nodeAnim->mRotationKeys[rotationIndex + 1].mValue.y,
  162. nodeAnim->mRotationKeys[rotationIndex + 1].mValue.z,
  163. nodeAnim->mRotationKeys[rotationIndex + 1].mValue.w);
  164. F32 deltaTime = nodeAnim->mRotationKeys[rotationIndex + 1].mTime - nodeAnim->mRotationKeys[rotationIndex].mTime;
  165. F32 factor = (frame - nodeAnim->mRotationKeys[rotationIndex].mTime) / deltaTime;
  166. rot.interpolate(rotStart, rotEnd, factor);
  167. }
  168. else
  169. {
  170. rot.set( nodeAnim->mRotationKeys[0].mValue.x,
  171. nodeAnim->mRotationKeys[0].mValue.y,
  172. nodeAnim->mRotationKeys[0].mValue.z,
  173. nodeAnim->mRotationKeys[0].mValue.w);
  174. }
  175. // interpolate position.
  176. if (nodeAnim->mNumPositionKeys > 1) {
  177. U32 posIndex = 0;
  178. for (U32 i = 0; i < nodeAnim->mNumPositionKeys - 1; i++)
  179. {
  180. if (frame < nodeAnim->mPositionKeys[i + 1].mTime) {
  181. posIndex = i;
  182. break;
  183. }
  184. }
  185. const Point3F& posStart = Point3F( nodeAnim->mPositionKeys[posIndex].mValue.x,
  186. nodeAnim->mPositionKeys[posIndex].mValue.y,
  187. nodeAnim->mPositionKeys[posIndex].mValue.z);
  188. const Point3F& posEnd = Point3F(nodeAnim->mPositionKeys[posIndex + 1].mValue.x,
  189. nodeAnim->mPositionKeys[posIndex + 1].mValue.y,
  190. nodeAnim->mPositionKeys[posIndex + 1].mValue.z);
  191. F32 deltaTime = nodeAnim->mPositionKeys[posIndex + 1].mTime - nodeAnim->mPositionKeys[posIndex].mTime;
  192. F32 factor = (frame - nodeAnim->mPositionKeys[posIndex].mTime) / deltaTime;
  193. trans = posStart + factor * (posEnd - posStart);
  194. }
  195. else
  196. {
  197. trans.set( nodeAnim->mPositionKeys[0].mValue.x,
  198. nodeAnim->mPositionKeys[0].mValue.y,
  199. nodeAnim->mPositionKeys[0].mValue.z);
  200. }
  201. rot.setMatrix(&mat);
  202. mat.inverse();
  203. mat.setPosition(trans);
  204. mat.scale(scale);
  205. return;
  206. }
  207. }
  208. // Node not found in the animation channels
  209. mat = mNodeTransform;
  210. }
  211. bool AssimpAppNode::animatesTransform(const AppSequence* appSeq)
  212. {
  213. return false;
  214. }
  215. /// Get the world transform of the node at the specified time
  216. MatrixF AssimpAppNode::getNodeTransform(F32 time)
  217. {
  218. // Avoid re-computing the default transform if possible
  219. if (mDefaultTransformValid && time == TSShapeLoader::DefaultTime)
  220. {
  221. return mDefaultNodeTransform;
  222. }
  223. else
  224. {
  225. MatrixF nodeTransform = getTransform(time);
  226. // Check for inverted node coordinate spaces => can happen when modelers
  227. // use the 'mirror' tool in their 3d app. Shows up as negative <scale>
  228. // transforms in the collada model.
  229. if (m_matF_determinant(nodeTransform) < 0.0f)
  230. {
  231. // Mark this node as inverted so we can mirror mesh geometry, then
  232. // de-invert the transform matrix
  233. mInvertMeshes = true;
  234. nodeTransform.scale(Point3F(1, 1, -1));
  235. }
  236. // Cache the default transform
  237. if (time == TSShapeLoader::DefaultTime)
  238. {
  239. mDefaultTransformValid = true;
  240. mDefaultNodeTransform = nodeTransform;
  241. }
  242. return nodeTransform;
  243. }
  244. }
  245. void AssimpAppNode::assimpToTorqueMat(const aiMatrix4x4& inAssimpMat, MatrixF& outMat)
  246. {
  247. outMat.setRow(0, Point4F((F32)inAssimpMat.a1, (F32)inAssimpMat.a2,
  248. (F32)inAssimpMat.a3, (F32)inAssimpMat.a4));
  249. outMat.setRow(1, Point4F((F32)inAssimpMat.b1, (F32)inAssimpMat.b2,
  250. (F32)inAssimpMat.b3, (F32)inAssimpMat.b4));
  251. outMat.setRow(2, Point4F((F32)inAssimpMat.c1, (F32)inAssimpMat.c2,
  252. (F32)inAssimpMat.c3, (F32)inAssimpMat.c4));
  253. outMat.setRow(3, Point4F((F32)inAssimpMat.d1, (F32)inAssimpMat.d2,
  254. (F32)inAssimpMat.d3, (F32)inAssimpMat.d4));
  255. }
  256. void AssimpAppNode::convertMat(MatrixF& outMat)
  257. {
  258. MatrixF rot(true);
  259. switch (ColladaUtils::getOptions().upAxis)
  260. {
  261. case UPAXISTYPE_X_UP:
  262. // rotate 90 around Y-axis, then 90 around Z-axis
  263. rot(0, 0) = 0.0f; rot(1, 0) = 1.0f;
  264. rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
  265. rot(0, 2) = 1.0f; rot(2, 2) = 0.0f;
  266. // pre-multiply the transform by the rotation matrix
  267. outMat.mulL(rot);
  268. break;
  269. case UPAXISTYPE_Y_UP:
  270. // rotate 180 around Y-axis, then 90 around X-axis
  271. rot(0, 0) = -1.0f;
  272. rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
  273. rot(1, 2) = 1.0f; rot(2, 2) = 0.0f;
  274. // pre-multiply the transform by the rotation matrix
  275. outMat.mulL(rot);
  276. break;
  277. case UPAXISTYPE_Z_UP:
  278. default:
  279. // nothing to do
  280. break;
  281. }
  282. }
  283. aiNode* AssimpAppNode::findChildNodeByName(const char* nodeName, aiNode* rootNode)
  284. {
  285. aiNode* retNode = NULL;
  286. if (strcmp(nodeName, rootNode->mName.C_Str()) == 0)
  287. return rootNode;
  288. for (U32 i = 0; i < rootNode->mNumChildren; ++i)
  289. {
  290. retNode = findChildNodeByName(nodeName, rootNode->mChildren[i]);
  291. if (retNode)
  292. return retNode;
  293. }
  294. return nullptr;
  295. }