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

Fix downstream traversal in graph editor #1349

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b9998d7
Inlude nodegraph connections to port connection cache and add downs-t…
kwokcb May 4, 2023
c8f82d1
Cleanup.
kwokcb May 4, 2023
0543cdc
Add Python Nodegraph::getDownstreamPorts() interface
kwokcb May 4, 2023
a011a45
Minor cleanup.
kwokcb May 4, 2023
5b5ce84
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb May 4, 2023
69b3abc
Remove material type filter from renderer as it's not required. Any n…
kwokcb May 4, 2023
695a245
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb May 13, 2023
b111832
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb May 17, 2023
e264f53
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb May 22, 2023
acd7594
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb May 24, 2023
e3d2537
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb May 30, 2023
6515777
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Jun 16, 2023
285cb7c
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Jun 23, 2023
b423b74
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Jun 29, 2023
59758e8
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Jul 4, 2023
9fce312
Review cleanup.
kwokcb Jul 4, 2023
fa118ef
Merge branch 'main' into downstream_traversal
jstone-lucasfilm Jul 12, 2023
3bdb7df
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Jul 14, 2023
f5d8984
Disallow trying to traverse through nodes in definition as there is a…
kwokcb Jul 14, 2023
46c8fb2
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Jul 24, 2023
9a05a2b
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Jul 30, 2023
371a783
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Aug 16, 2023
9c0cbde
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Aug 21, 2023
9314f92
Merge branch 'AcademySoftwareFoundation:main' into downstream_traversal
kwokcb Aug 23, 2023
be459d9
Add in simplified parent traversal code.
kwokcb Aug 23, 2023
b5f9cf8
Merge branch 'main' into downstream_traversal
jstone-lucasfilm Aug 24, 2023
c1ba086
Merge branch 'main' into downstream_traversal
jstone-lucasfilm Aug 24, 2023
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
12 changes: 12 additions & 0 deletions source/MaterialXCore/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ class Document::Cache
portElementMap.emplace(portElem->getQualifiedName(nodeName), portElem);
}
}
else
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved
{
const string& nodegraphName = elem->getAttribute(PortElement::NODE_GRAPH_ATTRIBUTE);
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved
if (!nodegraphName.empty())
{
PortElementPtr portElem = elem->asA<PortElement>();
if (portElem)
{
portElementMap.emplace(portElem->getQualifiedName(nodegraphName), portElem);
}
}
}
if (!nodeString.empty())
{
NodeDefPtr nodeDef = elem->asA<NodeDef>();
Expand Down
27 changes: 27 additions & 0 deletions source/MaterialXCore/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,33 @@ InterfaceElementPtr NodeGraph::getImplementation() const
return nodedef ? nodedef->getImplementation() : InterfaceElementPtr();
}

vector<PortElementPtr> NodeGraph::getDownstreamPorts() const
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved
{
vector<PortElementPtr> downstreamPorts;
for (PortElementPtr port : getDocument()->getMatchingPorts(getQualifiedName(getName())))
{
ConstGraphElementPtr graph = nullptr;
ElementPtr node = port->getParent();
if (node)
{
node = node->getParent();
if (node->isA<GraphElement>())
{
graph = node->asA<GraphElement>();
}
}
if (graph && graph->getChild(getName()) == getSelf())
{
downstreamPorts.push_back(port);
}
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved
}
std::sort(downstreamPorts.begin(), downstreamPorts.end(), [](const ConstElementPtr& a, const ConstElementPtr& b)
{
return a->getName() > b->getName();
});
return downstreamPorts;
}

