AcademySoftwareFoundation / AcademySoftwareFoundation/MaterialX
Feature Proposal: Support Nested NodeGraphs
- Dominant language
- C++
- Stars
- 2.3k
- Forks
- 451
- Avg merge
- 6d 6h
- Merged PRs (30d)
- 5
Description
# MaterialX Nested Nodegraphs
This document outlines the proposal to support a `` which is a child of another ``. As there are no syntax changes, the proposal is for a **1.38.x** incremental release.
## Authors
Niklas Harrysson, Bernard Kwok, Jonathan Stone
## Motivation
Currently compound `nodegraph`s can be specified at the document level. The extension to this is to allow nesting at **any** level in a graph hierarchy.
This allows for packaging of sub-parts of a graph into logical units for better organization and readability. When a graph becomes large it becomes convenient to have the ability to wrap parts of it into compounds where it make sense.
For example, in the nodegraph for `standard_surface` there are several parts of the graph that can be separated into child compounds that calculate a particular piece of logic such as:
* Tangent rotations
* How coat affect roughness
* How coat effect diffuse and sss colors
* How fresnel effects the EDF
Even the logical layering of BSDFs can probably have been separated out into compounds for better readability in a graph editor.
As an artist this becomes a useful tool in the toolbox for organizing graphs.
In addition, when such a compound is found to be reusable it can be published as a new definition (`nodedef`) with a functional nodegraph allowing it to be instantiated and reused. Without the ability to create child compounds an artist currently has to first move the graph up to the document level, then recreate the logic there, and then perform the "publish" to a nodedef.
Another motivation is that a user is presented with the ability to
construct nested nodegraphs in the Graph Editor, but cannot save the result to a document.
## Syntax Changes
None
## Connection Logic Changes
Connection handling becomes more consistent between nodes and nodegraphs by
generalizing connections. This is achieved by removing the restriction that some things you can do on nodes are not allowed on nodegraphs. Namely:
* `interfacename` can be specified on nodegraph ``s to allow connections between inputs on a child nodegraph and a parent nodegraph.
## Possible Configurations
Given a parent `` called `parentNG` and a child nodegraph `childNG`, and child nodes `childNodeUp` and `childNodeDown`:
1. The `` on `childNG` is connected to the output of an upstream node `childNodeUp`
```
[output="output on childNodeUp"]>
```
```mermaid
graph TB;
subgraph parentNG
childNodeUp
childNG
end
subgraph childNG
input([input])
end
childNodeUp --> input
style input fill:#0bb, color:#111
```
The `output` is specified if `childNodeUp` has multiple outputs.
If the upstream node was a nodegraph then syntax would be `nodegraph=`
instead of `node=`. (See *)
2. The `` on `childNG` is connected to the input of a downstream node `childNodeDown`
```
[output="output on childNG"]>
```
```mermaid
graph TB;
subgraph parentNG
childNodeDown
childNG
end
subgraph childNG
output([output])
end
output --> childNodeDown
style output fill:#0b0, color:#111
```
The `output` is specified if `childNG` has multiple outputs.
3. The `` on `childNG` is connected to the interface `` called `parentNGInput` of the parent nodegraph `parentNG`
```
```
```mermaid
graph TB;
subgraph parentNG
parentNGInput([parentNGInput])
childNG
end
subgraph childNG
input([input])
end
parentNGInput --interfacename--> input
style input fill:#0bb, color:#111
style parentNGInput fill:#0bb, color:#111
```
4. The `` on `childNG` is connected to the `` of the parent nodegraph `parentNG`
```
```
```mermaid
graph TB;
subgraph parentNG
outputparentNG([output])
childNG
end
subgraph childNG
output([output])
end
output --> outputparentNG
style output fill:#0b0, color:#111
style outputparentNG fill:#0b0, color:#111
```
with the `output` being specified if `childNG` has multiple outputs.
(*) Note that `` to `` connections are already supported so is similar to the node to nodegraph connection scenario.
## Interface Example
Example shows interfaces being connected between parent and child `nodegraph`s
```xml
```
```mermaid
graph TD;
top_shader[top_shader]
parentNG_childNG_multiplyNode[multiplyNode] --> childNGOutput
parentNG_childNG_childNGInputINT([childNGInput]) ==.in1==> parentNG_childNG_multiplyNode[multiplyNode]
style parentNG_childNG_childNGInputINT fill:#0bb, color:#111
parentNG_childNG_childNGInput2INT([childNGInput2]) ==.in2==> parentNG_childNG_multiplyNode[multiplyNode]
style parentNG_childNG_childNGInput2INT fill:#0bb, color:#111
parentNGOutput --".base_color"--> top_shader[top_shader]
subgraph parentNG
parentNG_childNG
parentNG_parentInput([parentInput])
parentNG_parentInput2([parentInput2])
style parentNG_parentInput2 fill:#0bb, color:#111
style parentNG_parentInput fill:#0bb, color:#111
parentNGOutput([parentNGOutput])
style parentNGOutput fill:#0b0, color:#111
end
subgraph parentNG_childNG[childNG]
parentNG_childNG_childNGInput2INT
parentNG_childNG_childNGInputINT
parentNG_childNG_multiplyNode
childNGOutput([childNGOutput]) --> parentNGOutput
style childNGOutput fill:#0b0, color:#111
end
parentNG_parentInput([parentInput]) --> parentNG_childNG_childNGInputINT
parentNG_parentInput2([parentInput2]) --> parentNG_childNG_childNGInput2INT
```
The resulting rendering in MaterialXView would look something like this,
where the parent nodegraph inputs (`parentNGInput`, `parentNGInput2`) are exposed as input uniforms via shader code generation.

## Implementation Requirements
* Graph traversal logic, shader generation, and value evaluation handles `interfacename` on nodegraph inputs, and traversal from a parent nodegraph `output` to a child nodegraph `output`
* "Inherited" properties (such as `fileprefix`, `colorspace`) evaluate properly through parent/child `nodegraph`s. This should already be the case.
* No "upgrade" path is required.
Contributor guide
Research direction
The issue names graph traversal logic, shader generation, and value evaluation as the entry points; begin by locating those subsystems and their existing nodegraph-to-nodegraph handling. Use the nested XML interface example to trace parent-to-child connections. Done means nested nodegraphs support the listed connection cases, inherited properties continue to evaluate correctly, and no upgrade path is required.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- computer-graphics
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100