From 57a00d5faad172440447ac0a8e52ea8866ce6e93 Mon Sep 17 00:00:00 2001 From: Angelo Scandaliato Date: Tue, 11 Oct 2016 15:28:04 -0700 Subject: [PATCH] find skeleton root joint and only allow four joint weights per vertex --- code/glTFAsset.h | 2 + code/glTFExporter.cpp | 86 +++++++++++++++++++++++++++---------------- code/glTFExporter.h | 7 +++- 3 files changed, 63 insertions(+), 32 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 247dfd148..2e49b0d8f 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -811,6 +811,8 @@ namespace glTF Ref skin; //!< The ID of the skin referenced by this node. std::string jointName; //!< Name used when this node is a joint in a skin. + Ref parent; //!< This is not part of the glTF specification. Used as a helper. + Node() {} void Read(Value& obj, Asset& r); }; diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 90c74f30e..b474b47ca 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -132,7 +132,7 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc ExportMaterials(); if (mScene->mRootNode) { - ExportNode(mScene->mRootNode); + ExportNodeHierarchy(mScene->mRootNode); } ExportMeshes(); @@ -391,39 +391,33 @@ bool FindMeshNode(Ref& nodeIn, Ref& meshNode, std::string meshID) /* * Find the root joint of the skeleton. + * Starts will any joint node and traces up the tree, + * until a parent is found that does not have a jointName. + * Returns the first parent Ref found that does not have a jointName. */ Ref FindSkeletonRootJoint(Ref& skinRef) { - Ref candidateNodeRef; - Ref testNodeRef; + Ref startNodeRef; + Ref parentNodeRef; - for (unsigned int i = 0; i < skinRef->jointNames.size(); ++i) { - candidateNodeRef = skinRef->jointNames[i]; - bool candidateIsRoot = true; + // Arbitrarily use the first joint to start the search. + startNodeRef = skinRef->jointNames[0]; + parentNodeRef = skinRef->jointNames[0]; - for (unsigned int j = 0; j < skinRef->jointNames.size(); ++j) { - if (i == j) continue; + do { + startNodeRef = parentNodeRef; + parentNodeRef = startNodeRef->parent; + } while (!parentNodeRef->jointName.empty()); - testNodeRef = skinRef->jointNames[j]; - for (unsigned int k = 0; k < testNodeRef->children.size(); ++k) { - std::string childNodeRefID = testNodeRef->children[k]->id; - - if (childNodeRefID.compare(candidateNodeRef->id) == 0) { - candidateIsRoot = false; - } - } - } - - if(candidateIsRoot == true) { - return candidateNodeRef; - } - } - - return candidateNodeRef; + return parentNodeRef; } void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref& meshRef, Ref& bufferRef) { + if (aim->mNumBones < 1) { + return; + } + std::string skinName = aim->mName.C_Str(); skinName = mAsset.FindUniqueID(skinName, "skin"); Ref skinRef = mAsset.skins.Create(skinName); @@ -434,7 +428,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref& meshRef, RefmNumVertices]; vec4* vertexWeightData = new vec4[aim->mNumVertices]; - unsigned int* jointsPerVertex = new unsigned int[aim->mNumVertices]; + int* jointsPerVertex = new int[aim->mNumVertices]; for (size_t i = 0; i < aim->mNumVertices; ++i) { jointsPerVertex[i] = 0; for (size_t j = 0; j < 4; ++j) { @@ -462,11 +456,16 @@ void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref& meshRef, RefmWeights =====> vertexWeightData for (unsigned int idx_weights = 0; idx_weights < aib->mNumWeights; ++idx_weights) { - aiVertexWeight tmpVertWeight = aib->mWeights[idx_weights]; - vertexJointData[tmpVertWeight.mVertexId][jointsPerVertex[tmpVertWeight.mVertexId]] = idx_bone; - vertexWeightData[tmpVertWeight.mVertexId][jointsPerVertex[tmpVertWeight.mVertexId]] = tmpVertWeight.mWeight; + unsigned int vertexId = aib->mWeights[idx_weights].mVertexId; + float vertWeight = aib->mWeights[idx_weights].mWeight; - jointsPerVertex[tmpVertWeight.mVertexId] += 1; + // A vertex can only have at most four joint weights. Ignore all others. + if (jointsPerVertex[vertexId] > 3) { continue; } + + vertexJointData[vertexId][jointsPerVertex[vertexId]] = idx_bone; + vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight; + + jointsPerVertex[vertexId] += 1; } } // End: for-loop mNumMeshes @@ -714,7 +713,8 @@ void glTFExporter::ExportMeshes() }// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) } -unsigned int glTFExporter::ExportNode(const aiNode* n) + +unsigned int glTFExporter::ExportNodeHierarchy(const aiNode* n) { Ref node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node")); @@ -728,7 +728,31 @@ unsigned int glTFExporter::ExportNode(const aiNode* n) } for (unsigned int i = 0; i < n->mNumChildren; ++i) { - unsigned int idx = ExportNode(n->mChildren[i]); + unsigned int idx = ExportNode(n->mChildren[i], node); + node->children.push_back(mAsset->nodes.Get(idx)); + } + + return node.GetIndex(); +} + + +unsigned int glTFExporter::ExportNode(const aiNode* n, Ref& parent) +{ + Ref node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node")); + + node->parent = parent; + + if (!n->mTransformation.IsIdentity()) { + node->matrix.isPresent = true; + CopyValue(n->mTransformation, node->matrix.value); + } + + for (unsigned int i = 0; i < n->mNumMeshes; ++i) { + node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i])); + } + + for (unsigned int i = 0; i < n->mNumChildren; ++i) { + unsigned int idx = ExportNode(n->mChildren[i], node); node->children.push_back(mAsset->nodes.Get(idx)); } diff --git a/code/glTFExporter.h b/code/glTFExporter.h index 0f9c169e5..49df9193e 100644 --- a/code/glTFExporter.h +++ b/code/glTFExporter.h @@ -58,8 +58,12 @@ struct aiMaterial; namespace glTF { + template + class Ref; + class Asset; struct TexProperty; + struct Node; } namespace Assimp @@ -98,7 +102,8 @@ namespace Assimp void ExportMetadata(); void ExportMaterials(); void ExportMeshes(); - unsigned int ExportNode(const aiNode* node); + unsigned int ExportNodeHierarchy(const aiNode* n); + unsigned int ExportNode(const aiNode* node, glTF::Ref& parent); void ExportScene(); void ExportAnimations(); };