This is a technical document for advanced riggers who have a good knowledge of Python and wish to create their own nodes.

The documentation is divided into several pages.

Before you write your own node, please read all the documents thoroughly.


 

FOLDER STRUCTURE:

To start a new node, go to: 'arise\io_modules\io_modules_node'.

Here you can duplicate an existing node folder and modify the duplicate according to the steps below:

  • Rename the new top folder with the name of the new node.

  • If there are any, delete any numbered folders under 'version' folder except for '001'.

  • Under 'versions/001', delete the compiled (.pyc) file and create a new python file (.py) with the same name as the top folder.

  • In the 'icon_folder' you can change the 'icon.png' to give your new node its own icon. Keep it 36x36 pixels.

  • Later you can modify the 'docs.html' file under docs_folder with your own documentations in HTML.

(An example of a node folder structure)


{New in version 1.06.03} Added support for relative imports in Node modules. You can now place modules in the 'utils' folder of each Node version's directory, and they will automatically be imported into your main module. For example, if you create a 'helper_module.py' file in the 'utils' folder containing a method 'helper_method', you can call on it using 'helper_module.helper_method()'



PYTHON FILE STRUCTURE:

Use the code below as a starting point in your Python file (.py).
(Read the comments to understand the different sections of the class)

"""Your node docstring here. """

import logging

import maya.cmds as mc

from arise.data_types import node_data
from arise.utils.io_nodes.io_transform import IoTransform
from arise.utils import matrix_utils

LOGGER = logging.getLogger("node_rig_logger")

MAYA_VERSION = 2016  # the version of maya from which this module supports.
AUTHER = "Your Name Here"  # name of person who created this module.
RIG_CATEGORY = "Basic"  # either 'Basic', 'Cartoon', 'Vfx', 'Game' or 'All'.
RIG_TYPE = "All"  # Biped, Car, Quadruped, ..., All.
TAGS = ["basic", "base", "root", "top", "origin"]
TOOL_TIP = "Write your hover over tooltip text here"


class YourNode(node_data.NodeData):  # NODE CLASS NAME MUST MATCH MODULE NAME AND TOP FOLDER NAME! 
    """Your node docstring here. """
    sort_priority = 1000  # index of position in inventory nodes list.

    def __init__(self, parent, docs, icon, module_dict):
        node_data.NodeData.__init__(
            self,
            parent=parent,
            icon=icon,
            docs=docs,
            module_dict=module_dict
        )

    def attributes_creation(self):  # REIMPLEMENTED!
        """Here you add the module attributes. """


    def evaluate_creation_methods(self):  # REIMPLEMENTED!
        """Reimplemented to enable/disable attrs. """
        # If you have attributes that should be disabled/enabled based on another attribute value, you set the condition here.
        # if you do not need this method delete it from your code.
        # for example: self.geo_node_attr.set_disabled(False if self.is_geo_display_attr.value else True)

        node_data.NodeData.evaluate_creation_methods(self)  # keep this line at the end of your method.

    def guides_creation(self):
        """Create guides based on attributes values. """


    def joints_creation(self):
        """Create joints based on attributes values and guides. (Without positioning as this point). """


    def ctrls_creation(self):
        """Create controls based on attributes values, guides and joints. (Without positioning as this point). """
        

    def rig_creation(self):
       """Using the attributes values, guides, joints, and ctrls, build the rig. """


  1. MAYA_VERSION Any Maya version prior to this one will hide this node.
  2. RIG_CATEGORY, RIG_TYPE, and TAGS are used when filtering for nodes in the inventory UI.
  3. The class name should be changed from 'YourNode' to match the name of the module and top folder.



Now, after preparing an empty node, we can start writing the code of our new node.
An overview of the steps will be: 

  1. Create the node's attributes we see in the Attribute Editor.
  2. Create the guides of the node we will see when the node enters 'Template' mode.
  3. Declare the joints that our node will use.
  4. Declare the ctrls that our node will use.
  5. And finally we will create our rig in the rig_creation() method using the attributes, guides, joints, and ctrls we previously created.


ATTRIBUTES_CREATION METHOD:

The first step is to populate the node attributes, then we can use their values in other methods that create the guides, joints, ctrls, and finally the method that creates the rig itself.

