Coding with Aniseed - mikemalinowski/aniseed GitHub Wiki
Coding With Aniseed
If you want to add your own rigging components you can either:
-
Place your components within the aniseed/components folder (or subfolder). This is useful for small development studios or individuals.
-
Place your components in a folder and declare that folder path in an environment variable called ANISEED_RIG_COMPONENT_PATHS. This option is particularly useful for larger development studio's whom have a requirement to keep open source code seperate from their internally developed code.
Aniseed Classes
The Rig class is the one you will typically use as the entrypoint to working with Aniseed at a code level. The rig class gives a pointer to the node representing the rig as well as containing all the information about the components that form to make up the rigs execution.
Crucially it also gives access to the rigs configuration - which is covered below.
You can create a new rig using the following code. This will create a rig called MyNewRig in the scene. It will expose all the components that are available to aniseed out the box.
import aniseed
new_rig = aniseed.MayaRig(label="MyNewRig")
Alternatively, if there is already a rig in the scene, assuming the rig transform is called MyNewRig, you can do...
import aniseed
new_rig = aniseed.MayaRig(host="MyNewRig")
Now that you have a rig class instanced, you can start adding components to your rig. In this example we add some basic components to demonstrate.
new_component = new_rig.add_component(
component_type="simple_fk",
)
As well as just adding the component, we can define options and requirement values at the same time as adding the component, like so:
new_component = new_rig.add_component(
component_type="simple_fk",
requirements={
"Parent": "Foobar",
"Joints To Drive": ["A", "B", "C"],
},
options={
"Label": "Head",
}
)
The approach above allows you to specify values at the time of the components creation. However, you can also set these values directly on the component after creation too. This is done like this:
new_component = new_rig.add_component(
component_type="simple_fk",
)
new_component.requirement("Parent").set("Foobar")
new_component.requirement("Joints To Drive").set(["A", "B", "C"])
new_component.option("Label").set("Head")
The result between these two examples is exactly the same.
Now that we have components in our rig, we can build it. To do this is simply:
new_rig.build()
That will run through all the components in the rig and execute them.
Note that a rig must ALWAYS have a Rig Configuration component added to it in order to build. A RigConfiguration is nothing more than a component that exposes a specific set of parameters and functions that allow a user to tailor how a rig is built.
Aniseed comes packaged with a rig configuration which is designed to be flexible, however if you find that you need something more, you can always subclass the RigConfiguration component and implement your own. This is explained below.
Adding Components
Components are where most of the code exists within any Aniseed deployment. It is utlimately where all your rig building code resides. Out the box aniseed comes with a library of components that will hopefully allow you to create a variety of rigs but you can also extend it with your own additional components as well.
To do this, you will need to subclass the aniseed.RigComponent class. Here is a documented example:
import aniseed
import maya.cmds as mc
# -- The name of the class is not important but it must inherit
# -- from the RigComponent class
class MyCustomComponent(aniseed.RigComponent):
# -- All components require a unique identifier string
# -- to allow it to be dinstinguishable from other
# -- components
identifier = "my_custom_component_example"
# -- We need to re-implement the __init__. This is where we declare
# -- any options and requirements the component should have
def __init__(self, *args, **kwargs):
super(MyCustomComponent, self).__init__(*args, **kwargs)
# -- Here we are defining a requirement. A requirement is considered
# -- to be an input that this component needs fullfilling by the user
# -- in order to execute.
# -- Note that we can set validate to either true or false. If it is
# -- true then the requirement will be tested before execution to ensure
# -- that the user has a set a value.
self.declare_requirement(
name="Parent Node",
value=None,
validate=True,
)
# -- Now we will declare an option. Options are much like requirements
# -- except they are not typically mandatory and serve more to allow a
# -- user to tailor the execution of the component
self.declare_option(
name="Name Prefix",
value=""
)
# -- The run function is what is executed when a rig is built
def run(self):
# -- In our example we are just going to create a transform
# -- node and name and parent it to demonstrate how we access
# -- the properties we have declared
# -- Notice that when we access the requirement, we use .get()
# -- in order to get the actual value from the property
parent = self.requirement("Parent Node").get()
# -- We now do the same for the options
prefix = self.option("Name Prefix").get()
# -- At this point we're now just running vanilla maya code.
node = mc.createNode("transform")
mc.parent(
node,
parent,
)
mc.rename(
node,
prefix + "MyNode",
)
By default, the aniseed application will attempt to display requirements and options in the UI based on the variable type that they are set to. For instance, if you set a requirement as a string it will show it as a text field in the ui.
However, quite often we want to display our options in richer ways. For instance, whilst an object might be a string, it is useful to have a mechanism to allow the user to set it from the current selection, or to select the object.
This is done through the option_widget
and requirement_widget
functions which can
be re-implemented. Here is an example:
import aniseed
import PySide6
# -- The name of the class is not important but it must inherit
# -- from the RigComponent class
class MyCustomComponent(aniseed.RigComponent):
class MyCustomWidget()
That is a simple example of implementing a custom component in aniseed. In order to utilise your component it will need to be placed in a location where aniseed is set to search.
If you store your components outside of the aniseed base location (which is recommended) then you will need to pass your component folder to the rig at time of instancing using
import aniseed
rig = aniseed.MayaRig(
label="foo",
component_paths=["my/path/to/my/components"]
)
Alternatively you can add your component path to the following environment variable:
ANISEED_RIG_COMPONENT_PATHS
For studio deployments it is strongly recommended to use the environment variable approach and to keep your custom components seperate from the aniseed deployment.