Browse Source

sceneconverter: ability to apply a converter to each mesh in the scene.

pull/594/head
Vladimír Vondruš 4 years ago
parent
commit
387d0dcd84
  1. 170
      src/Magnum/SceneTools/Test/SceneConverterTest.cpp
  2. 201
      src/Magnum/SceneTools/sceneconverter.cpp

170
src/Magnum/SceneTools/Test/SceneConverterTest.cpp

@ -117,29 +117,30 @@ const struct {
Containers::Array<Containers::String> args;
const char* requiresImporter;
const char* requiresConverter;
const char* requiresMeshConverter;
const char* expected;
const char* expected2;
Containers::String message;
} ConvertData[]{
{"one mesh", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
{}},
{"one mesh, whole scene converter", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"ObjImporter", "GltfSceneConverter",
"ObjImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin",
{}},
{"one mesh, explicit importer and converter", Containers::array<Containers::String>({
"-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
{}},
{"one mesh, map", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
{}},
{"one mesh, options", Containers::array<Containers::String>({
@ -148,7 +149,7 @@ const struct {
just verify the (nonexistent) options arrive there */
"-i", "nonexistentOption=13", "-c", "nonexistentConverterOption=26",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
"Trade::AnySceneImporter::openFile(): option nonexistentOption not recognized by ObjImporter\n"
"Trade::AnySceneConverter::beginFile(): option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
@ -159,7 +160,7 @@ const struct {
"-i", "nonexistentOption=13", "-c", "nonexistentConverterOption=26",
"-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
"Option nonexistentOption not recognized by ObjImporter\n"
"Option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
@ -167,20 +168,20 @@ const struct {
/* Removing the generator identifier to have the file fully roundtrip */
"-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
/* There should be a minimal difference compared to the original */
"two-quads.gltf", "two-quads.bin",
{}},
{"concatenate meshes without a scene", Containers::array<Containers::String>({
"--concatenate-meshes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad-duplicates.ply", nullptr,
{}},
{"concatenate meshes with a scene", Containers::array<Containers::String>({
"--concatenate-meshes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles-transformed.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}),
"GltfImporter", "StanfordSceneConverter",
"GltfImporter", "StanfordSceneConverter", nullptr,
"quad-duplicates.ply", nullptr,
{}},
/** @todo drop --mesh once it's not needed anymore again, then add a
@ -189,19 +190,19 @@ const struct {
/* Only 0 gets picked from here, others ignored */
"--mesh", "0", "--only-mesh-attributes", "17,0,25-36",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
{}},
{"concatenate meshes, filter mesh attributes", Containers::array<Containers::String>({
"--concatenate-meshes", "--only-mesh-attributes", "17,0,25-36",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
{}},
{"one implicit mesh, remove vertex duplicates", Containers::array<Containers::String>({
"--remove-duplicate-vertices",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
{}},
{"one implicit mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
@ -209,7 +210,7 @@ const struct {
AnySceneConverter delegation messages */
"--remove-duplicate-vertices", "-v", "-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
"Mesh 0 duplicate removal: 6 -> 4 vertices\n"},
{"one selected mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
@ -217,7 +218,7 @@ const struct {
AnySceneConverter delegation messages */
"--mesh", "1", "--remove-duplicate-vertices", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "StanfordSceneConverter",
"GltfImporter", "StanfordSceneConverter", nullptr,
/* The second mesh in the glTF is deliberately the same as in
quad-duplicates.obj, so this produces the same file */
"quad.ply", nullptr,
@ -229,7 +230,7 @@ const struct {
/* Removing the generator identifier for a smaller file */
"-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
/* There should be a minimal difference compared to the original */
"two-quads.gltf", "two-quads.bin",
"Mesh 0 duplicate removal: 5 -> 4 vertices\n"
@ -237,7 +238,7 @@ const struct {
{"one implicit mesh, remove duplicate vertices fuzzy", Containers::array<Containers::String>({
"--remove-duplicate-vertices-fuzzy", "1.0e-1",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates-fuzzy.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
{}},
{"one implicit mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
@ -245,7 +246,7 @@ const struct {
AnySceneConverter delegation messages */
"--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates-fuzzy.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
"Mesh 0 fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"one selected mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
@ -253,7 +254,7 @@ const struct {
AnySceneConverter delegation messages */
"--mesh 1", "--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "StanfordSceneConverter",
"GltfImporter", "StanfordSceneConverter", nullptr,
/* The second mesh in the glTF is deliberately the same as in
quad-duplicates-fuzzy.obj, so this produces the same file */
"quad.ply", nullptr,
@ -265,26 +266,26 @@ const struct {
/* Removing the generator identifier for a smaller file */
"-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"two-quads.gltf", "two-quads.bin",
"Mesh 0 fuzzy duplicate removal: 5 -> 4 vertices\n"
"Mesh 1 fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"one implicit mesh, two converters", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin",
{}},
{"one implicit mesh, two converters, explicit last", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "GltfSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin",
{}},
{"one implicit mesh, two converters, verbose", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin",
/* While this looks like a no-op in the output, it converts a
triangle strip to indexed triangles, which verifies that the output
@ -308,7 +309,7 @@ const struct {
{"one implicit mesh, two converters, explicit last, verbose", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "GltfSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin",
/* As the importers and converters are specified explicitly, there's
no messages from AnySceneConverter, OTOH as we have more than one -C
@ -333,7 +334,7 @@ const struct {
"-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one implicit mesh, two converters, explicit last, options for the first only", Containers::array<Containers::String>({
@ -341,7 +342,7 @@ const struct {
"-c", "nonexistentMeshOptimizerOption=yes",
"-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one implicit mesh, two converters, options for both", Containers::array<Containers::String>({
@ -349,7 +350,7 @@ const struct {
"-c", "nonexistentMeshOptimizerOption=yes",
"-c", "nonexistentAnyConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::AnySceneConverter::beginFile(): option nonexistentAnyConverterOption not recognized by GltfSceneConverter\n"},
@ -359,7 +360,7 @@ const struct {
"-C", "StanfordSceneConverter",
"-c", "nonexistentStanfordConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Option nonexistentStanfordConverterOption not recognized by StanfordSceneConverter\n"},
@ -367,7 +368,7 @@ const struct {
"--remove-duplicate-vertices",
"-C", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr,
"Trade::AnySceneImporter::openFile(): using ObjImporter\n"
"Mesh 0 duplicate removal: 6 -> 4 vertices\n"
@ -395,7 +396,7 @@ const struct {
original */
"--remove-duplicate-vertices", "-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-name-custom-attributes-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-name-custom-attributes.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
/* The output should be mostly the same, except that there's now only 4
vertices instead of 6. The code that adds meshes manually instead of
using addSupportedImporterContents() should take care of propagating
@ -407,13 +408,96 @@ const struct {
original */
"--mesh", "0", "--remove-duplicate-vertices", "-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-name-custom-attributes-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-name-custom-attributes.gltf")}),
"GltfImporter", "GltfSceneConverter",
"GltfImporter", "GltfSceneConverter", nullptr,
/* The output should be mostly the same, except that there's now only 4
vertices instead of 6. The code that adds meshes manually instead of
using addSupportedImporterContents() should take care of propagating
mesh names and custom attributes as well. */
"quad-name-custom-attributes.gltf", "quad-name-custom-attributes.bin",
{}},
{"mesh converter", Containers::array<Containers::String>({
"-M", "MeshOptimizerSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "MeshOptimizerSceneConverter",
/* Converts a triangle strip to indexed triangles, which verifies that
the output of MeshOptimizerSceneConverter got actually passed
further and not discarded */
"quad.gltf", "quad.bin",
{}},
{"mesh converter, two meshes, verbose", Containers::array<Containers::String>({
/* Removing the generator identifier for a smaller file */
"-I", "GltfImporter", "-C", "GltfSceneConverter", "-c", "generator=",
"-M", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter", "MeshOptimizerSceneConverter",
"two-quads.gltf", "two-quads.bin",
"Processing mesh 0 with MeshOptimizerSceneConverter...\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"
"Processing mesh 1 with MeshOptimizerSceneConverter...\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"},
{"two mesh converters, two options, one mesh, verbose", Containers::array<Containers::String>({
"-I", "GltfImporter", "-C", "GltfSceneConverter",
"-M", "MeshOptimizerSceneConverter",
"-m", "nonexistentFirstOption=yes",
"-M", "MeshOptimizerSceneConverter",
"-m", "nonexistentSecondOption=yes", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "MeshOptimizerSceneConverter",
"quad.gltf", "quad.bin",
"Processing mesh 0 (1/2) with MeshOptimizerSceneConverter...\n"
"Option nonexistentFirstOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"
"Processing mesh 0 (2/2) with MeshOptimizerSceneConverter...\n"
"Option nonexistentSecondOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"},
};
const struct {
@ -538,6 +622,30 @@ const struct {
"-I", "ObjImporter", "-C", "StanfordSceneConverter", "-C", "StanfordSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "StanfordSceneConverter",
"StanfordSceneConverter doesn't support importer conversion, only ConvertMeshToData\n"},
{"can't load mesh converter plugin", Containers::array<Containers::String>({
/* Override also the plugin directory for consistent output, however
then the importer plugin has to be loaded through an absolute file
path (unless using static plugins) */
"--plugin-dir", "nonexistent", "-I",
#ifndef MAGNUM_BUILD_STATIC
Utility::Path::join(MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR, "ObjImporter" + Trade::AbstractImporter::pluginSuffix()),
#else
"ObjImporter",
#endif
"-M", "NonexistentSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
/* Just a prefix */
"PluginManager::Manager::load(): plugin NonexistentSceneConverter is not static and was not found in nonexistent/sceneconverters\n"
"Available mesh converter plugins: "},
{"plugin doesn't support mesh conversion", Containers::array<Containers::String>({
"-I", "ObjImporter", "-M", "StanfordSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "StanfordSceneConverter",
"StanfordSceneConverter doesn't support mesh conversion, only ConvertMeshToData\n"},
{"can't process a mesh", Containers::array<Containers::String>({
"-I", "ObjImporter", "-M", "MeshOptimizerSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "MeshOptimizerSceneConverter",
"Trade::MeshOptimizerSceneConverter::convert(): expected a triangle mesh, got MeshPrimitive::Points\n"
"Cannot process mesh 0 with MeshOptimizerSceneConverter\n"},
};
#endif
@ -1779,6 +1887,8 @@ void SceneConverterTest::convert() {
CORRADE_SKIP(data.requiresImporter << "plugin can't be loaded.");
if(data.requiresConverter && !(converterManager.load(data.requiresConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresConverter << "plugin can't be loaded.");
if(data.requiresMeshConverter && !(converterManager.load(data.requiresMeshConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresMeshConverter << "plugin can't be loaded.");
/* AnySceneImporter & AnySceneConverter are required implicitly for
simplicity */
if(!(importerManager.load("AnySceneImporter") & PluginManager::LoadState::Loaded))

201
src/Magnum/SceneTools/sceneconverter.cpp

@ -117,12 +117,13 @@ magnum-sceneconverter chair.obj -C MeshOptimizerSceneConverter \
@code{.sh}
magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN]
[-C|--converter PLUGIN]... [--plugin-dir DIR] [--map]
[--only-mesh-attributes N1,N2-N3] [--remove-duplicate-vertices]
[--remove-duplicate-vertices-fuzzy EPSILON]
[-C|--converter PLUGIN]... [-M|--mesh-converter PLUGIN]...
[--plugin-dir DIR] [--map] [--only-mesh-attributes N1,N2-N3]
[--remove-duplicate-vertices] [--remove-duplicate-vertices-fuzzy EPSILON]
[-i|--importer-options key=val,key2=val2,]
[-c|--converter-options key=val,key2=val2,]... [--mesh ID]
[--mesh-level INDEX] [--concatenate-meshes] [--info-animations]
[-c|--converter-options key=val,key2=val2,]...
[-m|--mesh-converter-options key=val,key2=val2,]...
[--mesh ID] [--mesh-level INDEX] [--concatenate-meshes] [--info-animations]
[--info-images] [--info-lights] [--info-cameras] [--info-materials]
[--info-meshes] [--info-objects] [--info-scenes] [--info-skins]
[--info-textures] [--info] [--color on|4bit|off|auto] [--bounds]
@ -137,6 +138,8 @@ Arguments:
- `-I`, `--importer PLUGIN` --- scene importer plugin (default:
@ref Trade::AnySceneImporter "AnySceneImporter")
- `-C`, `--converter PLUGIN` --- scene converter plugin(s)
- `-M`, `--mesh-converter PLUGIN` --- converter plugin(s) to apply to each
mesh in the scene
- `--plugin-dir DIR` --- override base plugin dir
- `--map` --- memory-map the input for zero-copy import (works only for
standalone files)
@ -152,7 +155,9 @@ Arguments:
- `-i`, `--importer-options key=val,key2=val2,` --- configuration options to
pass to the importer
- `-c`, `--converter-options key=val,key2=val2,` --- configuration options
to pass to the converter(s)
to pass to scene converter(s)
- `-m`, `--mesh-converter-options key=val,key2=val2,` --- configuration
options to pass to mesh converter(s)
- `--mesh ID` --- convert just a single mesh instead of the whole scene
- `--mesh-level LEVEL` --- level to select for single-mesh conversion
- `--concatenate-meshes` -- flatten mesh hierarchy and concatenate them all
@ -183,29 +188,39 @@ and both `--info-*` options are specified, the output will also list reference
count (for example, `--info-scenes` together with `--info-meshes` will print
how many objects reference given mesh).
The `-i` / `--importer-options` and `-c` / `--converter-options` arguments
accept a comma-separated list of key/value pairs to set in the importer /
converter plugin configuration. If the `=` character is omitted, it's
equivalent to saying `key=true`; configuration subgroups are delimited with
`/`.
It's possible to specify the `-C` / `--converter` option (and correspondingly
also `-c` / `--converter-options`) multiple times in order to chain more
converters together. All converters in the chain have to support the
@ref Trade::SceneConverterFeature::ConvertMesh feature,
the last converter either @ref Trade::SceneConverterFeature::ConvertMesh or
@ref Trade::SceneConverterFeature::ConvertMeshToFile. If the last converter
doesn't support conversion to a file,
@ref Trade::AnySceneConverter "AnySceneConverter" is used to save its output;
if no `-C` / `--converter` is specified,
@ref Trade::AnySceneConverter "AnySceneConverter" is used.
The `-i`, `-c` and `-m` arguments accept a comma-separated list of key/value
pairs to set in the importer / converter plugin configuration. If the `=`
character is omitted, it's equivalent to saying `key=true`; configuration
subgroups are delimited with `/`.
It's possible to specify the `-C` option (and correspondingly also `-c`)
multiple times in order to chain more converters together. All converters in
the chain have to support the
@ref Trade::SceneConverterFeature::ConvertMultiple or
@relativeref{Trade::SceneCOnverterFeature,ConvertMesh} feature, the last
converter either @ref Trade::SceneConverterFeature::ConvertMultiple,
@relativeref{Trade::SceneCOnverterFeature,ConvertMesh},
@relativeref{Trade::SceneCOnverterFeature,ConvertMultipleToFile} or
@relativeref{Trade::SceneCOnverterFeature,ConvertMeshToFile}. If the last
converter doesn't support conversion to a file,
@relativeref{Trade,AnySceneConverter} is used to save its output. If no `-C` is
specified, @relativeref{Trade,AnySceneConverter} is used.
Similarly, the `-M` option (and correspondingly also `-m`) can be specified
multiple times in order to chain more mesh converters together. All mesh
converters in the chain have to support the ConvertMesh feature. If no `-M` is
specified, the imported meshes are passed directly to the scene converter.
The `--remove-duplicate-vertices` operations are performed before passing them
to any converter.
If `--concatenate-meshes` is given, all meshes of the input file are
concatenated into a single mesh using @ref MeshTools::concatenate(), with the
scene hierarchy transformation baked in using
@ref SceneTools::flattenMeshHierarchy3D(). Only attributes that are present in
the first mesh are taken, if `--only-mesh-attributes` is specified as well, the
IDs reference attributes of the first mesh.
first concatenated into a single mesh using @ref MeshTools::concatenate(), with
the scene hierarchy transformation baked in using
@ref SceneTools::flattenMeshHierarchy3D(), and then passed through the
remaining operations. Only attributes that are present in the first mesh are
taken, if `--only-mesh-attributes` is specified as well, the IDs reference
attributes of the first mesh.
*/
}
@ -237,6 +252,7 @@ int main(int argc, char** argv) {
.addArgument("output").setHelp("output", "output file; ignored if --info is present")
.addOption('I', "importer", "AnySceneImporter").setHelp("importer", "scene importer plugin", "PLUGIN")
.addArrayOption('C', "converter").setHelp("converter", "scene converter plugin(s)", "PLUGIN")
.addArrayOption('M', "mesh-converter").setHelp("mesh-converter", "converter plugin(s) to apply to each mesh in the scene", "PLUGIN")
.addOption("plugin-dir").setHelp("plugin-dir", "override base plugin dir", "DIR")
#if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT))
.addBooleanOption("map").setHelp("map", "memory-map the input for zero-copy import (works only for standalone files)")
@ -246,6 +262,7 @@ int main(int argc, char** argv) {
.addOption("remove-duplicate-vertices-fuzzy").setHelp("remove-duplicate-vertices-fuzzy", "remove duplicate vertices with fuzzy comparison in all meshes after import", "EPSILON")
.addOption('i', "importer-options").setHelp("importer-options", "configuration options to pass to the importer", "key=val,key2=val2,…")
.addArrayOption('c', "converter-options").setHelp("converter-options", "configuration options to pass to the converter(s)", "key=val,key2=val2,…")
.addArrayOption('m', "mesh-converter-options").setHelp("mesh-converter-options", "configuration options to pass to the mesh converter(s)", "key=val,key2=val2,…")
.addOption("mesh").setHelp("mesh", "convert just a single mesh instead of the whole scene, ignored if --concatenate-meshes is specified", "ID")
.addOption("mesh-level").setHelp("mesh-level", "level to select for single-mesh conversion", "index")
.addBooleanOption("concatenate-meshes").setHelp("concatenate-meshes", "flatten mesh hierarchy and concatenate them all together")
@ -281,24 +298,32 @@ and both --info-* options are specified, the output will also list reference
count (for example, --info-scenes together with --info-meshes will print how
many objects reference given mesh).
The -i / --importer-options and -c / --converter-options arguments accept a
comma-separated list of key/value pairs to set in the importer / converter
plugin configuration. If the = character is omitted, it's equivalent to saying
key=true; configuration subgroups are delimited with /.
It's possible to specify the -C / --converter option (and correspondingly also
-c / --converter-options) multiple times in order to chain more converters
together. All converters in the chain have to support the ConvertMesh feature,
the last converter either ConvertMesh or ConvertMeshToFile. If the last
converter doesn't support conversion to a file, AnySceneConverter is used to
save its output; if no -C / --converter is specified, AnySceneConverter is
used.
If --concatenate-meshes is given, all meshes of the input file are concatenated
into a single mesh, with the scene hierarchy transformation baked in. Only
attributes that are present in the first mesh are taken, if
--only-mesh-attributes is specified as well, the IDs reference attributes of
the first mesh.)")
The -i, -c and -m arguments accept a comma-separated list of key/value
pairs to set in the importer / converter plugin configuration. If the =
character is omitted, it's equivalent to saying key=true; configuration
subgroups are delimited with /.
It's possible to specify the -C option (and correspondingly also -c) multiple
times in order to chain more scene converters together. All converters in the
chain have to support the ConvertMultiple or ConvertMesh feature, the last
converter either ConvertMultiple, ConvertMesh, ConvertMultipleToFile or
ConvertMeshToFile. If the last converter doesn't support conversion to a file,
AnySceneConverter is used to save its output. If no -C is specified,
AnySceneConverter is used.
Similarly, the -M option (and correspondingly also -m) can be specified
multiple times in order to chain more mesh converters together. All mesh
converters in the chain have to support the ConvertMesh feature. If no -M is
specified, the imported meshes are passed directly to the scene converter.
The --remove-duplicate-vertices operations are performed on meshes before
passing them to any converter.
If --concatenate-meshes is given, all meshes of the input file are first
concatenated into a single mesh, with the scene hierarchy transformation baked
in, and then passed through the remaining operations. Only attributes that are
present in the first mesh are taken, if --only-mesh-attributes is specified as
well, the IDs reference attributes of the first mesh.)")
.parse(argc, argv);
/* Colored output. Enable only if a TTY. */
@ -572,7 +597,8 @@ the first mesh.)")
meshes are supplied manually to the converter from the array below. */
Containers::Array<Trade::MeshData> meshes;
if(args.isSet("remove-duplicate-vertices") ||
args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy"))
args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy") ||
args.arrayValueCount("mesh-converter"))
{
for(UnsignedInt i = 0; i != importer->meshCount(); ++i) {
Containers::Optional<Trade::MeshData> mesh;
@ -586,30 +612,71 @@ the first mesh.)")
}
}
const UnsignedInt beforeVertexCount = mesh->vertexCount();
const bool fuzzy = !!args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy");
/* Duplicate removal */
if(args.isSet("remove-duplicate-vertices") ||
args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy"))
{
const UnsignedInt beforeVertexCount = mesh->vertexCount();
const bool fuzzy = !!args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy");
/** @todo accept two values for float and double fuzzy comparison,
or maybe also different for positions, normals and texcoords?
ugh... */
if(fuzzy) {
Trade::Implementation::Duration d{conversionTime};
mesh = MeshTools::removeDuplicatesFuzzy(*std::move(mesh), args.value<Float>("remove-duplicate-vertices-fuzzy"));
} else {
Trade::Implementation::Duration d{conversionTime};
mesh = MeshTools::removeDuplicates(*std::move(mesh));
/** @todo accept two values for float and double fuzzy
comparison, or maybe also different for positions, normals
and texcoords? ugh... */
if(fuzzy) {
Trade::Implementation::Duration d{conversionTime};
mesh = MeshTools::removeDuplicatesFuzzy(*std::move(mesh), args.value<Float>("remove-duplicate-vertices-fuzzy"));
} else {
Trade::Implementation::Duration d{conversionTime};
mesh = MeshTools::removeDuplicates(*std::move(mesh));
}
if(args.isSet("verbose")) {
Debug d;
/* Mesh index 0 would be confusing in case of
--concatenate-meshes and plain wrong with --mesh, so
don't even print it */
if(singleMesh)
d << (fuzzy ? "Fuzzy duplicate removal:" : "Duplicate removal:");
else
d << "Mesh" << i << (fuzzy ? "fuzzy duplicate removal:" : "duplicate removal:");
d << beforeVertexCount << "->" << mesh->vertexCount() << "vertices";
}
}
if(args.isSet("verbose")) {
Debug d;
/* Mesh index 0 would be confusing in case of
--concatenate-meshes and plain wrong with --mesh, so
don't even print it */
if(singleMesh)
d << (fuzzy ? "Fuzzy duplicate removal:" : "Duplicate removal:");
else
d << "Mesh" << i << (fuzzy ? "fuzzy duplicate removal:" : "duplicate removal:");
d << beforeVertexCount << "->" << mesh->vertexCount() << "vertices";
/* Arbitrary mesh converters */
for(std::size_t j = 0, meshConverterCount = args.arrayValueCount("mesh-converter"); j != meshConverterCount; ++j) {
const Containers::StringView meshConverterName = args.arrayValue<Containers::StringView>("mesh-converter", j);
if(args.isSet("verbose")) {
Debug d;
d << "Processing mesh" << i;
if(meshConverterCount > 1)
d << "(" << Debug::nospace << (j+1) << Debug::nospace << "/" << Debug::nospace << meshConverterCount << Debug::nospace << ")";
d << "with" << meshConverterName << Debug::nospace << "...";
}
Containers::Pointer<Trade::AbstractSceneConverter> meshConverter = converterManager.loadAndInstantiate(meshConverterName);
if(!meshConverter) {
Debug{} << "Available mesh converter plugins:" << ", "_s.join(converterManager.aliasList());
return 2;
}
/* Set options, if passed. The AnySceneConverter check makes no
sense here, is just there because the helper wants it */
if(args.isSet("verbose")) meshConverter->addFlags(Trade::SceneConverterFlag::Verbose);
if(j < args.arrayValueCount("mesh-converter-options"))
Implementation::setOptions(*meshConverter, "AnySceneConverter", args.arrayValue("mesh-converter-options", j));
if(!(meshConverter->features() & (Trade::SceneConverterFeature::ConvertMesh))) {
Error{} << meshConverterName << "doesn't support mesh conversion, only" << Debug::packed << meshConverter->features();
return 1;
}
/** @todo handle mesh levels here, once any plugin is capable
of converting them */
if(!(mesh = meshConverter->convert(*mesh))) {
Error{} << "Cannot process mesh" << i << "with" << meshConverterName;
return 1;
}
}
arrayAppend(meshes, *std::move(mesh));

Loading…
Cancel
Save