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]")
{