Browse Source

sceneconverter: add --passthrough-on-*-converter-failure.

When using the -P or -M options on a large scene, it can happen that
the conversion would fail for a small number of outliers. For example
there can be some line meshes which aren't supported by MeshOptimizer,
or there are 16-bit images not supported by a certain image conversion
plugin.

Failing the whole operation in that case may be too radical, especially
if the only alternative would be to write a Python script that deals
with the outliers in a custom way. The option simply makes the
processing step pass through the original data unchanged, which may be a
simple and good-enough solution in many of those cases.
pull/620/head
Vladimír Vondruš 3 years ago
parent
commit
12c58babe2
  1. 6
      src/Magnum/SceneTools/Test/CMakeLists.txt
  2. 29
      src/Magnum/SceneTools/Test/SceneConverterTest.cpp
  3. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.0.png
  4. 10
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.gltf
  5. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin
  6. 16
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin.in
  7. 37
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.gltf
  8. 24
      src/Magnum/SceneTools/sceneconverter.cpp

6
src/Magnum/SceneTools/Test/CMakeLists.txt

@ -106,6 +106,10 @@ if(CORRADE_TARGET_UNIX AND NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT)
SceneConverterTestFiles/broken-scene.gltf
SceneConverterTestFiles/dxt1.dds
SceneConverterTestFiles/empty.gltf
# Same as blue4x4.png, just named like this to have the file
# roundtrip on conversion
SceneConverterTestFiles/image-passthrough-on-failure.0.png
SceneConverterTestFiles/image-passthrough-on-failure.gltf
SceneConverterTestFiles/image-dds.gltf
SceneConverterTestFiles/images-2d.gltf
SceneConverterTestFiles/images-2d-1x1.bin
@ -125,6 +129,8 @@ if(CORRADE_TARGET_UNIX AND NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT)
SceneConverterTestFiles/materials-phong.mtl
SceneConverterTestFiles/materials-phong.obj
SceneConverterTestFiles/materials-separate-metalness-roughness.mtl
SceneConverterTestFiles/mesh-passthrough-on-failure.bin
SceneConverterTestFiles/mesh-passthrough-on-failure.gltf
SceneConverterTestFiles/point.obj
SceneConverterTestFiles/quad-duplicates-fuzzy.obj
SceneConverterTestFiles/quad-duplicates.obj

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

