Author Topic: [SOLVED] Create a graph from scratch  (Read 277 times)

I'm interested in automating the generation of a graph with Python.

By reading the Designer Scripting documentation, it looks like we can only access information in the graph, but not create it. Am I missing something ?

I also read about SAK and it seems it can do this, but I'm curious if we can do this directly from Designer.
Last Edit: October 15, 2020, 10:42:42 am

Reply to myself : there is a newNode() function which allow to create a graph node. So creating a graph from scratch should be possible.

I'm interested in something similar - generating graphs from an interchange format. We have the node creation and linking done, we are just caught on setting up the 3D View.

Our use case is converting UE4 Template Materials into a serialized format (JSON, YAML, etc.) with the various textures required. Based on that structure, we generate output nodes (with reasonable defaults).

Some code:
Code: [Select]
layout = ShaderDescriptor('ue4/shader/descriptor.json')
app = sd.getContext().getSDApplication()

# Generate a fresh package
new_package = app.getPackageMgr().newUserPackage()
graph = sd.api.sbs.sdsbscompgraph.SDSBSCompGraph.sNew(new_package)

# Set up the layout with all the required parts
layout.initialize_graph(graph)

# With the new graph, and the layout, we generate
for output_descriptor in layout:
    output_node = graph.newNode('sbs::compositing::output')

    # !! Ideally, in here, we can set this node to the appropriate view based on the material
    layout.intialize_output(output_descriptor, output_node)

If this isn't possible currently, that would be excellent to know too.

So, while it's not perfect, I was able to divine that a node can be set to the 3D View through the node "usages" - as long as you know the material the 3D View defaults to and can grep to the correct outputs.

Code: [Select]
# Build output
node = graph.newNode('sbs::compositing::output')

# Find the usage property
usage_prop = None
for p in node.getProperties(SDPropertyCategory.Annotation):
    if p.getLabel() == 'Usages':
        usage_prop = p
        break
else:
    print ("-- No property --")

# Create a new usage for this node
usage = sd.api.sdusage.SDUsage.sNew(
    'baseColor',         # !!! This is the real magic. Change to be metallic, specular, etc.
    'RGBA',
    '' # colorspace... TODO?
)
# Wrap in a usage
value_usage = sd.api.sdvalueusage.SDValueUsage.sNew(usage)

# Find the array of usages, append to it and set the prop value again
usage_array = node.getPropertyValue(usage_prop)
usage_array.pushBack(value_usage)
node.setPropertyValue(usage_prop, usage_array)

This accomplished, for all intents and purposes, what we're after for a interchange -> designer workflow. Hope this may one day help someone.

The python API, while better than some applications, is a bit non-pythonic. It could probably use a beauty pass. One important use would be to add a proxy layer to node property management. Something like:

Code: [Select]
# Generate a new node in graph 'graph'
uni = Node("uniform", graph)
output = Node("output", graph)

# Hook Up, use SDNode.outputs and SDNode.inputs as a property that wraps
# an underlying call to getting the properties and allowing for a simple connection
uni.outputs.unique_filter_output.connect(output.inputs.inputNodeOutput)

This is a node-based application after all. You don't have to have that functionality on the C++ or shim layer, just at the top of the python and monkey-patch the various proxy objects/methods. If I find time, perhaps I'll tinker with it.

Another answer to myself : there is a python sample showing exactly how to create a complete graph. It's located in:

Code: [Select]
%INSTALL_DIR%/resources/python/scripts/samples/sample_sbs_graph.py