From what I can tell, in Python you need to get a Blueprint object, then get the controller for the blueprint.
It’s the MVC programming pattern; model, view, controller. The model is the graph itself, the view is the viewport, and the controller is what allows the two to interact.
However, I was only able to accomplish this with ControlRig and using control rig’s python log in the messages window.
As an example, here’s the code I used in Python after getting the control rig’s Blueprint:
def add_forward_solve(cls, bp_rig: unreal.ControlRigBlueprint):
controller = bp_rig.get_controller_by_name('RigVMModel')
script_path = '/Script/ControlRig.RigUnit_'
# Add the Forward Solve Event node
node_name = 'BeginExecution'
controller.add_unit_node_from_struct_path(script_struct_path=script_path + node_name,
position=unreal.Vector2D(0.0, 0.0),
node_name='RigUnit_' + node_name)
# Add the for_each node
node = unreal.StringLibrary.conv_string_to_name(
'DISPATCH_RigVMDispatch_ArrayIterator(in Array,out Element,out Index,out Count,out Ratio)'
)
controller.add_template_node(node,
unreal.Vector2D(256.0, 0.0),
'DISPATCH_RigVMDispatch_ArrayIterator')
# add the GetAllControls node
node_name = 'CollectionGetAll'
controller.add_unit_node_from_struct_path(script_struct_path= script_path + node_name,
position=unreal.Vector2D(-160.0, 80.0),
node_name=node_name)
controller.set_pin_default_value(pin_path='CollectionGetAll.TypeToSearch',
default_value='Control',
resize_arrays=False)
controller.add_link('CollectionGetAll.Items',
'DISPATCH_RigVMDispatch_ArrayIterator.Array')
# Attach Execution from Forward Solve
controller.add_link('RigUnit_BeginExecution.ExecuteContext',
'DISPATCH_RigVMDispatch_ArrayIterator.ExecuteContext')
# Get Bone Transform from Element
node_name = 'GetTransform'
controller.add_unit_node_from_struct_path(script_struct_path= script_path + node_name,
position=unreal.Vector2D(512.0, 208.0),
node_name=node_name)
controller.set_pin_expansion('GetTransform.Item', False)
controller.set_pin_default_value('GetTransform.Space', 'GlobalSpace')
controller.set_pin_default_value('GetTransform.bInitial', 'False')
controller.add_link('DISPATCH_RigVMDispatch_ArrayIterator.Element',
'GetTransform.Item')
# Set Bone Transform
node = unreal.StringLibrary.conv_string_to_name(
'Set Transform::Execute(in Item,in Space,in bInitial,in Value,in Weight,in bPropagateToChildren)',
)
controller.add_template_node(notation=node,
position=unreal.Vector2D(869.0, 0.0),
node_name='Set Transform')
controller.set_pin_expansion('Set Transform.Item', True)
controller.set_pin_default_value('Set Transform.Item',
'(Type=Bone,Name="None")')
controller.set_pin_default_value('Set Transform.Space', 'GlobalSpace')
controller.set_pin_default_value('Set Transform.bInitial', 'False')
controller.set_pin_default_value('Set Transform.Weight', '1.0')
controller.set_pin_default_value('Set Transform.bPropagateToChildren', 'True')
controller.add_link('GetTransform.Transform', 'Set Transform.Value')
# Add the Name replacement node
node = unreal.StringLibrary.conv_string_to_name('Replace::Execute(in Name,in Old,in New,out Result)')
controller.add_template_node(notation=node,
position=unreal.Vector2D(576.0, 64.0),
node_name='Replace')
controller.add_link('DISPATCH_RigVMDispatch_ArrayIterator.Element.Name',
'Replace.Name')
controller.set_pin_default_value('Replace.Old','CRC_', False)
controller.add_link('Replace.Result', 'Set transform.Item.Name')
controller.add_link('DISPATCH_RigVMDispatch_ArrayIterator.ExecuteContext',
'Set Transform.ExecuteContext')
Figuring out the names and types of nodes to add to the graph is probably going to be very difficult, but as I need this for work, I’ll continue to naturally chase down where these things can be found.