From ca7d74a7ec6fca9fcdc9b57eca8763114e9a0989 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 18 Mar 2026 13:15:59 -0700 Subject: [PATCH 1/2] Propose an initial graph refactoring framework for shader generation This changelist proposes an initial graph refactoring framework for MaterialX shader generation, replacing hardcoded graph optimizations with a composable set of named refactoring passes. The following specific changes are included: - Add a `ShaderGraphRefactor` base class, with three concrete subclasses for node elision, premultiplied BSDF add (valuable in hardware languages), and layer-over-mix distribution (valuable in MDL). - Add a virtual `setDefaultOptions` method to `ShaderGenerator`, enabling each subclass to set target-appropriate defaults at `GenContext` construction time. - Add a `MIX` classification bit to ShaderNode for efficient mix node identification. - Remove hand-authored GLSL and MDL graph overrides for `open_pbr_surface` and `standard_surface`, as these refactoring steps are now generated automatically. --- libraries/bxdf/genglsl/open_pbr_surface.mtlx | 597 ------------------ libraries/bxdf/genglsl/standard_surface.mtlx | 343 ---------- libraries/bxdf/genmdl/open_pbr_surface.mtlx | 594 ----------------- .../JsMaterialXGenShader/JsGenOptions.cpp | 3 + source/MaterialXGenHw/HwShaderGenerator.cpp | 6 + source/MaterialXGenHw/HwShaderGenerator.h | 3 + source/MaterialXGenMdl/MdlShaderGenerator.cpp | 6 + source/MaterialXGenMdl/MdlShaderGenerator.h | 3 + source/MaterialXGenShader/GenContext.cpp | 3 + source/MaterialXGenShader/GenOptions.h | 13 + source/MaterialXGenShader/ShaderGenerator.cpp | 10 + source/MaterialXGenShader/ShaderGenerator.h | 17 + source/MaterialXGenShader/ShaderGraph.cpp | 125 ++-- source/MaterialXGenShader/ShaderGraph.h | 32 +- .../ShaderGraphRefactor.cpp | 403 ++++++++++++ .../MaterialXGenShader/ShaderGraphRefactor.h | 80 +++ source/MaterialXGenShader/ShaderNode.cpp | 14 + source/MaterialXGenShader/ShaderNode.h | 17 +- source/MaterialXView/Viewer.cpp | 24 + .../PyMaterialXGenShader/PyGenOptions.cpp | 3 + 20 files changed, 663 insertions(+), 1633 deletions(-) delete mode 100644 libraries/bxdf/genglsl/open_pbr_surface.mtlx delete mode 100644 libraries/bxdf/genglsl/standard_surface.mtlx delete mode 100644 libraries/bxdf/genmdl/open_pbr_surface.mtlx create mode 100644 source/MaterialXGenShader/ShaderGraphRefactor.cpp create mode 100644 source/MaterialXGenShader/ShaderGraphRefactor.h diff --git a/libraries/bxdf/genglsl/open_pbr_surface.mtlx b/libraries/bxdf/genglsl/open_pbr_surface.mtlx deleted file mode 100644 index 3a6e3eb627..0000000000 --- a/libraries/bxdf/genglsl/open_pbr_surface.mtlx +++ /dev/null @@ -1,597 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/bxdf/genglsl/standard_surface.mtlx b/libraries/bxdf/genglsl/standard_surface.mtlx deleted file mode 100644 index bedae8e366..0000000000 --- a/libraries/bxdf/genglsl/standard_surface.mtlx +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/bxdf/genmdl/open_pbr_surface.mtlx b/libraries/bxdf/genmdl/open_pbr_surface.mtlx deleted file mode 100644 index c6950c5251..0000000000 --- a/libraries/bxdf/genmdl/open_pbr_surface.mtlx +++ /dev/null @@ -1,594 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/JsMaterialX/JsMaterialXGenShader/JsGenOptions.cpp b/source/JsMaterialX/JsMaterialXGenShader/JsGenOptions.cpp index d12cba9d9f..972035d7ca 100644 --- a/source/JsMaterialX/JsMaterialXGenShader/JsGenOptions.cpp +++ b/source/JsMaterialX/JsMaterialXGenShader/JsGenOptions.cpp @@ -36,6 +36,9 @@ EMSCRIPTEN_BINDINGS(GenOptions) .property("targetDistanceUnit", &mx::GenOptions::targetDistanceUnit) .property("addUpstreamDependencies", &mx::GenOptions::addUpstreamDependencies) .property("emitColorTransforms", &mx::GenOptions::emitColorTransforms) + .property("elideConstantNodes", &mx::GenOptions::elideConstantNodes) + .property("premultipliedBsdfAdd", &mx::GenOptions::premultipliedBsdfAdd) + .property("distributeLayerOverBsdfMix", &mx::GenOptions::distributeLayerOverBsdfMix) .property("hwTransparency", &mx::GenOptions::hwTransparency) .property("hwSpecularEnvironmentMethod", &mx::GenOptions::hwSpecularEnvironmentMethod) .property("hwDirectionalAlbedoMethod", &mx::GenOptions::hwDirectionalAlbedoMethod) diff --git a/source/MaterialXGenHw/HwShaderGenerator.cpp b/source/MaterialXGenHw/HwShaderGenerator.cpp index 68872ce5d2..ed8cbed2cd 100644 --- a/source/MaterialXGenHw/HwShaderGenerator.cpp +++ b/source/MaterialXGenHw/HwShaderGenerator.cpp @@ -88,6 +88,12 @@ HwShaderGenerator::HwShaderGenerator(TypeSystemPtr typeSystem, SyntaxPtr syntax) _tokenSubstitutions[HW::T_CLOSURE_DATA_CONSTRUCTOR] = HW::CLOSURE_DATA_CONSTRUCTOR; } +void HwShaderGenerator::setDefaultOptions(GenOptions& options) const +{ + ShaderGenerator::setDefaultOptions(options); + options.premultipliedBsdfAdd = true; +} + ShaderPtr HwShaderGenerator::createShader(const string& name, ElementPtr element, GenContext& context) const { // Create the root shader graph diff --git a/source/MaterialXGenHw/HwShaderGenerator.h b/source/MaterialXGenHw/HwShaderGenerator.h index d42f7dbb1f..429a8aea4c 100644 --- a/source/MaterialXGenHw/HwShaderGenerator.h +++ b/source/MaterialXGenHw/HwShaderGenerator.h @@ -43,6 +43,9 @@ class MX_GENHW_API HwShaderGenerator : public ShaderGenerator void emitClosureDataArg(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; void emitClosureDataParameter(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; + /// Set the default GenOptions for hardware shader generation. + void setDefaultOptions(GenOptions& options) const override; + /// Logic to indicate whether code to support direct lighting should be emitted. /// By default if the graph is classified as a shader, or BSDF node then lighting is assumed to be required. /// Derived classes can override this logic. diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 5e89ac38c1..47768ff82b 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -125,6 +125,12 @@ MdlShaderGenerator::MdlShaderGenerator(TypeSystemPtr typeSystem) : registerImplementation("IM_image_vector4_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); } +void MdlShaderGenerator::setDefaultOptions(GenOptions& options) const +{ + ShaderGenerator::setDefaultOptions(options); + options.distributeLayerOverBsdfMix = true; +} + ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, GenContext& context) const { // For MDL we cannot cache node implementations between generation calls, diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.h b/source/MaterialXGenMdl/MdlShaderGenerator.h index 04415798c3..380f7a4f45 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.h +++ b/source/MaterialXGenMdl/MdlShaderGenerator.h @@ -70,6 +70,9 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator /// Return a unique identifier for the target this generator is for const string& getTarget() const override { return TARGET; } + /// Set the default GenOptions for MDL shader generation. + void setDefaultOptions(GenOptions& options) const override; + /// Generate a shader starting from the given element, translating /// the element and all dependencies upstream into shader code. ShaderPtr generate(const string& name, ElementPtr element, GenContext& context) const override; diff --git a/source/MaterialXGenShader/GenContext.cpp b/source/MaterialXGenShader/GenContext.cpp index 3fea10c930..85c0eec1e6 100644 --- a/source/MaterialXGenShader/GenContext.cpp +++ b/source/MaterialXGenShader/GenContext.cpp @@ -20,6 +20,9 @@ GenContext::GenContext(ShaderGeneratorPtr sg) : throw ExceptionShaderGenError("GenContext must have a valid shader generator"); } + // Apply the generator's default options for its target. + _sg->setDefaultOptions(_options); + // Collect and cache reserved words from the shader generator StringSet reservedWords; diff --git a/source/MaterialXGenShader/GenOptions.h b/source/MaterialXGenShader/GenOptions.h index 034ab782c3..93f5f7677d 100644 --- a/source/MaterialXGenShader/GenOptions.h +++ b/source/MaterialXGenShader/GenOptions.h @@ -82,6 +82,8 @@ class MX_GENSHADER_API GenOptions libraryPrefix("libraries"), emitColorTransforms(true), elideConstantNodes(true), + premultipliedBsdfAdd(false), + distributeLayerOverBsdfMix(false), hwTransparency(false), hwSpecularEnvironmentMethod(SPECULAR_ENVIRONMENT_FIS), hwDirectionalAlbedoMethod(DIRECTIONAL_ALBEDO_ANALYTIC), @@ -141,6 +143,17 @@ class MX_GENSHADER_API GenOptions /// Enable eliding constant nodes. Defaults to true. bool elideConstantNodes; + /// Enable replacing BSDF mix nodes with premultiplied add nodes. + /// This folds the mix weight into each BSDF's weight input, enabling + /// hardware shading languages to skip BSDF evaluation via dynamic + /// branching when the weight is zero. Defaults to false. + bool premultipliedBsdfAdd; + + /// Enable distributing layer operations over mix nodes. + /// Transforms layer(mix(A, B, w), C) into mix(layer(A, C), layer(B, C), w) + /// for backends with limited layering capabilities. Defaults to false. + bool distributeLayerOverBsdfMix; + /// Sets if transparency is needed or not for HW shaders. /// If a surface shader has potential of being transparent /// this must be set to true, otherwise no transparency diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index 9dc2d5f212..4fa048050a 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -32,6 +32,16 @@ ShaderGenerator::ShaderGenerator(TypeSystemPtr typeSystem, SyntaxPtr syntax) : _typeSystem(typeSystem), _syntax(syntax) { + // Register all graph refactoring passes. + registerRefactor(std::make_shared()); + registerRefactor(std::make_shared()); + registerRefactor(std::make_shared()); +} + +void ShaderGenerator::setDefaultOptions(GenOptions& /*options*/) const +{ + // Base implementation sets no additional defaults. + // Derived generators override to set target-specific defaults. } void ShaderGenerator::emitScopeBegin(ShaderStage& stage, Syntax::Punctuation punc) const diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index ce6c3cf996..2d1ad45da1 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -214,6 +215,21 @@ class MX_GENSHADER_API ShaderGenerator return _tokenSubstitutions; } + /// Register a shader graph refactoring pass. + void registerRefactor(ShaderGraphRefactorPtr refactor) + { + _refactors.push_back(refactor); + } + + /// Return the registered graph refactoring passes. + const vector& getRefactors() const + { + return _refactors; + } + + /// Set the default GenOptions for this generator's target. + virtual void setDefaultOptions(GenOptions& options) const; + /// Register type definitions from the document. virtual void registerTypeDefs(const DocumentPtr& doc); @@ -261,6 +277,7 @@ class MX_GENSHADER_API ShaderGenerator ColorManagementSystemPtr _colorManagementSystem; UnitSystemPtr _unitSystem; mutable StringMap _tokenSubstitutions; + vector _refactors; friend ShaderGraph; }; diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index c1dee169eb..10c41b757f 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -910,8 +911,18 @@ void ShaderGraph::finalize(GenContext& context) _inputUnitTransformMap.clear(); _outputUnitTransformMap.clear(); - // Optimize the graph, removing redundant paths. - optimize(context); + // Run registered graph refactoring passes. + size_t totalEdits = 0; + for (auto& refactor : context.getShaderGenerator().getRefactors()) + { + totalEdits += refactor->execute(*this, context); + } + + // Remove unused nodes if any refactoring pass made edits. + if (totalEdits > 0) + { + removeUnusedNodes(); + } // Sort the nodes in topological order. topologicalSort(); @@ -971,97 +982,57 @@ void ShaderGraph::disconnect(ShaderNode* node) const } } -void ShaderGraph::optimize(GenContext& context) +void ShaderGraph::removeUnusedNodes() { - size_t numEdits = 0; - for (ShaderNode* node : getNodes()) + std::set usedNodesSet; + std::vector usedNodesVec; + + // Traverse the graph to find nodes still in use. + for (ShaderGraphOutputSocket* outputSocket : getOutputSockets()) { - if (node->hasClassification(ShaderNode::Classification::CONSTANT)) + // Make sure to not include connections to the graph itself. + ShaderOutput* upstreamPort = outputSocket->getConnection(); + if (upstreamPort && upstreamPort->getNode() != this) { - if (node->numInputs() != 1 || node->numOutputs() != 1) - { - // Constant node doesn't follow expected interface, cannot elide. - continue; - } - // Constant nodes can be elided by moving their value downstream. - bool canElide = context.getOptions().elideConstantNodes; - if (!canElide) + for (ShaderGraphEdge edge : traverseUpstream(upstreamPort)) { - // We always elide filename constant nodes regardless of the - // option. See DOT below. - ShaderInput* in = node->getInput("value"); - if (in && in->getType() == Type::FILENAME) + ShaderNode* node = edge.upstream->getNode(); + if (usedNodesSet.count(node) == 0) { - canElide = true; + usedNodesSet.insert(node); + usedNodesVec.push_back(node); } } - if (canElide) - { - bypass(node, 0); - ++numEdits; - } - } - else if (node->hasClassification(ShaderNode::Classification::DOT)) - { - if (node->numOutputs() != 1) - { - // Dot node dosen't follow expected interface, cannot elide. - continue; - } - // Filename dot nodes must be elided so they do not create extra samplers. - ShaderInput* in = node->getInput("in"); - if (in && in->getType() == Type::FILENAME) - { - bypass(node, 0); - ++numEdits; - } } - // Adding more nodes here requires them to have an input that is tagged - // "uniform" in the NodeDef or to handle very specific cases, like FILENAME. } - if (numEdits > 0) + // Remove any unused nodes. + for (auto it = _nodeMap.begin(); it != _nodeMap.end();) { - std::set usedNodesSet; - std::vector usedNodesVec; - - // Traverse the graph to find nodes still in use - for (ShaderGraphOutputSocket* outputSocket : getOutputSockets()) + if (usedNodesSet.count(it->second.get()) == 0) { - // Make sure to not include connections to the graph itself. - ShaderOutput* upstreamPort = outputSocket->getConnection(); - if (upstreamPort && upstreamPort->getNode() != this) - { - for (ShaderGraphEdge edge : traverseUpstream(upstreamPort)) - { - ShaderNode* node = edge.upstream->getNode(); - if (usedNodesSet.count(node) == 0) - { - usedNodesSet.insert(node); - usedNodesVec.push_back(node); - } - } - } - } + // Break all connections. + disconnect(it->second.get()); - // Remove any unused nodes - for (auto it = _nodeMap.begin(); it != _nodeMap.end();) + // Erase from storage. + it = _nodeMap.erase(it); + } + else { - if (usedNodesSet.count(it->second.get()) == 0) - { - // Break all connections - disconnect(it->second.get()); - - // Erase from storage - it = _nodeMap.erase(it); - } - else - { - ++it; - } + ++it; } + } + + _nodeOrder = usedNodesVec; +} - _nodeOrder = usedNodesVec; +void ShaderGraph::replaceOutput(ShaderOutput* oldOutput, ShaderOutput* newOutput) +{ + ShaderInputVec downstreamConnections = oldOutput->getConnections(); + for (ShaderInput* downstream : downstreamConnections) + { + oldOutput->breakConnection(downstream); + downstream->makeConnection(newOutput); } } diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index f02f4fc7ae..9d95478d53 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -26,6 +26,7 @@ class Syntax; class ShaderGraphEdge; class ShaderGraphEdgeIterator; class GenOptions; +class ShaderGraphRefactor; /// An internal input socket in a shader graph, /// used for connecting internal nodes to the outside @@ -126,6 +127,23 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode /// Return the map of unique identifiers used in the scope of this graph. IdentifierMap& getIdentifierMap() { return _identifiers; } + /// Return the document associated with this graph. + ConstDocumentPtr getDocument() const { return _document; } + + /// Create a new node in the graph from a node definition. + ShaderNode* createNode(const string& name, const string& uniqueId, ConstNodeDefPtr nodeDef, GenContext& context); + + /// Bypass a node for a particular input and output, + /// effectively connecting the input's upstream connection + /// with the output's downstream connections. + void bypass(ShaderNode* node, size_t inputIndex, size_t outputIndex = 0); + + /// Remove nodes that are no longer connected to any output. + void removeUnusedNodes(); + + /// Rewire all downstream connections from one output to another. + void replaceOutput(ShaderOutput* oldOutput, ShaderOutput* newOutput); + protected: /// Create node connections corresponding to the connection between a pair of elements. /// @param downstreamElement Element representing the node to connect to. @@ -137,12 +155,6 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode ElementPtr connectingElement, GenContext& context); - /// Create a new node in a graph from a node definition. - /// The uniqueId argument is used as the node's key in the graph's node map. - /// Note - this does not initialize the node instance with any concrete values, but - /// instead creates an empty instance of the provided node definition - ShaderNode* createNode(const string& name, const string& uniqueId, ConstNodeDefPtr nodeDef, GenContext& context); - /// Add a node to the graph, keyed by the node's unique identifier. void addNode(ShaderNodePtr node); @@ -172,14 +184,6 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode /// Perform all post-build operations on the graph. void finalize(GenContext& context); - /// Optimize the graph, removing redundant paths. - void optimize(GenContext& context); - - /// Bypass a node for a particular input and output, - /// effectively connecting the input's upstream connection - /// with the output's downstream connections. - void bypass(ShaderNode* node, size_t inputIndex, size_t outputIndex = 0); - /// For inputs and outputs in the graph set the variable names to be used /// in generated code. Making sure variable names are valid and unique /// to avoid name conflicts during shader generation. diff --git a/source/MaterialXGenShader/ShaderGraphRefactor.cpp b/source/MaterialXGenShader/ShaderGraphRefactor.cpp new file mode 100644 index 0000000000..64e29500d1 --- /dev/null +++ b/source/MaterialXGenShader/ShaderGraphRefactor.cpp @@ -0,0 +1,403 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include + +#include + +MATERIALX_NAMESPACE_BEGIN + +namespace +{ + +bool isBsdfMixNode(ShaderNode* node) +{ + return node->hasClassification(ShaderNode::Classification::BSDF | + ShaderNode::Classification::CLOSURE | + ShaderNode::Classification::MIX); +} + +bool isLayerWithMixTop(ShaderNode* node) +{ + if (!node->hasClassification(ShaderNode::Classification::LAYER)) + { + return false; + } + ShaderInput* top = node->getInput("top"); + if (!top || !top->getConnection()) + { + return false; + } + return isBsdfMixNode(top->getConnection()->getNode()); +} + +// Fold a mix weight into one side of a BSDF mix node, inserting a multiply +// node to combine the existing weight (connected or constant) with the mix +// weight. Return the upstream output to connect to the replacement add node. +ShaderOutput* foldWeightIntoBsdf(ShaderGraph& graph, GenContext& context, + ShaderInput* bsdfInput, ShaderOutput* weightSource, + const string& namePrefix, + NodeDefPtr mulFloatDef, NodeDefPtr mulBsdfDef) +{ + ShaderOutput* bsdfUpstream = bsdfInput->getConnection(); + if (!bsdfUpstream) + { + return nullptr; + } + + ShaderNode* bsdfNode = bsdfUpstream->getNode(); + ShaderInput* weightInput = bsdfNode->getInput("weight"); + if (weightInput) + { + // Create a multiply node to combine existing weight with mix weight. + string mulName = namePrefix + "_weight"; + ShaderNode* mulNode = graph.createNode(mulName, mulName, mulFloatDef, context); + ShaderInput* mulIn1 = mulNode->getInput("in1"); + ShaderInput* mulIn2 = mulNode->getInput("in2"); + if (mulIn1 && mulIn2) + { + ShaderOutput* existingSource = weightInput->getConnection(); + if (existingSource) + { + weightInput->breakConnection(); + mulIn1->makeConnection(existingSource); + } + else if (weightInput->getValue()) + { + mulIn1->setValue(weightInput->getValue()); + } + else + { + mulIn1->setValue(Value::createValue(1.0f)); + } + mulIn2->makeConnection(weightSource); + weightInput->makeConnection(mulNode->getOutput()); + } + return bsdfUpstream; + } + else + { + // Wrap the BSDF with a BSDF*float multiply when no weight input exists. + string mulName = namePrefix + "_mul"; + ShaderNode* mulNode = graph.createNode(mulName, mulName, mulBsdfDef, context); + ShaderInput* mulIn1 = mulNode->getInput("in1"); + ShaderInput* mulIn2 = mulNode->getInput("in2"); + if (mulIn1 && mulIn2) + { + mulIn1->makeConnection(bsdfUpstream); + mulIn2->makeConnection(weightSource); + return mulNode->getOutput(); + } + return bsdfUpstream; + } +} + +} // anonymous namespace + +// +// NodeElisionRefactor +// + +const string& NodeElisionRefactor::getName() const +{ + static const string name = "nodeElision"; + return name; +} + +size_t NodeElisionRefactor::execute(ShaderGraph& graph, GenContext& context) +{ + size_t numEdits = 0; + for (ShaderNode* node : graph.getNodes()) + { + if (node->hasClassification(ShaderNode::Classification::CONSTANT)) + { + if (node->numInputs() != 1 || node->numOutputs() != 1) + { + // Constant node doesn't follow expected interface, cannot elide. + continue; + } + // Constant nodes can be elided by moving their value downstream. + bool canElide = context.getOptions().elideConstantNodes; + if (!canElide) + { + // We always elide filename constant nodes regardless of the + // option. See DOT below. + ShaderInput* in = node->getInput("value"); + if (in && in->getType() == Type::FILENAME) + { + canElide = true; + } + } + if (canElide) + { + graph.bypass(node, 0); + ++numEdits; + } + } + else if (node->hasClassification(ShaderNode::Classification::DOT)) + { + if (node->numOutputs() != 1) + { + // Dot node doesn't follow expected interface, cannot elide. + continue; + } + // Filename dot nodes must be elided so they do not create extra samplers. + ShaderInput* in = node->getInput("in"); + if (in && in->getType() == Type::FILENAME) + { + graph.bypass(node, 0); + ++numEdits; + } + } + } + return numEdits; +} + +// +// PremultipliedBsdfAddRefactor +// + +const string& PremultipliedBsdfAddRefactor::getName() const +{ + static const string name = "premultipliedBsdfAdd"; + return name; +} + +size_t PremultipliedBsdfAddRefactor::execute(ShaderGraph& graph, GenContext& context) +{ + if (!context.getOptions().premultipliedBsdfAdd) + { + return 0; + } + + // Look up all required node definitions up front. + ConstDocumentPtr doc = graph.getDocument(); + NodeDefPtr invertDef = doc->getNodeDef("ND_invert_float"); + NodeDefPtr mulFloatDef = doc->getNodeDef("ND_multiply_float"); + NodeDefPtr mulBsdfDef = doc->getNodeDef("ND_multiply_bsdfF"); + NodeDefPtr addBsdfDef = doc->getNodeDef("ND_add_bsdf"); + if (!invertDef || !mulFloatDef || !mulBsdfDef || !addBsdfDef) + { + return 0; + } + + // Collect mix nodes with connected weights (avoid modifying the graph while iterating). + vector mixNodes; + for (ShaderNode* node : graph.getNodes()) + { + if (isBsdfMixNode(node)) + { + ShaderInput* mix = node->getInput("mix"); + if (mix && mix->getConnection()) + { + mixNodes.push_back(node); + } + } + } + + size_t numEdits = 0; + + for (ShaderNode* mixNode : mixNodes) + { + ShaderInput* fgInput = mixNode->getInput("fg"); + ShaderInput* bgInput = mixNode->getInput("bg"); + ShaderInput* mixInput = mixNode->getInput("mix"); + ShaderOutput* mixOutput = mixNode->getOutput(); + + if (!fgInput || !bgInput || !mixInput || !mixOutput) + { + continue; + } + + ShaderOutput* mixWeightSource = mixInput->getConnection(); + + // Create an invert node to compute (1 - mix). + string invertName = mixNode->getName() + "_mix_inv"; + ShaderNode* invertNode = graph.createNode(invertName, invertName, invertDef, context); + ShaderInput* invertIn = invertNode->getInput("in"); + if (invertIn) + { + invertIn->makeConnection(mixWeightSource); + } + ShaderOutput* invertOutput = invertNode->getOutput(); + + // Fold mix weights into each BSDF side. + string namePrefix = mixNode->getName(); + ShaderOutput* fgUpstream = foldWeightIntoBsdf(graph, context, fgInput, mixWeightSource, + namePrefix + "_fg", mulFloatDef, mulBsdfDef); + ShaderOutput* bgUpstream = foldWeightIntoBsdf(graph, context, bgInput, invertOutput, + namePrefix + "_bg", mulFloatDef, mulBsdfDef); + + // Create an add node to replace the mix. + string addName = mixNode->getName() + "_add"; + ShaderNode* addNode = graph.createNode(addName, addName, addBsdfDef, context); + ShaderInput* addIn1 = addNode->getInput("in1"); + ShaderInput* addIn2 = addNode->getInput("in2"); + if (!addIn1 || !addIn2) + { + continue; + } + + if (fgUpstream) + { + addIn1->makeConnection(fgUpstream); + } + if (bgUpstream) + { + addIn2->makeConnection(bgUpstream); + } + + // Rewire all downstream connections from the mix output to the add output. + graph.replaceOutput(mixOutput, addNode->getOutput()); + + // Disconnect the mix node's inputs. + fgInput->breakConnection(); + bgInput->breakConnection(); + mixInput->breakConnection(); + + ++numEdits; + } + + return numEdits; +} + +// +// DistributeLayerOverMixRefactor +// + +const string& DistributeLayerOverMixRefactor::getName() const +{ + static const string name = "distributeLayerOverMix"; + return name; +} + +size_t DistributeLayerOverMixRefactor::execute(ShaderGraph& graph, GenContext& context) +{ + if (!context.getOptions().distributeLayerOverBsdfMix) + { + return 0; + } + + // Look up all required node definitions up front. + ConstDocumentPtr doc = graph.getDocument(); + NodeDefPtr layerBsdfDef = doc->getNodeDef("ND_layer_bsdf"); + NodeDefPtr mixBsdfDef = doc->getNodeDef("ND_mix_bsdf"); + if (!layerBsdfDef || !mixBsdfDef) + { + return 0; + } + + // Collect layer nodes to process (avoid modifying the graph while iterating). + vector layerNodes; + for (ShaderNode* node : graph.getNodes()) + { + if (isLayerWithMixTop(node)) + { + layerNodes.push_back(node); + } + } + + size_t numEdits = 0; + + for (ShaderNode* layerNode : layerNodes) + { + ShaderInput* topInput = layerNode->getInput("top"); + ShaderInput* baseInput = layerNode->getInput("base"); + ShaderOutput* layerOutput = layerNode->getOutput(); + + if (!topInput || !baseInput || !layerOutput) + { + continue; + } + + ShaderOutput* topConnection = topInput->getConnection(); + if (!topConnection) + { + continue; + } + + ShaderNode* mixNode = topConnection->getNode(); + ShaderInput* fgInput = mixNode->getInput("fg"); + ShaderInput* bgInput = mixNode->getInput("bg"); + ShaderInput* mixInput = mixNode->getInput("mix"); + + if (!fgInput || !bgInput || !mixInput) + { + continue; + } + + ShaderOutput* fgUpstream = fgInput->getConnection(); + ShaderOutput* bgUpstream = bgInput->getConnection(); + ShaderOutput* baseUpstream = baseInput->getConnection(); + ShaderOutput* mixWeightSource = mixInput->getConnection(); + + // Create layer(fg, base). + string layer1Name = layerNode->getName() + "_tf"; + ShaderNode* layer1 = graph.createNode(layer1Name, layer1Name, layerBsdfDef, context); + ShaderInput* layer1Top = layer1->getInput("top"); + ShaderInput* layer1Base = layer1->getInput("base"); + if (layer1Top && fgUpstream) + { + layer1Top->makeConnection(fgUpstream); + } + if (layer1Base && baseUpstream) + { + layer1Base->makeConnection(baseUpstream); + } + + // Create layer(bg, base). + string layer2Name = layerNode->getName() + "_notf"; + ShaderNode* layer2 = graph.createNode(layer2Name, layer2Name, layerBsdfDef, context); + ShaderInput* layer2Top = layer2->getInput("top"); + ShaderInput* layer2Base = layer2->getInput("base"); + if (layer2Top && bgUpstream) + { + layer2Top->makeConnection(bgUpstream); + } + if (layer2Base && baseUpstream) + { + layer2Base->makeConnection(baseUpstream); + } + + // Create mix(layer1, layer2, w). + string newMixName = layerNode->getName(); + ShaderNode* newMixNode = graph.createNode(newMixName + "_mix", newMixName + "_mix", mixBsdfDef, context); + ShaderInput* newFg = newMixNode->getInput("fg"); + ShaderInput* newBg = newMixNode->getInput("bg"); + ShaderInput* newMix = newMixNode->getInput("mix"); + if (newFg) + { + newFg->makeConnection(layer1->getOutput()); + } + if (newBg) + { + newBg->makeConnection(layer2->getOutput()); + } + if (newMix && mixWeightSource) + { + newMix->makeConnection(mixWeightSource); + } + else if (newMix && mixInput->getValue()) + { + newMix->setValue(mixInput->getValue()); + } + + // Rewire downstream connections from the old layer to the new mix. + graph.replaceOutput(layerOutput, newMixNode->getOutput()); + + // Disconnect the old layer node's inputs. + topInput->breakConnection(); + baseInput->breakConnection(); + + ++numEdits; + } + + return numEdits; +} + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/ShaderGraphRefactor.h b/source/MaterialXGenShader/ShaderGraphRefactor.h new file mode 100644 index 0000000000..c09bdadf29 --- /dev/null +++ b/source/MaterialXGenShader/ShaderGraphRefactor.h @@ -0,0 +1,80 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef MATERIALX_SHADERGRAPHREFACTOR_H +#define MATERIALX_SHADERGRAPHREFACTOR_H + +/// @file +/// Shader graph refactoring passes + +#include + +MATERIALX_NAMESPACE_BEGIN + +class GenContext; +class ShaderGraph; + +/// A shared pointer to a shader graph refactor +using ShaderGraphRefactorPtr = shared_ptr; + +/// @class ShaderGraphRefactor +/// Base class for shader graph refactoring passes. +/// Each pass identifies a structural pattern in the shader graph and +/// rewrites it into a mathematically equivalent form better suited +/// to the target backend. +class MX_GENSHADER_API ShaderGraphRefactor +{ + public: + virtual ~ShaderGraphRefactor() { } + + /// Return the name of this refactoring pass. + virtual const string& getName() const = 0; + + /// Execute the pass on the given graph. + /// Return the number of graph edits made, or zero if + /// the pass is not applicable to the current context. + virtual size_t execute(ShaderGraph& graph, GenContext& context) = 0; +}; + +/// @class NodeElisionRefactor +/// Removes constant and dot nodes by bypassing them. +/// Constant nodes have their values moved downstream, and +/// dot nodes with filename-typed inputs are elided to prevent +/// extra samplers. +class MX_GENSHADER_API NodeElisionRefactor : public ShaderGraphRefactor +{ + public: + const string& getName() const override; + size_t execute(ShaderGraph& graph, GenContext& context) override; +}; + +/// @class PremultipliedBsdfAddRefactor +/// Replaces BSDF mix nodes with premultiplied add nodes. +/// Transforms mix(A, B, w) into add(A*w, B*(1-w)) by folding +/// the mix weight into each BSDF's weight input, enabling +/// hardware shading languages to skip BSDF evaluation when +/// the weight is zero. +class MX_GENSHADER_API PremultipliedBsdfAddRefactor : public ShaderGraphRefactor +{ + public: + const string& getName() const override; + size_t execute(ShaderGraph& graph, GenContext& context) override; +}; + +/// @class DistributeLayerOverMixRefactor +/// Distributes layer operations over mix nodes. +/// Transforms layer(mix(A, B, w), C) into mix(layer(A, C), layer(B, C), w) +/// to satisfy backends that cannot handle a mixed BSDF as the top +/// operand of a layer node. +class MX_GENSHADER_API DistributeLayerOverMixRefactor : public ShaderGraphRefactor +{ + public: + const string& getName() const override; + size_t execute(ShaderGraph& graph, GenContext& context) override; +}; + +MATERIALX_NAMESPACE_END + +#endif diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 4d54d5a6d6..843cef071f 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -284,14 +284,28 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, { newNode->_classification |= Classification::LAYER; } + + // Check specifically for the mix node + if (nodeDefName == "ND_mix_bsdf") + { + newNode->_classification |= Classification::MIX; + } } else if (primaryOutput->getType() == Type::EDF) { newNode->_classification = Classification::EDF | Classification::CLOSURE; + if (nodeDefName == "ND_mix_edf") + { + newNode->_classification |= Classification::MIX; + } } else if (primaryOutput->getType() == Type::VDF) { newNode->_classification = Classification::VDF | Classification::CLOSURE; + if (nodeDefName == "ND_mix_vdf") + { + newNode->_classification |= Classification::MIX; + } } // Second, check for specific nodes types else if (nodeDef.getNodeString() == CONSTANT) diff --git a/source/MaterialXGenShader/ShaderNode.h b/source/MaterialXGenShader/ShaderNode.h index fabefc74fc..7059e0cdba 100644 --- a/source/MaterialXGenShader/ShaderNode.h +++ b/source/MaterialXGenShader/ShaderNode.h @@ -349,16 +349,17 @@ class MX_GENSHADER_API ShaderNode static const uint32_t EDF = 1 << 10; /// A EDF node static const uint32_t VDF = 1 << 11; /// A VDF node static const uint32_t LAYER = 1 << 12; /// A node for vertical layering of other closure nodes + static const uint32_t MIX = 1 << 13; /// A node for mixing of other closure nodes // Specific shader types - static const uint32_t SURFACE = 1 << 13; /// A surface shader node - static const uint32_t VOLUME = 1 << 14; /// A volume shader node - static const uint32_t LIGHT = 1 << 15; /// A light shader node - static const uint32_t UNLIT = 1 << 16; /// An unlit surface shader node + static const uint32_t SURFACE = 1 << 14; /// A surface shader node + static const uint32_t VOLUME = 1 << 15; /// A volume shader node + static const uint32_t LIGHT = 1 << 16; /// A light shader node + static const uint32_t UNLIT = 1 << 17; /// An unlit surface shader node // Types based on nodegroup - static const uint32_t SAMPLE2D = 1 << 17; /// Can be sampled in 2D (uv space) - static const uint32_t SAMPLE3D = 1 << 18; /// Can be sampled in 3D (position) - static const uint32_t GEOMETRIC = 1 << 19; /// Geometric input - static const uint32_t DOT = 1 << 20; /// A dot node + static const uint32_t SAMPLE2D = 1 << 18; /// Can be sampled in 2D (uv space) + static const uint32_t SAMPLE3D = 1 << 19; /// Can be sampled in 3D (position) + static const uint32_t GEOMETRIC = 1 << 20; /// Geometric input + static const uint32_t DOT = 1 << 21; /// A dot node }; static const ShaderNodePtr NONE; diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 9fc69cfa2f..1b7bff04e1 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -846,6 +846,30 @@ void Viewer::createAdvancedSettings(ng::ref parent) setShaderInterfaceType(interfaceType); }); + ng::ref constantElisionBox = new ng::CheckBox(settingsGroup, "Constant Elision"); + constantElisionBox->set_checked(_genContext.getOptions().elideConstantNodes); + constantElisionBox->set_callback([this](bool enable) + { + _genContext.getOptions().elideConstantNodes = enable; + reloadShaders(); + }); + + ng::ref premultipliedBsdfAddBox = new ng::CheckBox(settingsGroup, "Premultiplied BSDF Add"); + premultipliedBsdfAddBox->set_checked(_genContext.getOptions().premultipliedBsdfAdd); + premultipliedBsdfAddBox->set_callback([this](bool enable) + { + _genContext.getOptions().premultipliedBsdfAdd = enable; + reloadShaders(); + }); + + ng::ref distributeLayerBox = new ng::CheckBox(settingsGroup, "Distribute Layer Over Mix"); + distributeLayerBox->set_checked(_genContext.getOptions().distributeLayerOverBsdfMix); + distributeLayerBox->set_callback([this](bool enable) + { + _genContext.getOptions().distributeLayerOverBsdfMix = enable; + reloadShaders(); + }); + ng::ref albedoGroup = new Widget(settingsGroup); albedoGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(albedoGroup, "Albedo Method:"); diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyGenOptions.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyGenOptions.cpp index 3949d50b8d..30dec2565f 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyGenOptions.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyGenOptions.cpp @@ -31,6 +31,9 @@ void bindPyGenOptions(py::module& mod) .def_readwrite("addUpstreamDependencies", &mx::GenOptions::addUpstreamDependencies) .def_readwrite("libraryPrefix", &mx::GenOptions::libraryPrefix) .def_readwrite("emitColorTransforms", &mx::GenOptions::emitColorTransforms) + .def_readwrite("elideConstantNodes", &mx::GenOptions::elideConstantNodes) + .def_readwrite("premultipliedBsdfAdd", &mx::GenOptions::premultipliedBsdfAdd) + .def_readwrite("distributeLayerOverBsdfMix", &mx::GenOptions::distributeLayerOverBsdfMix) .def_readwrite("hwTransparency", &mx::GenOptions::hwTransparency) .def_readwrite("hwSpecularEnvironmentMethod", &mx::GenOptions::hwSpecularEnvironmentMethod) .def_readwrite("hwSrgbEncodeOutput", &mx::GenOptions::hwSrgbEncodeOutput) From 48e9a5fb8a3436bb92aab3ec3d6d72066fa01347 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 21 Mar 2026 12:30:10 -0700 Subject: [PATCH 2/2] Rename setDefaultOptions to applyDefaultOptions for clarity --- source/MaterialXGenHw/HwShaderGenerator.cpp | 4 ++-- source/MaterialXGenHw/HwShaderGenerator.h | 4 ++-- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 4 ++-- source/MaterialXGenMdl/MdlShaderGenerator.h | 4 ++-- source/MaterialXGenShader/GenContext.cpp | 2 +- source/MaterialXGenShader/ShaderGenerator.cpp | 2 +- source/MaterialXGenShader/ShaderGenerator.h | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/MaterialXGenHw/HwShaderGenerator.cpp b/source/MaterialXGenHw/HwShaderGenerator.cpp index ed8cbed2cd..318a9dadf1 100644 --- a/source/MaterialXGenHw/HwShaderGenerator.cpp +++ b/source/MaterialXGenHw/HwShaderGenerator.cpp @@ -88,9 +88,9 @@ HwShaderGenerator::HwShaderGenerator(TypeSystemPtr typeSystem, SyntaxPtr syntax) _tokenSubstitutions[HW::T_CLOSURE_DATA_CONSTRUCTOR] = HW::CLOSURE_DATA_CONSTRUCTOR; } -void HwShaderGenerator::setDefaultOptions(GenOptions& options) const +void HwShaderGenerator::applyDefaultOptions(GenOptions& options) const { - ShaderGenerator::setDefaultOptions(options); + ShaderGenerator::applyDefaultOptions(options); options.premultipliedBsdfAdd = true; } diff --git a/source/MaterialXGenHw/HwShaderGenerator.h b/source/MaterialXGenHw/HwShaderGenerator.h index 429a8aea4c..9e4651ca79 100644 --- a/source/MaterialXGenHw/HwShaderGenerator.h +++ b/source/MaterialXGenHw/HwShaderGenerator.h @@ -43,8 +43,8 @@ class MX_GENHW_API HwShaderGenerator : public ShaderGenerator void emitClosureDataArg(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; void emitClosureDataParameter(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; - /// Set the default GenOptions for hardware shader generation. - void setDefaultOptions(GenOptions& options) const override; + /// Apply the default GenOptions for hardware shader generation. + void applyDefaultOptions(GenOptions& options) const override; /// Logic to indicate whether code to support direct lighting should be emitted. /// By default if the graph is classified as a shader, or BSDF node then lighting is assumed to be required. diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 47768ff82b..4b4fe676dc 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -125,9 +125,9 @@ MdlShaderGenerator::MdlShaderGenerator(TypeSystemPtr typeSystem) : registerImplementation("IM_image_vector4_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); } -void MdlShaderGenerator::setDefaultOptions(GenOptions& options) const +void MdlShaderGenerator::applyDefaultOptions(GenOptions& options) const { - ShaderGenerator::setDefaultOptions(options); + ShaderGenerator::applyDefaultOptions(options); options.distributeLayerOverBsdfMix = true; } diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.h b/source/MaterialXGenMdl/MdlShaderGenerator.h index 380f7a4f45..a3fa888c2f 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.h +++ b/source/MaterialXGenMdl/MdlShaderGenerator.h @@ -70,8 +70,8 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator /// Return a unique identifier for the target this generator is for const string& getTarget() const override { return TARGET; } - /// Set the default GenOptions for MDL shader generation. - void setDefaultOptions(GenOptions& options) const override; + /// Apply the default GenOptions for MDL shader generation. + void applyDefaultOptions(GenOptions& options) const override; /// Generate a shader starting from the given element, translating /// the element and all dependencies upstream into shader code. diff --git a/source/MaterialXGenShader/GenContext.cpp b/source/MaterialXGenShader/GenContext.cpp index 85c0eec1e6..5f219d72ce 100644 --- a/source/MaterialXGenShader/GenContext.cpp +++ b/source/MaterialXGenShader/GenContext.cpp @@ -21,7 +21,7 @@ GenContext::GenContext(ShaderGeneratorPtr sg) : } // Apply the generator's default options for its target. - _sg->setDefaultOptions(_options); + _sg->applyDefaultOptions(_options); // Collect and cache reserved words from the shader generator StringSet reservedWords; diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index 4fa048050a..577b7869f0 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -38,7 +38,7 @@ ShaderGenerator::ShaderGenerator(TypeSystemPtr typeSystem, SyntaxPtr syntax) : registerRefactor(std::make_shared()); } -void ShaderGenerator::setDefaultOptions(GenOptions& /*options*/) const +void ShaderGenerator::applyDefaultOptions(GenOptions& /*options*/) const { // Base implementation sets no additional defaults. // Derived generators override to set target-specific defaults. diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index 2d1ad45da1..7a53631142 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -227,8 +227,8 @@ class MX_GENSHADER_API ShaderGenerator return _refactors; } - /// Set the default GenOptions for this generator's target. - virtual void setDefaultOptions(GenOptions& options) const; + /// Apply the default GenOptions for this generator's target. + virtual void applyDefaultOptions(GenOptions& options) const; /// Register type definitions from the document. virtual void registerTypeDefs(const DocumentPtr& doc);