diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 394264a12..038a52b32 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -432,10 +432,10 @@ static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsign #endif // ASSIMP_BUILD_DEBUG template -aiColor4D *GetVertexColorsForType(Ref input) { +aiColor4D *GetVertexColorsForType(Ref input, std::vector *vertexRemappingTable) { constexpr float max = std::numeric_limits::max(); aiColor4t *colors; - input->ExtractData(colors); + input->ExtractData(colors, vertexRemappingTable); auto output = new aiColor4D[input->count]; for (size_t i = 0; i < input->count; i++) { output[i] = aiColor4D( @@ -450,20 +450,26 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { ASSIMP_LOG_DEBUG("Importing ", r.meshes.Size(), " meshes"); std::vector> meshes; - unsigned int k = 0; meshOffsets.clear(); + meshOffsets.reserve(r.meshes.Size() + 1); + mVertexRemappingTables.clear(); + // Count the number of aiMeshes + unsigned int num_aiMeshes = 0; + for (unsigned int m = 0; m < r.meshes.Size(); ++m) { + meshOffsets.push_back(num_aiMeshes); + num_aiMeshes += unsigned(r.meshes[m].primitives.size()); + } + meshOffsets.push_back(num_aiMeshes); // add a last element so we can always do meshOffsets[n+1] - meshOffsets[n] - std::vector usedVertexIndices; std::vector reverseMappingIndices; std::vector indexBuffer; + meshes.reserve(num_aiMeshes); + mVertexRemappingTables.resize(num_aiMeshes); for (unsigned int m = 0; m < r.meshes.Size(); ++m) { Mesh &mesh = r.meshes[m]; - meshOffsets.push_back(k); - k += unsigned(mesh.primitives.size()); - for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { Mesh::Primitive &prim = mesh.primitives[p]; @@ -477,14 +483,14 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { // Extract used vertices: bool useIndexBuffer = prim.indices; - std::vector* vertexRemappingTable = nullptr; + std::vector *vertexRemappingTable = nullptr; + if (useIndexBuffer) { size_t count = prim.indices->count; indexBuffer.resize(count); - usedVertexIndices.clear(); reverseMappingIndices.clear(); - usedVertexIndices.reserve(count / 3); // this is a very rough heuristic to reduce re-allocations - vertexRemappingTable = &usedVertexIndices; + vertexRemappingTable = &mVertexRemappingTables[meshes.size()]; + vertexRemappingTable->reserve(count / 3); // this is a very rough heuristic to reduce re-allocations Accessor::Indexer data = prim.indices->GetIndexer(); if (!data.IsValid()) { throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name)); @@ -504,8 +510,8 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { reverseMappingIndices.resize(index + 1, unusedIndex); } if (reverseMappingIndices[index] == unusedIndex) { - reverseMappingIndices[index] = static_cast(usedVertexIndices.size()); - usedVertexIndices.push_back(index); + reverseMappingIndices[index] = static_cast(vertexRemappingTable->size()); + vertexRemappingTable->push_back(index); } indexBuffer[i] = reverseMappingIndices[index]; } @@ -586,9 +592,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { attr.color[c]->ExtractData(aim->mColors[c], vertexRemappingTable); } else { if (componentType == glTF2::ComponentType_UNSIGNED_BYTE) { - aim->mColors[c] = GetVertexColorsForType(attr.color[c]); + aim->mColors[c] = GetVertexColorsForType(attr.color[c], vertexRemappingTable); } else if (componentType == glTF2::ComponentType_UNSIGNED_SHORT) { - aim->mColors[c] = GetVertexColorsForType(attr.color[c]); + aim->mColors[c] = GetVertexColorsForType(attr.color[c], vertexRemappingTable); } } } @@ -864,8 +870,6 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { } } - meshOffsets.push_back(k); - CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); } @@ -998,7 +1002,8 @@ static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) { } } -static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector> &map) { +static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector> &map, std::vector* vertexRemappingTablePtr) { + Mesh::Primitive::Attributes &attr = primitive.attributes; if (attr.weight.empty() || attr.joint.empty()) { return; @@ -1007,14 +1012,14 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vectorcount; + size_t num_vertices = 0; struct Weights { float values[4]; }; Weights **weights = new Weights*[attr.weight.size()]; for (size_t w = 0; w < attr.weight.size(); ++w) { - attr.weight[w]->ExtractData(weights[w]); + num_vertices = attr.weight[w]->ExtractData(weights[w], vertexRemappingTablePtr); } struct Indices8 { @@ -1028,12 +1033,12 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vectorGetElementSize() == 4) { indices8 = new Indices8*[attr.joint.size()]; for (size_t j = 0; j < attr.joint.size(); ++j) { - attr.joint[j]->ExtractData(indices8[j]); + attr.joint[j]->ExtractData(indices8[j], vertexRemappingTablePtr); } } else { indices16 = new Indices16 *[attr.joint.size()]; for (size_t j = 0; j < attr.joint.size(); ++j) { - attr.joint[j]->ExtractData(indices16[j]); + attr.joint[j]->ExtractData(indices16[j], vertexRemappingTablePtr); } } // @@ -1100,7 +1105,7 @@ void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) { } } -aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector &meshOffsets, glTF2::Ref &ptr) { +aiNode *glTF2Importer::ImportNode(glTF2::Asset &r, glTF2::Ref &ptr) { Node &node = *ptr; aiNode *ainode = new aiNode(GetNodeName(node)); @@ -1112,7 +1117,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & std::fill(ainode->mChildren, ainode->mChildren + ainode->mNumChildren, nullptr); for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { - aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]); + aiNode *child = ImportNode(r, node.children[i]); child->mParent = ainode; ainode->mChildren[i] = child; } @@ -1145,11 +1150,13 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & if (node.skin) { for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { - aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo]; + unsigned int aiMeshIdx = meshOffsets[mesh_idx] + primitiveNo; + aiMesh *mesh = mScene->mMeshes[aiMeshIdx]; unsigned int numBones = static_cast(node.skin->jointNames.size()); + std::vector *vertexRemappingTablePtr = mVertexRemappingTables[aiMeshIdx].empty() ? nullptr : &mVertexRemappingTables[aiMeshIdx]; std::vector> weighting(numBones); - BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); + BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting, vertexRemappingTablePtr); mesh->mNumBones = static_cast(numBones); mesh->mBones = new aiBone *[mesh->mNumBones]; @@ -1166,7 +1173,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & // mapping which makes things doubly-slow. mat4 *pbindMatrices = nullptr; - node.skin->inverseBindMatrices->ExtractData(pbindMatrices); + node.skin->inverseBindMatrices->ExtractData(pbindMatrices, nullptr); for (uint32_t i = 0; i < numBones; ++i) { const std::vector &weights = weighting[i]; @@ -1212,11 +1219,11 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } if (node.camera) { - pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; + mScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; } if (node.light) { - pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; + mScene->mLights[node.light.GetIndex()]->mName = ainode->mName; // range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual // it is added to meta data of parent node, because there is no other place to put it @@ -1248,7 +1255,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) { // The root nodes unsigned int numRootNodes = unsigned(rootNodes.size()); if (numRootNodes == 1) { // a single root node: use it - mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); + mScene->mRootNode = ImportNode(r, rootNodes[0]); } else if (numRootNodes > 1) { // more than one root node: create a fake root aiNode *root = mScene->mRootNode = new aiNode("ROOT"); @@ -1256,7 +1263,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) { std::fill(root->mChildren, root->mChildren + numRootNodes, nullptr); for (unsigned int i = 0; i < numRootNodes; ++i) { - aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); + aiNode *node = ImportNode(r, rootNodes[i]); node->mParent = root; root->mChildren[root->mNumChildren++] = node; } @@ -1657,6 +1664,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO // clean all member arrays meshOffsets.clear(); + mVertexRemappingTables.clear(); mEmbeddedTexIdxs.clear(); this->mScene = pScene; diff --git a/code/AssetLib/glTF2/glTF2Importer.h b/code/AssetLib/glTF2/glTF2Importer.h index 80cf689dc..bc2234687 100644 --- a/code/AssetLib/glTF2/glTF2Importer.h +++ b/code/AssetLib/glTF2/glTF2Importer.h @@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_GLTF2IMPORTER_H_INC #include +#include struct aiNode; @@ -77,9 +78,12 @@ private: void ImportAnimations(glTF2::Asset &a); void ImportCommonMetadata(glTF2::Asset &a); -private: + aiNode *ImportNode(glTF2::Asset &r, glTF2::Ref &ptr); + + private: std::vector meshOffsets; std::vector mEmbeddedTexIdxs; + std::vector> mVertexRemappingTables; // for each converted aiMesh in the scene, it stores a list of vertices that are actually used aiScene *mScene; /// An instance of rapidjson::IRemoteSchemaDocumentProvider