diff --git a/Engine/source/ts/assimp/assimpAppNode.cpp b/Engine/source/ts/assimp/assimpAppNode.cpp index f150f4ee2..b4208c608 100644 --- a/Engine/source/ts/assimp/assimpAppNode.cpp +++ b/Engine/source/ts/assimp/assimpAppNode.cpp @@ -32,6 +32,9 @@ #include AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* node, AssimpAppNode* parent) +: mInvertMeshes(false), + mLastTransformTime(TSShapeLoader::DefaultTime - 1), + mDefaultTransformValid(false) { mScene = scene; mNode = node; @@ -45,7 +48,8 @@ AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* n } mParentName = dStrdup(parent ? parent->getName() : "ROOT"); - Con::printf("[ASSIMP] Node Created: %s", mName); + assimpToTorqueMat(node->mTransformation, mNodeTransform); + Con::printf("[ASSIMP] Node Created: %s, Parent: %s", mName, mParentName); } // Get all child nodes @@ -73,66 +77,27 @@ void AssimpAppNode::buildMeshList() MatrixF AssimpAppNode::getTransform(F32 time) { - // Translate from assimp matrix to torque matrix. - // They're both row major, I wish I could just cast - // but that doesn't seem to be an option. + // Check if we can use the last computed transform + if (time == mLastTransformTime) + return mLastTransform; - // Note: this should be cached, it doesn't change - // at this level. This is base transform. + if (appParent) { + // Get parent node's transform + mLastTransform = appParent->getTransform(time); + } + else { + // no parent (ie. root level) => scale by global shape + mLastTransform.identity(); + if (!isBounds()) + convertMat(mLastTransform); - // Y and Z and optionally swapped. - - MatrixF mat(false); - mat.setRow(0, Point4F((F32)mNode->mTransformation.a1, - (F32)mNode->mTransformation.a3, - (F32)mNode->mTransformation.a2, - (F32)mNode->mTransformation.a4) - ); - - // Check for Y Z Swap - if ( Con::getBoolVariable("$Assimp::SwapYZ", false) ) - { - mat.setRow(1, Point4F((F32)mNode->mTransformation.c1, - (F32)mNode->mTransformation.c3, - (F32)mNode->mTransformation.c2, - (F32)mNode->mTransformation.c4) - ); - mat.setRow(2, Point4F((F32)mNode->mTransformation.b1, - (F32)mNode->mTransformation.b3, - (F32)mNode->mTransformation.b2, - (F32)mNode->mTransformation.b4) - ); - } - else - { - mat.setRow(1, Point4F((F32)mNode->mTransformation.b1, - (F32)mNode->mTransformation.b3, - (F32)mNode->mTransformation.b2, - (F32)mNode->mTransformation.b4) - ); - mat.setRow(2, Point4F((F32)mNode->mTransformation.c1, - (F32)mNode->mTransformation.c3, - (F32)mNode->mTransformation.c2, - (F32)mNode->mTransformation.c4) - ); + //mLastTransform.scale(ColladaUtils::getOptions().unit); } - mat.setRow(3, Point4F((F32)mNode->mTransformation.d1, - (F32)mNode->mTransformation.d3, - (F32)mNode->mTransformation.d2, - (F32)mNode->mTransformation.d4) - ); + mLastTransform.mul(mNodeTransform); + mLastTransformTime = time; - // Node transformations are carried down the hiearchy - // so we need all of our parents transforms to make - // this work. - /*if ( appParent != 0 ) - { - MatrixF parentMat = appParent->getNodeTransform(time); - mat.mul(parentMat); - }*/ - - return mat; + return mLastTransform; } bool AssimpAppNode::animatesTransform(const AppSequence* appSeq) @@ -143,5 +108,69 @@ bool AssimpAppNode::animatesTransform(const AppSequence* appSeq) /// Get the world transform of the node at the specified time MatrixF AssimpAppNode::getNodeTransform(F32 time) { - return getTransform(time); -} \ No newline at end of file + // Avoid re-computing the default transform if possible + if (mDefaultTransformValid && time == TSShapeLoader::DefaultTime) + { + return mDefaultNodeTransform; + } + else + { + MatrixF nodeTransform = getTransform(time); + + // Check for inverted node coordinate spaces => can happen when modelers + // use the 'mirror' tool in their 3d app. Shows up as negative + // transforms in the collada model. + if (m_matF_determinant(nodeTransform) < 0.0f) + { + // Mark this node as inverted so we can mirror mesh geometry, then + // de-invert the transform matrix + mInvertMeshes = true; + nodeTransform.scale(Point3F(1, 1, -1)); + } + + // Cache the default transform + if (time == TSShapeLoader::DefaultTime) + { + mDefaultTransformValid = true; + mDefaultNodeTransform = nodeTransform; + } + + return nodeTransform; + } +} + +void AssimpAppNode::assimpToTorqueMat(const aiMatrix4x4& inAssimpMat, MatrixF& outMat) +{ + outMat.setRow(0, Point4F((F32)inAssimpMat.a1, (F32)inAssimpMat.a2, + (F32)inAssimpMat.a3, (F32)inAssimpMat.a4)); + + outMat.setRow(1, Point4F((F32)inAssimpMat.b1, (F32)inAssimpMat.b2, + (F32)inAssimpMat.b3, (F32)inAssimpMat.b4)); + + outMat.setRow(2, Point4F((F32)inAssimpMat.c1, (F32)inAssimpMat.c2, + (F32)inAssimpMat.c3, (F32)inAssimpMat.c4)); + + outMat.setRow(3, Point4F((F32)inAssimpMat.d1, (F32)inAssimpMat.d2, + (F32)inAssimpMat.d3, (F32)inAssimpMat.d4)); +} + +void AssimpAppNode::convertMat(MatrixF& outMat) +{ + if (Con::getBoolVariable("$Assimp::SwapYZ", false)) + { + MatrixF rotMat(EulerF(-M_HALFPI_F, 0, 0)); + Point3F pos = outMat.getPosition(); + outMat.mulL(rotMat); + rotMat.mulP(pos); + outMat.setPosition(pos); + } +} + +void AssimpAppNode::convertPoint(Point3F& outPoint) +{ + if (Con::getBoolVariable("$Assimp::SwapYZ", false)) + { + MatrixF rotMat(EulerF(-M_HALFPI_F, 0, 0)); + rotMat.mulP(outPoint); + } +} diff --git a/Engine/source/ts/assimp/assimpAppNode.h b/Engine/source/ts/assimp/assimpAppNode.h index 4bba7554e..55dfe14c9 100644 --- a/Engine/source/ts/assimp/assimpAppNode.h +++ b/Engine/source/ts/assimp/assimpAppNode.h @@ -33,6 +33,10 @@ #include "ts/collada/colladaExtensions.h" #endif +#ifndef AI_TYPES_H_INC +#include +#endif + class AssimpAppNode : public AppNode { typedef AppNode Parent; @@ -44,9 +48,16 @@ class AssimpAppNode : public AppNode protected: - const struct aiScene* mScene; - const struct aiNode* mNode; ///< Pointer to the node in the Collada DOM - AssimpAppNode* appParent; ///< Parent node in Collada-space + const struct aiScene* mScene; + const struct aiNode* mNode; ///< Pointer to the assimp scene node + AssimpAppNode* appParent; ///< Parent node + MatrixF mNodeTransform; ///< Scene node transform converted to TorqueSpace (filled for ALL nodes) + + bool mInvertMeshes; ///< True if this node's coordinate space is inverted (left handed) + F32 mLastTransformTime; ///< Time of the last transform lookup (getTransform) + MatrixF mLastTransform; ///< Last transform lookup (getTransform) (Only Non-Dummy Nodes) + bool mDefaultTransformValid; ///< Flag indicating whether the defaultNodeTransform is valid + MatrixF mDefaultNodeTransform; ///< Transform at DefaultTime (Only Non-Dummy Nodes) public: @@ -93,6 +104,10 @@ public: MatrixF getNodeTransform(F32 time); bool animatesTransform(const AppSequence* appSeq); bool isParentRoot() { return (appParent == NULL); } + + static void assimpToTorqueMat(const aiMatrix4x4& inAssimpMat, MatrixF& outMat); + static void convertMat(MatrixF& outMat); + static void convertPoint(Point3F& outPoint); }; #endif // _ASSIMP_APPNODE_H_