1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2021, assimp team
7 
8 All rights reserved.
9 
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13 
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17 
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22 
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27 
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41 
42 #include "AbstractImportExportBase.h"
43 #include "UnitTestPCH.h"
44 
45 #include <assimp/commonMetaData.h>
46 #include <assimp/material.h>
47 #include <assimp/postprocess.h>
48 #include <assimp/scene.h>
49 #include <assimp/types.h>
50 #include <assimp/Importer.hpp>
51 
52 using namespace Assimp;
53 
54 class utFBXImporterExporter : public AbstractImportExportBase {
55 public:
importerTest()56     virtual bool importerTest() {
57         Assimp::Importer importer;
58         const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/spider.fbx", aiProcess_ValidateDataStructure);
59         return nullptr != scene;
60     }
61 };
62 
TEST_F(utFBXImporterExporter,importXFromFileTest)63 TEST_F(utFBXImporterExporter, importXFromFileTest) {
64     EXPECT_TRUE(importerTest());
65 }
66 
TEST_F(utFBXImporterExporter,importBareBoxWithoutColorsAndTextureCoords)67 TEST_F(utFBXImporterExporter, importBareBoxWithoutColorsAndTextureCoords) {
68     Assimp::Importer importer;
69     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/box.fbx", aiProcess_ValidateDataStructure);
70     EXPECT_NE(nullptr, scene);
71     EXPECT_EQ(scene->mNumMeshes, 1u);
72     aiMesh *mesh = scene->mMeshes[0];
73     EXPECT_EQ(mesh->mNumFaces, 12u);
74     EXPECT_EQ(mesh->mNumVertices, 36u);
75 }
76 
TEST_F(utFBXImporterExporter,importCubesWithNoNames)77 TEST_F(utFBXImporterExporter, importCubesWithNoNames) {
78     Assimp::Importer importer;
79     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_nonames.fbx", aiProcess_ValidateDataStructure);
80     ASSERT_TRUE(scene);
81 
82     ASSERT_TRUE(scene->mRootNode);
83     const auto root = scene->mRootNode;
84     ASSERT_STREQ(root->mName.C_Str(), "RootNode");
85     ASSERT_TRUE(root->mChildren);
86     ASSERT_EQ(root->mNumChildren, 2u);
87 }
88 
TEST_F(utFBXImporterExporter,importCubesWithUnicodeDuplicatedNames)89 TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) {
90     Assimp::Importer importer;
91     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_names.fbx", aiProcess_ValidateDataStructure);
92     ASSERT_TRUE(scene);
93 
94     ASSERT_TRUE(scene->mRootNode);
95     const auto root = scene->mRootNode;
96     ASSERT_STREQ(root->mName.C_Str(), "RootNode");
97     ASSERT_TRUE(root->mChildren);
98     ASSERT_EQ(root->mNumChildren, 2u);
99 
100     const auto child0 = root->mChildren[0];
101     ASSERT_TRUE(child0);
102     ASSERT_STREQ(child0->mName.C_Str(), "Cube2");
103     ASSERT_TRUE(child0->mChildren);
104     ASSERT_EQ(child0->mNumChildren, 1u);
105 
106     const auto child00 = child0->mChildren[0];
107     ASSERT_TRUE(child00);
108     ASSERT_STREQ(child00->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31");
109 
110     const auto child1 = root->mChildren[1];
111     ASSERT_TRUE(child1);
112     ASSERT_STREQ(child1->mName.C_Str(), "Cube3");
113     ASSERT_TRUE(child1->mChildren);
114     ASSERT_EQ(child1->mNumChildren, 1u);
115 
116     const auto child10 = child1->mChildren[0];
117     ASSERT_TRUE(child10);
118     ASSERT_STREQ(child10->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31");
119 }
120 
TEST_F(utFBXImporterExporter,importCubesComplexTransform)121 TEST_F(utFBXImporterExporter, importCubesComplexTransform) {
122     Assimp::Importer importer;
123     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_mirroring_and_pivot.fbx", aiProcess_ValidateDataStructure);
124     ASSERT_TRUE(scene);
125 
126     ASSERT_TRUE(scene->mRootNode);
127     const auto root = scene->mRootNode;
128     ASSERT_STREQ(root->mName.C_Str(), "RootNode");
129     ASSERT_TRUE(root->mChildren);
130     ASSERT_EQ(root->mNumChildren, 2u);
131 
132     const auto child0 = root->mChildren[0];
133     ASSERT_TRUE(child0);
134     ASSERT_STREQ(child0->mName.C_Str(), "Cube2");
135     ASSERT_TRUE(child0->mChildren);
136     ASSERT_EQ(child0->mNumChildren, 1u);
137 
138     const auto child00 = child0->mChildren[0];
139     ASSERT_TRUE(child00);
140     ASSERT_STREQ(child00->mName.C_Str(), "Cube1");
141 
142     const auto child1 = root->mChildren[1];
143     ASSERT_TRUE(child1);
144     ASSERT_STREQ(child1->mName.C_Str(), "Cube3");
145 
146     auto parent = child1;
147     const size_t chain_length = 8u;
148     const char *chainStr[chain_length] = {
149         "Cube1_$AssimpFbx$_Translation",
150         "Cube1_$AssimpFbx$_RotationPivot",
151         "Cube1_$AssimpFbx$_RotationPivotInverse",
152         "Cube1_$AssimpFbx$_ScalingOffset",
153         "Cube1_$AssimpFbx$_ScalingPivot",
154         "Cube1_$AssimpFbx$_Scaling",
155         "Cube1_$AssimpFbx$_ScalingPivotInverse",
156         "Cube1"
157     };
158     for (size_t i = 0; i < chain_length; ++i) {
159         ASSERT_TRUE(parent->mChildren);
160         ASSERT_EQ(parent->mNumChildren, 1u);
161         auto node = parent->mChildren[0];
162         ASSERT_TRUE(node);
163         ASSERT_STREQ(node->mName.C_Str(), chainStr[i]);
164         parent = node;
165     }
166     ASSERT_EQ(0u, parent->mNumChildren) << "Leaf node";
167 }
168 
TEST_F(utFBXImporterExporter,importCloseToIdentityTransforms)169 TEST_F(utFBXImporterExporter, importCloseToIdentityTransforms) {
170     Assimp::Importer importer;
171     // This was asserting in FBXConverter.cpp because the transforms appeared to be the identity by one test, but not by another.
172     // This asset should now load successfully.
173     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/close_to_identity_transforms.fbx", aiProcess_ValidateDataStructure);
174     ASSERT_TRUE(scene);
175 }
176 
TEST_F(utFBXImporterExporter,importPhongMaterial)177 TEST_F(utFBXImporterExporter, importPhongMaterial) {
178     Assimp::Importer importer;
179     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/phong_cube.fbx", aiProcess_ValidateDataStructure);
180     EXPECT_NE(nullptr, scene);
181     EXPECT_EQ(1u, scene->mNumMaterials);
182     const aiMaterial *mat = scene->mMaterials[0];
183     EXPECT_NE(nullptr, mat);
184     float f;
185     aiColor3D c;
186 
187     // phong_cube.fbx has all properties defined
188     EXPECT_EQ(mat->Get(AI_MATKEY_COLOR_DIFFUSE, c), aiReturn_SUCCESS);
189     EXPECT_EQ(c, aiColor3D(0.5, 0.25, 0.25));
190     EXPECT_EQ(mat->Get(AI_MATKEY_COLOR_SPECULAR, c), aiReturn_SUCCESS);
191     EXPECT_EQ(c, aiColor3D(0.25, 0.25, 0.5));
192     EXPECT_EQ(mat->Get(AI_MATKEY_SHININESS_STRENGTH, f), aiReturn_SUCCESS);
193     EXPECT_EQ(f, 0.5f);
194     EXPECT_EQ(mat->Get(AI_MATKEY_SHININESS, f), aiReturn_SUCCESS);
195     EXPECT_EQ(f, 10.0f);
196     EXPECT_EQ(mat->Get(AI_MATKEY_COLOR_AMBIENT, c), aiReturn_SUCCESS);
197     EXPECT_EQ(c, aiColor3D(0.125, 0.25, 0.25));
198     EXPECT_EQ(mat->Get(AI_MATKEY_COLOR_EMISSIVE, c), aiReturn_SUCCESS);
199     EXPECT_EQ(c, aiColor3D(0.25, 0.125, 0.25));
200     EXPECT_EQ(mat->Get(AI_MATKEY_COLOR_TRANSPARENT, c), aiReturn_SUCCESS);
201     EXPECT_EQ(c, aiColor3D(0.75, 0.5, 0.25));
202     EXPECT_EQ(mat->Get(AI_MATKEY_OPACITY, f), aiReturn_SUCCESS);
203     EXPECT_EQ(f, 0.5f);
204 }
205 
TEST_F(utFBXImporterExporter,importUnitScaleFactor)206 TEST_F(utFBXImporterExporter, importUnitScaleFactor) {
207     Assimp::Importer importer;
208     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/global_settings.fbx", aiProcess_ValidateDataStructure);
209 
210     EXPECT_NE(nullptr, scene);
211     EXPECT_NE(nullptr, scene->mMetaData);
212 
213     float factor(0.0f);
214     scene->mMetaData->Get("UnitScaleFactor", factor);
215     EXPECT_EQ(500.0f, factor);
216 
217     scene->mMetaData->Set("UnitScaleFactor", factor * 2.0f);
218     scene->mMetaData->Get("UnitScaleFactor", factor);
219     EXPECT_EQ(1000.0f, factor);
220 }
221 
TEST_F(utFBXImporterExporter,importEmbeddedAsciiTest)222 TEST_F(utFBXImporterExporter, importEmbeddedAsciiTest) {
223     // see https://github.com/assimp/assimp/issues/1957
224     Assimp::Importer importer;
225     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box.FBX", aiProcess_ValidateDataStructure);
226     EXPECT_NE(nullptr, scene);
227 
228     EXPECT_EQ(1u, scene->mNumMaterials);
229     aiMaterial *mat = scene->mMaterials[0];
230     ASSERT_NE(nullptr, mat);
231 
232     aiString path;
233     aiTextureMapMode modes[2];
234     EXPECT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
235     ASSERT_STREQ(path.C_Str(), "..\\..\\..\\Desktop\\uv_test.png");
236 
237     ASSERT_EQ(1u, scene->mNumTextures);
238     ASSERT_TRUE(scene->mTextures[0]->pcData);
239     ASSERT_EQ(439176u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture";
240 }
241 
TEST_F(utFBXImporterExporter,importEmbeddedFragmentedAsciiTest)242 TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) {
243     // see https://github.com/assimp/assimp/issues/1957
244     Assimp::Importer importer;
245     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx", aiProcess_ValidateDataStructure);
246     EXPECT_NE(nullptr, scene);
247 
248     EXPECT_EQ(1u, scene->mNumMaterials);
249     aiMaterial *mat = scene->mMaterials[0];
250     ASSERT_NE(nullptr, mat);
251 
252     aiString path;
253     aiTextureMapMode modes[2];
254     ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
255     ASSERT_STREQ(path.C_Str(), "paper.png");
256 
257     ASSERT_EQ(1u, scene->mNumTextures);
258     ASSERT_TRUE(scene->mTextures[0]->pcData);
259     ASSERT_EQ(968029u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture";
260 }
261 
TEST_F(utFBXImporterExporter,fbxTokenizeTestTest)262 TEST_F(utFBXImporterExporter, fbxTokenizeTestTest) {
263     //Assimp::Importer importer;
264     //const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/transparentTest2.fbx", aiProcess_ValidateDataStructure);
265     //EXPECT_NE(nullptr, scene);
266 }
267 
TEST_F(utFBXImporterExporter,importOrphantEmbeddedTextureTest)268 TEST_F(utFBXImporterExporter, importOrphantEmbeddedTextureTest) {
269     // see https://github.com/assimp/assimp/issues/1957
270     Assimp::Importer importer;
271     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/box_orphant_embedded_texture.fbx", aiProcess_ValidateDataStructure);
272     EXPECT_NE(nullptr, scene);
273 
274     EXPECT_EQ(1u, scene->mNumMaterials);
275     aiMaterial *mat = scene->mMaterials[0];
276     ASSERT_NE(nullptr, mat);
277 
278     aiString path;
279     aiTextureMapMode modes[2];
280     ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
281     ASSERT_STREQ(path.C_Str(), "..\\Primitives\\GridGrey.tga");
282 
283     ASSERT_EQ(1u, scene->mNumTextures);
284     ASSERT_TRUE(scene->mTextures[0]->pcData);
285     ASSERT_EQ(9026u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression used for a texture.";
286 }
287 
TEST_F(utFBXImporterExporter,sceneMetadata)288 TEST_F(utFBXImporterExporter, sceneMetadata) {
289     Assimp::Importer importer;
290     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/global_settings.fbx",
291             aiProcess_ValidateDataStructure);
292     ASSERT_NE(scene, nullptr);
293     ASSERT_NE(scene->mMetaData, nullptr);
294     {
295         ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT));
296         aiString format;
297         ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format));
298         ASSERT_EQ(strcmp(format.C_Str(), "Autodesk FBX Importer"), 0);
299     }
300     {
301         ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION));
302         aiString version;
303         ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version));
304         ASSERT_EQ(strcmp(version.C_Str(), "7400"), 0);
305     }
306     {
307         ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR));
308         aiString generator;
309         ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator));
310         ASSERT_EQ(strncmp(generator.C_Str(), "Blender", 7), 0);
311     }
312 }
313 
TEST_F(utFBXImporterExporter,importCubesWithOutOfRangeFloat)314 TEST_F(utFBXImporterExporter, importCubesWithOutOfRangeFloat) {
315     Assimp::Importer importer;
316     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_outofrange_float.fbx", aiProcess_ValidateDataStructure);
317     ASSERT_NE(nullptr, scene);
318     ASSERT_TRUE(scene->mRootNode);
319 }
320 
TEST_F(utFBXImporterExporter,importMaxPbrMaterialsMetalRoughness)321 TEST_F(utFBXImporterExporter, importMaxPbrMaterialsMetalRoughness) {
322     Assimp::Importer importer;
323     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/maxPbrMaterial_metalRough.fbx", aiProcess_ValidateDataStructure);
324     ASSERT_NE(nullptr, scene);
325     ASSERT_TRUE(scene->mRootNode);
326 
327     ASSERT_EQ(scene->mNumMaterials, 1u);
328     const aiMaterial* mat = scene->mMaterials[0];
329     aiString texture;
330     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0), texture), AI_SUCCESS);
331     EXPECT_EQ(texture, aiString("Textures\\albedo.png"));
332     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_METALNESS, 0), texture), AI_SUCCESS);
333     EXPECT_EQ(texture, aiString("Textures\\metalness.png"));
334     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_EMISSION_COLOR, 0), texture), AI_SUCCESS);
335     EXPECT_EQ(texture, aiString("Textures\\emission.png"));
336     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMAL_CAMERA, 0), texture), AI_SUCCESS);
337     EXPECT_EQ(texture, aiString("Textures\\normal.png"));
338     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE_ROUGHNESS, 0), texture), AI_SUCCESS);
339     EXPECT_EQ(texture, aiString("Textures\\roughness.png"));
340     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION, 0), texture), AI_SUCCESS);
341     EXPECT_EQ(texture, aiString("Textures\\occlusion.png"));
342     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_OPACITY, 0), texture), AI_SUCCESS);
343     EXPECT_EQ(texture, aiString("Textures\\opacity.png"));
344 
345     // The material contains values for standard properties (e.g. SpecularColor), where 3ds Max has presumably
346     // used formulas to map the Pbr values into the standard material model. However, the pbr values themselves
347     // are available in the material as untyped "raw" properties. We check that these are correctly parsed:
348 
349     aiColor4D baseColor;
350     ASSERT_EQ(mat->Get("$raw.3dsMax|main|basecolor", aiTextureType_NONE, 0, baseColor), aiReturn_SUCCESS);
351     EXPECT_EQ(baseColor, aiColor4D(0, 1, 1, 1));
352 
353     float metalness;
354     ASSERT_EQ(mat->Get("$raw.3dsMax|main|metalness", aiTextureType_NONE, 0, metalness), aiReturn_SUCCESS);
355     EXPECT_EQ(metalness, 0.25f);
356 
357     float roughness;
358     ASSERT_EQ(mat->Get("$raw.3dsMax|main|roughness", aiTextureType_NONE, 0, roughness), aiReturn_SUCCESS);
359     EXPECT_EQ(roughness, 0.5f);
360 
361     int useGlossiness;
362     ASSERT_EQ(mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness), aiReturn_SUCCESS);
363     EXPECT_EQ(useGlossiness, 2); // 1 = Roughness map is glossiness, 2 = Roughness map is roughness.
364 
365     float bumpMapAmt; // Presumably amount.
366     ASSERT_EQ(mat->Get("$raw.3dsMax|main|bump_map_amt", aiTextureType_NONE, 0, bumpMapAmt), aiReturn_SUCCESS);
367     EXPECT_EQ(bumpMapAmt, 0.75f);
368 
369     aiColor4D emitColor;
370     ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS);
371     EXPECT_EQ(emitColor, aiColor4D(1, 1, 0, 1));
372 }
373 
TEST_F(utFBXImporterExporter,importMaxPbrMaterialsSpecularGloss)374 TEST_F(utFBXImporterExporter, importMaxPbrMaterialsSpecularGloss) {
375     Assimp::Importer importer;
376     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/maxPbrMaterial_specGloss.fbx", aiProcess_ValidateDataStructure);
377     ASSERT_NE(nullptr, scene);
378     ASSERT_TRUE(scene->mRootNode);
379 
380     ASSERT_EQ(scene->mNumMaterials, 1u);
381     const aiMaterial* mat = scene->mMaterials[0];
382     aiString texture;
383     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0), texture), AI_SUCCESS);
384     EXPECT_EQ(texture, aiString("Textures\\albedo.png"));
385     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_SPECULAR, 0), texture), AI_SUCCESS);
386     EXPECT_EQ(texture, aiString("Textures\\specular.png"));
387     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_EMISSION_COLOR, 0), texture), AI_SUCCESS);
388     EXPECT_EQ(texture, aiString("Textures\\emission.png"));
389     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMAL_CAMERA, 0), texture), AI_SUCCESS);
390     EXPECT_EQ(texture, aiString("Textures\\normal.png"));
391     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_SHININESS, 0), texture), AI_SUCCESS);
392     EXPECT_EQ(texture, aiString("Textures\\glossiness.png"));
393     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION, 0), texture), AI_SUCCESS);
394     EXPECT_EQ(texture, aiString("Textures\\occlusion.png"));
395     ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_OPACITY, 0), texture), AI_SUCCESS);
396     EXPECT_EQ(texture, aiString("Textures\\opacity.png"));
397 
398     // The material contains values for standard properties (e.g. SpecularColor), where 3ds Max has presumably
399     // used formulas to map the Pbr values into the standard material model. However, the pbr values themselves
400     // are available in the material as untyped "raw" properties. We check that these are correctly parsed:
401 
402     aiColor4D baseColor;
403     ASSERT_EQ(mat->Get("$raw.3dsMax|main|basecolor", aiTextureType_NONE, 0, baseColor), aiReturn_SUCCESS);
404     EXPECT_EQ(baseColor, aiColor4D(0, 1, 1, 1));
405 
406     aiColor4D specular;
407     ASSERT_EQ(mat->Get("$raw.3dsMax|main|Specular", aiTextureType_NONE, 0, specular), aiReturn_SUCCESS);
408     EXPECT_EQ(specular, aiColor4D(1, 1, 0, 1));
409 
410     float glossiness;
411     ASSERT_EQ(mat->Get("$raw.3dsMax|main|glossiness", aiTextureType_NONE, 0, glossiness), aiReturn_SUCCESS);
412     EXPECT_EQ(glossiness, 0.33f);
413 
414     int useGlossiness;
415     ASSERT_EQ(mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness), aiReturn_SUCCESS);
416     EXPECT_EQ(useGlossiness, 1); // 1 = Glossiness map is glossiness, 2 = Glossiness map is roughness.
417 
418     float bumpMapAmt; // Presumably amount.
419     ASSERT_EQ(mat->Get("$raw.3dsMax|main|bump_map_amt", aiTextureType_NONE, 0, bumpMapAmt), aiReturn_SUCCESS);
420     EXPECT_EQ(bumpMapAmt, 0.66f);
421 
422     aiColor4D emitColor;
423     ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS);
424     EXPECT_EQ(emitColor, aiColor4D(1, 0, 1, 1));
425 }
426