From 123dd495bd8bc035a471a836cbed57bec72364d4 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Thu, 2 Dec 2010 01:52:04 +0000 Subject: Added a readme file that gives a brief explanation of the internals of Rigify and how to write your own rig types. --- rigify/README | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 rigify/README (limited to 'rigify') diff --git a/rigify/README b/rigify/README new file mode 100644 index 00000000..ae26c806 --- /dev/null +++ b/rigify/README @@ -0,0 +1,238 @@ +INTRODUCTION +------------ +Rigify is an auto-rigging system based on a "building blocks" paradigm. The +user can create a rig by putting together any combination of rig types, in any +confguration that they want. + +A rig type is something like "biped arm" or "spine" or "finger". + +The input to the Rigify system is something called a "metarig". It is an +armature that contains data about how to construct the rig. In particular, it +contains bones in the basic configuration of the rig, with some bones tagged +to indicate the rig type. + +For example, a metaig might contain a chain of three bones, the root-most of +which is tagged as being a biped arm. When given as input to Rigify, Rigify +will then generate a fully-featured biped arm rig in the same position and +proportions as the 3-bone chain. + +One could also have another chain of bones, the root-most of which is tagged as +being a spine. And the root-most bone of the arm chain could be the child of +any of those spine bones. Then the rig that Rigify would generate would be a +spine rig with an arm rig attached to it. + + +THE GUTS OF RIGIFY, SUMMARIZED +------------------------------ +The concept behind rigify is fairly simple. It recieves an armature as input +with some of the bones tagged as being certain rig types (arm, leg, etc.) + +When Rigify recieves that armature as input, the first thing it does is +duplicate the armature. From here on out, the original armature is totally +ignored. Only the duplicate is used. And this duplicate armature object will +become the generated rig. + +Rigify next prepends "ORG-" to all of the bones. These are the "original" +bones of the metarig, and they are used as the glue between rig types, as I +will explain later. + +Rigify then generates the rig in two passes. The first pass is the +"information gathering" stage. + +The information gathering stage doesn't modify the armature at all. It simply +gathers information about it. Or, rather, it lets the rig types gather +information about it. +It traverses the bones in a root-most to leaf-most order, and whenever it +stumbles upon a bone that has a rig type tagged on it, it creates a rig-type +python object (rig types will be explained further down) for that rig type, +and executes the resulting object's information gathering code. + +At the end of the information gathering stage, Rigify has a collection of +python objects, each of which know all the information they need to generate +their own bit of the rig. + +The next stage is the rig generation stage. This part is pretty simple. All +Rigify does is it loops over all of the rig-type python objects that it created +in the previous stage (also in root-most to leaf-most order), and executes +their rig-generate code. All of the actual rig generation happens in the +rig-type python objects. + +And that's pretty much it. As you can see, most of the important code is +actually in the rig types themselves, not in Rigify. Rigify is pretty sparse +when it comes right down to it. + +There is one final stage to rig generation. Rigify checks all of the bones +for "DEF-", "MCH-", and "ORG-" prefixes, and moves those bones to their own +layers. It also sets all of the "DEF-" bones to deform, and sets all other +bones to _not_ deform. And finally, it looks for any bone that does not have +a parent, and sets the root bone (which Rigify creates) as their parent. + + +THE GUTS OF A RIG TYPE, BASIC +----------------------------- +A rig type is simply a python module containing a class named "Rig". The Rig +class is only required to have two methods: __init__() and generate() + +__init__() is the "information gathering" code for the rig type. When Rigify +loops through the bones and finds a tagged bone, it will create a python +object from the Rig class, executing this method. +In addition to the default "self" parameter, __init__() needs to take the +armature object, the name of the bone that was tagged, and the bone's rig type +parameters object. + +A proper rig-type __init__() will look like this: + + def __init__(self, obj, bone, params): + # code goes here + +At the bare minimum, you are going to want to store the object and bone name +in the rig type object for later reference in the generate method. So: + + def __init__(self, obj, bone, params): + self.obj = obj + self.org_bone = bone + +Most rig types involve more than just that one bone, though, so you will also +want to store the names of any other relevant bones. For example, maybe the +parent of the tagged bone: + + def __init__(self, obj, bone, params): + self.obj = obj + self.org_bone = bone + self.org_parent = obj.data.bones[bone].parent.name + +It is important that store the _names_ of the bones, and not direct references. +Due to how the armature system in Blender works, when flipping in and out of +edit mode, pose-bone and edit-bone references get lost. (Arg...) + +Remember that it is critical that the information-gathering method does _not_ +modify the armature in any way. This way all of the rig type's info-gathering +methods can execute on a clean armature. Many rig types depend on traversing +parent-child relationships to figure out what bones are relevant to them, for +example. + + +Next is the generate() method. This is the method that Rigify calls to +actually generate the rig. It takes the form: + + def generate(self): + # code goes here + +It doesn't take any parameters beyond "self". So you really need to store any +information you need with the __init__() method. + +Generate pretty much has free reign to do whatever it wants, with the exception +of two simple rules: +1. Other than the "ORG-" bones, do not touch anything that is not created by +this method (this prevents rig types from messing each other up). +2. Even with "ORG-" bones, the only thing you are allowed to do is add children +and add constraints. Do not rename them, do not remove children or +constraints, and especially do not change their parents. (Adding constraints +and adding children are encouraged, though. ;-)) This is because the "ORG-" +bones are the glue that holds everything together, and changing them beyond +adding children/constraints ruins the glue, so to speak. + +In short: with the exception of adding children/constraints to "ORG-" +bones, only mess with things that you yourself create. + +It is also generally a good idea (though not strictly required) that the rig +type add constraints to the "ORG-" bones it was generated from so that the +"ORG-" bones move with the animation controls. +For example, if I make a simple arm rig type, the controls that the animator +uses should also move the "ORG-" bones. That way, any other rig-types that are +children of those "ORG-" bones will move along with them. For example, any +fingers on the end of the arm. + +Also, any bones that the animator should not directly animate with should have +their names prefixed with "DEF-" or "MCH-". The former if it is a bone that +is intended to deform the mesh, the latter if it is not. +It should be obvious, then, that a bone cannot be both an animation control and +a deforming bone in Rigify. This is on purpose. + +Also note that there are convenience functions in utils.py for prepending +"DEF-" and "MCH-" to bone names: deformer() and mch() +There is also a convenience function for stripping "ORG-" from a bone name: +strip_org() +Which is useful for removing "ORG-" from bones you create by duplicating +the "ORG-" bones. +I recommend you use these functions instead of manually adding/stripping +these prefixes. That way if the prefixes are changed, it can be changed in +one place (those functions) and all the rig types will still work. + + +THE GUTS OF A RIG TYPE, ADVANCED +-------------------------------- +If you look at any of the rig types included with Rigify, you'll note that they +have several more methods than just __init__() and generate(). +THESE ADDITIONAL METHODS ARE _NOT_ REQUIRED for a rig type to function. But +they can add some nifty functionality to your rig. + +Not all of the additional methods you see in the included rig types have any +special purpose for Rigify, however. For example, I often create separate +methods for generating the deformation and control rigs, and then call them +both from the main generate() method. But that is just for organization, and +has nothing to do with Rigify itself. + +Here are the additional methods relevant to Rigify, with brief decriptions of +what they are for: + + +RIG PARAMETERS +-------------- +For many rig types, it is handy for the user to be able to tweak how they are +generated. For example, the included biped arm rig allows the user to specify +the axis of rotation for the elbow. + +There are two methods necessary to give a rig type user-tweakable parameters, +both of which must be class methods: +add_parameters() +parameters_ui() + +add_parameters() takes an IDPropertyGroup as input, and adds its parameters +to that group as RNA properties. For example: + + @classmethod + def add_parameters(self, group): + group.toggle_param = bpy.props.BoolProperty(name="Test toggle:", default=False, description="Just a test, not really used for anything.") + +parameter_ui() recieves a Blender UILayout object, the metarig object, and the +tagged bone name. It creates a GUI in the UILayout for the user to tweak the +parameters. For example: + + @classmethod + def parameters_ui(self, layout, obj, bone): + params = obj.pose.bones[bone].rigify_parameters[0] + r = layout.row() + r.prop(params, "toggle_param") + + +SAMPLE METARIG +-------------- +It is a good idea for all rig types to have a sample metarig that the user can +add to their own metarig. This is what the create_sample() method is for. +Like the parameter methods above, create_sample() must be a class method. + +create_sample() takes the current armature object as input, and adds the bones +for its rig-type's metarig. For example: + + @classmethod + def create_sample(self, obj): + bpy.ops.object.mode_set(mode='EDIT') + arm = obj.data + + bone = arm.edit_bones.new('Bone') + bone.head[:] = 0.0000, 0.0000, 0.0000 + bone.tail[:] = 0.0000, 0.0000, 1.0000 + bone.roll = 0.0000 + bone.use_connect = False + + bpy.ops.object.mode_set(mode='OBJECT') + pbone = obj.pose.bones[bone] + pbone.rigify_type = 'copy' + pbone.rigify_parameters.add() + +Obviously, this isn't something that you generally want to hand-code, +especially with more complex samples. There is a function in utils.py +that will generate the code for create_sample() for you, based on a selected +armature. The function is called write_metarig() + -- cgit v1.2.3