Переглянути джерело

Merge pull request #2704 from MalcolmTyrrell/fix-gltf-importer-crash

Fix gltf importer crash
Kim Kulling 5 роки тому
батько
коміт
bd25cc7c8f

+ 18 - 0
code/glTF/glTFImporter.cpp

@@ -170,6 +170,8 @@ void glTFImporter::ImportMaterials(glTF::Asset& r) {
 
     if (mScene->mNumMaterials == 0) {
         mScene->mNumMaterials = 1;
+        // Delete the array of length zero created above.
+        delete[] mScene->mMaterials;
         mScene->mMaterials = new aiMaterial*[1];
         mScene->mMaterials[0] = new aiMaterial();
     }
@@ -330,6 +332,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
 
                     case PrimitiveMode_LINES: {
                         nFaces = count / 2;
+                        if (nFaces * 2 != count) {
+                            ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
+                            count = nFaces * 2;
+                        }
                         faces = new aiFace[nFaces];
                         for (unsigned int i = 0; i < count; i += 2) {
                             SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
@@ -353,6 +359,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
 
                     case PrimitiveMode_TRIANGLES: {
                         nFaces = count / 3;
+                        if (nFaces * 3 != count) {
+                            ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
+                            count = nFaces * 3;
+                        }
                         faces = new aiFace[nFaces];
                         for (unsigned int i = 0; i < count; i += 3) {
                             SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
@@ -395,6 +405,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
 
                 case PrimitiveMode_LINES: {
                     nFaces = count / 2;
+                    if (nFaces * 2 != count) {
+                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
+                        count = nFaces * 2;
+                    }
                     faces = new aiFace[nFaces];
                     for (unsigned int i = 0; i < count; i += 2) {
                         SetFace(faces[i / 2], i, i + 1);
@@ -418,6 +432,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
 
                 case PrimitiveMode_TRIANGLES: {
                     nFaces = count / 3;
+                    if (nFaces * 3 != count) {
+                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
+                        count = nFaces * 3;
+                    }
                     faces = new aiFace[nFaces];
                     for (unsigned int i = 0; i < count; i += 3) {
                         SetFace(faces[i / 3], i, i + 1, i + 2);

+ 16 - 0
code/glTF2/glTF2Importer.cpp

@@ -530,6 +530,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
 
                     case PrimitiveMode_LINES: {
                         nFaces = count / 2;
+                        if (nFaces * 2 != count) {
+                            ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
+                            count = nFaces * 2;
+                        }
                         faces = new aiFace[nFaces];
                         for (unsigned int i = 0; i < count; i += 2) {
                             SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
@@ -553,6 +557,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
 
                     case PrimitiveMode_TRIANGLES: {
                         nFaces = count / 3;
+                        if (nFaces * 3 != count) {
+                            ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
+                            count = nFaces * 3;
+                        }
                         faces = new aiFace[nFaces];
                         for (unsigned int i = 0; i < count; i += 3) {
                             SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
@@ -604,6 +612,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
 
                 case PrimitiveMode_LINES: {
                     nFaces = count / 2;
+                    if (nFaces * 2 != count) {
+                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
+                        count = nFaces * 2;
+                    }
                     faces = new aiFace[nFaces];
                     for (unsigned int i = 0; i < count; i += 2) {
                         SetFace(faces[i / 2], i, i + 1);
@@ -627,6 +639,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
 
                 case PrimitiveMode_TRIANGLES: {
                     nFaces = count / 3;
+                    if (nFaces * 3 != count) {
+                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
+                        count = nFaces * 3;
+                    }
                     faces = new aiFace[nFaces];
                     for (unsigned int i = 0; i < count; i += 3) {
                         SetFace(faces[i / 3], i, i + 1, i + 2);

BIN
test/models/glTF/IncorrectVertexArrays/Cube.bin


+ 283 - 0
test/models/glTF/IncorrectVertexArrays/Cube_v1.gltf

@@ -0,0 +1,283 @@
+{
+   "accessors" : {
+      "accessor_0" : {
+         "bufferView" : "bufferView_0",
+         "byteOffset" : 0,
+         "componentType" : 5123,
+         "count" : 36,
+         "max" : [
+            35
+         ],
+         "min" : [
+            0
+         ],
+         "type" : "SCALAR"
+      },
+      "accessor_1" : {
+         "bufferView" : "bufferView_1",
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000,
+            1.000001
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC3"
+      },
+      "accessor_2" : {
+         "bufferView" : "bufferView_2",
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000,
+            1.000000
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC3"
+      },
+      "accessor_3" : {
+         "bufferView" : "bufferView_3",
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            -0.000000,
+            -0.000000,
+            1.000000
+         ],
+         "min" : [
+            0.000000,
+            -0.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC4"
+      },
+      "accessor_4" : {
+         "bufferView" : "bufferView_4",
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC2"
+      },
+      "accessor_5" : {
+         "bufferView" : "bufferView_1",
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "type" : "VEC3"
+       },
+       "accessor_6" : {
+         "bufferView" : "bufferView_1",
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 35,
+         "type" : "VEC3"
+       },
+       "accessor_7" : {
+         "bufferView" : "bufferView_0",
+         "byteOffset" : 0,
+         "componentType" : 5123,
+         "count" : 35,
+         "max" : [
+            35
+         ],
+         "min" : [
+            0
+         ],
+         "type" : "SCALAR"
+      }
+   },
+   "asset" : {
+      "generator" : "VKTS glTF 2.0 exporter",
+      "version" : "1.0"
+   },
+   "bufferViews" : {
+      "bufferView_0" : {
+         "buffer" : "buffer_0",
+         "byteLength" : 72,
+         "byteOffset" : 0,
+         "target" : 34963
+      },
+      "bufferView_1" : {
+         "buffer" : "buffer_0",
+         "byteLength" : 432,
+         "byteOffset" : 72,
+         "target" : 34962
+      },
+      "bufferView_2" : {
+         "buffer" : "buffer_0",
+         "byteLength" : 432,
+         "byteOffset" : 504,
+         "target" : 34962
+      },
+      "bufferView_3" : {
+         "buffer" : "buffer_0",
+         "byteLength" : 576,
+         "byteOffset" : 936,
+         "target" : 34962
+      },
+      "bufferView_4" : {
+         "buffer" : "buffer_0",
+         "byteLength" : 288,
+         "byteOffset" : 1512,
+         "target" : 34962
+      }
+   },
+   "buffers" : {
+      "buffer_0" : {
+         "byteLength" : 514,
+         "uri" : "Cube.bin"
+      }
+   },
+   "meshes" : {
+      "mesh_0" : {
+         "name" : "Cube",
+         "primitives" : [
+            {
+               "attributes" : {
+                  "POSITION" : "accessor_1"
+               },
+               "mode" : 4
+            }
+         ]
+      },
+      "mesh_1" : {
+         "name" : "TruncatedCube",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : "accessor_6"
+           },
+		   "mode" : 4
+         } ]
+       },
+	   "mesh_2" : {
+         "name" : "Lines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : "accessor_5"
+           },
+		   "mode" : 1
+         } ]
+       },
+       "mesh_3" : {
+         "name" : "TruncatedLines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : "accessor_6"
+           },
+		   "mode" : 1
+         } ]
+       },
+       "mesh_4" : {
+          "name" : "IndexedCube",
+          "primitives" : [ {
+             "attributes" : {
+                "POSITION" : "accessor_1"
+             },
+             "mode" : 4,
+             "indices" : "accessor_0"
+          } ]
+       },
+       "mesh_5" : {
+          "name" : "TruncatedIndexedCube",
+          "primitives" : [ {
+             "attributes" : {
+                "POSITION" : "accessor_6"
+             },
+             "mode" : 4,
+             "indices" : "accessor_7"
+          } ]
+       },
+       "mesh_6" : {
+         "name" : "IndexedLines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : "accessor_5"
+           },
+		   "mode" : 1,
+         "indices" : "accessor_0"
+         } ]
+       },
+       "mesh_7" : {
+         "name" : "TruncatedIndexedLines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : "accessor_6"
+           },
+		   "mode" : 1,
+         "indices" : "accessor_7"
+         } ]
+       }
+   },
+   "nodes" : {
+      "node_0" : {
+         "meshes" : [ "mesh_0" ],
+         "name" : "Cube"
+      },
+      "node_1" : {
+         "meshes" : [ "mesh_1" ],
+         "name" : "TruncatedCube",
+         "translation": [ 2.5, 0.0, 2.5 ]
+      },
+	  "node_2" : {
+		"meshes" : [ "mesh_2" ],
+      "name" : "Lines",
+      "translation": [ 2.5, 0.0, 0.0 ]
+	  },	  
+     "node_3" : {
+		"meshes" : [ "mesh_3" ],
+      "name" : "TruncatedLines",
+      "translation": [ 2.5, 0.0, -2.5 ]
+	  },
+     "node_4" : {
+       "meshes" : [ "mesh_4" ],
+       "name" : "IndexedCube",
+       "translation": [ -2.5, 0.0, 2.5 ]
+     },
+     "node_5" : {
+       "meshes" : [ "mesh_5" ],
+       "name" : "TruncatedIndexedCube",
+       "translation": [ -2.5, 0.0, 0.0 ]
+     },
+     	"node_6" : {
+		"meshes" : [ "mesh_6" ],
+      "name" : "IndexedLines",
+      "translation": [ -2.5, 0.0, -2.5 ]
+	  },
+     "node_7" : {
+		"meshes" : [ "mesh_7" ],
+      "name" : "TruncatedIndexedLines",
+      "translation": [ 0.0, 0.0, -2.5 ]
+	  }
+   },
+   "scene" : "defaultScene",
+   "scenes" : {
+      "defaultScene" : {
+         "nodes" : [
+            "node_0", "node_1", "node_2", "node_3", "node_4", "node_5", "node_6", "node_7"
+         ]
+      }
+   }
+}

BIN
test/models/glTF2/IncorrectVertexArrays/Cube.bin


+ 286 - 0
test/models/glTF2/IncorrectVertexArrays/Cube.gltf

@@ -0,0 +1,286 @@
+{
+   "accessors" : [
+      {
+         "bufferView" : 0,
+         "byteOffset" : 0,
+         "componentType" : 5123,
+         "count" : 36,
+         "max" : [
+            35
+         ],
+         "min" : [
+            0
+         ],
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 1,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000,
+            1.000001
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000,
+            1.000000
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 3,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            -0.000000,
+            -0.000000,
+            1.000000
+         ],
+         "min" : [
+            0.000000,
+            -0.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC4"
+      },
+      {
+         "bufferView" : 4,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC2"
+      },
+      {
+         "bufferView" : 1,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "type" : "VEC3"
+       },
+       {
+         "bufferView" : 1,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 35,
+         "type" : "VEC3"
+       },
+       {
+         "bufferView" : 0,
+         "byteOffset" : 0,
+         "componentType" : 5123,
+         "count" : 35,
+         "max" : [
+            35
+         ],
+         "min" : [
+            0
+         ],
+         "type" : "SCALAR"
+      }
+   ],
+   "asset" : {
+      "generator" : "VKTS glTF 2.0 exporter",
+      "version" : "2.0"
+   },
+   "bufferViews" : [
+      {
+         "buffer" : 0,
+         "byteLength" : 72,
+         "byteOffset" : 0,
+         "target" : 34963
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 432,
+         "byteOffset" : 72,
+         "target" : 34962
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 432,
+         "byteOffset" : 504,
+         "target" : 34962
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 576,
+         "byteOffset" : 936,
+         "target" : 34962
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 288,
+         "byteOffset" : 1512,
+         "target" : 34962
+      }
+   ],
+   "buffers" : [
+      {
+         "byteLength" : 514,
+         "uri" : "Cube.bin"
+      }
+   ],
+   "meshes" : [
+      {
+         "name" : "Cube",
+         "primitives" : [
+            {
+               "attributes" : {
+                  "POSITION" : 1
+               },
+               "mode" : 4
+            }
+         ]
+      },
+      {
+         "name" : "TruncatedCube",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : 6
+           },
+		   "mode" : 4
+         } ]
+       },
+	   {
+         "name" : "Lines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : 5
+           },
+		   "mode" : 1
+         } ]
+       },
+       {
+         "name" : "TruncatedLines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : 6
+           },
+		   "mode" : 1
+         } ]
+       },
+       {
+          "name" : "IndexedCube",
+          "primitives" : [ {
+             "attributes" : {
+                "POSITION" : 1
+             },
+             "mode" : 4,
+             "indices" : 0
+          } ]
+       },
+       {
+          "name" : "TruncatedIndexedCube",
+          "primitives" : [ {
+             "attributes" : {
+                "POSITION" : 6
+             },
+             "mode" : 4,
+             "indices" : 7
+          } ]
+       },
+       {
+         "name" : "IndexedLines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : 5
+           },
+		   "mode" : 1,
+         "indices" : 0
+         } ]
+       },
+       {
+         "name" : "TruncatedIndexedLines",
+         "primitives" : [ {
+           "attributes" : {
+             "POSITION" : 6
+           },
+		   "mode" : 1,
+         "indices" : 7
+         } ]
+       }
+   ],
+   "nodes" : [
+      {
+         "mesh" : 0,
+         "name" : "Cube"
+      },
+      {
+         "mesh" : 1,
+         "name" : "TruncatedCube",
+         "translation": [ 2.5, 0.0, 2.5 ]
+      },
+	  {
+		"mesh" : 2,
+      "name" : "Lines",
+      "translation": [ 2.5, 0.0, 0.0 ]
+	  },	  
+     {
+		"mesh" : 3,
+      "name" : "TruncatedLines",
+      "translation": [ 2.5, 0.0, -2.5 ]
+	  },
+     {
+       "mesh" : 4,
+       "name" : "IndexedCube",
+       "translation": [ -2.5, 0.0, 2.5 ]
+     },
+     {
+       "mesh" : 5,
+       "name" : "TruncatedIndexedCube",
+       "translation": [ -2.5, 0.0, 0.0 ]
+     },
+     	{
+		"mesh" : 6,
+      "name" : "IndexedLines",
+      "translation": [ -2.5, 0.0, -2.5 ]
+	  },
+     {
+		"mesh" : 7,
+      "name" : "TruncatedIndexedLines",
+      "translation": [ 0.0, 0.0, -2.5 ]
+	  }
+   ],
+   "samplers" : [
+      {}
+   ],
+   "scene" : 0,
+   "scenes" : [
+      {
+         "nodes" : [
+            0, 1, 2, 3, 4, 5, 6, 7
+         ]
+      }
+   ]
+}

