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_