Bladeren bron

Merge pull request #2215 from ruyo/gltf_skinmesh

glTF2 importer multiple primitives and 16-bit index buffer skinmesh support.
Kim Kulling 6 jaren geleden
bovenliggende
commit
e6905b6a5b
1 gewijzigde bestanden met toevoegingen van 47 en 37 verwijderingen
  1. 47 37
      code/glTF2Importer.cpp

+ 47 - 37
code/glTF2Importer.cpp

@@ -732,9 +732,9 @@ static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) {
     }
 }
 
-static void BuildVertexWeightMapping(Ref<Mesh>& mesh, std::vector<std::vector<aiVertexWeight>>& map)
+static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vector<std::vector<aiVertexWeight>>& map)
 {
-    Mesh::Primitive::Attributes& attr = mesh->primitives[0].attributes;
+    Mesh::Primitive::Attributes& attr = primitive.attributes;
     if (attr.weight.empty() || attr.joint.empty()) {
         return;
     }
@@ -745,15 +745,22 @@ static void BuildVertexWeightMapping(Ref<Mesh>& mesh, std::vector<std::vector<ai
     const int num_vertices = attr.weight[0]->count;
 
     struct Weights { float values[4]; };
-    struct Indices { uint8_t values[4]; };
     Weights* weights = nullptr;
-    Indices* indices = nullptr;
     attr.weight[0]->ExtractData(weights);
-    attr.joint[0]->ExtractData(indices);
+
+    struct Indices8 { uint8_t values[4]; };
+    struct Indices16 { uint16_t values[4]; };
+    Indices8* indices8 = nullptr;
+    Indices16* indices16 = nullptr;
+    if (attr.joint[0]->GetElementSize() == 4) {
+        attr.joint[0]->ExtractData(indices8);
+    }else {
+        attr.joint[0]->ExtractData(indices16);
+    }
 
     for (int i = 0; i < num_vertices; ++i) {
         for (int j = 0; j < 4; ++j) {
-            const unsigned int bone = indices[i].values[j];
+            const unsigned int bone = (indices8!=nullptr) ? indices8[i].values[j] : indices16[i].values[j];
             const float weight = weights[i].values[j];
             if (weight > 0 && bone < map.size()) {
                 map[bone].reserve(8);
@@ -763,7 +770,8 @@ static void BuildVertexWeightMapping(Ref<Mesh>& mesh, std::vector<std::vector<ai
     }
 
     delete[] weights;
-    delete[] indices;
+    delete[] indices8;
+    delete[] indices16;
 }
 
 aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>& meshOffsets, glTF2::Ref<glTF2::Node>& ptr)
@@ -797,37 +805,39 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>&
         ainode->mMeshes = new unsigned int[count];
 
         if (node.skin) {
-            aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]];
-            mesh->mNumBones = node.skin->jointNames.size();
-            mesh->mBones = new aiBone*[mesh->mNumBones];
-
-            // GLTF and Assimp choose to store bone weights differently.
-            // GLTF has each vertex specify which bones influence the vertex.
-            // Assimp has each bone specify which vertices it has influence over.
-            // To convert this data, we first read over the vertex data and pull
-            // out the bone-to-vertex mapping.  Then, when creating the aiBones,
-            // we copy the bone-to-vertex mapping into the bone.  This is unfortunate
-            // both because it's somewhat slow and because, for many applications,
-            // we then need to reconvert the data back into the vertex-to-bone
-            // mapping which makes things doubly-slow.
-            std::vector<std::vector<aiVertexWeight>> weighting(mesh->mNumBones);
-            BuildVertexWeightMapping(node.meshes[0], weighting);
-
-            for (size_t i = 0; i < mesh->mNumBones; ++i) {
-                aiBone* bone = new aiBone();
-
-                Ref<Node> joint = node.skin->jointNames[i];
-                bone->mName = joint->name;
-                GetNodeTransform(bone->mOffsetMatrix, *joint);
-
-                std::vector<aiVertexWeight>& weights = weighting[i];
-
-                bone->mNumWeights = weights.size();
-                if (bone->mNumWeights > 0) {
-                    bone->mWeights = new aiVertexWeight[bone->mNumWeights];
-                    memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
+            for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
+                aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]+primitiveNo];
+                mesh->mNumBones = node.skin->jointNames.size();
+                mesh->mBones = new aiBone*[mesh->mNumBones];
+
+                // GLTF and Assimp choose to store bone weights differently.
+                // GLTF has each vertex specify which bones influence the vertex.
+                // Assimp has each bone specify which vertices it has influence over.
+                // To convert this data, we first read over the vertex data and pull
+                // out the bone-to-vertex mapping.  Then, when creating the aiBones,
+                // we copy the bone-to-vertex mapping into the bone.  This is unfortunate
+                // both because it's somewhat slow and because, for many applications,
+                // we then need to reconvert the data back into the vertex-to-bone
+                // mapping which makes things doubly-slow.
+                std::vector<std::vector<aiVertexWeight>> weighting(mesh->mNumBones);
+                BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
+
+                for (size_t i = 0; i < mesh->mNumBones; ++i) {
+                    aiBone* bone = new aiBone();
+
+                    Ref<Node> joint = node.skin->jointNames[i];
+                    bone->mName = joint->name;
+                    GetNodeTransform(bone->mOffsetMatrix, *joint);
+
+                    std::vector<aiVertexWeight>& weights = weighting[i];
+
+                    bone->mNumWeights = weights.size();
+                    if (bone->mNumWeights > 0) {
+                        bone->mWeights = new aiVertexWeight[bone->mNumWeights];
+                        memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
+                    }
+                    mesh->mBones[i] = bone;
                 }
-                mesh->mBones[i] = bone;
             }
         }