From 03c5f8074f0012e1be79a3be653569eb5d2d681e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Delgado=20Kr=C3=A4mer?= Date: Fri, 8 Mar 2024 23:02:05 +0100 Subject: [PATCH] Implement KHR_materials_unlit extension --- src/libguc/src/cgltf_util.cpp | 1 + src/libguc/src/materialx.cpp | 35 +++++++++++++++++- src/libguc/src/materialx.h | 3 ++ src/libguc/src/usdpreviewsurface.cpp | 55 +++++++++++++++++++++------- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/libguc/src/cgltf_util.cpp b/src/libguc/src/cgltf_util.cpp index 131f95c..12c63b8 100644 --- a/src/libguc/src/cgltf_util.cpp +++ b/src/libguc/src/cgltf_util.cpp @@ -42,6 +42,7 @@ namespace detail strcmp(name, "KHR_materials_sheen") == 0 || strcmp(name, "KHR_materials_specular") == 0 || strcmp(name, "KHR_materials_transmission") == 0 || + strcmp(name, "KHR_materials_unlit") == 0 || strcmp(name, "KHR_materials_variants") == 0 || strcmp(name, "KHR_materials_volume") == 0 || strcmp(name, "KHR_texture_transform") == 0; diff --git a/src/libguc/src/materialx.cpp b/src/libguc/src/materialx.cpp index f27d9a2..23c0a9e 100644 --- a/src/libguc/src/materialx.cpp +++ b/src/libguc/src/materialx.cpp @@ -428,7 +428,14 @@ namespace guc try { - createGltfPbrNodes(material, materialName); + if (material->unlit) + { + createUnlitSurfaceNodes(material, materialName); + } + else + { + createGltfPbrNodes(material, materialName); + } } catch (const mx::Exception& ex) { @@ -436,6 +443,32 @@ namespace guc } } + void MaterialXMaterialConverter::createUnlitSurfaceNodes(const cgltf_material* material, const std::string& materialName) + { + createMaterialNodes(material, materialName, "unlit_surface", [this](const cgltf_material* material, + mx::NodeGraphPtr nodeGraph, + mx::NodePtr shaderNode) { + mx::InputPtr emissionInput = shaderNode->addInput("emission", MTLX_TYPE_COLOR3); + + if (material->has_pbr_metallic_roughness) + { + const cgltf_pbr_metallic_roughness* pbrMetallicRoughness = &material->pbr_metallic_roughness; + + if (material->alpha_mode != cgltf_alpha_mode_opaque) + { + mx::InputPtr opacityInput = shaderNode->addInput("opacity", MTLX_TYPE_FLOAT); + setAlphaTextureInput(nodeGraph, opacityInput, &pbrMetallicRoughness->base_color_texture, pbrMetallicRoughness->base_color_factor[3]); + } + + setDiffuseTextureInput(nodeGraph, emissionInput, &pbrMetallicRoughness->base_color_texture, detail::makeMxColor3(pbrMetallicRoughness->base_color_factor)); + } + else + { + emissionInput->setValue(mx::Color3(1.0f)); + } + }); + } + void MaterialXMaterialConverter::createGltfPbrNodes(const cgltf_material* material, const std::string& materialName) { createMaterialNodes(material, materialName, "gltf_pbr", [this](const cgltf_material* material, diff --git a/src/libguc/src/materialx.h b/src/libguc/src/materialx.h index 351fc21..4be6476 100644 --- a/src/libguc/src/materialx.h +++ b/src/libguc/src/materialx.h @@ -48,6 +48,9 @@ namespace guc bool m_hdstormCompat; private: + void createUnlitSurfaceNodes(const cgltf_material* material, + const std::string& materialName); + void createGltfPbrNodes(const cgltf_material* material, const std::string& materialName); diff --git a/src/libguc/src/usdpreviewsurface.cpp b/src/libguc/src/usdpreviewsurface.cpp index ff411f1..d44f203 100644 --- a/src/libguc/src/usdpreviewsurface.cpp +++ b/src/libguc/src/usdpreviewsurface.cpp @@ -151,8 +151,47 @@ namespace guc auto shaderOutput = shader.CreateOutput(UsdShadeTokens->surface, SdfValueTypeNames->Token); surfaceOutput.ConnectToSource(shaderOutput); + auto setAlphaTextureInput = [&](const cgltf_pbr_metallic_roughness* pbrMetallicRoughness) + { + if (material->alpha_mode != cgltf_alpha_mode_opaque) + { + // Do nothing. + return; + } + + GfVec4f opacityFallback(1.0f); // image fallback value is 0.0, but opacity default should be 1.0 + + auto opacityInput = shader.CreateInput(_tokens->opacity, SdfValueTypeNames->Float); + setFloatTextureInput(path, opacityInput, pbrMetallicRoughness->base_color_texture, _tokens->a, GfVec4f(pbrMetallicRoughness->base_color_factor[3]), &opacityFallback); + + if (material->alpha_mode == cgltf_alpha_mode_mask) + { + auto opacityThresholdInput = shader.CreateInput(_tokens->opacityThreshold, SdfValueTypeNames->Float); + opacityThresholdInput.Set(material->alpha_cutoff); + } + }; + auto emissiveColorInput = shader.CreateInput(_tokens->emissiveColor, SdfValueTypeNames->Float3); auto emissiveFactor = GfVec4f(material->emissive_factor); + + if (material->unlit) // Not really 'unlit', but there's no better way + { + if (material->has_pbr_metallic_roughness) + { + const cgltf_pbr_metallic_roughness* pbrMetallicRoughness = &material->pbr_metallic_roughness; + + GfVec4f unlitColorFallback(1.0f); // not specified + + setSrgbTextureInput(path, emissiveColorInput, pbrMetallicRoughness->base_color_texture, GfVec4f(pbrMetallicRoughness->base_color_factor), &unlitColorFallback); + setAlphaTextureInput(pbrMetallicRoughness); + } + else + { + emissiveColorInput.Set(GfVec3f(1.0f)); + } + return; + } + if (material->has_emissive_strength) { const cgltf_emissive_strength* emissiveStrength = &material->emissive_strength; @@ -169,7 +208,6 @@ namespace guc // We need to set these values regardless of whether pbrMetallicRoughness is present or not, because UsdPreviewSurface's // default values differ (and we want to come as close as possible to the MaterialX look, although the shading model differs). auto diffuseColorInput = shader.CreateInput(_tokens->diffuseColor, SdfValueTypeNames->Float3); - auto opacityInput = shader.CreateInput(_tokens->opacity, SdfValueTypeNames->Float); auto metallicInput = shader.CreateInput(_tokens->metallic, SdfValueTypeNames->Float); auto roughnessInput = shader.CreateInput(_tokens->roughness, SdfValueTypeNames->Float); @@ -182,23 +220,11 @@ namespace guc GfVec4f metallicRoughnessFallback(1.0f); // same as glTF spec sec. 5.22.5: "When undefined, the texture MUST be sampled as having 1.0 in G and B components." setFloatTextureInput(path, metallicInput, pbrMetallicRoughness->metallic_roughness_texture, _tokens->b, GfVec4f(pbrMetallicRoughness->metallic_factor), &metallicRoughnessFallback); setFloatTextureInput(path, roughnessInput, pbrMetallicRoughness->metallic_roughness_texture, _tokens->g, GfVec4f(pbrMetallicRoughness->roughness_factor), &metallicRoughnessFallback); - - if (material->alpha_mode != cgltf_alpha_mode_opaque) - { - GfVec4f opacityFallback(1.0f); // image fallback value is 0.0, but opacity default should be 1.0 - setFloatTextureInput(path, opacityInput, pbrMetallicRoughness->base_color_texture, _tokens->a, GfVec4f(pbrMetallicRoughness->base_color_factor[3]), &opacityFallback); - - if (material->alpha_mode == cgltf_alpha_mode_mask) - { - auto opacityThresholdInput = shader.CreateInput(_tokens->opacityThreshold, SdfValueTypeNames->Float); - opacityThresholdInput.Set(material->alpha_cutoff); - } - } + setAlphaTextureInput(pbrMetallicRoughness); } else { diffuseColorInput.Set(GfVec3f(1.0f)); // 0.18 in UsdPreviewSurface spec - opacityInput.Set(1.0f); metallicInput.Set(1.0f); // 0.0 in UsdPreviewSurface spec roughnessInput.Set(1.0f); // 0.5 in UsdPreviewSurface spec } @@ -253,6 +279,7 @@ namespace guc float saturation = (baseColorMaxValue <= std::numeric_limits::min()) ? 0.0f : (baseColorRange / baseColorMaxValue); float opacity = 0.25f + 0.75f * saturation * (1.0f - transmission->transmission_factor); + auto opacityInput = shader.CreateInput(_tokens->opacity, SdfValueTypeNames->Float); // not set because of OPAQUE mode check opacityInput.Set(opacity); } }