In the attributes_creation() method, you create the attributes that will populate the Arise attribute editor.

Each command that creates an attribute returns a pointer of the attribute object, or None if something went wrong.

By storing the attributes' as class variables (example: self.my_attribute), you can access their values in other methods.

Name, version, and note attributes are automatically created.

Documentations on attributes creation commands.



EVALUATION_CREATION METHODS:
Next we have the evaluate_creation_methods() method that is called whenever an attribute changes value.
Its purpose is to disable or enable attributes based on other attributes values.
This is an optional method to use only if you want specific attributes disabled under certain conditions.

For example:

self.world_orientation_attr.set_disabled(True if self.clean_transformations_attr.value else False)



GUIDES_CREATION METHOD:
The next method is guides_creation() which is where we will declare our node's guides.

We will not create the guides, but rather objects that store instructions for creating them.

This method is also called and refreshes whenever an attribute value changes, meaning we can use the values of the attributes we created in the previous attributes_creation() method, like if we want an attribute that controls the number of guides.


Documentations on guides creation commands.



JOINTS_CREATION METHOD:
The joints_creation() method is where we declare our joints.
Same as with our guides, we will not create our joints but instead we will create objects that will store the instructions on how to create them.

This method is also called and refreshes whenever an attribute value changes, meaning we can use the values of the attributes we created in the attributes_creation() method, like if we want an attribute that controls the number of joints.
The rig_creation() method should never create joints; all joints should be declared here.

Be sure to store the joints you declare as class variables.


There is only one command to create a joint:


self.add_joint(name, skinning_jnt, tag_parent_jnt=None, radius=0.5)
Declare a joint that will be created when node switches to 'Build' state, but first must be declared in the joints_creation() method.
Arguments:
  • name {str} -- only the joint name. Node name prefix and '_jnt' suffix will be added automatically
  • skinning_jnt {bool} -- True to mark this joint as a skinning joint, False to mark it as a helper joint that shouldn't be used in the skinning process
  • tag_parent_jnt {another joint} -- this will mark another joint declared in this method as it's 'parent' it will not parent the joint to it when the joint is created but will help attachments such as 'FollowSkeleton', (default: None)
  • radius {float} -- display size of joint (default: {0.5})



CTRLS_CREATION METHOD:
The ctrls_creation() method is where we declare our ctrls.
Same as with our guides and joints, we will not create our joints but instead create objects that will store the instructions on how to create them.

This method is also called and refreshes whenever an attribute value changes, meaning we can use the attributes values here too.
The rig_creation() method should never create ctrls; all the ctrls should be declared here.

Be sure to store the ctrls you declare as class variables.

To create a ctrl:


self.add_ctrl(name, shape="circle", up_orient="+Y", size=1)
Declare a control (transform + shape + parent offset_grp) that will be created when node switches to 'Build' state, but first must be declared in the ctrls_creation() method.
Arguments:
  • name {str} -- only the ctrl name. Node name prefix and '_ctrl' suffix will be added automatically
  • shape {str} -- shape of the ctrl based on names in ctrls_shapes_dict.py (default: {"circle"}) [shapes lookup]
  • up_orient {str} -- direction the ctrl shape orients. "+Y", "-Y", "+X", "-X", "+Z", "-Z" (default: {"+Y"})
  • size {float or list} -- the size of the ctrl shape. Float value will scale uniformly, list value of XYZ will scale non-uniformly (default: {1})
Class variables you can modify after creation:
  • line_with {float} -- the ctrl curve thickness (default: {-1.0})
  • color {list, tuple} -- 3 floats between 0-1 representing RGB color of ctrl. Default color will be based on node name prefix.
  • translate_offset {list} -- of 3 floats [X,Y,Z]. The offset of the ctrl shape from its pivot.
  • rotate_offset {list} -- of 3 floats [X,Y,Z]. The rotation offset of the ctrl shape, not the ctrl orientations
  • tag_as_ctrl {bool} -- True to tag the ctrl as a ctrl, which Arise' tools use to identify ctrls within a scene (default: True)