+ 23 - 0
test/unit/utglTF2ImportExport.cpp

@@ -382,6 +382,29 @@ TEST_F(utglTF2ImportExport, import_cameras) {
     EXPECT_NE(nullptr, scene);
 }
 
+TEST_F(utglTF2ImportExport, incorrect_vertex_arrays) {
+    Assimp::Importer importer;
+    const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/IncorrectVertexArrays/Cube.gltf",
+        aiProcess_ValidateDataStructure);
+    EXPECT_NE(nullptr, scene);
+    EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 12u);
+    EXPECT_EQ(scene->mMeshes[1]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[1]->mNumFaces, 11u);
+    EXPECT_EQ(scene->mMeshes[2]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[2]->mNumFaces, 18u);
+    EXPECT_EQ(scene->mMeshes[3]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[3]->mNumFaces, 17u);
+    EXPECT_EQ(scene->mMeshes[4]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[4]->mNumFaces, 12u);
+    EXPECT_EQ(scene->mMeshes[5]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[5]->mNumFaces, 11u);
+    EXPECT_EQ(scene->mMeshes[6]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[6]->mNumFaces, 18u);
+    EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u);
+}
+
 #ifndef ASSIMP_BUILD_NO_EXPORT
 TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) {
     EXPECT_TRUE( exporterTest() );

+ 25 - 0
test/unit/utglTFImportExport.cpp

@@ -46,6 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Importer.hpp>
 #include <assimp/postprocess.h>
 
+#include <assimp/scene.h>
+
 using namespace Assimp;
 
 class utglTFImportExport : public AbstractImportExportBase {
@@ -60,3 +62,26 @@ public:
 TEST_F( utglTFImportExport, importglTFFromFileTest ) {
     EXPECT_TRUE( importerTest() );
 }
+
+TEST_F(utglTFImportExport, incorrect_vertex_arrays) {
+    Assimp::Importer importer;
+    const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF/IncorrectVertexArrays/Cube_v1.gltf",
+        aiProcess_ValidateDataStructure);
+    EXPECT_NE(nullptr, scene);
+    EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 12u);
+    EXPECT_EQ(scene->mMeshes[1]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[1]->mNumFaces, 11u);
+    EXPECT_EQ(scene->mMeshes[2]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[2]->mNumFaces, 18u);
+    EXPECT_EQ(scene->mMeshes[3]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[3]->mNumFaces, 17u);
+    EXPECT_EQ(scene->mMeshes[4]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[4]->mNumFaces, 12u);
+    EXPECT_EQ(scene->mMeshes[5]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[5]->mNumFaces, 11u);
+    EXPECT_EQ(scene->mMeshes[6]->mNumVertices, 36u);
+    EXPECT_EQ(scene->mMeshes[6]->mNumFaces, 18u);
+    EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u);
+    EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u);
+}