Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update API and Traversal to Support Nested NodeGraphs #1790

Closed
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0"?>
<materialx version="1.38" colorspace="lin_rec709">
<!-- Tests for nested nodegraphs -->

<!-- Test parent interface element connection to child nodegraph input and parent node connected to output of child graph output -->
<nodegraph name="parentNG">
<input name="parentNGInput" type="color3" value="1, 1, 0.2" />
<input name="parentNGInput2" type="color3" value="0.2, 1, 1" />
<input name="parentNGInput3" type="color3" value="1, 0.2, 1" />
<nodegraph name="childNG">
<input name="childNGInput" type="color3" interfacename="parentNGInput" />
<input name="childNGInput2" type="color3" interfacename="parentNGInput2" />
<multiply name="multiplyNode" type="color3">
<input name="in1" type="color3" interfacename="childNGInput" />
<input name="in2" type="color3" interfacename="childNGInput2" />
</multiply>
<output name="childNGOutput" type="color3" nodename="multiplyNode" />
</nodegraph>
<multiply name="parentmultiplyNode" type="color3">
<input name="in1" type="color3" nodegraph="childNG" output="childNGOutput"/>
<input name="in2" type="color3" interfacename="parentNGInput3" />
</multiply>
<output name="parentNGOutput1" type="color3" nodegraph="childNG" />
<output name="parentNGOutput2" type="color3" nodename="parentmultiplyNode" />
</nodegraph>

<standard_surface name="nestd_graph_shader" type="surfaceshader">
<input name="base_color" type="color3" nodegraph="parentNG" output="parentNGOutput1"/>
</standard_surface>

<surfacematerial name="nested_graph_material" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="nestd_graph_shader" />
<input name="displacementshader" type="displacementshader" value="" />
</surfacematerial>

<standard_surface name="nestd_graph_shader2" type="surfaceshader">
<input name="base_color" type="color3" nodegraph="parentNG" output="parentNGOutput2"/>
</standard_surface>

<surfacematerial name="nested_graph_material2" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="nestd_graph_shader2" />
<input name="displacementshader" type="displacementshader" value="" />
</surfacematerial>

</materialx>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0"?>
<materialx version="1.38" colorspace="lin_rec709">
<!-- Tests for nested nodegraphs -->

<!-- Test parent interface element connection to child nodegraph input and parent node connected to output of child graph output -->
<nodegraph name="parentNG">
<input name="parentNGInput" type="color3" value="1, 1, 0.2" />
<input name="parentNGInput2" type="color3" value="0.2, 1, 1" />

<nodegraph name="childNG">
<input name="childNGInput" type="color3" interfacename="parentNGInput" />
<input name="childNGInput2" type="color3" interfacename="parentNGInput2" />

<nodegraph name="subchildNG">
<input name="subchildNGInput" type="color3" interfacename="childNGInput" />
<input name="subchildNGInput2" type="color3" interfacename="childNGInput2" />
<multiply name="submultiplyNode" type="color3">
<input name="in1" type="color3" interfacename="subchildNGInput" />
<input name="in2" type="color3" interfacename="subchildNGInput2" />
</multiply>
<output name="subchildNGOutput" type="color3" nodename="submultiplyNode" />
</nodegraph>

<output name="childNGOutput" type="color3" nodegraph="subchildNG" />

</nodegraph>

<output name="parentNGOutput3" type="color3" nodegraph="childNG" />
</nodegraph>

<surface_unlit name="nested_graph_shader3" type="surfaceshader" >
<input name="emission_color" type="color3" nodegraph="parentNG" />
</surface_unlit>

<surfacematerial name="nested_graph_material3" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="nested_graph_shader3" />
<input name="displacementshader" type="displacementshader" value="" />
</surfacematerial>