bool NodeGraph::validate(string* message) const
{
bool res = true;
Expand Down
8 changes: 8 additions & 0 deletions source/MaterialXCore/Node.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,14 @@ class MX_CORE_API NodeGraph : public GraphElement
/// none was found.
InterfaceElementPtr getImplementation() const;

/// @}
/// @name Traversal
/// @{

/// Return a vector of all downstream ports that connect to this graph, ordered by
/// the names of the port elements.
vector<PortElementPtr> getDownstreamPorts() const;

/// @}
/// @name Utility
/// @{
Expand Down
150 changes: 92 additions & 58 deletions source/MaterialXGraphEditor/Graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,8 +681,13 @@ void Graph::selectMaterial(UiNodePtr uiNode)
// set the node to display in render veiw based off the selected node or nodegraph
void Graph::setRenderMaterial(UiNodePtr node)
{
// For now surface shaders and materials are considered renderable.
// This can be adjusted as desired to includ being able to use outputs,
// and / a sub-graph in the nodegraph.
mx::StringSet renderableTypes = { "material", "surfaceshader" };
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved

// set render node right away is node is a material
if (node->getNode() && node->getNode()->getType() == "material")
if (node->getNode() && renderableTypes.count(node->getNode()->getType()))
{
// only set new render node if different material has been selected
if (_currRenderNode != node)
Expand All @@ -694,92 +699,124 @@ void Graph::setRenderMaterial(UiNodePtr node)
}
else
{
// continue downstream using output connections until a material node is found
std::vector<UiNodePtr> outNodes = node->getOutputConnections();
if (outNodes.size() > 0)
// Traverse downstream looking for the first renderable item found.
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved
mx::NodePtr mtlxNode = node->getNode();
mx::NodeGraphPtr mtlxNodeGraph = node->getNodeGraph();
mx::OutputPtr mtlxOutput = node->getOutput();
if (mtlxOutput)
{
mx::ElementPtr parent = mtlxOutput->getParent();
if (parent->isA<mx::NodeGraph>())
mtlxNodeGraph = parent->asA<mx::NodeGraph>();
else if (parent->isA<mx::Node>())
mtlxNode = parent->asA<mx::Node>();
}
mx::StringSet testPaths;
if (mtlxNode)
{
testPaths.insert(mtlxNode->getNamePath());
}
else if (mtlxNodeGraph)
{
testPaths.insert(mtlxNodeGraph->getNamePath());
}

mx::NodePtr foundNode = nullptr;
while (!testPaths.empty() && !foundNode)
{
if (outNodes[0]->getNode())
mx::StringSet nextPaths;
for (const std::string& testPath : testPaths)
{
if (outNodes[0]->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING)
mx::ElementPtr testElem = _graphDoc->getDescendant(testPath);
mx::NodePtr testNode = testElem->asA<mx::Node>();
std::vector<mx::PortElementPtr> downstreamPorts;
if (testNode)
{
downstreamPorts = testNode->getDownstreamPorts();
}
else
{
std::vector<UiNodePtr> shaderOut = outNodes[0]->getOutputConnections();
if (shaderOut.size() > 0)
mx::NodeGraphPtr testGraph = testElem->asA<mx::NodeGraph>();
if (testGraph)
{
if (shaderOut[0])
downstreamPorts = testGraph->getDownstreamPorts();
}
}
// Test all downstream ports. If the port's node is renderable
// then stop searching.
for (mx::PortElementPtr downstreamPort : downstreamPorts)
{
mx::ElementPtr parent = downstreamPort->getParent();
if (parent)
{
mx::NodePtr downstreamNode = parent->asA<mx::Node>();
if (downstreamNode)
{
if (shaderOut[0]->getNode()->getType() == "material")
mx::NodeDefPtr nodeDef = downstreamNode->getNodeDef();
if (nodeDef)
{
if (_currRenderNode != shaderOut[0])
if (renderableTypes.count(nodeDef->getType()))
{
_currRenderNode = shaderOut[0];
_frameCount = ImGui::GetFrameCount();
_renderer->setMaterialCompilation(true);
foundNode = downstreamNode;
break;
}
}
}
}
else
{
_currRenderNode = nullptr;
if (!foundNode)
{
nextPaths.insert(parent->getNamePath());
}
}
}
else if (outNodes[0]->getNode()->getType() == mx::MATERIAL_TYPE_STRING)
if (foundNode)
{
if (_currRenderNode != outNodes[0])
break;
}
}

// Set up next set of nodes to search downstream
testPaths = nextPaths;
}

// Update rendering. If found use that node, otherwise
// use the current fallback of using the first renderable node.
if (foundNode)
{
for (auto uiNode : _graphNodes)
{
if (uiNode->getNode() == foundNode)
{
if (_currRenderNode != uiNode)
{
_currRenderNode = outNodes[0];
_currRenderNode = uiNode;
_frameCount = ImGui::GetFrameCount();
_renderer->setMaterialCompilation(true);
}
break;
}
}
else
{
_currRenderNode = nullptr;
}
}
else
{
_currRenderNode = nullptr;
_frameCount = ImGui::GetFrameCount();
_renderer->setMaterialCompilation(true);
}
}
}

void Graph::updateMaterials(mx::InputPtr input, mx::ValuePtr value)
{
std::string renderablePath;
mx::TypedElementPtr renderableElem;
std::vector<mx::TypedElementPtr> elems = mx::findRenderableElements(_graphDoc);

size_t num = 0;
int num2 = 0;
for (mx::TypedElementPtr elem : elems)
if (_currRenderNode)
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved
{
renderableElem = elem;
mx::NodePtr node = elem->asA<mx::Node>();
if (node)
if (_currRenderNode->getNode())
{
if (_currRenderNode)
{
if (node->getName() == _currRenderNode->getName())
{
renderablePath = renderableElem->getNamePath();
break;
}
}
else
{
renderablePath = renderableElem->getNamePath();
}
renderablePath = _currRenderNode->getNode()->getNamePath();
}
else
else if (_currRenderNode->getOutput())
{
renderablePath = renderableElem->getNamePath();
if (num2 == 2)
{
break;
}
num2++;
renderablePath = _currRenderNode->getOutput()->getNamePath();
}
}

Expand Down Expand Up @@ -810,7 +847,7 @@ void Graph::updateMaterials(mx::InputPtr input, mx::ValuePtr value)
// Note that if there is a topogical change due to
// this value change or a transparency change, then
// this is not currently caught here.
_renderer->getMaterials()[num]->modifyUniform(name, value);
_renderer->getMaterials()[0]->modifyUniform(name, value);
}
}
}
Expand Down Expand Up @@ -3619,10 +3656,7 @@ void Graph::drawGraph(ImVec2 mousePos)
// update render material if needed
if (_currUiNode->getNode())
{
if (_currUiNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING || _currUiNode->getNode()->getType() == mx::MATERIAL_TYPE_STRING)
{
setRenderMaterial(_currUiNode);
}
setRenderMaterial(_currUiNode);
jstone-lucasfilm marked this conversation as resolved.
Show resolved Hide resolved
}
else if (_currUiNode->getNodeGraph())
{
Expand Down
1 change: 1 addition & 0 deletions source/PyMaterialX/PyMaterialXCore/PyNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ void bindPyNode(py::module& mod)
.def("addInterfaceName", &mx::NodeGraph::addInterfaceName)
.def("removeInterfaceName", &mx::NodeGraph::removeInterfaceName)
.def("modifyInterfaceName", &mx::NodeGraph::modifyInterfaceName)
.def("getDownstreamPorts", &mx::NodeGraph::getDownstreamPorts)
.def_readonly_static("CATEGORY", &mx::NodeGraph::CATEGORY);

py::class_<mx::Backdrop, mx::BackdropPtr, mx::Element>(mod, "Backdrop")
Expand Down