diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index 5b187f80aa..66ddc0e3c3 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -218,4 +218,9 @@ bool LayerableNodeMdl::isEditable(const ShaderInput& input) const return BASE::isEditable(input); } +StringVec LayerableNodeMdl::addedInputNames() const +{ + return {1, StringConstantsMdl::BASE}; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h index 8b6f987287..1883228a07 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h @@ -51,6 +51,7 @@ class MX_GENMDL_API LayerableNodeMdl : public SourceCodeNodeMdl static ShaderNodeImplPtr create(); void addInputs(ShaderNode& node, GenContext&) const override; + StringVec addedInputNames() const override; bool isEditable(const ShaderInput& input) const override; }; diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp index 502711fe01..adb0f3d13d 100644 --- a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp @@ -23,6 +23,13 @@ void ImageNodeMdl::addInputs(ShaderNode& node, GenContext& context) const node.addInput(ImageNodeMdl::FLIP_V, Type::BOOLEAN)->setUniform(); } +StringVec ImageNodeMdl::addedInputNames() const +{ + auto retVal = BASE::addedInputNames(); + retVal.push_back(ImageNodeMdl::FLIP_V); + return retVal; +} + bool ImageNodeMdl::isEditable(const ShaderInput& input) const { if (input.getName() == ImageNodeMdl::FLIP_V) diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h index 8363c6f4fa..402550a1f5 100644 --- a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h @@ -24,6 +24,8 @@ class MX_GENMDL_API ImageNodeMdl : public SourceCodeNodeMdl void addInputs(ShaderNode& node, GenContext& context) const override; + StringVec addedInputNames() const override; + bool isEditable(const ShaderInput& input) const override; void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; diff --git a/source/MaterialXGenShader/Nodes/CompoundNode.cpp b/source/MaterialXGenShader/Nodes/CompoundNode.cpp index a7903d437d..46ed06630a 100644 --- a/source/MaterialXGenShader/Nodes/CompoundNode.cpp +++ b/source/MaterialXGenShader/Nodes/CompoundNode.cpp @@ -45,6 +45,21 @@ void CompoundNode::initialize(const InterfaceElement& element, GenContext& conte _hash = std::hash{}(_functionName); } +void CompoundNode::addInputs(ShaderNode& node, GenContext&) const +{ + // Propagate inputs added to the ShaderGraph + for (auto const& name: _rootGraph->getPropagatedAddedInputs()) { + const auto* inputSocket = _rootGraph->getInputSocket(name); + if (inputSocket) + { + ShaderInput* input = node.addInput(name, inputSocket->getType()); + input->setValue(inputSocket->getValue()); + } + } +} + +// Note: No addedInputNames here. Not necessary unless we start nesting ShaderGraphs. + void CompoundNode::createVariables(const ShaderNode&, GenContext& context, Shader& shader) const { // Gather shader inputs from all child nodes diff --git a/source/MaterialXGenShader/Nodes/CompoundNode.h b/source/MaterialXGenShader/Nodes/CompoundNode.h index 128701db80..047e783059 100644 --- a/source/MaterialXGenShader/Nodes/CompoundNode.h +++ b/source/MaterialXGenShader/Nodes/CompoundNode.h @@ -20,6 +20,8 @@ class MX_GENSHADER_API CompoundNode : public ShaderNodeImpl void initialize(const InterfaceElement& element, GenContext& context) override; + void addInputs(ShaderNode& node, GenContext& context) const override; + void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override; void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; diff --git a/source/MaterialXGenShader/Nodes/HwImageNode.cpp b/source/MaterialXGenShader/Nodes/HwImageNode.cpp index e8eddd6e1a..95a6ffa8c2 100644 --- a/source/MaterialXGenShader/Nodes/HwImageNode.cpp +++ b/source/MaterialXGenShader/Nodes/HwImageNode.cpp @@ -28,6 +28,11 @@ void HwImageNode::addInputs(ShaderNode& node, GenContext&) const input->setValue(Value::createValue(Vector2(0.0f, 0.0f))); } +StringVec HwImageNode::addedInputNames() const +{ + return {UV_SCALE, UV_OFFSET}; +} + void HwImageNode::setValues(const Node& node, ShaderNode& shaderNode, GenContext& context) const { // Remap uvs to normalized 0..1 space if the original UDIMs in a UDIM set diff --git a/source/MaterialXGenShader/Nodes/HwImageNode.h b/source/MaterialXGenShader/Nodes/HwImageNode.h index 58ddb9305c..9da376c94e 100644 --- a/source/MaterialXGenShader/Nodes/HwImageNode.h +++ b/source/MaterialXGenShader/Nodes/HwImageNode.h @@ -17,6 +17,9 @@ class MX_GENSHADER_API HwImageNode : public SourceCodeNode static ShaderNodeImplPtr create(); void addInputs(ShaderNode& node, GenContext& context) const override; + + StringVec addedInputNames() const override; + void setValues(const Node& node, ShaderNode& shaderNode, GenContext& context) const override; }; diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index c60910aaed..95091b0a0f 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -93,6 +93,7 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, if (!newNode) { newNode = createNode(upstreamNode, context); + propagateAddedInputs(*newNode, newNode->addedInputNames()); } // Handle interface inputs with default geometric properties. @@ -448,6 +449,9 @@ ShaderGraphPtr ShaderGraph::create(const ShaderGraph* parent, const NodeGraph& n // Clear classification graph->_classification = 0; + // Allow added input propagation since this ShaderGraph is for a CompoundNode + graph->_propagateAddedInputs = true; + // Create input sockets from the nodedef graph->addInputSockets(*nodeDef, context); @@ -466,6 +470,35 @@ ShaderGraphPtr ShaderGraph::create(const ShaderGraph* parent, const NodeGraph& n return graph; } +void ShaderGraph::propagateAddedInputs(ShaderNode& node, const StringVec& addedInputs) +{ + if (!_propagateAddedInputs) { + return; + } + + for (auto const& name: addedInputs) { + auto* nodeInput = node.getInput(name); + if (nodeInput) { + auto* inputSocket = getInputSocket(name); + if (!inputSocket) { + // Only add an input socket once. This means that a NodeGraph + // with three embedded image nodes will only get a single + // pair of uv_scale and uv_offset inputs shared between + // all three nodes. + // TODO: Have as many uv_scale inputs as there are embedded image + // nodes. Requires a scheme to make their names unique. Bonus + // points if that name can be related to the filename input. + // NOTE: This is enough to have UDIMs working with ND_gltf_colorimage + // and ND_UsdUVTexture, so we stop here at this time. + inputSocket = addInputSocket(name, nodeInput->getType()); + _propagatedAddedInputs.push_back(name); + } + inputSocket->makeConnection(nodeInput); + inputSocket->setValue(nodeInput->getValue()); + } + } +} + ShaderGraphPtr ShaderGraph::create(const ShaderGraph* parent, const string& name, ElementPtr element, GenContext& context) { ShaderGraphPtr graph; diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index 77fd090b66..577720cb36 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -58,6 +58,9 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode static ShaderGraphPtr create(const ShaderGraph* parent, const NodeGraph& nodeGraph, GenContext& context); + /// Get the list of added inputs to propagate further up + const StringVec& getPropagatedAddedInputs() const { return _propagatedAddedInputs; } + /// Return true if this node is a graph. bool isAGraph() const override { return true; } @@ -132,6 +135,9 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode /// Add a node to the graph void addNode(ShaderNodePtr node); + /// Propagate additional inputs added on a node. + void propagateAddedInputs(ShaderNode& node, const StringVec& addedInputs); + /// Add input sockets from an interface element (nodedef, nodegraph or node) void addInputSockets(const InterfaceElement& elem, GenContext& context); @@ -188,6 +194,10 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode std::vector _nodeOrder; IdentifierMap _identifiers; + // Propagate or not the extra inputs added by nodes + bool _propagateAddedInputs = false; + StringVec _propagatedAddedInputs; + // Temporary storage for inputs that require color transformations std::unordered_map _inputColorTransformMap; // Temporary storage for inputs that require unit transformations diff --git a/source/MaterialXGenShader/ShaderNode.h b/source/MaterialXGenShader/ShaderNode.h index 4f2f44e27b..3f09f33b39 100644 --- a/source/MaterialXGenShader/ShaderNode.h +++ b/source/MaterialXGenShader/ShaderNode.h @@ -484,6 +484,12 @@ class MX_GENSHADER_API ShaderNode return (!_impl || _impl->isEditable(input)); } + /// Return input names that are added by the implementation of this node + virtual StringVec addedInputNames() const + { + return _impl ? _impl->addedInputNames() : StringVec{}; + } + protected: /// Create metadata from the nodedef according to registered metadata. void createMetadata(const NodeDef& nodeDef, GenContext& context); diff --git a/source/MaterialXGenShader/ShaderNodeImpl.cpp b/source/MaterialXGenShader/ShaderNodeImpl.cpp index 7cd929a8e0..8e02170f81 100644 --- a/source/MaterialXGenShader/ShaderNodeImpl.cpp +++ b/source/MaterialXGenShader/ShaderNodeImpl.cpp @@ -38,6 +38,11 @@ void ShaderNodeImpl::addInputs(ShaderNode&, GenContext&) const { } +StringVec ShaderNodeImpl::addedInputNames() const +{ + return {}; +} + void ShaderNodeImpl::setValues(const Node&, ShaderNode&, GenContext&) const { } diff --git a/source/MaterialXGenShader/ShaderNodeImpl.h b/source/MaterialXGenShader/ShaderNodeImpl.h index b9fd2a5148..7a816c276c 100644 --- a/source/MaterialXGenShader/ShaderNodeImpl.h +++ b/source/MaterialXGenShader/ShaderNodeImpl.h @@ -62,6 +62,9 @@ class MX_GENSHADER_API ShaderNodeImpl /// Add additional inputs on a node. virtual void addInputs(ShaderNode& node, GenContext& context) const; + /// Return input names that are added by this implementation + virtual StringVec addedInputNames() const; + /// Set values for additional inputs on a node. virtual void setValues(const Node& node, ShaderNode& shaderNode, GenContext& context) const;