NodeDelegate
The NodeDelegate is a higher level node abstraction, which can be used to simply query, modify or animate node’s attributes, including the transformation matrix.
That abstraction can be used on the maquina nodes, but also on nodes from a virtual scene, like from a USD scene.
See also
The C++ NodeDelegate and Python rumba.NodeDelegate documentation.
NodeDelegate basics
You can get a NodeDelegate from a Maquina node using the rumba.Node.node_delegate() method.
# Get the node delegate from a maquina node
nd = node.node_delegate()
# Print its name
print(nd.name())
# Print its path
print(nd.path())
# Get a child node
child_node = nd.child("child_name")
NodeDelegate attributes
# Access an attribute
show_attr = nd.show
# Query an attribute value as a boolean value
print(show_attr.value().as_bool())
NodeDelegate attributes modification
NodeDelegate makes it simple to modify or animate a node attribute. The rumba.ModificationContext
object can be used to control how the modification should be done.
# We assume here the node is animated on an editable layer.
# If it is not the case, the following commands silently fail.
# Start a modification undo step
rumba.modify_begin("Modify show")
# Set the node show attribute to True in its active layer
nd.show.set_value(True, rumba.ModificationContext.layer)
# Set the node show attribute to True and force to add a keyframe at the current time
nd.show.set_value(True, rumba.ModificationContext.animated)
# Set the node show attribute to False at frame 10 with a keyframe
nd.show.set_value(False, rumba.ModificationContext(rumba.ModificationContextSetValueMode.animated, 10.0))
# End of the modification undo step
rumba.modify_end()
NodeDelegate transformation
NodeDelegate gives access to a high level transformation model. The node has a single local matrix. The final world matrix is world_matrix = matrix * parent_world_matrix.
First, make sure the node has a transform node using rumba.NodeDelegate.has_transform().
In order to be animated, the matrix is decomposed in scale, rotation, rotate_pivot, scale_pivot, joint_orient and translation components. The scale, rotation, and translation components can be animated.
The final matrix composition is : matrix = scale_pivot^-1 * scale * scale_pivot * rotate_pivot^-1 * rotation * joint_orient * rotate_pivot * translation
Rotations are Euler angles in radians, the rotation order for rotation is given by
rumba.NodeDelegate.rotate_order(). The rotation order for joint_orient is XYZ.
Query the node transform:
# Make sure this node has a transform
if nd.has_transform():
# The local matrix at the current frame
m = nd.matrix()
# Get the node translation at the current frame
t = m.translation()
# Get the node scale at the current frame
s = nd.scale()
# Get the node rotation order
ro = nd.rotate_order()
# Get the node rotation at the current frame
r = nd.rotation()
# Get the node rotation at the frame 10
r = nd.rotation(rumba.QueryContext(10.0))
Modify the node transform:
# Get its local matrix
m = nd.matrix()
# Start a modification undo step
rumba.modify_begin("Move")
# Set the node translation in its active layer
nd.set_translation(m.translation()+Imath.V3d(1.0, 0, 0), rumba.ModificationContext.layer)
# Set the node translation and force to set a keyframe
nd.set_translation(m.translation()+Imath.V3d(1.0, 0, 0), rumba.ModificationContext.animated)
# Set the node translation at a different time
nd.set_translation(m.translation()+Imath.V3d(1.0, 0, 0), rumba.ModificationContext(rumba.ModificationContextSetValueMode.animated, 10.0))
# End of the modification undo step
rumba.modify_end()
Here is a full snapping example which set the local matrix of a node in order for the node to match the world space matrix of the target node at the current frame.
For simplicity, it does not handle scale_pivot, rotate_pivot and joint_orient.
def snap():
# Get the current selection as node delegate objects
selection = rumba.delegate_selection()
if len(selection) != 2:
return
# Our target node delegate
target = selection[1]
# Get the target world matrix to match
world_matrix = target.world_matrix()
# Start a modification undo step
rumba.modify_begin("Snap")
# Get the node delegate
nd = selection[0]
# Compute our new local matrix
local_matrix = world_matrix * nd.parent_world_matrix().inverse()
# Decompose the matrix
scale = Imath.V3d()
shear = Imath.V3d()
rotate = Imath.V3d()
translate = Imath.V3d()
Imath.extractSHRT(local_matrix, scale, shear, rotate, translate, False)
# Set the node transformation components in the active layer using the ModificationContext.layer mode.
# If the components are animated, it creates/modifies the keyframe.
# If it is not animated, if modifies the current layer's value in order to get those final values.
nd.set_scale(scale, rumba.ModificationContext.layer)
nd.set_rotation(rotate, rumba.ModificationContext.layer)
nd.set_translation(translate, rumba.ModificationContext.layer)
# End of the modification undo step
rumba.modify_end()