diff --git a/libraries/bxdf/gltf_pbr.mtlx b/libraries/bxdf/gltf_pbr.mtlx index edc7d40ec1..05d8e3d1ff 100644 --- a/libraries/bxdf/gltf_pbr.mtlx +++ b/libraries/bxdf/gltf_pbr.mtlx @@ -360,6 +360,7 @@ + diff --git a/libraries/pbrlib/pbrlib_defs.mtlx b/libraries/pbrlib/pbrlib_defs.mtlx index 0f8f5c57ac..33b3cb6b86 100644 --- a/libraries/pbrlib/pbrlib_defs.mtlx +++ b/libraries/pbrlib/pbrlib_defs.mtlx @@ -244,6 +244,7 @@ + diff --git a/source/MaterialXGenHw/Nodes/HwSurfaceNode.cpp b/source/MaterialXGenHw/Nodes/HwSurfaceNode.cpp index 860e382144..96dcef199e 100644 --- a/source/MaterialXGenHw/Nodes/HwSurfaceNode.cpp +++ b/source/MaterialXGenHw/Nodes/HwSurfaceNode.cpp @@ -18,6 +18,7 @@ namespace const string INPUT_BSDF = "bsdf"; const string INPUT_EDF = "edf"; const string INPUT_OPACITY = "opacity"; +const string INPUT_OCCLUSION = "occlusion"; } // anonymous namespace @@ -45,6 +46,11 @@ const string& HwSurfaceNode::getOpacityInputName() const return INPUT_OPACITY; } +const string& HwSurfaceNode::getOcclusionInputName() const +{ + return INPUT_OCCLUSION; +} + void HwSurfaceNode::createVariables(const ShaderNode&, GenContext& context, Shader& shader) const { // TODO: @@ -123,7 +129,7 @@ void HwSurfaceNode::emitFunctionCall(const ShaderNode& node, GenContext& context shadergen.emitLine(vec3+" V = normalize(" + HW::T_VIEW_POSITION + " - " + prefix + HW::T_POSITION_WORLD + ")", stage); shadergen.emitLine(vec3+" P = " + prefix + HW::T_POSITION_WORLD, stage); shadergen.emitLine(vec3+" L = "+vec3_zero, stage); - shadergen.emitLine("float occlusion = 1.0", stage); + shadergen.emitLine("float closureOcclusion = 1.0", stage); shadergen.emitLineBreak(stage); const string outColor = output->getVariable() + ".color"; @@ -146,7 +152,7 @@ void HwSurfaceNode::emitFunctionCall(const ShaderNode& node, GenContext& context shadergen.emitComment("Shadow occlusion", stage); if (context.getOptions().hwShadowMap) { - shadergen.emitLine("occlusion = mx_shadow_occlusion(" + HW::T_SHADOW_MAP + ", " + HW::T_SHADOW_MATRIX + ", " + prefix + HW::T_POSITION_WORLD + ")", stage); + shadergen.emitLine("closureOcclusion = mx_shadow_occlusion(" + HW::T_SHADOW_MAP + ", " + HW::T_SHADOW_MATRIX + ", " + prefix + HW::T_POSITION_WORLD + ")", stage); } shadergen.emitLineBreak(stage); @@ -164,11 +170,19 @@ void HwSurfaceNode::emitFunctionCall(const ShaderNode& node, GenContext& context { shadergen.emitLine("ambOccUv = "+vec2+"(ambOccUv.x, 1.0 - ambOccUv.y)", stage); } - shadergen.emitLine("occlusion = mix(1.0, texture(" + HW::T_AMB_OCC_MAP + ", ambOccUv).x, " + HW::T_AMB_OCC_GAIN + ")", stage); + shadergen.emitLine("closureOcclusion = mix(1.0, texture(" + HW::T_AMB_OCC_MAP + ", ambOccUv).x, " + HW::T_AMB_OCC_GAIN + ")", stage); } else { - shadergen.emitLine("occlusion = 1.0", stage); + shadergen.emitLine("closureOcclusion = 1.0", stage); + } + const ShaderInput* occlusionInput = node.getInput(getOcclusionInputName()); + if (occlusionInput) + { + shadergen.emitLineBegin(stage); + shadergen.emitString("closureOcclusion *= ", stage); + shadergen.emitInput(occlusionInput, context, stage); + shadergen.emitLineEnd(stage); } shadergen.emitLineBreak(stage); @@ -178,7 +192,7 @@ void HwSurfaceNode::emitFunctionCall(const ShaderNode& node, GenContext& context // indirect lighting if (bsdf->hasClassification(ShaderNode::Classification::BSDF_R)) { - shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_INDIRECT, L, V, N, P, occlusion)", stage); + shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_INDIRECT, L, V, N, P, closureOcclusion)", stage); shadergen.emitFunctionCall(*bsdf, context, stage); } else @@ -189,7 +203,7 @@ void HwSurfaceNode::emitFunctionCall(const ShaderNode& node, GenContext& context } shadergen.emitLineBreak(stage); - shadergen.emitLine(outColor + " += occlusion * " + bsdf->getOutput()->getVariable() + ".response", stage); + shadergen.emitLine(outColor + " += closureOcclusion * " + bsdf->getOutput()->getVariable() + ".response", stage); shadergen.emitScopeEnd(stage); shadergen.emitLineBreak(stage); } @@ -208,7 +222,7 @@ void HwSurfaceNode::emitFunctionCall(const ShaderNode& node, GenContext& context if (edf->hasClassification(ShaderNode::Classification::EDF)) { - shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_EMISSION, L, V, N, P, occlusion)", stage); + shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_EMISSION, L, V, N, P, closureOcclusion)", stage); shadergen.emitFunctionCall(*edf, context, stage); } else @@ -234,7 +248,7 @@ void HwSurfaceNode::emitFunctionCall(const ShaderNode& node, GenContext& context shadergen.emitComment("Calculate the BSDF transmission for viewing direction", stage); if (bsdf->hasClassification(ShaderNode::Classification::BSDF_T) || bsdf->hasClassification(ShaderNode::Classification::VDF)) { - shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_TRANSMISSION, L, V, N, P, occlusion)", stage); + shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_TRANSMISSION, L, V, N, P, closureOcclusion)", stage); shadergen.emitFunctionCall(*bsdf, context, stage); } else @@ -299,7 +313,7 @@ void HwSurfaceNode::emitLightLoop(const ShaderNode& node, GenContext& context, S shadergen.emitComment("Calculate the BSDF response for this light source", stage); if (bsdf->hasClassification(ShaderNode::Classification::BSDF_R)) { - shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_REFLECTION, L, V, N, P, occlusion)", stage); + shadergen.emitLine("ClosureData closureData = makeClosureData(CLOSURE_TYPE_REFLECTION, L, V, N, P, closureOcclusion)", stage); shadergen.emitFunctionCall(*bsdf, context, stage); } else @@ -317,7 +331,7 @@ void HwSurfaceNode::emitLightLoop(const ShaderNode& node, GenContext& context, S shadergen.emitLineBreak(stage); shadergen.emitComment("Clear shadow factor for next light", stage); - shadergen.emitLine("occlusion = 1.0", stage); + shadergen.emitLine("closureOcclusion = 1.0", stage); shadergen.emitScopeEnd(stage); shadergen.emitLineBreak(stage); diff --git a/source/MaterialXGenHw/Nodes/HwSurfaceNode.h b/source/MaterialXGenHw/Nodes/HwSurfaceNode.h index 3e3f5f4f4c..eb0478b012 100644 --- a/source/MaterialXGenHw/Nodes/HwSurfaceNode.h +++ b/source/MaterialXGenHw/Nodes/HwSurfaceNode.h @@ -33,6 +33,9 @@ class MX_GENHW_API HwSurfaceNode : public HwImplementation /// Return the name of the opacity input on the node. virtual const string& getOpacityInputName() const; + + /// Return the name of the occlusion input on the node. + virtual const string& getOcclusionInputName() const; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp index e99d83a452..a6267dc1d0 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp @@ -125,6 +125,34 @@ TEST_CASE("GenShader: GLSL Light Shaders", "[genglsl]") REQUIRE_NOTHROW(mx::HwShaderGenerator::bindLightShader(*spotLightShader, 66, context)); } +TEST_CASE("GenShader: GLSL glTF PBR Occlusion", "[genglsl]") +{ + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); + mx::DocumentPtr doc = mx::createDocument(); + loadLibraries({ "libraries" }, searchPath, doc); + readFromXmlFile(doc, searchPath.find("resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx")); + + mx::NodeDefPtr surfaceDef = doc->getNodeDef("ND_surface"); + REQUIRE(surfaceDef != nullptr); + REQUIRE(surfaceDef->getInput("occlusion") != nullptr); + + mx::TypedElementPtr gltfPbr = doc->getNode("SR_default"); + REQUIRE(gltfPbr != nullptr); + + mx::GenContext context(mx::GlslShaderGenerator::create()); + context.registerSourceCodeSearchPath(searchPath); + context.getShaderGenerator().registerTypeDefs(doc); + + mx::ShaderPtr shader = context.getShaderGenerator().generate("gltfPbrOcclusion", gltfPbr, context); + REQUIRE(shader != nullptr); + + const std::string& pixelSourceCode = shader->getSourceCode(mx::Stage::PIXEL); + REQUIRE(pixelSourceCode.find("float closureOcclusion = 1.0") != std::string::npos); + REQUIRE(pixelSourceCode.find("closureOcclusion *=") != std::string::npos); + REQUIRE(pixelSourceCode.find("makeClosureData(CLOSURE_TYPE_INDIRECT, L, V, N, P, closureOcclusion)") != std::string::npos); + REQUIRE(pixelSourceCode.find("float occlusion = 1.0") == std::string::npos); +} + #ifdef MATERIALX_BUILD_BENCHMARK_TESTS TEST_CASE("GenShader: GLSL Performance Test", "[genglsl]") {