assimpAppNode.cpp
Engine/source/ts/assimp/assimpAppNode.cpp
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