</materialx>
4 changes: 0 additions & 4 deletions source/JsMaterialX/JsMaterialXCore/JsDocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ EMSCRIPTEN_BINDINGS(document)
mx::StringSet set = self.getReferencedSourceUris();
return ems::val::array(set.begin(), set.end());
}))
BIND_MEMBER_FUNC("addNodeGraph", mx::Document, addNodeGraph, 0, 1, stRef)
.function("getNodeGraph", &mx::Document::getNodeGraph)
.function("getNodeGraphs", &mx::Document::getNodeGraphs)
.function("removeNodeGraph", &mx::Document::removeNodeGraph)
.function("getMatchingPorts", &mx::Document::getMatchingPorts)
BIND_MEMBER_FUNC("addGeomInfo", mx::Document, addGeomInfo, 0, 2, stRef, stRef)
.function("getGeomInfo", &mx::Document::getGeomInfo)
Expand Down
4 changes: 4 additions & 0 deletions source/JsMaterialX/JsMaterialXCore/JsNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ EMSCRIPTEN_BINDINGS(node)
.function("getBackdrop", &mx::GraphElement::getBackdrop)
.function("getBackdrops", &mx::GraphElement::getBackdrops)
.function("removeBackdrop", &mx::GraphElement::removeBackdrop)
BIND_MEMBER_FUNC("addNodeGraph", mx::GraphElement, addNodeGraph, 0, 1, stRef)
.function("getNodeGraph", &mx::GraphElement::getNodeGraph)
.function("getNodeGraphs", &mx::GraphElement::getNodeGraphs)
.function("removeNodeGraph", &mx::GraphElement::removeNodeGraph)
BIND_MEMBER_FUNC("flattenSubgraphs", mx::GraphElement, flattenSubgraphs, 0, 2, stRef, mx::NodePredicate)
.function("topologicalSort", &mx::GraphElement::topologicalSort)
.function("asStringDot", &mx::GraphElement::asStringDot);
Expand Down
31 changes: 0 additions & 31 deletions source/MaterialXCore/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,37 +62,6 @@ class MX_CORE_API Document : public GraphElement
/// Get a list of source URI's referenced by the document
StringSet getReferencedSourceUris() const;

/// @name NodeGraph Elements
/// @{

/// Add a NodeGraph to the document.
/// @param name The name of the new NodeGraph.
/// If no name is specified, then a unique name will automatically be
/// generated.
/// @return A shared pointer to the new NodeGraph.
NodeGraphPtr addNodeGraph(const string& name = EMPTY_STRING)
{
return addChild<NodeGraph>(name);
}

/// Return the NodeGraph, if any, with the given name.
NodeGraphPtr getNodeGraph(const string& name) const
{
return getChildOfType<NodeGraph>(name);
}

/// Return a vector of all NodeGraph elements in the document.
vector<NodeGraphPtr> getNodeGraphs() const
{
return getChildrenOfType<NodeGraph>();
}

/// Remove the NodeGraph, if any, with the given name.
void removeNodeGraph(const string& name)
{
removeChildOfType<NodeGraph>(name);
}

/// Return a vector of all port elements that match the given node name.
/// Port elements support spatially-varying upstream connections to
/// nodes, and include both Input and Output elements.
Expand Down
4 changes: 4 additions & 0 deletions source/MaterialXCore/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,10 @@ bool ValueElement::validate(string* message) const
{
validateRequire(isA<Input>() || isA<Token>(), res, message, "Only input and token elements support interface names");
ConstNodeGraphPtr nodeGraph = getAncestorOfType<NodeGraph>();
if (getParent() && getParent()->isA<NodeGraph>())
{
nodeGraph = nodeGraph->getParent()->getAncestorOfType<NodeGraph>();
}
ConstInterfaceElementPtr decl = nodeGraph ? nodeGraph->getDeclaration() : nullptr;
if (decl)
{
Expand Down
151 changes: 119 additions & 32 deletions source/MaterialXCore/Interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,11 @@ OutputPtr PortElement::getConnectedOutput() const
NodeGraphPtr nodeGraph = resolveNameReference<NodeGraph>(getNodeGraphString(), scope);
if (!nodeGraph)
{
nodeGraph = resolveNameReference<NodeGraph>(getNodeGraphString());
nodeGraph = resolveNameReference<NodeGraph>(getNodeGraphString(), parent);
if (!nodeGraph)
{
nodeGraph = resolveNameReference<NodeGraph>(getNodeGraphString());
}
}
if (nodeGraph)
{
Expand All @@ -122,6 +126,12 @@ OutputPtr PortElement::getConnectedOutput() const
}
}
}

// Handl direct nodegraph -> nodegraph output connections
while (result && result->hasNodeGraphString())
{
result = result->getConnectedOutput();
}
}
// Look for a node output.
else if (hasNodeName())
Expand Down Expand Up @@ -154,49 +164,66 @@ OutputPtr PortElement::getConnectedOutput() const
{
result = getDocument()->getOutput(outputString);
}

return result;
}