Class methods you can use after creation:

  • add_limit_attr(attr, min_active=False, min_value=None, max_active=False, max_value=None)
    Add limits to a transformation attribute on the ctrl.
    Arguments:
  • attr {str} -- full name of an attribute e.g. "translateX"
  • min_active {bool} -- if min limit is active
  • min_value {float} -- min limit (even when min limit is inactive it needs a value)
  • max_active {bool} -- if max limit is active
  • max_value {float} -- max limit (even when max limit is inactive it needs a value)

  • add_hidden_attr(attr)
    Hide a transformation attribute on the ctrl.
    (A ctrl visibility attribute is hidden by default.)
    Arguments:
  • attr {str} -- full name of an attribute e.g. "translateX"

  • add_locked_attr(sttr)
    Lock a transformation attribute on the ctrl. 
    (A ctrl visibility attribute is locked by default.)
    Arguments:
  • attr {str} -- full name of an attribute e.g. "translateX"

RIG_CREATION METHOD:
The rig_creation() method is where all of our previous setups come together and we create our Maya rig parts.
Since we stored our attributes, guides, joints, and ctrls as class variables, we can access them in this method.


Accessing Attributes Values:
We can access our attributes values as described in the attributes creation commands
Usually by calling: 'self.my_attribute.value'

   

Accessing guides values:

With any type of guide, we can access its values using the following commands:


self.my_guide.world_transformations["translate"] -- {list} of 3 floats representing the guide position [X,Y,Z] in world space.

self.my_guide.world_transformations["rotate"] -- {list} of 3 floats representing the guide rotation [X,Y,Z] in world space.

self.my_guide.world_transformations["is_mirrored"] -- {bool} True if node is mirrored False if not.

self.my_guide.world_transformations["matrix"] -- {list} of 16 floats representing the guide matrix in world space with normalized scale.



Accessing the node joints:

Arise creates the joints we declared previously, during the 'Build' process. 

You can access them by calling:


self.my_joint.pointer -- {IoJoint} returns an object, much like a PyMel object


The returned IoJoint had its __repr__ reimplemented to return the joint long name so you can still use it with Maya's cmds library, as if it was a variable storing the string name of the joint.
For example: cmds.xform(self.my_joint.pointer, q=True, matrix=True)

In addition to using IoJoint as a variable holding the joint name, you can also access its methods.
You can see its methods and variables in the IoJoint document.



Accessing the node ctrls:

Much like the joints, Arise creates the ctrls we declared previously, during the 'Build' process.
You can access them by calling:


self.my_ctrl.pointer -- {IoTransform} returns an object, much like a PyMel object


Since every ctrl also has an 'offset_grp' above it, you can access it by calling:


self.my_ctrl.pointer.offset_grp -- {IoTransform} returns an object, much like a PyMel object


The IoTransform is very similar to the IoJoint and just like it, can be used as a variable that holds the ctrl name and to use its methods.



Setting up driven and driver attributes:
There should be at least one driver and at least one driven attribute on every node.
Those attributes also appear on the node shapes themselves and with them we connect nodes to one another.
We set them up as follows:

  1. First creating them in the attributes_creation() using the self.add_driver_attribute and the self.add_driven_attribute commands. Check the attributes creation document for more information.
    The driven attribute holds all the arguments on how the connection is made, the type of connection, maintain offset, skip attributes, and etc.

  2. In the rig_creation() method, after we created the whole rig in Maya, we assign one or more Maya transforms we created, such as the rig top groups or the top joints, to the driven attribute.
    To assign a transform or transforms to the driven attribute we use the 'set_maya_object' method which can take values of type: string, list, tuple, IoJoint, and IoTransform.
    For Example: self.my_driven_attr.set_maya_object([input_root_grp_A, input_root_grp_B])

  3. We also assign a single Maya transform to the driver attribute. Usually a transform at the tip of our node, like the end of our arm or tip of our foot.
    We use the same method of 'set_maya_object' which can take values of type: string, IoJoint, or IoTransform.
    For Example: self.my_driver_attr.set_maya_object(output_root_grp)

If a Maya attribute with the same name is present on both the driver and the driven Maya objects, Arise will connect between them. This enables the transfer of custom information between different parts of the rig.



And that's it!
Although a little complicated, this will ensure that your node can work with Arise logic, attachments, and tools.



_____________________________________________

Get Arise at: https://www.ariserigging.com

Follow on LinkedIn