@@ -44,10 +44,14 @@ std::string EFileType_enumToString(const EFileType meshFileType)
4444 return " obj" ;
4545 case EFileType::FBX:
4646 return " fbx" ;
47- case EFileType::STL:
48- return " stl" ;
4947 case EFileType::GLTF:
5048 return " gltf" ;
49+ case EFileType::GLB:
50+ return " glb" ;
51+ case EFileType::STL:
52+ return " stl" ;
53+ case EFileType::PLY:
54+ return " ply" ;
5155 }
5256 throw std::out_of_range (" Unrecognized EMeshFileType" );
5357}
@@ -61,10 +65,15 @@ EFileType EFileType_stringToEnum(const std::string& meshFileType)
6165 return EFileType::OBJ;
6266 if (m == " fbx" )
6367 return EFileType::FBX;
64- if (m == " stl" )
65- return EFileType::STL;
6668 if (m == " gltf" )
6769 return EFileType::GLTF;
70+ if (m == " glb" )
71+ return EFileType::GLB;
72+ if (m == " stl" )
73+ return EFileType::STL;
74+ if (m == " ply" )
75+ return EFileType::PLY;
76+
6877 throw std::out_of_range (" Invalid mesh file type " + meshFileType);
6978}
7079
@@ -81,26 +90,42 @@ void Mesh::save(const std::string& filepath)
8190 const std::string fileTypeStr = std::filesystem::path (filepath).extension ().string ().substr (1 );
8291 const EFileType fileType = mesh::EFileType_stringToEnum (fileTypeStr);
8392
84- ALICEVISION_LOG_INFO (" Save " << fileTypeStr << " mesh file" );
93+ ALICEVISION_LOG_INFO (" Saving " << fileTypeStr << " mesh file using Assimp. " );
8594
95+ // Assimp scene setup
96+ // create scene and root node
8697 aiScene scene;
98+ scene.mRootNode = new aiNode ();
8799
88- scene.mRootNode = new aiNode;
89-
100+ // create default material
101+ scene.mMaterials = new aiMaterial*[1 ];
102+ scene.mMaterials [0 ] = new aiMaterial ();
103+ scene.mNumMaterials = 1 ;
104+
105+ // create mesh
90106 scene.mMeshes = new aiMesh*[1 ];
107+ scene.mMeshes [0 ] = new aiMesh ();
91108 scene.mNumMeshes = 1 ;
109+
110+ // link mesh to root node
92111 scene.mRootNode ->mMeshes = new unsigned int [1 ];
112+ scene.mRootNode ->mMeshes [0 ] = 0 ;
93113 scene.mRootNode ->mNumMeshes = 1 ;
114+
115+ // fill mesh data
116+ aiMesh* aimesh = scene.mMeshes [0 ];
94117
95- scene.mMaterials = new aiMaterial*[1 ];
96- scene.mNumMaterials = 1 ;
97- scene.mMaterials [0 ] = new aiMaterial;
118+ // set default material index
119+ aimesh->mMaterialIndex = 0 ;
98120
99- scene.mRootNode ->mMeshes [0 ] = 0 ;
100- scene.mMeshes [0 ] = new aiMesh;
101- aiMesh* aimesh = scene.mMeshes [0 ];
102- aimesh->mMaterialIndex = 0 ;
121+ if (fileType == EFileType::GLTF || fileType == EFileType::GLB)
122+ {
123+ // set primitive types to triangles, required for gltf and glb export
124+ // for other file types, primitive types is unspecified to avoid normal generation
125+ aimesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
126+ }
103127
128+ // fill mesh vertices
104129 aimesh->mNumVertices = pts.size ();
105130 aimesh->mVertices = new aiVector3D[pts.size ()];
106131
@@ -114,6 +139,7 @@ void Mesh::save(const std::string& filepath)
114139 ++index;
115140 }
116141
142+ // fill mesh faces
117143 aimesh->mNumFaces = tris.size ();
118144 aimesh->mFaces = new aiFace[tris.size ()];
119145
@@ -128,31 +154,57 @@ void Mesh::save(const std::string& filepath)
128154 }
129155 }
130156
131- std::string formatId = fileTypeStr;
157+ // exporter setup
158+ std::string pFormatId = fileTypeStr;
132159 unsigned int pPreprocessing = 0u ;
133- // If gltf, use gltf 2.0
134- if (fileType == EFileType::GLTF)
160+
161+ if (fileType == EFileType::GLTF || fileType == EFileType::GLB )
135162 {
136- formatId = " gltf2" ;
163+ if (fileType == EFileType::GLTF)
164+ {
165+ // gltf file, use gltf 2.0
166+ pFormatId = " gltf2" ;
167+ }
168+ else
169+ {
170+ // glb file, use glb 2.0
171+ pFormatId = " glb2" ;
172+ }
173+
137174 // gen normals in order to have correct shading in Qt 3D Scene
138175 // but cause problems with assimp importer
139176 pPreprocessing |= aiProcess_GenNormals;
140177 }
141- // If obj, do not use material
142178 else if (fileType == EFileType::OBJ)
143179 {
144- formatId = " objnomtl" ;
180+ // obj file, do not use material
181+ pFormatId = " objnomtl" ;
145182 }
146183
184+ // export mesh
147185 Assimp::Exporter exporter;
148- exporter.Export (&scene, formatId, filepath, pPreprocessing);
186+ const aiReturn ret = exporter.Export (&scene, pFormatId, filepath, pPreprocessing);
187+
188+ // log mesh information
189+ ALICEVISION_LOG_DEBUG (" Mesh information:" << std::endl
190+ << " \t - # vertices: " << pts.size () << std::endl
191+ << " \t - # triangles: " << tris.size () << std::endl
192+ << " \t - # UVs: " << uvCoords.size () << std::endl
193+ << " \t - # normals: " << normals.size ());
149194
150- ALICEVISION_LOG_INFO (" Save mesh to " << fileTypeStr << " done." );
195+ // check for errors
196+ if (ret != AI_SUCCESS)
197+ {
198+ if (ret == AI_OUTOFMEMORY)
199+ {
200+ ALICEVISION_LOG_ERROR (" Assimp exporter ran out of memory while exporting mesh to " << filepath);
201+ }
151202
152- ALICEVISION_LOG_DEBUG (" Vertices: " << pts.size ());
153- ALICEVISION_LOG_DEBUG (" Triangles: " << tris.size ());
154- ALICEVISION_LOG_DEBUG (" UVs: " << uvCoords.size ());
155- ALICEVISION_LOG_DEBUG (" Normals: " << normals.size ());
203+ ALICEVISION_THROW_ERROR (" Assimp exporter failed to export mesh to " << filepath << " , error: " << exporter.GetErrorString ());
204+ return ;
205+ }
206+
207+ ALICEVISION_LOG_INFO (" Mesh saved." );
156208}
157209
158210bool Mesh::loadFromBin (const std::string& binFilepath)
@@ -2560,52 +2612,72 @@ void Mesh::load(const std::string& filepath, bool mergeCoincidentVerts, Material
25602612 f.v [2 ] = oldToNewMap[f.v [2 ]];
25612613 }
25622614 }
2615+
2616+ // get number of materials used and materials properties
2617+ if (material== nullptr || scene->mNumMaterials <= 1 )
2618+ {
2619+ std::unordered_set<int > materialIds = std::unordered_set<int >(_trisMtlIds.begin (), _trisMtlIds.end ());
25632620
2564- // set number of materials used
2565- const std::unordered_set<int > materialIds = std::unordered_set<int >(_trisMtlIds.begin (), _trisMtlIds.end ());
2566- nmtls = static_cast <int >(materialIds.size ());
2567-
2568- // store textures per atlas
2569- if (material != nullptr )
2621+ // set number of materials used
2622+ nmtls = static_cast <int >(materialIds.size ());
2623+ }
2624+ else
25702625 {
2626+ std::unordered_set<int > materialIds; // does not preserve insertion order
2627+ std::vector<int > materialIdsWithTriangleOrder;
2628+
2629+ // build materialIds and materialIdsWithTriangleOrder
2630+ for (int id : _trisMtlIds)
2631+ {
2632+ if (materialIds.insert (id).second )
2633+ materialIdsWithTriangleOrder.push_back (id);
2634+ }
2635+
2636+ // set number of materials used
2637+ nmtls = static_cast <int >(materialIds.size ());
2638+
25712639 // get material properties from the first material as they are shared across all others
25722640 scene->mMaterials [1 ]->Get (AI_MATKEY_COLOR_AMBIENT, material->ambient );
25732641 scene->mMaterials [1 ]->Get (AI_MATKEY_COLOR_DIFFUSE, material->diffuse );
25742642 scene->mMaterials [1 ]->Get (AI_MATKEY_COLOR_SPECULAR, material->specular );
25752643 scene->mMaterials [1 ]->Get (AI_MATKEY_SHININESS, material->shininess );
25762644
2577- for (int id : materialIds)
2645+ // get textures from the next materials
2646+ for (int id : materialIdsWithTriangleOrder)
25782647 {
25792648 aiString diffuse;
2580- if (scene->mMaterials [id + 1 ]->Get (AI_MATKEY_TEXTURE_DIFFUSE (0 ), diffuse) == aiReturn_SUCCESS)
2649+ if (scene->mMaterials [id + materialIdOffset ]->Get (AI_MATKEY_TEXTURE_DIFFUSE (0 ), diffuse) == aiReturn_SUCCESS)
25812650 {
25822651 material->addTexture (Material::TextureType::DIFFUSE, std::string (diffuse.C_Str ()));
25832652 }
25842653
25852654 aiString displacement;
2586- if (scene->mMaterials [id + 1 ]->Get (AI_MATKEY_TEXTURE_DISPLACEMENT (0 ), displacement) == aiReturn_SUCCESS)
2655+ if (scene->mMaterials [id + materialIdOffset ]->Get (AI_MATKEY_TEXTURE_DISPLACEMENT (0 ), displacement) == aiReturn_SUCCESS)
25872656 {
25882657 material->addTexture (Material::TextureType::DISPLACEMENT, std::string (displacement.C_Str ()));
25892658 }
25902659
25912660 aiString normal;
2592- if (scene->mMaterials [id + 1 ]->Get (AI_MATKEY_TEXTURE_NORMALS (0 ), normal) == aiReturn_SUCCESS)
2661+ if (scene->mMaterials [id + materialIdOffset ]->Get (AI_MATKEY_TEXTURE_NORMALS (0 ), normal) == aiReturn_SUCCESS)
25932662 {
25942663 material->addTexture (Material::TextureType::NORMAL, std::string (normal.C_Str ()));
25952664 }
25962665
25972666 aiString height;
2598- if (scene->mMaterials [id + 1 ]->Get (AI_MATKEY_TEXTURE_HEIGHT (0 ), height) == aiReturn_SUCCESS)
2667+ if (scene->mMaterials [id + materialIdOffset ]->Get (AI_MATKEY_TEXTURE_HEIGHT (0 ), height) == aiReturn_SUCCESS)
25992668 {
26002669 material->addTexture (Material::TextureType::BUMP, std::string (height.C_Str ()));
26012670 }
26022671 }
26032672 }
26042673
2605- ALICEVISION_LOG_DEBUG (" Vertices: " << pts.size ());
2606- ALICEVISION_LOG_DEBUG (" Triangles: " << tris.size ());
2607- ALICEVISION_LOG_DEBUG (" UVs: " << uvCoords.size ());
2608- ALICEVISION_LOG_DEBUG (" Num Materials: " + std::to_string (nmtls));
2674+ // log mesh information
2675+ ALICEVISION_LOG_DEBUG (" Mesh information:" << std::endl
2676+ << " \t - # vertices: " << pts.size () << std::endl
2677+ << " \t - # triangles: " << tris.size () << std::endl
2678+ << " \t - # UVs: " << uvCoords.size () << std::endl
2679+ << " \t - # normals: " << normals.size () << std::endl
2680+ << " \t - # materials: " << nmtls);
26092681}
26102682
26112683bool Mesh::getEdgeNeighTrisInterval (Pixel& itr, Pixel& edge, StaticVector<Voxel>& edgesXStat, StaticVector<Voxel>& edgesXYStat)
0 commit comments