autorigging front end, access in pose mode armature panel (at the bottom)
[blender.git] / release / scripts / modules / rigify / leg_biped_generic.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 import bpy
22 from rigify import RigifyError, get_layer_dict
23 from rigify_utils import bone_class_instance, copy_bone_simple, blend_bone_list, get_side_name, get_base_name
24 from rna_prop_ui import rna_idprop_ui_prop_get
25
26 METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe", "heel"
27
28
29 def metarig_template():
30     # generated by rigify.write_meta_rig
31     bpy.ops.object.mode_set(mode='EDIT')
32     obj = bpy.context.active_object
33     arm = obj.data
34     bone = arm.edit_bones.new('hips')
35     bone.head[:] = 0.0000, 0.0000, 0.0000
36     bone.tail[:] = 0.0000, 0.0000, 0.2506
37     bone.roll = 0.0000
38     bone.connected = False
39     bone = arm.edit_bones.new('thigh')
40     bone.head[:] = 0.1253, 0.0000, -0.0000
41     bone.tail[:] = 0.0752, -0.0251, -0.4260
42     bone.roll = 0.1171
43     bone.connected = False
44     bone.parent = arm.edit_bones['hips']
45     bone = arm.edit_bones.new('shin')
46     bone.head[:] = 0.0752, -0.0251, -0.4260
47     bone.tail[:] = 0.0752, 0.0000, -0.8771
48     bone.roll = 0.0000
49     bone.connected = True
50     bone.parent = arm.edit_bones['thigh']
51     bone = arm.edit_bones.new('foot')
52     bone.head[:] = 0.0752, 0.0000, -0.8771
53     bone.tail[:] = 0.1013, -0.1481, -0.9773
54     bone.roll = -0.4662
55     bone.connected = True
56     bone.parent = arm.edit_bones['shin']
57     bone = arm.edit_bones.new('toe')
58     bone.head[:] = 0.1013, -0.1481, -0.9773
59     bone.tail[:] = 0.1100, -0.2479, -0.9773
60     bone.roll = 3.1416
61     bone.connected = True
62     bone.parent = arm.edit_bones['foot']
63     bone = arm.edit_bones.new('heel')
64     bone.head[:] = 0.0652, 0.0501, -1.0024
65     bone.tail[:] = 0.0927, -0.1002, -1.0024
66     bone.roll = 0.0000
67     bone.connected = False
68     bone.parent = arm.edit_bones['foot']
69
70     bpy.ops.object.mode_set(mode='OBJECT')
71     pbone = obj.pose.bones['thigh']
72     pbone['type'] = 'leg_biped_generic'
73
74
75 def metarig_definition(obj, orig_bone_name):
76     '''
77     The bone given is the first in a chain
78     Expects a chain of at least 3 children.
79     eg.
80         thigh -> shin -> foot -> [toe, heel]
81     '''
82
83     bone_definition = []
84
85     orig_bone = obj.data.bones[orig_bone_name]
86     orig_bone_parent = orig_bone.parent
87
88     if orig_bone_parent is None:
89         raise RigifyError("expected the thigh bone to have a parent hip bone")
90
91     bone_definition.append(orig_bone_parent.name)
92     bone_definition.append(orig_bone.name)
93
94
95     bone = orig_bone
96     chain = 0
97     while chain < 2: # first 2 bones only have 1 child
98         children = bone.children
99
100         if len(children) != 1:
101             raise RigifyError("expected the thigh bone to have 3 children without a fork")
102         bone = children[0]
103         bone_definition.append(bone.name) # shin, foot
104         chain += 1
105
106     children = bone.children
107     # Now there must be 2 children, only one connected
108     if len(children) != 2:
109         raise RigifyError("expected the foot bone:'%s' to have 2 children" % bone.name)
110
111     if children[0].connected == children[1].connected:
112         raise RigifyError("expected one bone to be connected")
113
114     toe, heel = children
115     if heel.connected:
116         toe, heel = heel, toe
117
118
119     bone_definition.append(toe.name)
120     bone_definition.append(heel.name)
121
122     if len(bone_definition) != len(METARIG_NAMES):
123         raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
124
125     return bone_definition
126
127
128 def ik(obj, bone_definition, base_names, options):
129     arm = obj.data
130
131     # setup the existing bones, use names from METARIG_NAMES
132     mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
133     mt = bone_class_instance(obj, ["hips", "heel"])
134
135     mt.attr_initialize(METARIG_NAMES, bone_definition)
136     mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
137
138     # children of ik_foot
139     ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target"])
140
141     # Make a new chain
142     ik_chain = mt_chain.copy(to_fmt="MCH-%s", base_names=base_names)
143
144     # simple rename
145     ik_chain.rename("thigh", ik_chain.thigh + "_ik")
146     ik_chain.rename("shin", ik_chain.shin + "_ik")
147
148     # make sure leg is child of hips
149     ik_chain.thigh_e.parent = mt.hips_e
150
151     # ik foot: no parents
152     base_foot_name = get_base_name(base_names[mt_chain.foot])
153     ik.foot_e = copy_bone_simple(arm, mt_chain.foot, base_foot_name + "_ik" + get_side_name(base_names[mt_chain.foot]))
154     ik.foot = ik.foot_e.name
155     ik.foot_e.tail.z = ik.foot_e.head.z
156     ik.foot_e.roll = 0.0
157     ik.foot_e.local_location = False
158
159     # foot roll: heel pointing backwards, half length
160     ik.foot_roll_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_roll" + get_side_name(base_names[mt_chain.foot]))
161     ik.foot_roll = ik.foot_roll_e.name
162     ik.foot_roll_e.tail = ik.foot_roll_e.head + ik.foot_roll_e.vector / 2.0
163     ik.foot_roll_e.parent = ik.foot_e # heel is disconnected
164
165     # heel pointing forwards to the toe base, parent of the following 2 bones
166     ik.foot_roll_01_e = copy_bone_simple(arm, mt.heel, "MCH-%s_roll.01" % base_foot_name)
167     ik.foot_roll_01 = ik.foot_roll_01_e.name
168     ik.foot_roll_01_e.tail = mt_chain.foot_e.tail
169     ik.foot_roll_01_e.parent = ik.foot_e # heel is disconnected
170
171     # same as above but reverse direction
172     ik.foot_roll_02_e = copy_bone_simple(arm, mt.heel, "MCH-%s_roll.02" % base_foot_name)
173     ik.foot_roll_02 = ik.foot_roll_02_e.name
174     ik.foot_roll_02_e.parent = ik.foot_roll_01_e # heel is disconnected
175     ik.foot_roll_02_e.head = mt_chain.foot_e.tail
176     ik.foot_roll_02_e.tail = mt.heel_e.head
177
178     del base_foot_name
179
180     # rename 'MCH-toe' --> to 'toe_ik' and make the child of ik.foot_roll_01
181     # ------------------ FK or IK?
182     ik_chain.rename("toe", get_base_name(base_names[mt_chain.toe]) + "_ik" + get_side_name(base_names[mt_chain.toe]))
183     ik_chain.toe_e.connected = False
184     ik_chain.toe_e.parent = ik.foot_roll_01_e
185
186     # re-parent ik_chain.foot to the
187     ik_chain.foot_e.connected = False
188     ik_chain.foot_e.parent = ik.foot_roll_02_e
189
190
191     # knee target is the heel moved up and forward on its local axis
192     ik.knee_target_e = copy_bone_simple(arm, mt.heel, "knee_target")
193     ik.knee_target = ik.knee_target_e.name
194     offset = ik.knee_target_e.tail - ik.knee_target_e.head
195     offset.z = 0
196     offset.length = mt_chain.shin_e.head.z - mt.heel_e.head.z
197     offset.z += offset.length
198     ik.knee_target_e.translate(offset)
199     ik.knee_target_e.length *= 0.5
200     ik.knee_target_e.parent = ik.foot_e
201     ik.knee_target_e.local_location = False
202
203     # roll the bone to point up... could also point in the same direction as ik.foot_roll
204     # ik.foot_roll_02_e.matrix * Vector(0.0, 0.0, 1.0) # ACK!, no rest matrix in editmode
205     ik.foot_roll_01_e.align_roll((0.0, 0.0, -1.0))
206
207     bpy.ops.object.mode_set(mode='OBJECT')
208
209     ik.update()
210     mt_chain.update()
211     ik_chain.update()
212
213     # Set IK dof
214     ik_chain.shin_p.ik_dof_x = True
215     ik_chain.shin_p.ik_dof_y = False
216     ik_chain.shin_p.ik_dof_z = False
217
218     # Set rotation modes and axis locks
219     ik.foot_roll_p.rotation_mode = 'XYZ'
220     ik.foot_roll_p.lock_rotation = False, True, True
221     ik_chain.toe_p.rotation_mode = 'YXZ'
222     ik_chain.toe_p.lock_rotation = False, True, True
223
224     # IK
225     con = ik_chain.shin_p.constraints.new('IK')
226     con.chain_length = 2
227     con.iterations = 500
228     con.pole_angle = -90.0 # XXX - in deg!
229     con.use_tail = True
230     con.use_stretch = True
231     con.use_target = True
232     con.use_rotation = False
233     con.weight = 1.0
234
235     con.target = obj
236     con.subtarget = ik_chain.foot
237
238     con.pole_target = obj
239     con.pole_subtarget = ik.knee_target
240
241     # foot roll
242     cons = [ \
243         (ik.foot_roll_01_p.constraints.new('COPY_ROTATION'), ik.foot_roll_01_p.constraints.new('LIMIT_ROTATION')), \
244         (ik.foot_roll_02_p.constraints.new('COPY_ROTATION'), ik.foot_roll_02_p.constraints.new('LIMIT_ROTATION'))]
245
246     for con, con_l in cons:
247         con.target = obj
248         con.subtarget = ik.foot_roll
249         con.use_x, con.use_y, con.use_z = True, False, False
250         con.target_space = con.owner_space = 'LOCAL'
251
252         con = con_l
253         con.use_limit_x, con.use_limit_y, con.use_limit_z = True, False, False
254         con.owner_space = 'LOCAL'
255
256         if con_l is cons[-1][-1]:
257             con.minimum_x = 0.0
258             con.maximum_x = 180.0 # XXX -deg
259         else:
260             con.minimum_x = -180.0 # XXX -deg
261             con.maximum_x = 0.0
262
263
264     # last step setup layers
265     layers = get_layer_dict(options)
266     lay = layers["ik"]
267     for attr in ik_chain.attr_names:
268         getattr(ik_chain, attr + "_b").layer = lay
269     for attr in ik.attr_names:
270         getattr(ik, attr + "_b").layer = lay
271
272     bpy.ops.object.mode_set(mode='EDIT')
273
274     return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe, None
275
276
277 def fk(obj, bone_definition, base_names, options):
278     from Mathutils import Vector
279     arm = obj.data
280
281     # these account for all bones in METARIG_NAMES
282     mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
283     mt = bone_class_instance(obj, ["hips", "heel"])
284
285     # new bones
286     ex = bone_class_instance(obj, ["thigh_socket", "thigh_hinge"])
287
288     for bone_class in (mt, mt_chain):
289         for attr in bone_class.attr_names:
290             i = METARIG_NAMES.index(attr)
291             ebone = arm.edit_bones[bone_definition[i]]
292             setattr(bone_class, attr, ebone.name)
293         bone_class.update()
294
295     ex.thigh_socket_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_socket" % base_names[mt_chain.thigh], parent=True)
296     ex.thigh_socket = ex.thigh_socket_e.name
297     ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector(0.0, 0.0, ex.thigh_socket_e.length / 4.0)
298
299     ex.thigh_hinge_e = copy_bone_simple(arm, mt.hips, "MCH-%s_hinge" % base_names[mt_chain.thigh], parent=False)
300     ex.thigh_hinge = ex.thigh_hinge_e.name
301
302     fk_chain = mt_chain.copy(base_names=base_names) # fk has no prefix!
303
304     fk_chain.thigh_e.connected = False
305     fk_chain.thigh_e.parent = ex.thigh_hinge_e
306
307     bpy.ops.object.mode_set(mode='OBJECT')
308
309     ex.update()
310     mt_chain.update()
311     fk_chain.update()
312
313     # Set rotation modes and axis locks
314     fk_chain.shin_p.rotation_mode = 'XYZ'
315     fk_chain.shin_p.lock_rotation = False, True, True
316     fk_chain.foot_p.rotation_mode = 'YXZ'
317     fk_chain.toe_p.rotation_mode = 'YXZ'
318     fk_chain.toe_p.lock_rotation = False, True, True
319
320     con = fk_chain.thigh_p.constraints.new('COPY_LOCATION')
321     con.target = obj
322     con.subtarget = ex.thigh_socket
323
324     # hinge
325     prop = rna_idprop_ui_prop_get(fk_chain.thigh_p, "hinge", create=True)
326     fk_chain.thigh_p["hinge"] = 0.5
327     prop["soft_min"] = 0.0
328     prop["soft_max"] = 1.0
329
330     con = ex.thigh_hinge_p.constraints.new('COPY_ROTATION')
331     con.target = obj
332     con.subtarget = mt.hips
333
334     # add driver
335     hinge_driver_path = fk_chain.thigh_p.path_to_id() + '["hinge"]'
336
337     fcurve = con.driver_add("influence", 0)
338     driver = fcurve.driver
339     tar = driver.targets.new()
340     driver.type = 'AVERAGE'
341     tar.name = "var"
342     tar.id_type = 'OBJECT'
343     tar.id = obj
344     tar.data_path = hinge_driver_path
345
346     mod = fcurve.modifiers[0]
347     mod.poly_order = 1
348     mod.coefficients[0] = 1.0
349     mod.coefficients[1] = -1.0
350
351
352     # last step setup layers
353     layers = get_layer_dict(options)
354     lay = layers["fk"]
355     for attr in fk_chain.attr_names:
356         getattr(fk_chain, attr + "_b").layer = lay
357
358     lay = layers["extra"]
359     for attr in ex.attr_names:
360         getattr(ex, attr + "_b").layer = lay
361
362
363     bpy.ops.object.mode_set(mode='EDIT')
364
365     # dont blend the hips or heel
366     return None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe, None
367
368
369 def main(obj, bone_definition, base_names, options):
370     bones_fk = fk(obj, bone_definition, base_names, options)
371     bones_ik = ik(obj, bone_definition, base_names, options)
372
373     bpy.ops.object.mode_set(mode='OBJECT')
374     blend_bone_list(obj, bone_definition, bones_fk, bones_ik, target_bone=bones_ik[1], blend_default=0.0)