@@ -1304,23 +1304,30 @@ void Texturing::saveAs(const fs::path& dir, const std::string& basename, EFileTy
13041304 const std::string meshFileTypeStr = EFileType_enumToString (meshFileType);
13051305 const std::string filepath = (dir / (basename + " ." + meshFileTypeStr)).string ();
13061306
1307- ALICEVISION_LOG_INFO (" Save " << filepath << " mesh file" );
1307+ ALICEVISION_LOG_INFO (" Saving " << meshFileTypeStr << " mesh file using Assimp. " );
13081308
13091309 if (_atlases.empty ())
13101310 {
1311+ ALICEVISION_LOG_ERROR (" No texture atlases available. Cannot save mesh." );
13111312 return ;
13121313 }
13131314
1315+ // Assimp scene setup
1316+ // create scene and root node
13141317 aiScene scene;
1318+ scene.mRootNode = new aiNode ();
13151319
1316- scene.mRootNode = new aiNode;
1320+ // create material array
1321+ scene.mMaterials = new aiMaterial*[_atlases.size ()];
1322+ scene.mNumMaterials = _atlases.size ();
13171323
1324+ // create mesh array
13181325 scene.mMeshes = new aiMesh*[_atlases.size ()];
13191326 scene.mNumMeshes = _atlases.size ();
1327+
1328+ // link mesh array to root node
13201329 scene.mRootNode ->mMeshes = new unsigned int [_atlases.size ()];
13211330 scene.mRootNode ->mNumMeshes = _atlases.size ();
1322- scene.mMaterials = new aiMaterial*[_atlases.size ()];
1323- scene.mNumMaterials = _atlases.size ();
13241331
13251332 // define shared material properties
13261333 const aiVector3D valcolor = {material.diffuse .r , material.diffuse .g , material.diffuse .b };
@@ -1340,7 +1347,7 @@ void Texturing::saveAs(const fs::path& dir, const std::string& basename, EFileTy
13401347 // Set material for this atlas
13411348 const aiString texName (" material_" + Material::textureId (atlasId));
13421349
1343- scene.mMaterials [atlasId] = new aiMaterial;
1350+ scene.mMaterials [atlasId] = new aiMaterial () ;
13441351 scene.mMaterials [atlasId]->AddProperty (&valcolor, 1 , AI_MATKEY_COLOR_DIFFUSE);
13451352 scene.mMaterials [atlasId]->AddProperty (&valambient, 1 , AI_MATKEY_COLOR_AMBIENT);
13461353 scene.mMaterials [atlasId]->AddProperty (&valspecular, 1 , AI_MATKEY_COLOR_SPECULAR);
@@ -1376,11 +1383,18 @@ void Texturing::saveAs(const fs::path& dir, const std::string& basename, EFileTy
13761383 }
13771384
13781385 scene.mRootNode ->mMeshes [atlasId] = atlasId;
1379- scene.mMeshes [atlasId] = new aiMesh;
1386+ scene.mMeshes [atlasId] = new aiMesh () ;
13801387 aiMesh* aimesh = scene.mMeshes [atlasId];
13811388 aimesh->mMaterialIndex = atlasId;
13821389 aimesh->mNumUVComponents [0 ] = 2 ;
13831390
1391+ if (meshFileType == EFileType::GLTF || meshFileType == EFileType::GLB)
1392+ {
1393+ // set primitive types to triangles, required for gltf and glb export
1394+ // for other file types, primitive types is unspecified to avoid normal generation
1395+ aimesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
1396+ }
1397+
13841398 // Assimp does not allow vertex indices different from uv indices
13851399 // So we need to group and duplicate
13861400 std::map<std::pair<int , int >, int > unique_pairs;
@@ -1398,24 +1412,31 @@ void Texturing::saveAs(const fs::path& dir, const std::string& basename, EFileTy
13981412
13991413 aimesh->mNumVertices = unique_pairs.size ();
14001414 aimesh->mVertices = new aiVector3D[unique_pairs.size ()];
1401- aimesh->mTextureCoords [0 ] = new aiVector3D[unique_pairs.size ()];
1415+
1416+ if (hasUVs ())
1417+ {
1418+ aimesh->mTextureCoords [0 ] = new aiVector3D[unique_pairs.size ()];
1419+ }
14021420
14031421 int index = 0 ;
14041422 for (auto & p : unique_pairs)
14051423 {
1406- int vertexId = p.first .first ;
1407- int uvId = p.first .second ;
1424+ const int vertexId = p.first .first ;
14081425
14091426 aimesh->mVertices [index].x = mesh->pts [vertexId].x ;
14101427 aimesh->mVertices [index].y = -mesh->pts [vertexId].y ;
14111428 aimesh->mVertices [index].z = -mesh->pts [vertexId].z ;
14121429
1413- aimesh-> mTextureCoords [ 0 ][index]. x = mesh-> uvCoords [uvId]. x ;
1414- aimesh-> mTextureCoords [ 0 ][index]. y = mesh-> uvCoords [uvId]. y ;
1415- aimesh-> mTextureCoords [ 0 ][index]. z = 0.0 ;
1430+ if ( hasUVs ())
1431+ {
1432+ const int uvId = p. first . second ;
14161433
1417- p.second = index;
1434+ aimesh->mTextureCoords [0 ][index].x = mesh->uvCoords [uvId].x ;
1435+ aimesh->mTextureCoords [0 ][index].y = mesh->uvCoords [uvId].y ;
1436+ aimesh->mTextureCoords [0 ][index].z = 0.0 ;
1437+ }
14181438
1439+ p.second = index;
14191440 ++index;
14201441 }
14211442
@@ -1440,21 +1461,49 @@ void Texturing::saveAs(const fs::path& dir, const std::string& basename, EFileTy
14401461 }
14411462 }
14421463
1443- std::string formatId = meshFileTypeStr;
1464+ // exporter setup
1465+ std::string pFormatId = meshFileTypeStr;
14441466 unsigned int pPreprocessing = 0u ;
1445- // If gltf, use gltf 2.0
1446- if (meshFileType == EFileType::GLTF)
1467+
1468+ if (meshFileType == EFileType::GLTF || meshFileType == EFileType::GLB )
14471469 {
1448- formatId = " gltf2" ;
1449- // Flip UVs when exporting (issue with UV origin for gltf2)
1470+ if (meshFileType == EFileType::GLTF)
1471+ {
1472+ // gltf file, use gltf 2.0
1473+ pFormatId = " gltf2" ;
1474+ }
1475+ else
1476+ {
1477+ // glb file, use glb 2.0
1478+ pFormatId = " glb2" ;
1479+ }
1480+
1481+ // flip UVs when exporting (issue with UV origin for gltf2)
14501482 // https://github.com/around-media/ue4-custom-prompto/commit/044dbad90fc2172f4c5a8b67c779b80ceace5e1e
1451- pPreprocessing |= aiPostProcessSteps::aiProcess_FlipUVs | aiProcess_GenNormals;
1483+ // pPreprocessing |= aiProcess_FlipUVs;
1484+
1485+ // gen normals in order to have correct shading in Qt 3D Scene
1486+ // but cause problems with assimp importer
1487+ pPreprocessing |= aiProcess_GenNormals;
14521488 }
14531489
1490+ // export mesh
14541491 Assimp::Exporter exporter;
1455- exporter.Export (&scene, formatId, filepath, pPreprocessing);
1492+ const aiReturn ret = exporter.Export (&scene, pFormatId, filepath, pPreprocessing);
1493+
1494+ // check for errors
1495+ if (ret != AI_SUCCESS)
1496+ {
1497+ if (ret == AI_OUTOFMEMORY)
1498+ {
1499+ ALICEVISION_LOG_ERROR (" Assimp exporter ran out of memory while exporting mesh to " << filepath);
1500+ }
1501+
1502+ ALICEVISION_THROW_ERROR (" Assimp exporter failed to export mesh to " << filepath << " , error: " << exporter.GetErrorString ());
1503+ return ;
1504+ }
14561505
1457- ALICEVISION_LOG_INFO (" Save mesh to " << meshFileTypeStr << " done ." );
1506+ ALICEVISION_LOG_INFO (" Mesh saved ." );
14581507}
14591508
14601509void Texturing::_generateNormalAndHeightMaps (const mvsUtils::MultiViewParams& mp,
0 commit comments