Nodes

See also

The C++ Node and Python rumba.Node documentation.

Type

Nodes are typed. The basic type is Node, the document node type is Document. Node types can be derived.

  • python
import rumba
doc = rumba.active_document()

# Print the Python type of doc
print(type(doc))

# Print the maquina Node type of doc
print(doc.type_name())

# Print all the maquina Node types doc is inheriting
print(doc.bases())

# Test if a node matches a Node type
if doc.is_instance("Document"):
    print("OK")

# Find all the children or grandchildren Camera nodes
def find_all_cameras(node, name):
    cameras = []
    to_visit = [node]
    while to_visit:
        node = to_visit.pop()
        if node.is_instance("Camera"):
            cameras.append(node)
        for child in node.children():
            to_visit.append(child)
    return cameras
cameras = find_all_cameras(doc)

""" Produces :
<class 'rumba.Node'>
Document
['Document', 'Node']
OK
"""

See also

A node list.

Creation

To create a node, you need the node type name, the node name and the parent node where to create that node:

  • python
import rumba
# Get the document node
doc = rumba.active_document()
# Create a node named "Group" in the document
group = rumba.Node("Node", "Group", doc)
# Create a SceneGraphNode node named "Node" in the group node
node = rumba.Node("SceneGraphNode", "Node", group)

Naming And Path

A node has a name. Two nodes with the same parent must have different names. Multiple nodes may share the same name across the framework.

A node can be accessed by a path relative to a parent or grandparent node. The Document Path is the node path relative to its document. The Full Path is the path relative to the framework.

Nodes can be nested without any restriction. However some conventions might impose rules, for example, a document root node should be located in /documents.

The root node of maquina is the Framework node.

  • python
# Print the node's name
print(node.name())
# Print the node's document path
print(node.full_document_name())
# Print the node's full path
print(node.full_name())

""" Produces :
"Node"
"Group/Node"
"//documents/Document_0/Group/Node"
"""

Note

There is no Maya style namespaces in Rumba. See Prepare a Maya scene assembly. Reference clashes are solved by renaming the root node of the reference.

Children

Nodes may contain children nodes. Nodes can be children of the framework or not. If they don’t, they are detached nodes.

Here is how to access the children nodes:

  • python
# Get a child by its name
try:
    child = node.child("Bart")
    child = node.child("Kids/Bart")
except RuntimeError:
    # The child does not exist
    pass

# Iterate the children
for child in node.children():
    print(child.name())

# Get the first child or grandchild node matching a name
try:
    child = node.find_first("Bart")
except RuntimeError:
    # The child does not exist
    pass

# Find all the children or grandchildren matching a name
def find_all_children(node, name):
    nodes = []
    to_visit = [node]
    while to_visit:
        node = to_visit.pop()
        if node.name() == name:
            nodes.append(node)
        for child in node.children():
            to_visit.append(child)
    return nodes
children = find_all_children(node, "Bart")

Selection

Here is how to retrieve the node selection and print their full path:

  • python
selection = rumba.selection()
for node in selection:
    print(node.full_name())

Plugs

Nodes are composed of multiple Plugs, either static or dynamic. Static plugs are described during the node registration. Dynamic plugs can be created and removed on the fly.

A node contains plugs. Here is how to access a node plugs:

  • c++
  • python
// Get the show plug from the node
maquina::Plug show_plug = node.plug("show");

// Iterate the node plugs
for(const auto& plug : node.plugs())
    std::cout << plug.name() << std::endl;
# Get the show plug from the node
show_plug = node.plug("show")
show_plug = node.show           # alternative

# Iterate the node plugs
for plug in node.plugs():
    print(plug.name())

Note

Writing plug-ins, you should not have to deal so much with the Plug class.

Document

The loaded document (.rumba file) is contained in a single Document node. The document path from the Framework could be for instance /documents/my_document.

Reference

A node can be a reference of a node described in a file. For instance, a Seed2 rig in Rumba is a node located in /documents/my_project/seed2 referencing a seed2.rumbanode file located on the filesystem. A referenced node is a regular node, except that its contents won’t be serialized but replaced by a reference on the node file. Only the root referenced node plugs can be modified or connected.

Any node can be saved in a file (.rumbanode) and later imported or referenced.

Here is how to create a node referenced from a file

  • python
# Reference the "maracas.rumbanode" file in the doc node
node = rumba.reference(doc, "$(RUMBA_DATA)/props/maracas.rumbanode", "Maracas")

Registration

New node types can be created using a plug-in. An example of a node plug-in declaration and registration.

  • c++
  • python
using namespace maquina;

// The evaluation function
static Value eval_result( EvalContext& ctx )
{
    return ctx.as_float(0) + ctx.as_float(1);
}

// Register the node type
void register_MyAdd( Registry &r )
{
  r.register_node
  (
    "MyAdd", // The node type name
    "Node",  // The parent type name
    {
      // ** The node plugs declaration
      { "input1", 0.f }, // Input float
      { "input2", 0.f }, // Input float

      // Output
      { "result", 0.f, 0, "",
        // The output evaluation function
        eval_result,
        {
          // The output plug dependencies
          { "input1" }, // Dependance #0
          { "input2" }  // Dependance #1
        }
      },
    }
  );
}
from rumba import *

# The evaluation function
def eval_result(ctx):
    return ctx.as_float(0) + ctx.as_float(1)

# Register the node type
def rumba_register_plugins(registry):
    registry.register_node (
        "MyAdd", # Node type name
        "Node",  # Parent type name
        [
            # The node plugs declaration
            PlugDescriptor("input1", 0.0), # Input float
            PlugDescriptor("input2", 0.0), # Input float

            # Output
            PlugDescriptor("result", 0.0, 0, "", eval_result,
                [
                    # The output plug dependencies
                    PlugDescriptor.InternalDependencies("input1"), # Dependance #0
                    PlugDescriptor.InternalDependencies("input2")  # Dependance #1
                ]),
        ]
    )

Warning

It is not recommended to develop node plug-ins in Python. Python node plug-ins are drastically slower and not parallelizable. Python support for plug-ins is proposed only to port existing Maya Python plugins. A scripting node will be soon available in Rumba 2.0 to generate fast evaluation code using the Python syntax.