Process/Addons/Rigify/RigClass
Implementing a Rig
Each rig component is implemented as a Rig
class located in a separate module
within the rigs
sub-package of a feature set or Rigify itself. This explains
how it is done.
BaseRig class
All new rigs should inherit either directly or indirectly from rigify.base_rig.BaseRig
,
which implements the basic interface of a rig component. Classes that do not inherit from
BaseRig
are considered to be using the deprecated legacy interface.
This class manages a number of standard fields that represents relations between the rig, bones, and other rigs. It also provides a set of utility methods, as well as empty methods to be overridden.
Fields
All rigs have the following standard fields provided by the base class:
obj
- The armature Object of the rig being generated.
base_bone
- Name of the main ORG bone of the rig component (the one holding its type and parameters).
params
- Parameter property collection for the rig component.
generator
- Reference to the main object managing the generation process.
script
- Reference to the object managing generation of the UI script.
bones
- A dictionary for storing names of the bones. Uses BoneDict, which allows access to contents via attribute syntax instead of requiring the regular dictionary access syntax. The standard layout is to store ORG bones coming from the metarig in
bones.org
, control bones inbones.ctrl
, mechanism inbones.mch
and deformation bones inbones.deform
. The dictionary may contain strings, lists and nestedBoneDict
s.
rigify_parent
- Parent rig of the current rig, i.e. the rig that owns the parent of the main bone.
rigify_children
- List of child rigs.
rigify_org_bones
- Set of ORG bones owned by the rig; equal to flattened
bones.org
.
rigify_child_bones
- Set of ORG bones that are children of ORG bones owned by this rig, and aren't owned by any other rig.
rigify_new_bones
- Dictionary of bones generated by the rig, mapping them to the name of the bone they were copied from, if applicable.
rigify_derived_bones
- Reverse of the
rigify_new_bones
dictionary, mapping originals to sets of bones copied from them.
Note: The term 'ORG bones' refers to bones that were copied directly from the metarig, as their names are prefixed with ORG-
during the initial stages of the generation process. By convention, Rigify also prefixes internal 'mechanism' bones with MCH-
, and deforming bones with DEF-
.
Methods
BaseRig
by itself primarily provides the following methods:
rig.__init__(generator, pose_bone)
- Initializes the rig component. Unlike the legacy rig interface, normal rig components are not expected to override
__init__
itself.
rig.find_org_bones(pose_bone)
callback- This method should be overridden to define which ORG bones are exclusively owned by this rig, and will be used in the generation process. It is called by
__init__
to computebones.org
, and indirectlyrigify_org_bones
. - May return a single name, a list of names, or a
BoneDict
.
It also provides many more utility and callback methods by inheriting from other mixin classes. For example:
rig.report_error(message, ...)
from rigify.utils.errors.RaiseErrorMixin- Throws an exception reporting a generation error, using the message with added information about the rig component itself. The message is presented using
message.format(...)
.
rig.get_bone(name)
from BoneUtilityMixin- Returns the
PoseBone
orEditBone
with the specified name, based on the current mode.
rig.make_constraint(bone_name, con_type, subtarget=None, ...)
from MechanismUtilityMixin- Adds and returns a new constraint to the given bone. Named arguments are used to initialize properties of the constraint.
For more details see the information about the mentioned mixin classes.
Generation Stages
In order to avoid frequent object mode switches, as well as to facilitate interaction between rigs, the generation process is performed in stages. Each stage is represented by a callback method, and all callbacks of the same stage are called for all rigs before proceeding to the next stage.
Each stage is called in a specific mode, and is intended for a specific kind of activity. Rigs should not switch modes themselves.
Stage Order
Before all stage processing starts, Rigify copies the metarig, renames bones to ORG-
, instantiates all rig components, and links them to each other and bones via the above mentioned parent-child fields. After that it proceeds to execute stages in order:
initialize
- This stage is called in Object mode to allow rigs to collect information about the bones and other rigs, so rigs may not change the armature in any way. This stage takes the place of
__init__
in really initializing the rig.
prepare_bones
- Called in Edit mode to allow rigs to align and adjust ORG bone positions and orientations before generating new bones.
generate_bones
- Called in Edit mode to let the rigs generate new bones. This is the only stage that can add bones.
parent_bones
- Called in Edit mode to allow setting the parent links and other Edit mode properties after all bones have been generated.
configure_bones
- Called in Object mode to set bone transformation mode, layers, create custom properties. Existing rigs also generate the UI script panels here. Can be used to add constraints that need to be applied during rig creation.
preapply_bones
- Called in Object mode to allow reading bone positions after constraints that were added during the
configure_bones
stage are evaluated.
apply_bones
- Called in Edit mode to allow final adjustments to the rest pose, e.g. to apply a temporary constraint added in the
configure_bones
stage.
rig_bones
- Called in Object mode to create all constraints, drivers and other mechanics of the rig.
generate_widgets
- Called in Object mode to create all bone widget objects.
finalize
- Called in Object mode at the very end of generation to do final processing, e.g. used internally to emit the UI script.
Stage Callbacks
The rig classes can run code in a stage in two ways. The simplest is to override the method with the name of the stage. The more advanced way is to use a decorator to mark an arbitrary method as belonging to a stage.
The direct callback is called first, followed by the custom decorated methods:
def generate_bones(self):
print('first')
@stage.generate_bones
def foo(self):
print('second')
If decorated methods are overridden in a subclass, the decorator must be repeated for code clarity reasons, or a warning will be printed to the console.
Multiple methods decorated with the same stage are called in the order of first definition, with class bodies scanned in reverse MRO order in case of inheritance:
class Base(...):
@stage.generate_bones
def first(self):...
@stage.generate_bones
def second(self):...
class Derived(Base):
@stage.generate_bones
def third(self):...
# Was first defined in Base so still first:
@stage.generate_bones
def first(self):...
@stage.generate_bones
def fourth(self):...
The callbacks of any rig instance are called after all callbacks for all of its parent rigs for that stage are completed.
However, for clarity, it is best not to rely on this order unless absolutely necessary, and write code as if the order within the stage was undefined, especially for the decorated callbacks. In some case this can be achieved by pre-calculating some data in a previous stage, or in the non-decorated direct callback.
Staged Sub-Components
All classes that support stages (i.e. inherit from GenerateCallbackHost
) also support having staged sub-objects. This is achieved via two attributes:
rigify_sub_objects
- A sequence of staged sub-objects of this object, used for recursive walk by the
rigify_invoke_stage
method. The default static value is an empty tuple, so adding items requires replacing it with a list first.
rigify_sub_object_run_late
- When false, this sub-object's stages are executed after its owner's direct callback and before the decorated methods. If true, this sub-object is processed after the decorated methods.
Two classes are provided to aid implementing sub-objects of rig classes: RigComponent
and LazyRigComponent
. They have the following attributes and methods:
owner
- The rig object that owns this component.
obj
- The armature Object of the rig being generated.
is_component_enabled
- This
LazyRigComponent
is already added to its owner's sub-objects.
component.__init__(owner)
- Initializes the component. For
RigComponent
immediately adds itself to the owner's list.
component.enable_component()
- Adds this
LazyRigComponent
to its owner's list (unless it is already added).
The components also inherit from BoneUtilityMixin and MechanismUtilityMixin to provide the usual utility methods.
It is not strictly necessary to inherit from these two classes if the owner's sub-object list is managed in some other way; the minimum necessary base for a sub-object is just GenerateCallbackHost
. This base class also means sub-objects can have sub-objects of their own.
Rig Parameters and UI
The rig components can have custom parameters, which can be set by the user via a panel in metarig Bone properties that appears when the matching rig type is selected. Registration of the parameters and UI layout of the panel are implemented via special callbacks.
Rig.add_parameters(params)
classmethod- Called to allow rigs to register their parameters via assigning
bpy.props
definitions to attributes of the parameter group. - All rigs share the same property group, so it is necessary to use descriptive property names to avoid conflicts. Rigify will detect incompatible redefinitions and print a warning to the console.
Rig.parameters_ui(layout, params)
classmethod- Called from the panel's
draw
method to present the rig-specific parameters.
Rig.on_parameter_update(context, pose_bone, params, param_name)
classmethod- Called when a parameter is changed by the user.
Rig Sample
Rigs normally provide a usage sample that can be added to a metarig in edit mode via a property panel. The sample is implemented by using the 'Encode Sample to Python' operator in armature edit mode, and pasting the resulting create_sample
function into the module of the rig component.
Guidelines
This describes some organization guidelines used for the new style Rigify rig code.
Store bone names in rig.bones
Since mode switches invalidate bone references, only names can be stored between stages. As a common convention, store names of all generated bones inside rig.bones
, separated by their purpose into control, mechanism and deform groups.
Fields of the class may be used to store extra redundant references for stage interaction purposes.
Stage decorators are provided so that all code related to a specific group of bones could be kept together, even though in reality it is split into stages, and executed interleaved with other groups of bones.
Thus, all bones of a rig should be split into logical groups, and all code for a group implemented as decorated stage callbacks placed together in the logical sequence.
The initialize
and prepare_bones
stages may/should be implemented as regular method overrides, since they only deal with the initial group of bones. The following stages should only use the regular override callbacks to collect data before any changes are applied. The finalize
stage is expected to be only rarely used, and no guideline is provided.
Avoid big loop bodies
Bodies of loops over bones should at most consist of one function call or assignment. More complex code should be split into a separate method, and the loop counter parameter provided even if not needed by the loop body. For standard rigs included in Rigify, the body should always be split into a method.
This makes it easier to subclass the rig later and slightly modify the behavior of the loop body for specific bones, without having to replace the whole loop.
Example
This demonstrates the above guidelines via a slightly simplified version of the SimpleChainRig
class.
class Rig(BaseRig):
"""A rig that consists of 3 connected chains of control, org and deform bones."""
def find_org_bones(self, bone):
return [bone.name] + connected_children_names(self.obj, bone.name)
def initialize(self):
if len(self.bones.org) <= 1:
self.raise_error("Input to rig type must be a chain of 2 or more bones.")
##############################
# BONES
#
# org[]:
# ORG bones
# ctrl[]:
# Control chain.
# deform[]:
# DEF bones
#
##############################
##############################
# Control chain
@stage.generate_bones
def make_control_chain(self):
self.bones.ctrl = map_list(self.make_control_bone, count(0), self.bones.org)
def make_control_bone(self, i, org):
return self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=True)
@stage.parent_bones
def parent_control_chain(self):
self.parent_bone_chain(self.bones.ctrl, use_connect=True)
@stage.configure_bones
def configure_control_chain(self):
for args in zip(count(0), self.bones.ctrl, self.bones.org):
self.configure_control_bone(*args)
def configure_control_bone(self, i, ctrl, org):
self.copy_bone_properties(org, ctrl)
@stage.generate_widgets
def make_control_widgets(self):
for ctrl in self.bones.ctrl:
self.make_control_widget(ctrl)
def make_control_widget(self, ctrl):
create_bone_widget(self.obj, ctrl)
##############################
# ORG chain
@stage.rig_bones
def rig_org_chain(self):
for args in zip(count(0), self.bones.org, self.bones.ctrl):
self.rig_org_bone(*args)
def rig_org_bone(self, i, org, ctrl):
self.make_constraint(org, 'COPY_TRANSFORMS', ctrl)
##############################
# Deform chain
@stage.generate_bones
def make_deform_chain(self):
self.bones.deform = map_list(self.make_deform_bone, count(0), self.bones.org)
def make_deform_bone(self, i, org):
return self.copy_bone(org, make_derived_name(org, 'def'), parent=True, bbone=True)
@stage.parent_bones
def parent_deform_chain(self):
self.parent_bone_chain(self.bones.deform, use_connect=True)
@stage.rig_bones
def rig_deform_chain(self):
for args in zip(count(0), self.bones.deform, self.bones.org):
self.rig_deform_bone(*args)
def rig_deform_bone(self, i, deform, org):
self.make_constraint(deform, 'COPY_TRANSFORMS', org)