Skip to content

Commit e9c58e7

Browse files
gregoire-dlcbentejac
authored andcommitted
[software] convertMesh: Use Texturing to load and export mesh/material
This allows `convertMesh` to convert textured or not textured mesh. Mesh can now be converted at any steps of the MVS pipeline (Meshing, MeshFiltering and now Texturing). Add options for texture files copy and flip normals. Update compatible mesh files list.
1 parent bee62cb commit e9c58e7

File tree

1 file changed

+63
-14
lines changed

1 file changed

+63
-14
lines changed

src/software/convert/main_convertMesh.cpp

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
// These constants define the current software version.
2424
// They must be updated when the command line is changed.
25-
#define ALICEVISION_SOFTWARE_VERSION_MAJOR 1
25+
#define ALICEVISION_SOFTWARE_VERSION_MAJOR 2
2626
#define ALICEVISION_SOFTWARE_VERSION_MINOR 0
2727

2828
using namespace aliceVision;
@@ -36,25 +36,39 @@ namespace fs = std::filesystem;
3636
int aliceVision_main(int argc, char** argv)
3737
{
3838
// timer initialization
39-
4039
system::Timer timer;
4140

42-
// command-line parameters
41+
// command-line required parameters
4342
std::string inputMeshPath;
44-
std::string outputFilePath;
43+
std::string outputMeshPath;
44+
45+
// command-line optional parameters
46+
bool flipNormals = false;
47+
bool copyTextures = true;
4548

4649
// clang-format off
4750
po::options_description requiredParams("Required parameters");
4851
requiredParams.add_options()
49-
("inputMesh", po::value<std::string>(&inputMeshPath)->default_value(inputMeshPath),
50-
"Mesh file path (*.obj, *.mesh, *.meshb, *.ply, *.off, *.stl).")
51-
("output,o", po::value<std::string>(&outputFilePath)->default_value(outputFilePath),
52-
"Output file path for the new mesh file (*.obj, *.mesh, *.meshb, *.ply, *.off, *.stl).");
52+
("inputMesh", po::value<std::string>(&inputMeshPath)->required(),
53+
"Mesh file path (*.obj, *.fbx, *.gltf, *.glb, *.stl, *.ply).")
54+
("output,o", po::value<std::string>(&outputMeshPath)->required(),
55+
"Output file path (*.obj, *.fbx, *.gltf, *.glb, *.stl *.ply).");
56+
57+
po::options_description optionalParams("Optional parameters");
58+
optionalParams.add_options()
59+
("flipNormals", po::value<bool>(&flipNormals)->default_value(flipNormals),
60+
"Flip face normals. It can be needed as it depends on the vertices order in triangles and the "
61+
"convention changes from one software to another.")
62+
("copyTextures", po::value<bool>(&copyTextures)->default_value(copyTextures),
63+
"Copy input mesh texture files to the output mesh folder.");
5364
// clang-format on
5465

5566
CmdLine cmdline("The program allows to convert a mesh to another mesh format.\n"
5667
"AliceVision convertMesh");
68+
5769
cmdline.add(requiredParams);
70+
cmdline.add(optionalParams);
71+
5872
if (!cmdline.execute(argc, argv))
5973
{
6074
return EXIT_FAILURE;
@@ -68,15 +82,15 @@ int aliceVision_main(int argc, char** argv)
6882
}
6983

7084
// check output file path
71-
if (outputFilePath.empty())
85+
if (outputMeshPath.empty())
7286
{
7387
ALICEVISION_LOG_ERROR("Invalid output");
7488
return EXIT_FAILURE;
7589
}
7690

7791
// ensure output folder exists
7892
{
79-
const std::string outputFolderPart = fs::path(outputFilePath).parent_path().string();
93+
const std::string outputFolderPart = fs::path(outputMeshPath).parent_path().string();
8094

8195
if (!outputFolderPart.empty() && !utils::exists(outputFolderPart))
8296
{
@@ -89,26 +103,61 @@ int aliceVision_main(int argc, char** argv)
89103
}
90104

91105
// load input mesh
106+
ALICEVISION_LOG_INFO("Loading input mesh.");
92107
mesh::Texturing texturing;
93-
texturing.loadWithAtlas(inputMeshPath);
108+
texturing.loadWithMaterial(inputMeshPath, flipNormals);
94109
mesh::Mesh* inputMesh = texturing.mesh;
95110

111+
// check if mesh is loaded
96112
if (!inputMesh)
97113
{
98114
ALICEVISION_LOG_ERROR("Unable to read input mesh from the file: " << inputMeshPath);
99115
return EXIT_FAILURE;
100116
}
101117

118+
// check if mesh is not empty
102119
if (inputMesh->pts.empty() || inputMesh->tris.empty())
103120
{
104-
ALICEVISION_LOG_ERROR("Error: empty mesh from the file " << inputMeshPath);
121+
ALICEVISION_LOG_ERROR("Empty input mesh from the file: " << inputMeshPath);
105122
ALICEVISION_LOG_ERROR("Input mesh: " << inputMesh->pts.size() << " vertices and " << inputMesh->tris.size() << " facets.");
106123
return EXIT_FAILURE;
107124
}
108125

126+
// copy textures files from the input mesh folder to the output mesh folder
127+
if (copyTextures)
128+
{
129+
const std::string outTypeStr = std::filesystem::path(outputMeshPath).extension().string().substr(1);
130+
const mesh::EFileType outType = mesh::EFileType_stringToEnum(outTypeStr);
131+
132+
// only copy textures for mesh formats that support textures
133+
if (outType == mesh::EFileType::OBJ ||
134+
outType == mesh::EFileType::FBX ||
135+
outType == mesh::EFileType::GLTF ||
136+
outType == mesh::EFileType::GLB)
137+
{
138+
std::vector<std::string> texturePaths;
139+
texturing.material.getAllTexturePaths(texturePaths);
140+
141+
for (const auto& texturePath : texturePaths)
142+
{
143+
ALICEVISION_LOG_DEBUG("Copying texture file: " << texturePath);
144+
145+
const fs::path srcPath = fs::path(inputMeshPath).parent_path() / texturePath;
146+
const fs::path dstPath = fs::path(outputMeshPath).parent_path() / texturePath;
147+
148+
fs::copy(srcPath, dstPath);
149+
}
150+
}
151+
}
152+
109153
// save output mesh
110-
ALICEVISION_LOG_INFO("Convert mesh.");
111-
inputMesh->save(outputFilePath);
154+
ALICEVISION_LOG_INFO("Saving output mesh.");
155+
{
156+
const auto outPath = std::filesystem::path(outputMeshPath);
157+
const mesh::EFileType outFileType = mesh::EFileType_stringToEnum(outPath.extension().string().substr(1));
158+
159+
texturing.saveAs(outPath.parent_path().string(), outPath.stem().string(), outFileType);
160+
}
112161

113162
ALICEVISION_LOG_INFO("Task done in (s): " + std::to_string(timer.elapsed()));
114163

0 commit comments

Comments
 (0)