bool PortElement::validate(string* message) const
{
bool res = true;

NodePtr connectedNode = getConnectedNode();
if (hasNodeName() || hasOutputString())
const string& outputString = getOutputString();
InterfaceElementPtr connectedElement = nullptr;
NodePtr connectedNode = nullptr;
NodeGraphPtr connectedGraph = nullptr;
if (hasNodeName())
{
NodeGraphPtr nodeGraph = resolveNameReference<NodeGraph>(getNodeName());
if (!nodeGraph)
connectedElement = connectedNode = getConnectedNode();
}
else if (hasNodeGraphString())
{
const string& nodeGraphString = getNodeGraphString();
connectedGraph = resolveNameReference<NodeGraph>(nodeGraphString);
if (!connectedGraph)
{
validateRequire(connectedNode != nullptr, res, message, "Invalid port connection");
if (getParent())
{
connectedGraph = resolveNameReference<NodeGraph>(nodeGraphString, getParent());
if (!connectedGraph)
{
connectedGraph = resolveNameReference<NodeGraph>(nodeGraphString, getParent()->getParent());
}
}
}
connectedElement = connectedGraph;
validateRequire(connectedGraph != nullptr, res, message,
"Nodegraph '" + nodeGraphString + "' not found for connection");
}
if (connectedNode)

if (connectedElement)
{
const string& outputString = getOutputString();
if (!outputString.empty())
{
OutputPtr output;
if (hasNodeName())
OutputPtr output = nullptr;
if (connectedNode)
{
NodeDefPtr nodeDef = connectedNode->getNodeDef();
output = nodeDef ? nodeDef->getOutput(outputString) : OutputPtr();
if (output)
{
validateRequire(connectedNode->getType() == MULTI_OUTPUT_TYPE_STRING, res, message,
"Multi-output type expected in port connection");
"Multi-output type expected in port connection'");
}
}
else if (hasNodeGraphString())
else if (connectedGraph)
{
NodeGraphPtr nodeGraph = resolveNameReference<NodeGraph>(getNodeGraphString());
if (nodeGraph)
output = connectedGraph->getOutput(outputString);
validateRequire(output != nullptr, res, message,
"Nodegraph output '" + outputString + "' not found for connection");
if (connectedGraph->getNodeDef())
{
output = nodeGraph->getOutput(outputString);
if (nodeGraph->getNodeDef())
{
validateRequire(nodeGraph->getOutputCount() > 1, res, message,
"Multi-output type expected in port connection");
}
validateRequire(connectedGraph->getOutputCount() > 1, res, message,
"Multi-output type expected in port connection");
}
}
else
Expand All @@ -215,18 +242,43 @@ bool PortElement::validate(string* message) const
}
else
{
validateRequire(getType() == output->getType(), res, message, "Mismatched types in port connection");
validateRequire(getType() == output->getType(), res, message, "Mismatched types in port connection:" +
getType() + " versus " + output->getType());
}
}
}
else if (hasChannels())
else
{
bool valid = validChannelsString(getChannels(), connectedNode->getType(), getType());
validateRequire(valid, res, message, "Invalid channels string in port connection");
}
else if (connectedNode->getType() != MULTI_OUTPUT_TYPE_STRING)
{
validateRequire(getType() == connectedNode->getType(), res, message, "Mismatched types in port connection");
OutputPtr output = nullptr;
string outputType = EMPTY_STRING;

if (connectedNode)
{
outputType = connectedNode->getType();
}
else if (connectedGraph)
{
std::vector<OutputPtr> outputs = connectedGraph->getOutputs();
if (!outputs.empty())
{
output = outputs[0];
outputType = output->getType();
}
}

if (!outputType.empty())
{
if (hasChannels())
{
bool valid = validChannelsString(getChannels(), outputType, getType());
validateRequire(valid, res, message, "Invalid channels string in port connection");
}
else if (outputType != MULTI_OUTPUT_TYPE_STRING)
{
validateRequire(getType() == outputType, res, message, "Mismatched types in port connection:" +
getType() + " versus " + outputType);
}
}
}
}
return ValueElement::validate(message) && res;
Expand Down Expand Up @@ -296,6 +348,18 @@ NodePtr Input::getConnectedNode() const
{
return node;
}
else if (output->hasNodeGraphString())
{
OutputPtr childGraphOutput = output->getConnectedOutput();
if (childGraphOutput)
{
NodePtr childGraphNode = childGraphOutput->getConnectedNode();
if (childGraphNode)
{
return childGraphNode;
}
}
}
}

return PortElement::getConnectedNode();
Expand All @@ -304,11 +368,34 @@ NodePtr Input::getConnectedNode() const
InputPtr Input::getInterfaceInput() const
{
if (hasInterfaceName())
{
ConstGraphElementPtr graph = getAncestorOfType<GraphElement>();
if (graph)
{
const string& interfaceName = getInterfaceName();
ConstElementPtr parent = getParent();
parent = parent->getParent();
ConstNodeGraphPtr graph = parent->asA<NodeGraph>();
if (graph && !graph->getNodeDef())
{
return graph->getInput(getInterfaceName());
InputPtr returnVal = graph->getInput(interfaceName);
if (returnVal)
{
if (returnVal->hasInterfaceName())
{
InputPtr val = returnVal->getInterfaceInput();
if (val)
{
returnVal = val;
}
return returnVal;
}
else
{
return returnVal;
}
}
else
{
throw Exception("Interface name cannot be found: '" + interfaceName + "'");
}
}
}
return nullptr;
Expand Down
Loading
Loading