assimpAppNode.cpp 11 KB

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