123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "ts/loader/appSequence.h"
- #include "ts/assimp/assimpAppNode.h"
- #include "ts/assimp/assimpAppMesh.h"
- // assimp include files.
- #include <assimp/cimport.h>
- #include <assimp/scene.h>
- #include <assimp/postprocess.h>
- #include <assimp/types.h>
- aiAnimation* AssimpAppNode::sActiveSequence = NULL;
- F32 AssimpAppNode::sTimeMultiplier = 1.0f;
- AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* node, AssimpAppNode* parent)
- : mInvertMeshes(false),
- mLastTransformTime(TSShapeLoader::DefaultTime - 1),
- mDefaultTransformValid(false)
- {
- mScene = scene;
- mNode = node;
- appParent = parent;
- mName = dStrdup(mNode->mName.C_Str());
- if ( dStrlen(mName) == 0 )
- {
- const char* defaultName = "null";
- mName = dStrdup(defaultName);
- }
- mParentName = dStrdup(parent ? parent->getName() : "ROOT");
- assimpToTorqueMat(node->mTransformation, mNodeTransform);
- Con::printf("[ASSIMP] Node Created: %s, Parent: %s", mName, mParentName);
- }
- // Get all child nodes
- void AssimpAppNode::buildChildList()
- {
- if (!mNode)
- {
- mNode = mScene->mRootNode;
- }
- for (U32 n = 0; n < mNode->mNumChildren; ++n) {
- mChildNodes.push_back(new AssimpAppNode(mScene, mNode->mChildren[n], this));
- }
- }
- // Get all geometry attached to this node
- void AssimpAppNode::buildMeshList()
- {
- for (U32 n = 0; n < mNode->mNumMeshes; ++n)
- {
- const struct aiMesh* mesh = mScene->mMeshes[mNode->mMeshes[n]];
- mMeshes.push_back(new AssimpAppMesh(mesh, this));
- }
- }
- MatrixF AssimpAppNode::getTransform(F32 time)
- {
- // Check if we can use the last computed transform
- if (time == mLastTransformTime)
- return mLastTransform;
- if (appParent) {
- // Get parent node's transform
- mLastTransform = appParent->getTransform(time);
- }
- else {
- // no parent (ie. root level) => scale by global shape <unit>
- mLastTransform.identity();
- mLastTransform.scale(ColladaUtils::getOptions().unit * ColladaUtils::getOptions().formatScaleFactor);
- if (!isBounds())
- convertMat(mLastTransform);
- }
- // If this node is animated in the active sequence, fetch the animated transform
- MatrixF mat(true);
- if (sActiveSequence)
- getAnimatedTransform(mat, time, sActiveSequence);
- else
- mat = mNodeTransform;
- // Remove node scaling?
- Point3F nodeScale = mat.getScale();
- if (nodeScale != Point3F::One && appParent && ColladaUtils::getOptions().ignoreNodeScale)
- {
- nodeScale.x = nodeScale.x ? (1.0f / nodeScale.x) : 0;
- nodeScale.y = nodeScale.y ? (1.0f / nodeScale.y) : 0;
- nodeScale.z = nodeScale.z ? (1.0f / nodeScale.z) : 0;
- mat.scale(nodeScale);
- }
- mLastTransform.mul(mat);
- mLastTransformTime = time;
- return mLastTransform;
- }
- void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq)
- {
- // Find the channel for this node
- for (U32 i = 0; i < animSeq->mNumChannels; ++i)
- {
- if (strcmp(mName, animSeq->mChannels[i]->mNodeName.C_Str()) == 0)
- {
- aiNodeAnim *nodeAnim = animSeq->mChannels[i];
- Point3F trans(Point3F::Zero);
- Point3F scale(Point3F::One);
- QuatF rot;
- rot.identity();
- // Transform
- if (nodeAnim->mNumPositionKeys == 1)
- trans.set(nodeAnim->mPositionKeys[0].mValue.x, nodeAnim->mPositionKeys[0].mValue.y, nodeAnim->mPositionKeys[0].mValue.z);
- else
- {
- Point3F curPos, lastPos;
- F32 lastT = 0.0;
- for (U32 key = 0; key < nodeAnim->mNumPositionKeys; ++key)
- {
- F32 curT = sTimeMultiplier * (F32)nodeAnim->mPositionKeys[key].mTime;
- curPos.set(nodeAnim->mPositionKeys[key].mValue.x, nodeAnim->mPositionKeys[key].mValue.y, nodeAnim->mPositionKeys[key].mValue.z);
- if ((curT > t) && (key > 0))
- {
- F32 factor = (t - lastT) / (curT - lastT);
- trans.interpolate(lastPos, curPos, factor);
- break;
- }
- else if ((curT >= t) || (key == nodeAnim->mNumPositionKeys - 1))
- {
- trans = curPos;
- break;
- }
- lastT = curT;
- lastPos = curPos;
- }
- }
- // Rotation
- if (nodeAnim->mNumRotationKeys == 1)
- rot.set(nodeAnim->mRotationKeys[0].mValue.x, nodeAnim->mRotationKeys[0].mValue.y,
- nodeAnim->mRotationKeys[0].mValue.z, nodeAnim->mRotationKeys[0].mValue.w);
- else
- {
- QuatF curRot, lastRot;
- F32 lastT = 0.0;
- for (U32 key = 0; key < nodeAnim->mNumRotationKeys; ++key)
- {
- F32 curT = sTimeMultiplier * (F32)nodeAnim->mRotationKeys[key].mTime;
- curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y,
- nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w);
- if ((curT > t) && (key > 0))
- {
- F32 factor = (t - lastT) / (curT - lastT);
- rot.interpolate(lastRot, curRot, factor);
- break;
- }
- else if ((curT >= t) || (key == nodeAnim->mNumRotationKeys - 1))
- {
- rot = curRot;
- break;
- }
- lastT = curT;
- lastRot = curRot;
- }
- }
- // Scale
- if (nodeAnim->mNumScalingKeys == 1)
- scale.set(nodeAnim->mScalingKeys[0].mValue.x, nodeAnim->mScalingKeys[0].mValue.y, nodeAnim->mScalingKeys[0].mValue.z);
- else
- {
- Point3F curScale, lastScale;
- F32 lastT = 0.0;
- for (U32 key = 0; key < nodeAnim->mNumScalingKeys; ++key)
- {
- F32 curT = sTimeMultiplier * (F32)nodeAnim->mScalingKeys[key].mTime;
- curScale.set(nodeAnim->mScalingKeys[key].mValue.x, nodeAnim->mScalingKeys[key].mValue.y, nodeAnim->mScalingKeys[key].mValue.z);
- if ((curT > t) && (key > 0))
- {
- F32 factor = (t - lastT) / (curT - lastT);
- scale.interpolate(lastScale, curScale, factor);
- break;
- }
- else if ((curT >= t) || (key == nodeAnim->mNumScalingKeys - 1))
- {
- scale = curScale;
- break;
- }
- lastT = curT;
- lastScale = curScale;
- }
- }
- rot.setMatrix(&mat);
- mat.inverse();
- mat.setPosition(trans);
- mat.scale(scale);
- return;
- }
- }
- // Node not found in the animation channels
- mat = mNodeTransform;
- }
- bool AssimpAppNode::animatesTransform(const AppSequence* appSeq)
- {
- return false;
- }
- /// Get the world transform of the node at the specified time
- MatrixF AssimpAppNode::getNodeTransform(F32 time)
- {
- // 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 <scale>
- // 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)
- {
- MatrixF rot(true);
- switch (ColladaUtils::getOptions().upAxis)
- {
- case UPAXISTYPE_X_UP:
- // rotate 90 around Y-axis, then 90 around Z-axis
- rot(0, 0) = 0.0f; rot(1, 0) = 1.0f;
- rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
- rot(0, 2) = 1.0f; rot(2, 2) = 0.0f;
- // pre-multiply the transform by the rotation matrix
- outMat.mulL(rot);
- break;
- case UPAXISTYPE_Y_UP:
- // rotate 180 around Y-axis, then 90 around X-axis
- rot(0, 0) = -1.0f;
- rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
- rot(1, 2) = 1.0f; rot(2, 2) = 0.0f;
- // pre-multiply the transform by the rotation matrix
- outMat.mulL(rot);
- break;
- case UPAXISTYPE_Z_UP:
- default:
- // nothing to do
- break;
- }
- }
- aiNode* AssimpAppNode::findChildNodeByName(const char* nodeName, aiNode* rootNode)
- {
- aiNode* retNode = NULL;
- if (strcmp(nodeName, rootNode->mName.C_Str()) == 0)
- return rootNode;
- for (U32 i = 0; i < rootNode->mNumChildren; ++i)
- {
- retNode = findChildNodeByName(nodeName, rootNode->mChildren[i]);
- if (retNode)
- return retNode;
- }
- return nullptr;
- }
|