I’m procedurally generating material graphs in python which works ok, however I want to update changes made to the material. What I can’t figure out is which output pin of a MaterialExpression connects to the next Expression. I would really appreciate any help.
def testGraphTraversalBackwardTrace(mat, prop = unreal.MaterialProperty.MP_EMISSIVE_COLOR):
output_node = unreal.MaterialEditingLibrary.get_material_property_input_node(mat, prop)
assert output_node != None, "No Output in selected property "+ str(prop) +" in material "+mat.get_name()
inputs = unreal.MaterialEditingLibrary.get_inputs_for_material_expression(mat, output_node)
if len(inputs) == 0:
print("Found input node")
else:
for i, node in enumerate(inputs):
if node == None:
print("input not connected")
else:
print("Node " +node.get_name() +" connected to pin"+str(i) + " of node " + output_node.get_name())
# WHICH output pin of node is connected?
material_path = "/Game/MatGraph/TestMat"
if unreal.EditorAssetLibrary.does_asset_exist(material_path):
matasset = unreal.EditorAssetLibrary.find_asset_data(material_path).get_asset()
testGraphTraversalBackwardTrace(matasset)
LogPython: Node MaterialExpressionVectorParameter_0 connected to pin0 of node MaterialExpressionMultiply_0
LogPython: Node MaterialExpressionVectorParameter_1 connected to pin1 of node MaterialExpressionMultiply_0
I’m not sure this will help, but the “output node” in the material is basically the whole material.
Change to use material attributes in the settings, and it will be represented as one pin.
You then have to hook up noodles into a make material attributes node.
Meaning that finding individual inputs of a material the way you are currently going about is not a good idea.
Simulate or copy the code off of a BreakMaterialAttributes node.
That way no matter how materials are set up the code for it will always work and allow you to get the results of individual pins.
And since I have never had a look at it before, its totally possible that break material attributes uses similar code to what you already used above.
Thank you for your reply. I can actually iterate over all MaterialProperty elements and find out if there is something connected. The problem is that I don’t know the output pins of MaterialExpressions, e.g. the VectorParameter Param_1 could output R or B and I don’t know which.
If it’s a material expression there’s kind of no way to tell is there?
It could be a function that’s 5000 nodes long or 1 node. So solving it backwards recursively while possible is a nightmare.
What about just testing R G and B separately for values?
Usually when making materials the editor puts 0 in pins that aren’t connected.
So in the event that only one channel is used for Diffuse, the reading of R G and B would contain different parameters ?
Backtracing is simply convenient in my case since I’m not interested in nodes that float around without doing anything. I could also just get a flat list of MaterialExpressions like this:
filter = ( unreal.MaterialExpression )
it = unreal.ObjectIterator()
for x in it:
if x.get_outer() == material:
if isinstance(x, filter):
#append to list of expressions in material
I can’t find any method to access the output and so can’t check their value. There is only the default value (in many MaterialExpressions not even that).
if type(node) == unreal.MaterialExpressionVectorParameter:
print_properties(node)
print(node.get_editor_property("default_value"))
That is the actual data value and doesn’t change depending on what is connected. I took a look at the c++ sources of componentmask and others. There seems to be a lot of different ways to do this, the most frustrating is MaterialExpression->GetOutputs() which is exactly what I want but simply am unable to execute in python. Thank you for your help.
I had the same problem in traversing the material graph and there is a way to get the outputname:
Unreal.MaterialEditingLibrary.get_input_node_output_name_for_material_expression(material expression, connected material expression)
And for the material expressions connected to material property there is another method:
Unreal.MaterialEditingLibrary.get_material_property_input_node_output_name(material, material property)
You can find the methods in Umaterialedittinglibrary class in C++ documentation but they are exposed to python api too