Channels
See also
The C++ Channel and Python rumba.Channel documentation.
Node’s plugs and node delegate’s attributes may be modified by animation layers through channels.
A channel is an animated value computed by the animation graph, the graph responsible to blend the animation curve values together along the animation layers.
A channel can be assigned to animation layers. When assigned to a layer, the channel has specific values, constant or animated, on that layer.
Editable layers are the channel’s animation layers which accept modifications. Editable layers are enabled, unlocked (open for edition), with a constant value or an animation curve for that channel.
The target layer is the first channel’s editable layer. This is the layer where the user modifications are stored.
The channel API can be used to assign or remove Plugs or NodeDelegate attributes to the animation layers.
It can also be used to inspect or manipulate the values or animation curves on each layer.
Access channels
You can get channels from Plug, Node, NodeDelegate and NodeDelegate::Attribute objects:
// Iterate over a plug's channels, same for nodes, node delegates and node delegate's attributes.
for(const maquina::Channel& channel : plug.channels())
{
}
// Get the node's transform channels, same for plugs, node delegates and node delegate's attributes.
auto channel = node.channel(maquina::ChannelType::sx); // Scale X channel
if (channel)
{
}
// Get the plug's channel, same for node delegate's attributes.
channel = node.plug("rotate_order").channel();
if (channel)
{
}
# Iterate over a plug's channels, same for nodes, node delegates and node delegate's attributes.
for channel in plug.channels():
pass
# Get the node's transform channels, same for plugs, node delegates and node delegate's attributes.
channel = node.channel(rumba.ChannelType.sx) # Scale X channel
if channel:
pass
# Get the plug's channel, same for node delegate's attributes.
channel = node.plug("rotate_order").channel()
if channel:
pass
Channel layers
Using the Channel objects, you can access and modify the layer assignment.
// Get the channel's target layer
auto target_layer = channel->target_layer();
if (target_layer)
{
}
// Iterates the channel editable layers
for (const maquina::Node& layer : channel->layers())
{
// Is this channel editable on that layer ?
if (channel->is_editable(layer))
{
}
}
# Get the channel's target layer
target_layer = channel.target_layer()
if target_layer:
pass
# Iterates the channel editable layers
for layer in channel.layers():
# Is this channel editable on that layer ?
if channel.is_editable(layer):
pass
Channel values
Using the Channel objects, you can access and modify value in time and layers.
// Get the channel value at frame 20
float value = channel->as_float(20.0, *target_layer);
/* Set the channel to value+1 on layer target_layer
If the channel is animated, add a keyframe at the current time
The channel must have been be assigned to the layer */
channel->set_value(value+1.0, *target_layer);
/* Add a keyframe of value+1 at frame 20 on layer target_layer
Create an animation curve if not yet done
The channel must have been be assigned to the layer */
channel->set_key(value+1.0, 20.0, *target_layer);
# Get the channel value at frame 20
value = channel.as_float(20.0, target_layer)
""" Set the channel to value+1 on layer target_layer
If the channel is animated, add a keyframe at the current time
The channel must have been be assigned to the layer """
channel.set_value(value+1.0, target_layer)
""" Add a keyframe of value+1 at frame 20 on layer target_layer
Create an animation curve if not yet done
The channel must have been be assigned to the layer """
channel.set_key(value+1.0, 20.0, target_layer)
Animation curves and keyframes
You can also access and modify the animation curves.
// Get the animation curve node if it exists
auto animation_curve_node = channel->animation_curve_node(*target_layer);
if (animation_curve_node)
{
}
// Get the animation curve if it exists
auto anim_curve = channel->animation_curve(*target_layer);
if (anim_curve)
{
// Duplicate the current curve (never modify a value you got from the API)
maquina::AnimCurveFloat new_anim_curve = anim_curve->duplicate();
// Do we have keys selected in the curve editor ?
const bool anim_curve_keys_selected = maquina::anim_curve_keys_selected();
// Iterate, read and modify keyframes
// Only the selected keyframes if keys are selected in the curve editor or all the keyframes.
for (maquina::AnimCurveFloat::Key key : new_anim_curve.keys(anim_curve_keys_selected))
{
std::cout << key.key.x << " " << key.key.y << std::endl;
// Add 1.0 to every keyframes
key.key.y += 1.f;
// Replace the previous key
new_anim_curve.set_key(key);
}
// Set the new curve
channel->set_animation_curve(new_anim_curve, *target_layer);
}
# Get the animation curve node if it exists
animation_curve_node = channel.animation_curve_node(target_layer)
if animation_curve_node:
pass
# Get the animation curve if it exists
anim_curve = channel.animation_curve(target_layer)
if anim_curve:
# Duplicate the current curve (never modify a value you got from the API)
new_anim_curve = rumba.AnimCurveFloat(anim_curve.duplicate())
# Do we have keyframes selected in the curve editor ?
anim_curve_keys_selected = rumba.anim_curve_keys_selected()
# Iterate, read and modify keyframes
# Only the selected keyframes if keyframes are selected in the curve editor or all the keyframes.
for key in new_anim_curve.keys(anim_curve_keys_selected):
print (key.key.x, key.key.y)
# Add 1.0 to every keyframes
key.key.y += 1.0
# Replace the previous key
new_anim_curve.set_key(key)
# Set the new curve
channel.set_animation_curve(new_anim_curve, target_layer)
Complete tool example
Here is a complete animation tool example, with undo/redo, operating on the current channels and keys selection.
The tool rounds the time of the selected keyframes (all keyframes if no selection) on integer frames.
import rumba
# Start the document modification for undo/redo
rumba.modify_begin("Snap key times")
# True if there are key selected in the curve editor
anim_curve_keys_selected = rumba.anim_curve_keys_selected()
# Iterate through the selected nodes channels filtered by the ChannelBox
for channel in rumba.channel_selection():
layer = channel.target_layer()
if layer:
curve = channel.animation_curve(layer)
# Use the AnimCurve interface because it can handle any kind of animation curves
if curve:
# Always duplicate a Value coming from the document before to modify it
new_curve = rumba.AnimCurve(curve.duplicate())
# Iterates the selected keyframes if some are selected in the curve editor, or all of them
for key in new_curve.keys(anim_curve_keys_selected):
# Round and modify the key time
key.set_time(round(key.time()))
# No need to sort the keys or normalize the curve, Channel.set_animation_curve normalizes it
channel.set_animation_curve(new_curve, layer)
# End the document modification
rumba.modify_end()
See also
The C++ AnimCurveFloat and Python rumba.AnimCurveFloat documentation.