From 1a7e6699c95da6677b4d1419192e5539f716de46 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Sun, 24 Mar 2019 06:18:20 -0400 Subject: [PATCH 1/6] Adds conversion functions and changes implementation of getTransform(). --- Engine/source/ts/assimp/assimpAppNode.cpp | 145 +++++++++++++--------- Engine/source/ts/assimp/assimpAppNode.h | 21 +++- 2 files changed, 105 insertions(+), 61 deletions(-) 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_ From 1d073e0b09a5a74c9d321cee3c82d24eb152524a Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Sun, 24 Mar 2019 06:23:58 -0400 Subject: [PATCH 2/6] Changes ObjectOffset parameter name to prevent confusion/conflict with the base class member AppMesh::objectOffset. Error checking for meshes that do not have stored normals. Incorrect first attempt at vertex weights. --- Engine/source/ts/assimp/assimpAppMesh.cpp | 40 +++++++++++------------ Engine/source/ts/assimp/assimpAppMesh.h | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppMesh.cpp b/Engine/source/ts/assimp/assimpAppMesh.cpp index 65c80a622..96703c271 100644 --- a/Engine/source/ts/assimp/assimpAppMesh.cpp +++ b/Engine/source/ts/assimp/assimpAppMesh.cpp @@ -59,7 +59,7 @@ MatrixF AssimpAppMesh::getMeshTransform(F32 time) return appNode->getNodeTransform(time); } -void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objectOffset) +void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) { // After this function, the following are expected to be populated: // points, normals, uvs, primitives, indices @@ -74,23 +74,21 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objectOffset) { // Points and Normals aiVector3D pt = mMeshData->mVertices[i]; - aiVector3D nrm = mMeshData->mNormals[i]; + aiVector3D nrm; + if (mMeshData->HasNormals()) + nrm = mMeshData->mNormals[i]; + else + nrm.Set(0, 0, 0); Point3F tmpVert; Point3F tmpNormal; - if (Con::getBoolVariable("$Assimp::SwapYZ", false)) - { - tmpVert = Point3F(pt.x, pt.z, pt.y); - tmpNormal = Point3F(nrm.x, nrm.z, nrm.y); - } - else - { - tmpVert = Point3F(pt.x, pt.y, pt.z); - tmpNormal = Point3F(nrm.x, nrm.y, nrm.z); - } + tmpVert = Point3F(pt.x, pt.y, pt.z); + tmpNormal = Point3F(nrm.x, nrm.y, nrm.z); + //AssimpAppNode::convertPoint(tmpVert); + //AssimpAppNode::convertPoint(tmpNormal); - //objectOffset.mulP(tmpVert); + //objOffset.mulP(tmpVert); points.push_back(tmpVert); @@ -214,20 +212,22 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objectOffset) String name = mMeshData->mBones[b]->mName.C_Str(); MatrixF boneTransform; + boneTransform.setRow(0, Point4F(mMeshData->mBones[b]->mOffsetMatrix.a1, mMeshData->mBones[b]->mOffsetMatrix.a2, mMeshData->mBones[b]->mOffsetMatrix.a3, mMeshData->mBones[b]->mOffsetMatrix.a4)); + boneTransform.setRow(1, Point4F(mMeshData->mBones[b]->mOffsetMatrix.b1, mMeshData->mBones[b]->mOffsetMatrix.b2, mMeshData->mBones[b]->mOffsetMatrix.b3, mMeshData->mBones[b]->mOffsetMatrix.b4)); + boneTransform.setRow(2, Point4F(mMeshData->mBones[b]->mOffsetMatrix.c1, mMeshData->mBones[b]->mOffsetMatrix.c2, mMeshData->mBones[b]->mOffsetMatrix.c3, mMeshData->mBones[b]->mOffsetMatrix.c4)); + boneTransform.setRow(3, Point4F(mMeshData->mBones[b]->mOffsetMatrix.d1, mMeshData->mBones[b]->mOffsetMatrix.d2, mMeshData->mBones[b]->mOffsetMatrix.d3, mMeshData->mBones[b]->mOffsetMatrix.d4)); - for (U32 m = 0; m < 16; ++m) - { - boneTransform[m] = *mMeshData->mBones[b]->mOffsetMatrix[m]; - } - - //initialTransforms.push_back(boneTransform); - initialTransforms.push_back(MatrixF::Identity); + //boneTransform.inverse(); + //AssimpAppNode::convertMat(boneTransform); // Will need a better animated reference shape to determine if this is needed. + //boneTransform.inverse(); + initialTransforms.push_back(boneTransform); //Weights U32 numWeights = mMeshData->mBones[b]->mNumWeights; weight.setSize(numWeights); vertexIndex.setSize(numWeights); + boneIndex.setSize(numWeights); for (U32 w = 0; w < numWeights; ++w) { diff --git a/Engine/source/ts/assimp/assimpAppMesh.h b/Engine/source/ts/assimp/assimpAppMesh.h index 7abb45685..59af65341 100644 --- a/Engine/source/ts/assimp/assimpAppMesh.h +++ b/Engine/source/ts/assimp/assimpAppMesh.h @@ -107,7 +107,7 @@ public: /// /// @param time Time at which to generate the mesh data /// @param objectOffset Transform to apply to the generated data (bounds transform) - void lockMesh(F32 time, const MatrixF& objectOffset); + void lockMesh(F32 time, const MatrixF& objOffset); /// Get the transform of this mesh at a certain time /// From 0be93d6cf5fdd370136ab63688431c9552f5de62 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Sun, 24 Mar 2019 06:25:38 -0400 Subject: [PATCH 3/6] Implements ignore filter for assimp fbx dummy nodes. Adds gltf binary to list of supported extensions. --- Engine/source/ts/assimp/assimpShapeLoader.cpp | 14 ++++++++++++-- Engine/source/ts/assimp/assimpShapeLoader.h | 4 +++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 039b67d62..fd94ffb6a 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -103,7 +103,8 @@ MODULE_BEGIN( AssimpShapeLoader ) TSShapeLoader::addFormat("3D GameStudio (3DGS)", "mdl"); TSShapeLoader::addFormat("3D GameStudio (3DGS) Terrain", "hmp"); TSShapeLoader::addFormat("Izware Nendo", "ndo"); - TSShapeLoader::addFormat("gltf", "gltf"); + TSShapeLoader::addFormat("gltf", "gltf"); + TSShapeLoader::addFormat("gltf binary", "glb"); } MODULE_END; @@ -146,7 +147,7 @@ void AssimpShapeLoader::enumerateScene() Con::getBoolVariable("$Assimp::OptimizeMeshes", false) ? aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph : 0 | 0; - if(Con::getBoolVariable("$Assimp::Triangulate", false)) + if(Con::getBoolVariable("$Assimp::Triangulate", true)) ppsteps |= aiProcess_Triangulate; if (Con::getBoolVariable("$Assimp::OptimizeMeshes", false)) @@ -276,6 +277,15 @@ bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path) return false; } +bool AssimpShapeLoader::ignoreNode(const String& name) +{ + // Do not add AssimpFbx dummy nodes to the TSShape. See: Assimp::FBX::ImportSettings::preservePivots + // https://github.com/assimp/assimp/blob/master/code/FBXImportSettings.h#L116-L135 + if (name.find("_$AssimpFbx$_") != String::NPos) + return true; + return false; +} + //----------------------------------------------------------------------------- /// This function is invoked by the resource manager based on file extension. TSShape* assimpLoadShape(const Torque::Path &path) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.h b/Engine/source/ts/assimp/assimpShapeLoader.h index f776ad798..807cd3fab 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.h +++ b/Engine/source/ts/assimp/assimpShapeLoader.h @@ -34,7 +34,9 @@ class AssimpShapeLoader : public TSShapeLoader protected: const struct aiScene* mScene; - + + virtual bool ignoreNode(const String& name); + public: AssimpShapeLoader(); ~AssimpShapeLoader(); From 2d795b24938178e38e81d87bd7f8206020d49a10 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Sun, 24 Mar 2019 07:08:24 -0400 Subject: [PATCH 4/6] Fixes indexing for vertex weights. --- Engine/source/ts/assimp/assimpAppMesh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppMesh.cpp b/Engine/source/ts/assimp/assimpAppMesh.cpp index 96703c271..073c50721 100644 --- a/Engine/source/ts/assimp/assimpAppMesh.cpp +++ b/Engine/source/ts/assimp/assimpAppMesh.cpp @@ -218,7 +218,7 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) boneTransform.setRow(3, Point4F(mMeshData->mBones[b]->mOffsetMatrix.d1, mMeshData->mBones[b]->mOffsetMatrix.d2, mMeshData->mBones[b]->mOffsetMatrix.d3, mMeshData->mBones[b]->mOffsetMatrix.d4)); //boneTransform.inverse(); - //AssimpAppNode::convertMat(boneTransform); // Will need a better animated reference shape to determine if this is needed. + //AssimpAppNode::convertMat(boneTransform); //boneTransform.inverse(); initialTransforms.push_back(boneTransform); @@ -231,7 +231,7 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) for (U32 w = 0; w < numWeights; ++w) { - aiVertexWeight* aiWeight = mMeshData->mBones[b]->mWeights; + aiVertexWeight* aiWeight = &mMeshData->mBones[b]->mWeights[w]; weight[w] = aiWeight->mWeight; vertexIndex[w] = aiWeight->mVertexId; From bc722a353d02cad55eabfcc2b4c4691f793414a9 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Wed, 27 Mar 2019 12:46:43 -0400 Subject: [PATCH 5/6] Fixes vertex weight assignments. Adds upaxis override option to match collada importer. --- Engine/source/ts/assimp/assimpAppMesh.cpp | 108 +++++++++++----------- Engine/source/ts/assimp/assimpAppMesh.h | 3 +- Engine/source/ts/assimp/assimpAppNode.cpp | 52 ++++++++--- Engine/source/ts/assimp/assimpAppNode.h | 2 +- 4 files changed, 100 insertions(+), 65 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppMesh.cpp b/Engine/source/ts/assimp/assimpAppMesh.cpp index 073c50721..4d7fcabd8 100644 --- a/Engine/source/ts/assimp/assimpAppMesh.cpp +++ b/Engine/source/ts/assimp/assimpAppMesh.cpp @@ -37,6 +37,15 @@ AssimpAppMesh::AssimpAppMesh(const struct aiMesh* mesh, AssimpAppNode* node) : mMeshData(mesh), appNode(node) { Con::printf("[ASSIMP] Mesh Created: %s", getName()); + + // See if it's a skinned mesh + mIsSkinMesh = false; + for (U32 b = 0; b < mesh->mNumBones; b++) + if (mMeshData->mBones[b]->mNumWeights > 0) + { + mIsSkinMesh = true; + break; + } } const char* AssimpAppMesh::getName(bool allowFixed) @@ -64,7 +73,6 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) // After this function, the following are expected to be populated: // points, normals, uvs, primitives, indices // There is also colors and uv2s but those don't seem to be required. - points.reserve(mMeshData->mNumVertices); uvs.reserve(mMeshData->mNumVertices); normals.reserve(mMeshData->mNumVertices); @@ -85,10 +93,8 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) tmpVert = Point3F(pt.x, pt.y, pt.z); tmpNormal = Point3F(nrm.x, nrm.y, nrm.z); - //AssimpAppNode::convertPoint(tmpVert); - //AssimpAppNode::convertPoint(tmpNormal); - //objOffset.mulP(tmpVert); + objOffset.mulP(tmpVert); points.push_back(tmpVert); @@ -126,7 +132,6 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) } U32 numFaces = mMeshData->mNumFaces; - U32 primCount = 0; primitives.reserve(numFaces); //Fetch the number of indices @@ -138,28 +143,6 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) indices.reserve(indicesCount); - /*U32 idxCount = 0; - - for (U32 j = 0; jmMaterials.size(); j++) - { - MikuModel::Material &mat = mModel->mMaterials[j]; - U32 nextIdxCount = idxCount + mat.numIndices; - - primitives.increment(); - - TSDrawPrimitive& primitive = primitives.last(); - primitive.start = indices.size(); - primitive.matIndex = (TSDrawPrimitive::Triangles | TSDrawPrimitive::Indexed) | j; - primitive.numElements = mat.numIndices; - - for (U32 i = idxCount; imIndices[i]); - } - - idxCount = nextIdxCount; - }*/ - for ( U32 n = 0; n < mMeshData->mNumFaces; ++n) { const struct aiFace* face = &mMeshData->mFaces[n]; @@ -191,11 +174,6 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) indices.push_back(index); } } - - // Load the indices in. - //indices.push_back(face->mIndices[0]); - //indices.push_back(face->mIndices[1]); - //indices.push_back(face->mIndices[2]); } else { @@ -204,41 +182,67 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) } U32 boneCount = mMeshData->mNumBones; - bones.setSize(boneCount); + // Count the total number of weights for all of the bones. + U32 totalWeights = 0; + U32 nonZeroWeights = 0; + for (U32 b = 0; b < boneCount; b++) + totalWeights += mMeshData->mBones[b]->mNumWeights; + + // Assimp gives weights sorted by bone index. We need them in vertex order. + Vector tmpWeight; + Vector tmpBoneIndex; + Vector tmpVertexIndex; + tmpWeight.setSize(totalWeights); + tmpBoneIndex.setSize(totalWeights); + tmpVertexIndex.setSize(totalWeights); + for (U32 b = 0; b < boneCount; b++) { String name = mMeshData->mBones[b]->mName.C_Str(); + aiNode* nodePtr = AssimpAppNode::findChildNodeByName(mMeshData->mBones[b]->mName.C_Str(), appNode->mScene->mRootNode); + bones[b] = new AssimpAppNode(appNode->mScene, nodePtr); MatrixF boneTransform; - boneTransform.setRow(0, Point4F(mMeshData->mBones[b]->mOffsetMatrix.a1, mMeshData->mBones[b]->mOffsetMatrix.a2, mMeshData->mBones[b]->mOffsetMatrix.a3, mMeshData->mBones[b]->mOffsetMatrix.a4)); - boneTransform.setRow(1, Point4F(mMeshData->mBones[b]->mOffsetMatrix.b1, mMeshData->mBones[b]->mOffsetMatrix.b2, mMeshData->mBones[b]->mOffsetMatrix.b3, mMeshData->mBones[b]->mOffsetMatrix.b4)); - boneTransform.setRow(2, Point4F(mMeshData->mBones[b]->mOffsetMatrix.c1, mMeshData->mBones[b]->mOffsetMatrix.c2, mMeshData->mBones[b]->mOffsetMatrix.c3, mMeshData->mBones[b]->mOffsetMatrix.c4)); - boneTransform.setRow(3, Point4F(mMeshData->mBones[b]->mOffsetMatrix.d1, mMeshData->mBones[b]->mOffsetMatrix.d2, mMeshData->mBones[b]->mOffsetMatrix.d3, mMeshData->mBones[b]->mOffsetMatrix.d4)); - - //boneTransform.inverse(); - //AssimpAppNode::convertMat(boneTransform); - //boneTransform.inverse(); + AssimpAppNode::assimpToTorqueMat(mMeshData->mBones[b]->mOffsetMatrix, boneTransform); initialTransforms.push_back(boneTransform); //Weights U32 numWeights = mMeshData->mBones[b]->mNumWeights; - weight.setSize(numWeights); - vertexIndex.setSize(numWeights); - boneIndex.setSize(numWeights); - for (U32 w = 0; w < numWeights; ++w) { aiVertexWeight* aiWeight = &mMeshData->mBones[b]->mWeights[w]; - weight[w] = aiWeight->mWeight; - vertexIndex[w] = aiWeight->mVertexId; - boneIndex[w] = b; - //vertWeight. = aiWeight-> + if (aiWeight->mWeight > 0.0f) + { + tmpWeight[nonZeroWeights] = aiWeight->mWeight; + tmpVertexIndex[nonZeroWeights] = aiWeight->mVertexId; + tmpBoneIndex[nonZeroWeights] = b; + nonZeroWeights++; + } + } + } + + weight.setSize(nonZeroWeights); + vertexIndex.setSize(nonZeroWeights); + boneIndex.setSize(nonZeroWeights); + + // Copy the weights to our vectors in vertex order + U32 nextWeight = 0; + for (U32 i = 0; i < mMeshData->mNumVertices; i++) + { + for (U32 ind = 0; ind < nonZeroWeights; ind++) + { + if (tmpVertexIndex[ind] == i) + { + weight[nextWeight] = tmpWeight[ind]; + vertexIndex[nextWeight] = tmpVertexIndex[ind]; + boneIndex[nextWeight] = tmpBoneIndex[ind]; + nextWeight++; + } } - //= mNumWeights } if ( noUVFound ) @@ -246,8 +250,8 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) } void AssimpAppMesh::lookupSkinData() -{ - +{ // This function is intentionally left blank. The skin data - bones, weights and indexes are + // processed in lockMesh() with the rest of the mesh data. } F32 AssimpAppMesh::getVisValue(F32 t) diff --git a/Engine/source/ts/assimp/assimpAppMesh.h b/Engine/source/ts/assimp/assimpAppMesh.h index 59af65341..9f6a4f87c 100644 --- a/Engine/source/ts/assimp/assimpAppMesh.h +++ b/Engine/source/ts/assimp/assimpAppMesh.h @@ -40,6 +40,7 @@ class AssimpAppMesh : public AppMesh protected: class AssimpAppNode* appNode; ///< Pointer to the node that owns this mesh const struct aiMesh* mMeshData; + bool mIsSkinMesh; public: @@ -100,7 +101,7 @@ public: /// Return true if this mesh is a skin bool isSkin() { - return false; + return mIsSkinMesh; } /// Generate the vertex, normal and triangle data for the mesh. diff --git a/Engine/source/ts/assimp/assimpAppNode.cpp b/Engine/source/ts/assimp/assimpAppNode.cpp index b4208c608..e09a8b374 100644 --- a/Engine/source/ts/assimp/assimpAppNode.cpp +++ b/Engine/source/ts/assimp/assimpAppNode.cpp @@ -156,21 +156,51 @@ void AssimpAppNode::assimpToTorqueMat(const aiMatrix4x4& inAssimpMat, MatrixF& o void AssimpAppNode::convertMat(MatrixF& outMat) { - if (Con::getBoolVariable("$Assimp::SwapYZ", false)) + MatrixF rot(true); + + // This is copied directly from ColladaUtils::convertTransform() + // ColladaUtils::getOptions().upAxis has been temporarily replaced with $Assimp::OverrideUpAxis for testing + // We need a plan for how the full set of assimp import options and settings is going to be managed. + switch (Con::getIntVariable("$Assimp::OverrideUpAxis", 2)) { - MatrixF rotMat(EulerF(-M_HALFPI_F, 0, 0)); - Point3F pos = outMat.getPosition(); - outMat.mulL(rotMat); - rotMat.mulP(pos); - outMat.setPosition(pos); + case 0: //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 1: //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 2: //UPAXISTYPE_Z_UP: + default: + // nothing to do + break; } } -void AssimpAppNode::convertPoint(Point3F& outPoint) +aiNode* AssimpAppNode::findChildNodeByName(const char* nodeName, aiNode* rootNode) { - if (Con::getBoolVariable("$Assimp::SwapYZ", false)) + aiNode* retNode = NULL; + if (strcmp(nodeName, rootNode->mName.C_Str()) == 0) + return rootNode; + + for (U32 i = 0; i < rootNode->mNumChildren; ++i) { - MatrixF rotMat(EulerF(-M_HALFPI_F, 0, 0)); - rotMat.mulP(outPoint); + retNode = findChildNodeByName(nodeName, rootNode->mChildren[i]); + if (retNode) + return retNode; } -} + return nullptr; +} \ No newline at end of file diff --git a/Engine/source/ts/assimp/assimpAppNode.h b/Engine/source/ts/assimp/assimpAppNode.h index 55dfe14c9..c54a65625 100644 --- a/Engine/source/ts/assimp/assimpAppNode.h +++ b/Engine/source/ts/assimp/assimpAppNode.h @@ -107,7 +107,7 @@ public: static void assimpToTorqueMat(const aiMatrix4x4& inAssimpMat, MatrixF& outMat); static void convertMat(MatrixF& outMat); - static void convertPoint(Point3F& outPoint); + static aiNode* findChildNodeByName(const char* nodeName, aiNode* rootNode); }; #endif // _ASSIMP_APPNODE_H_ From 71a5f9498b12113aaf6b922191293391cdb7f1aa Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Thu, 28 Mar 2019 04:16:22 -0400 Subject: [PATCH 6/6] Fixes primitive assignment. AppMesh::primitives in this case is a purely collada/dts concept and is not indices or faces. Any mesh with more than 2^16 vertices should be split into multiple primitives to avoid indexing across a 16 bit boundary. Mesh division into primitives has not been implemented for assimp yet. --- Engine/source/ts/assimp/assimpAppMesh.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppMesh.cpp b/Engine/source/ts/assimp/assimpAppMesh.cpp index 4d7fcabd8..82306eeb2 100644 --- a/Engine/source/ts/assimp/assimpAppMesh.cpp +++ b/Engine/source/ts/assimp/assimpAppMesh.cpp @@ -132,7 +132,7 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) } U32 numFaces = mMeshData->mNumFaces; - primitives.reserve(numFaces); + //primitives.reserve(numFaces); //Fetch the number of indices U32 indicesCount = 0; @@ -143,19 +143,18 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) indices.reserve(indicesCount); + // Create TSMesh primitive + primitives.increment(); + TSDrawPrimitive& primitive = primitives.last(); + primitive.start = 0; + primitive.matIndex = (TSDrawPrimitive::Triangles | TSDrawPrimitive::Indexed) | (S32)mMeshData->mMaterialIndex; + primitive.numElements = indicesCount; + for ( U32 n = 0; n < mMeshData->mNumFaces; ++n) { const struct aiFace* face = &mMeshData->mFaces[n]; if ( face->mNumIndices == 3 ) { - // Create TSMesh primitive - primitives.increment(); - TSDrawPrimitive& primitive = primitives.last(); - primitive.start = indices.size(); - primitive.matIndex = (TSDrawPrimitive::Triangles | TSDrawPrimitive::Indexed) | (S32)mMeshData->mMaterialIndex; - //primitive.numElements = face->mNumIndices;//3; - primitive.numElements = 3; - if (Con::getBoolVariable("$Assimp::FlipNormals", true)) { U32 indexCount = face->mNumIndices;