assimpAppNode.cpp 11 KB

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