@@ -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);
149187
150- ALICEVISION_LOG_INFO (" Save mesh to " << fileTypeStr << " done." );
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 ());
151194
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 ());
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+ }
202+
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)
0 commit comments