diff --git a/CMakeLists.txt b/CMakeLists.txt index d94148287..75d5d4431 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,7 @@ cmake_dependent_option(MAGNUM_WITH_TGAIMPORTER "Build TgaImporter plugin" OFF "N # Parts of the library cmake_dependent_option(MAGNUM_WITH_AUDIO "Build Audio library" OFF "NOT MAGNUM_WITH_AL_INFO;NOT MAGNUM_WITH_ANYAUDIOIMPORTER;NOT MAGNUM_WITH_WAVAUDIOIMPORTER" ON) option(MAGNUM_WITH_DEBUGTOOLS "Build DebugTools library" ON) -option(MAGNUM_WITH_MATERIALTOOLS "Build MaterialTools library" ON) +cmake_dependent_option(MAGNUM_WITH_MATERIALTOOLS "Build MaterialTools library" ON "NOT MAGNUM_WITH_SCENECONVERTER" ON) cmake_dependent_option(MAGNUM_WITH_MESHTOOLS "Build MeshTools library" ON "NOT MAGNUM_WITH_OBJIMPORTER;NOT MAGNUM_WITH_SCENECONVERTER" ON) option(MAGNUM_WITH_SCENEGRAPH "Build SceneGraph library" ON) cmake_dependent_option(MAGNUM_WITH_SCENETOOLS "Build SceneTools library" ON "NOT MAGNUM_WITH_SCENECONVERTER" ON) diff --git a/doc/changelog.dox b/doc/changelog.dox index e972472d2..58fe63dc9 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -235,6 +235,9 @@ See also: experimental `--concatenate-meshes` option, which will flatten the mesh hierarchy and concatenate all meshes together. Note that it doesn't correctly handle all corner cases yet and may assert on certain inputs. +- Added a `--phong-to-pbr` option to the @ref magnum-sceneconverter "magnum-sceneconverter" + utility to perform conversion of Phong materials to PBR, useful for example + when converting old OBJ and COLLADA files to glTF - The @ref magnum-sceneconverter "magnum-sceneconverter" `--info` output is now more compact and colored for better readability - Added `--info-importer`, `--info-converter` and `--info-image-converter` diff --git a/src/Magnum/SceneTools/CMakeLists.txt b/src/Magnum/SceneTools/CMakeLists.txt index db90132ef..6ffad5730 100644 --- a/src/Magnum/SceneTools/CMakeLists.txt +++ b/src/Magnum/SceneTools/CMakeLists.txt @@ -99,6 +99,7 @@ if(MAGNUM_WITH_SCENECONVERTER) target_link_libraries(magnum-sceneconverter PRIVATE Corrade::Main Magnum + MagnumMaterialTools MagnumMeshTools MagnumSceneTools MagnumTrade diff --git a/src/Magnum/SceneTools/Test/CMakeLists.txt b/src/Magnum/SceneTools/Test/CMakeLists.txt index 4239f0fed..eeaab8930 100644 --- a/src/Magnum/SceneTools/Test/CMakeLists.txt +++ b/src/Magnum/SceneTools/Test/CMakeLists.txt @@ -97,6 +97,7 @@ if(CORRADE_TARGET_UNIX AND NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT) SceneConverterTestFiles/blue4x4x1.ktx2 SceneConverterTestFiles/broken-image-2d.gltf SceneConverterTestFiles/broken-image-3d.gltf + SceneConverterTestFiles/broken-material.gltf SceneConverterTestFiles/broken-mesh.obj SceneConverterTestFiles/broken-scene.gltf SceneConverterTestFiles/dxt1.dds @@ -115,6 +116,11 @@ if(CORRADE_TARGET_UNIX AND NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT) SceneConverterTestFiles/info-image-converter.txt SceneConverterTestFiles/info-importer.txt SceneConverterTestFiles/info-importer-ignored-input-output.txt + SceneConverterTestFiles/materials-3d.gltf + SceneConverterTestFiles/materials-pbr.gltf + SceneConverterTestFiles/materials-phong.mtl + SceneConverterTestFiles/materials-phong.obj + SceneConverterTestFiles/materials-separate-metalness-roughness.mtl SceneConverterTestFiles/point.obj SceneConverterTestFiles/quad-duplicates-fuzzy.obj SceneConverterTestFiles/quad-duplicates.obj diff --git a/src/Magnum/SceneTools/Test/SceneConverterTest.cpp b/src/Magnum/SceneTools/Test/SceneConverterTest.cpp index 0c06d686f..85e7b7ed9 100644 --- a/src/Magnum/SceneTools/Test/SceneConverterTest.cpp +++ b/src/Magnum/SceneTools/Test/SceneConverterTest.cpp @@ -664,6 +664,48 @@ 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"}, + {"Phong to PBR", {InPlaceInit, { + "-I", "UfbxImporter", "-C", "GltfSceneConverter", "--phong-to-pbr", + /* We need the file as minimal as possible, so no index buffer. + OTOH, dropping meshes altogether would also lose + node/mesh/material assignment, which is important */ + "-i", "generateIndices=false", + /* Removing the generator identifier for a smaller file */ + "-c", "generator=", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/materials-phong.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/materials-pbr.gltf") + }}, + "UfbxImporter", "PngImporter", "GltfSceneConverter", {"PngImageConverter", nullptr}, nullptr, + /* The file should contain also material names and everything */ + "materials-pbr.gltf", nullptr, + "MaterialTools::phongToPbrMetallicRoughness(): unconvertable Trade::MaterialAttribute::AmbientColor attribute, skipping\n" + /** @todo remove this once StridedBitArray exists and SceneData + + UfbxImporter uses it for bit values */ + "Trade::GltfSceneConverter::add(): custom scene field Visibility has unsupported type Trade::SceneFieldType::UnsignedByte, skipping\n" + "Trade::GltfSceneConverter::add(): custom scene field GeometryTransformHelper has unsupported type Trade::SceneFieldType::UnsignedByte, skipping\n"}, + {"Phong to PBR, verbose", {InPlaceInit, { + /* Same as above, just with -v added */ + "-I", "UfbxImporter", "-C", "GltfSceneConverter", "--phong-to-pbr", + "-i", "generateIndices=false", "-c", "generator=", "-v", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/materials-phong.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/materials-pbr.gltf") + }}, + "UfbxImporter", "PngImporter", "GltfSceneConverter", {"PngImageConverter", nullptr}, nullptr, + "materials-pbr.gltf", nullptr, + "Converting material 0 to PBR\n" + "MaterialTools::phongToPbrMetallicRoughness(): unconvertable Trade::MaterialAttribute::AmbientColor attribute, skipping\n" + "Converting material 1 to PBR\n" + "Trade::AbstractSceneConverter::addImporterContents(): adding 2D image 0 out of 2\n" + "Trade::AnyImageImporter::openFile(): using PngImporter\n" + "Trade::AbstractSceneConverter::addImporterContents(): adding 2D image 1 out of 2\n" + "Trade::AnyImageImporter::openFile(): using PngImporter\n" + "Trade::AbstractSceneConverter::addImporterContents(): adding texture 0 out of 2\n" + "Trade::AbstractSceneConverter::addImporterContents(): adding texture 1 out of 2\n" + "Trade::AbstractSceneConverter::addImporterContents(): adding mesh 0 out of 2\n" + "Trade::AbstractSceneConverter::addImporterContents(): adding mesh 1 out of 2\n" + "Trade::AbstractSceneConverter::addImporterContents(): adding scene 0 out of 1\n" + /** @todo remove this once StridedBitArray exists and SceneData + + UfbxImporter uses it for bit values */ + "Trade::GltfSceneConverter::add(): custom scene field Visibility has unsupported type Trade::SceneFieldType::UnsignedByte, skipping\n" + "Trade::GltfSceneConverter::add(): custom scene field GeometryTransformHelper has unsupported type Trade::SceneFieldType::UnsignedByte, skipping\n"}, {"data unsupported by the converter", {InPlaceInit, { "-I", "GltfImporter", "-i", "experimentalKhrTextureKtx", "-C", "StanfordSceneConverter", @@ -675,7 +717,8 @@ const struct { "quad.ply", nullptr, "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 1 2D images not supported by the converter\n" "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 1 3D images not supported by the converter\n" - "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 2 textures not supported by the converter\n"}, + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 2 textures not supported by the converter\n" + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 1 materials not supported by the converter\n"}, {"per-image processed images unsupported by the converter", {InPlaceInit, { "-I", "GltfImporter", "-i", "experimentalKhrTextureKtx", "-P", "StbResizeImageConverter", "-p", "size=\"1 1\"", @@ -690,7 +733,23 @@ const struct { printed by sceneconverter itself, not the converter interface */ "Ignoring 1 2D images not supported by the converter\n" "Ignoring 1 3D images not supported by the converter\n" - "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 2 textures not supported by the converter\n"}, + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 2 textures not supported by the converter\n" + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 1 materials not supported by the converter\n"}, + {"per-material processed materials unsupported by the converter", {InPlaceInit, { + "-I", "GltfImporter", "-i", "experimentalKhrTextureKtx", + "--phong-to-pbr", "-C", "StanfordSceneConverter", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/ignoring-unsupported.gltf"), + Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply") + }}, + "GltfImporter", "KtxImporter", "StanfordSceneConverter", + {"StbResizeImageConverter", nullptr}, nullptr, + "quad.ply", nullptr, + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 1 2D images not supported by the converter\n" + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 1 3D images not supported by the converter\n" + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 2 textures not supported by the converter\n" + /* Compared to "data unsupported by the converter" this message is + printed by sceneconverter itself, not the converter interface */ + "Ignoring 1 materials not supported by the converter\n"}, }; const struct { @@ -978,6 +1037,46 @@ const struct { nullptr, "KtxImporter", nullptr, nullptr, "Sorry, 1D image conversion is not implemented yet\n"}, + {"can't load a material for Phong to PBR conversion", {InPlaceInit, { + "-I", "GltfImporter", "--phong-to-pbr", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-material.gltf"), + Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf") + }}, + "GltfImporter", nullptr, nullptr, + nullptr, + "Trade::GltfImporter::material(): unrecognized alphaMode TOUGH\n" + "Cannot import material 2\n"}, + {"can't add material dependencies", {InPlaceInit, { + /* --phong-to-pbr is a no-op because the input is PBR already, we + just need something that causes the materials to be added + directly */ + "-I", "GltfImporter", "--phong-to-pbr", + /* Not enabling experimentalKhrTextureKtx for the converter in + order to trigger this error */ + "-i", "experimentalKhrTextureKtx", "-C", "GltfSceneConverter", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/materials-3d.gltf"), + Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf") + }}, + "GltfImporter", "KtxImporter", "GltfSceneConverter", + nullptr, + "Trade::AbstractSceneConverter::addSupportedImporterContents(): ignoring 1 3D images not supported by the converter\n" + /* Another way this could fail is that the texture is now referencing a + 3D image out of bounds (because adding it failed above) */ + "Trade::GltfSceneConverter::add(): 2D array textures require experimentalKhrTextureKtx to be enabled\n" + "Cannot add material dependencies\n"}, + {"can't add processed material", {InPlaceInit, { + /* --phong-to-pbr is a no-op because the input is PBR already, we + just need something that causes the materials to be added + directly */ + "-I", "UfbxImporter", "--phong-to-pbr", + "-C", "GltfSceneConverter", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/materials-separate-metalness-roughness.mtl"), + Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf") + }}, + "UfbxImporter", "PngImporter", "GltfSceneConverter", + nullptr, + "Trade::GltfSceneConverter::add(): unsupported R/R packing of a metallic/roughness texture\n" + "Cannot add material 1\n"} }; SceneConverterTest::SceneConverterTest() { diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-material.gltf b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-material.gltf new file mode 100644 index 000000000..3731ae77d --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-material.gltf @@ -0,0 +1,12 @@ +{ + "asset": { + "version": "2.0" + }, + "materials": [ + {}, + {}, + { + "alphaMode": "TOUGH" + } + ] +} diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/ignoring-unsupported.gltf b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/ignoring-unsupported.gltf index 1cb4f720c..a97dd2d1a 100644 --- a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/ignoring-unsupported.gltf +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/ignoring-unsupported.gltf @@ -73,5 +73,14 @@ } } } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + } + } + } ] } diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-3d.gltf b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-3d.gltf new file mode 100644 index 000000000..54a44dc08 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-3d.gltf @@ -0,0 +1,35 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_texture_ktx" + ], + "extensionsRequired": [ + "KHR_texture_ktx" + ], + "textures": [ + { + "extensions": { + "KHR_texture_ktx": { + "source": 0, + "layer": 0 + } + } + } + ], + "images": [ + { + "uri": "red2x2x1.ktx2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + } + } + } + ] +} diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-pbr.gltf b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-pbr.gltf new file mode 100644 index 000000000..1bfc99080 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-pbr.gltf @@ -0,0 +1,122 @@ +{ + "asset": { + "version": "2.0" + }, + "buffers": [ + { + "uri": "materials-pbr.bin", + "byteLength": 72 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 36 + }, + { + "buffer": 0, + "byteOffset": 36, + "byteLength": 36 + } + ], + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 3, + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 3, + "type": "VEC3" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "POSITION": 0 + }, + "material": 0 + } + ] + }, + { + "primitives": [ + { + "attributes": { + "POSITION": 1 + }, + "material": 1 + } + ] + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + } + }, + "name": "Red" + }, + { + "pbrMetallicRoughness": { + "baseColorFactor": [0.5, 0.5, 0.5, 1], + "baseColorTexture": { + "index": 1 + } + }, + "name": "DarkBlue" + } + ], + "samplers": [ + { + "wrapS": 10497, + "wrapT": 10497, + "minFilter": 9987, + "magFilter": 9729 + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + }, + { + "sampler": 0, + "source": 1 + } + ], + "images": [ + { + "uri": "materials-pbr.0.png", + "name": "red2x2.png" + }, + { + "uri": "materials-pbr.1.png", + "name": "blue4x4.png" + } + ], + "nodes": [ + { + "mesh": 0, + "name": "First" + }, + { + "mesh": 1, + "name": "Second" + } + ], + "scenes": [ + { + "nodes": [0, 1] + } + ], + "scene": 0 +} diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-phong.mtl b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-phong.mtl new file mode 100644 index 000000000..8b44e7dc7 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-phong.mtl @@ -0,0 +1,7 @@ +newmtl Red +Ka 0.1 0.1 0.1 +map_Kd red2x2.png + +newmtl DarkBlue +Kd 0.5 0.5 0.5 +map_Kd blue4x4.png diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-phong.obj b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-phong.obj new file mode 100644 index 000000000..bfb51b071 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-phong.obj @@ -0,0 +1,15 @@ +mtllib materials-phong.mtl + +# Same as two-triangles.obj, but with material references +o First +usemtl Red +v -1 -1 0 +v 1 -1 0 +v -1 1 0 +f 1 2 3 +o Second +usemtl DarkBlue +v -1 1 0 +v 1 -1 0 +v 1 1 0 +f 4 5 6 diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-separate-metalness-roughness.mtl b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-separate-metalness-roughness.mtl new file mode 100644 index 000000000..c4d20f06d --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/materials-separate-metalness-roughness.mtl @@ -0,0 +1,9 @@ +newmtl Material +Kd 0.0 1.0 0.0 + +newmtl Separate metalness and roughness +# Has to be present as otherwise UfbxImporter doesn't load the textures at all +# https://github.com/ufbx/ufbx/issues/55 +Pm 0.0 +map_Pr blue4x4.png +map_Pm red2x2.png diff --git a/src/Magnum/SceneTools/sceneconverter.cpp b/src/Magnum/SceneTools/sceneconverter.cpp index a0c31e88f..70e30466e 100644 --- a/src/Magnum/SceneTools/sceneconverter.cpp +++ b/src/Magnum/SceneTools/sceneconverter.cpp @@ -33,6 +33,7 @@ #include #include /* parseNumberSequence() */ +#include "Magnum/MaterialTools/PhongToPbrMetallicRoughness.h" #include "Magnum/MeshTools/Concatenate.h" #include "Magnum/MeshTools/Reference.h" #include "Magnum/MeshTools/RemoveDuplicates.h" @@ -180,7 +181,7 @@ magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN] [-C|--converter PLUGIN]... [-P|--image-converter PLUGIN]... [-M|--mesh-converter PLUGIN]... [--plugin-dir DIR] [--map] [--only-mesh-attributes N1,N2-N3…] [--remove-duplicate-vertices] - [--remove-duplicate-vertices-fuzzy EPSILON] + [--remove-duplicate-vertices-fuzzy EPSILON] [--phong-to-pbr] [-i|--importer-options key=val,key2=val2,…] [-c|--converter-options key=val,key2=val2,…]... [-p|--image-converter-options key=val,key2=val2,…]... @@ -217,6 +218,8 @@ Arguments: - `--remove-duplicate-vertices-fuzzy EPSILON` --- remove duplicate vertices using @ref MeshTools::removeDuplicatesFuzzy(const Trade::MeshData&, Float, Double) in all meshes after import +- `--phong-to-pbr` --- convert Phong materials to PBR metallic/roughness + using @ref MaterialTools::phongToPbrMetallicRoughness() - `-i`, `--importer-options key=val,key2=val2,…` --- configuration options to pass to the importer - `-c`, `--converter-options key=val,key2=val2,…` --- configuration options @@ -292,8 +295,8 @@ feature for given image dimensions, all mesh converters in the chain have to support the ConvertMesh feature. If no `-P` / `-M` is specified, the imported images / meshes are passed directly to the scene converter. -The `--remove-duplicate-vertices` operations are performed before passing them -to any converter. +The `--remove-duplicate-vertices` and `--phong-to-pbr` operations are performed +on meshes and materials before passing them to any converter. If `--concatenate-meshes` is given, all meshes of the input file are first concatenated into a single mesh using @ref MeshTools::concatenate(), with @@ -404,6 +407,7 @@ int main(int argc, char** argv) { .addOption("only-mesh-attributes").setHelp("only-mesh-attributes", "include only mesh attributes of given IDs in the output", "N1,N2-N3…") .addBooleanOption("remove-duplicate-vertices").setHelp("remove-duplicate-vertices", "remove duplicate vertices in all meshes after import") .addOption("remove-duplicate-vertices-fuzzy").setHelp("remove-duplicate-vertices-fuzzy", "remove duplicate vertices with fuzzy comparison in all meshes after import", "EPSILON") + .addBooleanOption("phong-to-pbr").setHelp("phong-to-pbr", "convert Phong materials to PBR metallic/roughness") .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('p', "image-converter-options").setHelp("image-converter-options", "configuration options to pass to the image converter(s)", "key=val,key2=val2,…") @@ -478,8 +482,8 @@ feature for given image dimensions, all mesh converters in the chain have to support the ConvertMesh feature. If no -P / -M is specified, the imported images / meshes are passed directly to the scene converter. -The --remove-duplicate-vertices operations are performed on meshes before -passing them to any converter. +The --remove-duplicate-vertices and --phong-to-pbr operations are performed on +meshes and materials 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 @@ -943,6 +947,39 @@ well, the IDs reference attributes of the first mesh.)") } } + /* Operations to perform on all materials in the importer. If there are + any, materials are supplied manually to the converter from the array + below. */ + Containers::Array materials; + if(args.isSet("phong-to-pbr")) { + arrayReserve(materials, importer->materialCount()); + + for(UnsignedInt i = 0; i != importer->materialCount(); ++i) { + Containers::Optional material; + { + Trade::Implementation::Duration d{importConversionTime}; + if(!(material = importer->material(i))) { + Error{} << "Cannot import material" << i; + return 1; + } + } + + /* Phong to PBR conversion */ + if(args.isSet("phong-to-pbr")) { + if(args.isSet("verbose")) + Debug{} << "Converting material" << i << "to PBR"; + + Trade::Implementation::Duration d{conversionTime}; + /** @todo make the flags configurable as well? then the below + assert can actually fire, convert to a runtime error */ + material = MaterialTools::phongToPbrMetallicRoughness(*material, MaterialTools::PhongToPbrMetallicRoughnessFlag::DropUnconvertableAttributes); + CORRADE_INTERNAL_ASSERT(material); + } + + arrayAppend(materials, *std::move(material)); + } + } + /* Assume there's always one passed --converter option less, and the last is implicitly AnySceneConverter. All converters except the last one are expected to support ConvertMesh and the mesh is "piped" from one to the @@ -1113,6 +1150,59 @@ well, the IDs reference attributes of the first mesh.)") meshes = {}; } + /* If there are any loose materials from previous conversion steps, add + them directly, and clear the array so the next iteration (if any) + takes them from the importer instead */ + if(materials) { + /* Materials reference textures (and those reference images), thus + we need to add those first */ + { + const Trade::SceneContents materialDependencies = contents & + (Trade::SceneContent::Images1D| + Trade::SceneContent::Images2D| + Trade::SceneContent::Images3D| + Trade::SceneContent::ImageLevels| + Trade::SceneContent::Textures| + Trade::SceneContent::Names); + + Trade::Implementation::Duration d{importConversionTime}; + if(!converter->addSupportedImporterContents(*importer, materialDependencies)) { + Error{} << "Cannot add material dependencies"; + return 5; + } + + /* Ensure these are not added by addSupportedImporterContents() + again below, except for names -- those should be added as + long as they were in the contents originally. */ + contents &= ~(materialDependencies & ~Trade::SceneContent::Names); + } + + if(!(Trade::sceneContentsFor(*converter) & Trade::SceneContent::Materials)) { + Warning{} << "Ignoring" << materials.size() << "materials not supported by the converter"; + } else for(UnsignedInt i = 0; i != materials.size(); ++i) { + Trade::Implementation::Duration d{conversionTime}; + + if(!converter->add(materials[i], contents & Trade::SceneContent::Names ? importer->materialName(i) : Containers::String{})) { + Error{} << "Cannot add material" << i; + return 1; + } + } + + /* Ensure the materials are not added by + addSupportedImporterContents() below. Do this also in case the + converter actually doesn't support mesh addition, as it would + otherwise cause two warnings about the same "not supported" + thing being printed. */ + contents &= ~Trade::SceneContent::Materials; + + /* Delete the list to avoid adding them again for the next + converter (at which point they would be stale) */ + /** @todo this line is untested, needs two chained conversion steps + that each change the output to verify the old materials don't + get reused in the next step again */ + materials = {}; + } + { Trade::Implementation::Duration d{importConversionTime}; if(!converter->addSupportedImporterContents(*importer, contents)) {