1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
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()
|