Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libraries/bxdf/gltf_pbr.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@
<input name="bsdf" type="BSDF" nodename="clearcoat_layer" />
<input name="edf" type="EDF" nodename="emission" />
<input name="opacity" type="float" nodename="opacity" />
<input name="occlusion" type="float" interfacename="occlusion" />
</surface>
<output name="out" type="surfaceshader" nodename="shader_constructor" />
</nodegraph>
Expand Down
1 change: 1 addition & 0 deletions libraries/pbrlib/pbrlib_defs.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
<input name="bsdf" type="BSDF" value="" doc="Distribution function for surface scattering." />
<input name="edf" type="EDF" value="" doc="Distribution function for surface emission." />
<input name="opacity" type="float" value="1.0" doc="Surface cutout opacity" />
<input name="occlusion" type="float" value="1.0" doc="Ambient occlusion factor applied to indirect lighting. A value of 1.0 means no occlusion." />
<input name="thin_walled" type="boolean" value="false" uniform="true" doc="Option to make the surface thin-walled." />
<output name="out" type="surfaceshader" />
</nodedef>
Expand Down
34 changes: 24 additions & 10 deletions source/MaterialXGenHw/Nodes/HwSurfaceNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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";
Expand All @@ -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);

Expand All @@ -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);

Expand All @@ -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
Expand All @@ -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);
}
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions source/MaterialXGenHw/Nodes/HwSurfaceNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 28 additions & 0 deletions source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]")
{
Expand Down
Loading