@ -594,6 +594,20 @@ const struct {
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"},
{"mesh converter, passthrough on failure", {InPlaceInit, {
"-M", "MeshOptimizerSceneConverter",
"--passthrough-on-mesh-converter-failure",
/* Removing the generator identifier for a roundtrip */
"-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/mesh-passthrough-on-failure.gltf"),
Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/mesh-passthrough-on-failure.gltf")
}},
"GltfImporter", nullptr, "GltfSceneConverter",
{}, "MeshOptimizerSceneConverter",
/* The output is exactly the same as the input */
"mesh-passthrough-on-failure.gltf", "mesh-passthrough-on-failure.bin",
"Trade::MeshOptimizerSceneConverter::convert(): expected an indexed mesh\n"
"Cannot process mesh 0 with MeshOptimizerSceneConverter, passing the original through\n"},
{"2D image converter, two images", {InPlaceInit, {
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
/* Removing the generator identifier for a smaller file, bundling
@ -673,6 +687,21 @@ const struct {
"Processing 3D image 1 with StbResizeImageConverter...\n"
"Trade::AbstractSceneConverter::addImporterContents(): adding texture 0 out of 2\n"
"Trade::AbstractSceneConverter::addImporterContents(): adding texture 1 out of 2\n"},
{"2D image converter, passthrough on failure", {InPlaceInit, {
/* Size explicitly not set to trigger a failure */
"-P", "StbResizeImageConverter",
"--passthrough-on-image-converter-failure",
/* Removing the generator identifier for a roundtrip */
"-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/image-passthrough-on-failure.gltf"),
Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/image-passthrough-on-failure.gltf")
}},
"GltfImporter", "PngImporter", "GltfSceneConverter",
{"StbResizeImageConverter", "PngImageConverter"}, nullptr,
/* The output is exactly the same as the input */
"image-passthrough-on-failure.gltf", "image-passthrough-on-failure.0.png",
"Trade::StbResizeImageConverter::convert(): output size was not specified\n"
"Cannot process 2D image 0 with StbResizeImageConverter, passing the original through\n"},
{"Phong to PBR", {InPlaceInit, {
"-I", "UfbxImporter", "-C", "GltfSceneConverter", "--phong-to-pbr",
/* We need the file as minimal as possible, so no index buffer.

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.0.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

10
src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.gltf

@ -0,0 +1,10 @@
{
"asset": {
"version": "2.0"
},
"images": [
{
"uri": "image-passthrough-on-failure.0.png"
}
]
}

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin

Binary file not shown.

16
src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin.in

@ -0,0 +1,16 @@
type = "3f3f3f 3f3f3f"
input = [
# 2 3--5
# |\ \ |
# | \ \|
# 0--1 4
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
-1, 1, 0,
1, -1, 0,
1, 1, 0,
]
# kate: hl python

37
src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.gltf

@ -0,0 +1,37 @@
{
"asset": {
"version": "2.0"
},
"buffers": [
{
"uri": "mesh-passthrough-on-failure.bin",
"byteLength": 72
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 72
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 6,
"type": "VEC3"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"POSITION": 0
}
}
]
}
]
}

24
src/Magnum/SceneTools/sceneconverter.cpp

@ -186,6 +186,8 @@ magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN]
[-c|--converter-options key=val,key2=val2,]...
[-p|--image-converter-options key=val,key2=val2,]...
[-m|--mesh-converter-options key=val,key2=val2,]...
[--passthrough-on-image-converter-failure]
[--passthrough-on-mesh-converter-failure]
[--mesh ID] [--mesh-level INDEX] [--concatenate-meshes] [--info-importer]
[--info-converter] [--info-image-converter] [--info-animations]
[--info-images] [--info-lights] [--info-cameras] [--info-materials]
@ -228,6 +230,10 @@ Arguments:
options to pass to image converter(s)
- `-m`, `--mesh-converter-options key=val,key2=val2,` --- configuration
options to pass to mesh converter(s)
- `--passthrough-on-image-converter-failure` --- pass original data through
if `--image-converter` fails
- `--passthrough-on-mesh-converter-failure` --- pass original data through
if `--mesh-converter` fails
- `--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
@ -335,6 +341,8 @@ bool isDataInfoRequested(const Utility::Arguments& args) {
}
template<UnsignedInt dimensions> bool runImageConverters(PluginManager::Manager<Trade::AbstractImageConverter>& imageConverterManager, const Utility::Arguments& args, const UnsignedInt i, Containers::Optional<Trade::ImageData<dimensions>>& image) {
const bool passthroughOnConversionFailure = args.isSet("passthrough-on-image-converter-failure");
for(std::size_t j = 0, imageConverterCount = args.arrayValueCount("image-converter"); j != imageConverterCount; ++j) {
const Containers::StringView imageConverterName = args.arrayValue<Containers::StringView>("image-converter", j);
if(args.isSet("verbose")) {
@ -381,7 +389,11 @@ template<UnsignedInt dimensions> bool runImageConverters(PluginManager::Manager<
/** @todo handle image levels here, once GltfSceneConverter is capable
of converting them (which needs AbstractImageConverter to be
reworked around ImageData) */
if(!(image = imageConverter->convert(*image))) {
if(Containers::Optional<Trade::ImageData<dimensions>> converted = imageConverter->convert(*image)) {
image = std::move(converted);
} else if(passthroughOnConversionFailure) {
Warning{} << "Cannot process" << dimensions << Debug::nospace << "D image" << i << "with" << imageConverterName << Debug::nospace << ", passing the original through";
} else {
Error{} << "Cannot process" << dimensions << Debug::nospace << "D image" << i << "with" << imageConverterName;
return false;
}
@ -412,6 +424,8 @@ int main(int argc, char** argv) {
.addArrayOption('c', "converter-options").setHelp("converter-options", "configuration options to pass to the converter(s)", "key=val,key2=val2,…")
.addArrayOption('p', "image-converter-options").setHelp("image-converter-options", "configuration options to pass to the image 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,…")
.addBooleanOption("passthrough-on-image-converter-failure").setHelp("passthrough-on-image-converter-failure", "pass original data through if --image-converter fails")
.addBooleanOption("passthrough-on-mesh-converter-failure").setHelp("passthrough-on-mesh-converter-failure", "pass original data through if --mesh-converter fails")
.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")
@ -879,6 +893,8 @@ well, the IDs reference attributes of the first mesh.)")
args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy") ||
args.arrayValueCount("mesh-converter"))
{
const bool passthroughOnConversionFailure = args.isSet("passthrough-on-mesh-converter-failure");
arrayReserve(meshes, importer->meshCount());
for(UnsignedInt i = 0; i != importer->meshCount(); ++i) {
@ -954,7 +970,11 @@ well, the IDs reference attributes of the first mesh.)")
/** @todo handle mesh levels here, once any plugin is capable
of converting them */
if(!(mesh = meshConverter->convert(*mesh))) {
if(Containers::Optional<Trade::MeshData> converted = meshConverter->convert(*mesh)) {
mesh = std::move(converted);
} else if(passthroughOnConversionFailure) {
Warning{} << "Cannot process mesh" << i << "with" << meshConverterName << Debug::nospace << ", passing the original through";
} else {
Error{} << "Cannot process mesh" << i << "with" << meshConverterName;
return 1;
}

Loading…
Cancel
Save