rna data path names which are more likely to break animations.
[blender-staging.git] / release / scripts / modules / rigify / leg_quadruped.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 import bpy
22 from rna_prop_ui import rna_idprop_ui_prop_get
23 from math import pi
24 from rigify import RigifyError
25 from rigify_utils import bone_class_instance, copy_bone_simple, get_side_name, get_base_name
26 from mathutils import Vector
27
28 METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"
29
30
31 def metarig_template():
32     # generated by rigify.write_meta_rig
33     bpy.ops.object.mode_set(mode='EDIT')
34     obj = bpy.context.active_object
35     arm = obj.data
36     bone = arm.edit_bones.new('body')
37     bone.head[:] = -0.0728, -0.2427, 0.0000
38     bone.tail[:] = -0.0728, -0.2427, 0.2427
39     bone.roll = 0.0000
40     bone.use_connect = False
41     bone = arm.edit_bones.new('thigh')
42     bone.head[:] = 0.0000, 0.0000, -0.0000
43     bone.tail[:] = 0.0813, -0.2109, -0.3374
44     bone.roll = -0.4656
45     bone.use_connect = False
46     bone.parent = arm.edit_bones['body']
47     bone = arm.edit_bones.new('shin')
48     bone.head[:] = 0.0813, -0.2109, -0.3374
49     bone.tail[:] = 0.0714, -0.0043, -0.5830
50     bone.roll = -0.2024
51     bone.use_connect = True
52     bone.parent = arm.edit_bones['thigh']
53     bone = arm.edit_bones.new('foot')
54     bone.head[:] = 0.0714, -0.0043, -0.5830
55     bone.tail[:] = 0.0929, -0.0484, -0.7652
56     bone.roll = -0.3766
57     bone.use_connect = True
58     bone.parent = arm.edit_bones['shin']
59     bone = arm.edit_bones.new('toe')
60     bone.head[:] = 0.0929, -0.0484, -0.7652
61     bone.tail[:] = 0.1146, -0.1244, -0.7652
62     bone.roll = -0.0000
63     bone.use_connect = True
64     bone.parent = arm.edit_bones['foot']
65
66     bpy.ops.object.mode_set(mode='OBJECT')
67     pbone = obj.pose.bones['thigh']
68     pbone['type'] = 'leg_quadruped'
69
70
71 def metarig_definition(obj, orig_bone_name):
72     '''
73     The bone given is the first in a chain
74     Expects a chain of at least 3 children.
75     eg.
76         thigh -> shin -> foot -> [toe, heel]
77     '''
78
79     bone_definition = []
80
81     orig_bone = obj.data.bones[orig_bone_name]
82     orig_bone_parent = orig_bone.parent
83
84     if orig_bone_parent is None:
85         raise RigifyError("expected the thigh bone to have a parent hip bone")
86
87     bone_definition.append(orig_bone_parent.name)
88     bone_definition.append(orig_bone.name)
89
90
91     bone = orig_bone
92     chain = 0
93     while chain < 3: # first 2 bones only have 1 child
94         children = bone.children
95
96         if len(children) != 1:
97             raise RigifyError("expected the thigh bone to have 3 children without a fork")
98         bone = children[0]
99         bone_definition.append(bone.name) # shin, foot
100         chain += 1
101
102     if len(bone_definition) != len(METARIG_NAMES):
103         raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
104
105     return bone_definition
106
107
108 def ik(obj, bone_definition, base_names, options):
109     eb = obj.data.edit_bones
110     pb = obj.pose.bones
111     arm = obj.data
112     bpy.ops.object.mode_set(mode='EDIT')
113
114     # setup the existing bones, use names from METARIG_NAMES
115     mt = bone_class_instance(obj, ["hips"])
116     mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
117
118     mt.attr_initialize(METARIG_NAMES, bone_definition)
119     mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
120
121     ik_chain = mt_chain.copy(to_fmt="MCH-%s.ik", base_names=base_names)
122
123     ik_chain.thigh_e.use_connect = False
124     ik_chain.thigh_e.parent = mt.hips_e
125
126     ik_chain.foot_e.parent = None
127     ik_chain.rename("foot", get_base_name(base_names[bone_definition[3]]) + "_ik" + get_side_name(base_names[bone_definition[3]]))
128     ik_chain.rename("toe", get_base_name(base_names[bone_definition[4]]) + "_ik" + get_side_name(base_names[bone_definition[4]]))
129
130     # keep the foot_ik as the parent
131     ik_chain.toe_e.use_connect = False
132
133     # Foot uses pose space, not local space, for translation
134     ik_chain.foot_e.use_local_location = False
135
136     # must be after disconnecting the toe
137     ik_chain.foot_e.align_orientation(mt_chain.toe_e)
138
139     # children of ik_foot
140     ik = bone_class_instance(obj, ["foot_roll", "foot_roll_01", "foot_roll_02", "foot_target"])
141
142     # knee rotator
143     knee_rotator = copy_bone_simple(arm, mt_chain.toe, "knee_rotator" + get_side_name(base_names[mt_chain.foot]), parent=True).name
144     eb[knee_rotator].use_connect = False
145     eb[knee_rotator].parent = eb[mt.hips]
146     eb[knee_rotator].head = eb[ik_chain.thigh].head
147     eb[knee_rotator].tail = eb[knee_rotator].head + eb[mt_chain.toe].vector
148     eb[knee_rotator].length = eb[ik_chain.thigh].length / 2
149     eb[knee_rotator].roll += pi/2
150
151     # parent ik leg to the knee rotator
152     eb[ik_chain.thigh].parent = eb[knee_rotator]
153
154     # foot roll is an interesting one!
155     # plot a vector from the toe bones head, bactwards to the length of the foot
156     # then align it with the foot but reverse direction.
157     ik.foot_roll_e = copy_bone_simple(arm, mt_chain.toe, get_base_name(base_names[mt_chain.foot]) + "_roll" + get_side_name(base_names[mt_chain.foot]))
158     ik.foot_roll = ik.foot_roll_e.name
159     ik.foot_roll_e.use_connect = False
160     ik.foot_roll_e.parent = ik_chain.foot_e
161     ik.foot_roll_e.head -= mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length
162     ik.foot_roll_e.tail = ik.foot_roll_e.head - (mt_chain.foot_e.vector.normalize() * mt_chain.toe_e.length)
163     ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotation_part() * Vector((0.0, 0.0, -1.0)))
164
165     # MCH-foot
166     ik.foot_roll_01_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot])
167     ik.foot_roll_01 = ik.foot_roll_01_e.name
168     ik.foot_roll_01_e.parent = ik_chain.foot_e
169     ik.foot_roll_01_e.head, ik.foot_roll_01_e.tail = mt_chain.foot_e.tail, mt_chain.foot_e.head
170     ik.foot_roll_01_e.roll = ik.foot_roll_e.roll
171
172     # ik_target, child of MCH-foot
173     ik.foot_target_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot] + "_ik_target")
174     ik.foot_target = ik.foot_target_e.name
175     ik.foot_target_e.parent = ik.foot_roll_01_e
176     ik.foot_target_e.align_orientation(ik_chain.foot_e)
177     ik.foot_target_e.length = ik_chain.foot_e.length / 2.0
178     ik.foot_target_e.use_connect = True
179
180     # MCH-foot.02 child of MCH-foot
181     ik.foot_roll_02_e = copy_bone_simple(arm, mt_chain.foot, "MCH-%s_02" % base_names[mt_chain.foot])
182     ik.foot_roll_02 = ik.foot_roll_02_e.name
183     ik.foot_roll_02_e.parent = ik.foot_roll_01_e
184
185
186     bpy.ops.object.mode_set(mode='OBJECT')
187
188     mt.update()
189     mt_chain.update()
190     ik.update()
191     ik_chain.update()
192
193     # Set rotation modes and axis locks
194     #pb[knee_rotator].rotation_mode = 'YXZ'
195     #pb[knee_rotator].lock_rotation = False, True, False
196     pb[knee_rotator].lock_location = True, True, True
197     pb[ik.foot_roll].rotation_mode = 'XYZ'
198     pb[ik.foot_roll].lock_rotation = False, True, True
199     pb[ik_chain.toe].rotation_mode = 'XYZ'
200     pb[ik_chain.toe].lock_rotation = False, True, True
201
202     # IK switch property
203     prop = rna_idprop_ui_prop_get(pb[ik_chain.foot], "ik", create=True)
204     pb[ik_chain.foot]["ik"] = 1.0
205     prop["soft_min"] = 0.0
206     prop["soft_max"] = 1.0
207     prop["min"] = 0.0
208     prop["max"] = 1.0
209
210     ik_driver_path = pb[ik_chain.foot].path_from_id() + '["ik"]'
211
212     # simple constraining of orig bones
213     con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS')
214     con.target = obj
215     con.subtarget = ik_chain.thigh
216     fcurve = con.driver_add("influence")
217     driver = fcurve.driver
218     var = driver.variables.new()
219     driver.type = 'AVERAGE'
220     var.name = "var"
221     var.targets[0].id_type = 'OBJECT'
222     var.targets[0].id = obj
223     var.targets[0].data_path = ik_driver_path
224
225     con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
226     con.target = obj
227     con.subtarget = ik_chain.shin
228     fcurve = con.driver_add("influence")
229     driver = fcurve.driver
230     var = driver.variables.new()
231     driver.type = 'AVERAGE'
232     var.name = "var"
233     var.targets[0].id_type = 'OBJECT'
234     var.targets[0].id = obj
235     var.targets[0].data_path = ik_driver_path
236
237     con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
238     con.target = obj
239     con.subtarget = ik.foot_roll_02
240     fcurve = con.driver_add("influence")
241     driver = fcurve.driver
242     var = driver.variables.new()
243     driver.type = 'AVERAGE'
244     var.name = "var"
245     var.targets[0].id_type = 'OBJECT'
246     var.targets[0].id = obj
247     var.targets[0].data_path = ik_driver_path
248
249     con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
250     con.target = obj
251     con.subtarget = ik_chain.toe
252     fcurve = con.driver_add("influence")
253     driver = fcurve.driver
254     var = driver.variables.new()
255     driver.type = 'AVERAGE'
256     var.name = "var"
257     var.targets[0].id_type = 'OBJECT'
258     var.targets[0].id = obj
259     var.targets[0].data_path = ik_driver_path
260
261     # others...
262     con = ik.foot_roll_01_p.constraints.new('COPY_ROTATION')
263     con.target = obj
264     con.subtarget = ik.foot_roll
265     con.target_space = 'LOCAL'
266     con.owner_space = 'LOCAL'
267
268
269     # IK
270     con = ik_chain.shin_p.constraints.new('IK')
271     con.chain_count = 2
272     con.iterations = 500
273     con.pole_angle = -90.0 # XXX - in deg!
274     con.use_tail = True
275     con.use_stretch = True
276     con.use_target = True
277     con.use_rotation = False
278     con.weight = 1.0
279
280     con.target = obj
281     con.subtarget = ik.foot_target
282
283     con.pole_target = None
284
285     ik.update()
286     ik_chain.update()
287
288     # Set layers of the bones.
289     if "ik_layer" in options:
290         layer = [n==options["ik_layer"] for n in range(0,32)]
291     else:
292         layer = list(mt_chain.thigh_b.layers)
293     for attr in ik_chain.attr_names:
294         obj.data.bones[getattr(ik_chain, attr)].layers = layer
295     for attr in ik.attr_names:
296         obj.data.bones[getattr(ik, attr)].layers = layer
297     obj.data.bones[knee_rotator].layers = layer
298
299     return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe
300
301
302
303 def fk(obj, bone_definition, base_names, options):
304     eb = obj.data.edit_bones
305     pb = obj.pose.bones
306     arm = obj.data
307     bpy.ops.object.mode_set(mode='EDIT')
308
309     # setup the existing bones, use names from METARIG_NAMES
310     mt = bone_class_instance(obj, ["hips"])
311     mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
312
313     mt.attr_initialize(METARIG_NAMES, bone_definition)
314     mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
315
316     fk_chain = mt_chain.copy(to_fmt="%s", base_names=base_names)
317
318     # Create the socket
319     socket = copy_bone_simple(arm, mt_chain.thigh, "MCH-leg_socket").name
320     eb[socket].parent = eb[mt.hips]
321     eb[socket].length = eb[mt_chain.thigh].length / 4
322
323     # Create the hinge
324     hinge = copy_bone_simple(arm, mt.hips, "MCH-leg_hinge").name
325     eb[hinge].length = eb[mt.hips].length / 2
326
327     # Make leg child of hinge
328     eb[fk_chain.thigh].use_connect = False
329     eb[fk_chain.thigh].parent = eb[hinge]
330
331
332     bpy.ops.object.mode_set(mode='OBJECT')
333
334     # Set rotation modes and axis locks
335     pb[fk_chain.shin].rotation_mode = 'XYZ'
336     pb[fk_chain.shin].lock_rotation = False, True, True
337
338     # Constrain original bones to control bones
339     con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS')
340     con.target = obj
341     con.subtarget = fk_chain.thigh
342
343     con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
344     con.target = obj
345     con.subtarget = fk_chain.shin
346
347     con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
348     con.target = obj
349     con.subtarget = fk_chain.foot
350
351     con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
352     con.target = obj
353     con.subtarget = fk_chain.toe
354
355     # Socket constraint
356     con = pb[fk_chain.thigh].constraints.new('COPY_LOCATION')
357     con.target = obj
358     con.subtarget = socket
359
360     # Hinge constraint
361     con = pb[hinge].constraints.new('COPY_TRANSFORMS')
362     con.target = obj
363     con.subtarget = mt.hips
364
365     prop = rna_idprop_ui_prop_get(pb[fk_chain.thigh], "hinge", create=True)
366     pb[fk_chain.thigh]["hinge"] = 0.0
367     prop["soft_min"] = 0.0
368     prop["soft_max"] = 1.0
369     prop["min"] = 0.0
370     prop["max"] = 1.0
371
372     hinge_driver_path = pb[fk_chain.thigh].path_from_id() + '["hinge"]'
373
374     fcurve = con.driver_add("influence")
375     driver = fcurve.driver
376     var = driver.variables.new()
377     driver.type = 'AVERAGE'
378     var.name = "var"
379     var.targets[0].id_type = 'OBJECT'
380     var.targets[0].id = obj
381     var.targets[0].data_path = hinge_driver_path
382
383     mod = fcurve.modifiers[0]
384     mod.poly_order = 1
385     mod.coefficients[0] = 1.0
386     mod.coefficients[1] = -1.0
387
388     return None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe
389
390
391
392
393 def deform(obj, definitions, base_names, options):
394     bpy.ops.object.mode_set(mode='EDIT')
395
396     # Create upper leg bones: two bones, each half of the upper leg.
397     uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True)
398     uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True)
399     uleg1.use_connect = False
400     uleg2.use_connect = False
401     uleg2.parent = uleg1
402     center = uleg1.center
403     uleg1.tail = center
404     uleg2.head = center
405
406     # Create lower leg bones: two bones, each half of the lower leg.
407     lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True)
408     lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True)
409     lleg1.use_connect = False
410     lleg2.use_connect = False
411     lleg2.parent = lleg1
412     center = lleg1.center
413     lleg1.tail = center
414     lleg2.head = center
415
416     # Create a bone for the second lower leg deform bone to twist with
417     twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist")
418     twist.length /= 4
419     twist.use_connect = False
420     twist.parent = obj.data.edit_bones[definitions[3]]
421
422     # Create foot bone
423     foot = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True)
424
425     # Create toe bone
426     toe = copy_bone_simple(obj.data, definitions[4], "DEF-%s" % base_names[definitions[4]], parent=True)
427
428     # Store names before leaving edit mode
429     uleg1_name = uleg1.name
430     uleg2_name = uleg2.name
431     lleg1_name = lleg1.name
432     lleg2_name = lleg2.name
433     twist_name = twist.name
434     foot_name = foot.name
435     toe_name = toe.name
436
437     # Leave edit mode
438     bpy.ops.object.mode_set(mode='OBJECT')
439
440     # Get the pose bones
441     uleg1 = obj.pose.bones[uleg1_name]
442     uleg2 = obj.pose.bones[uleg2_name]
443     lleg1 = obj.pose.bones[lleg1_name]
444     lleg2 = obj.pose.bones[lleg2_name]
445     foot = obj.pose.bones[foot_name]
446     toe = obj.pose.bones[toe_name]
447
448     # Upper leg constraints
449     con = uleg1.constraints.new('DAMPED_TRACK')
450     con.name = "trackto"
451     con.target = obj
452     con.subtarget = definitions[2]
453
454     con = uleg2.constraints.new('COPY_ROTATION')
455     con.name = "copy_rot"
456     con.target = obj
457     con.subtarget = definitions[1]
458
459     # Lower leg constraints
460     con = lleg1.constraints.new('COPY_ROTATION')
461     con.name = "copy_rot"
462     con.target = obj
463     con.subtarget = definitions[2]
464
465     con = lleg2.constraints.new('COPY_ROTATION')
466     con.name = "copy_rot"
467     con.target = obj
468     con.subtarget = twist_name
469
470     con = lleg2.constraints.new('DAMPED_TRACK')
471     con.name = "trackto"
472     con.target = obj
473     con.subtarget = definitions[3]
474
475     # Foot constraint
476     con = foot.constraints.new('COPY_ROTATION')
477     con.name = "copy_rot"
478     con.target = obj
479     con.subtarget = definitions[3]
480
481     # Toe constraint
482     con = toe.constraints.new('COPY_ROTATION')
483     con.name = "copy_rot"
484     con.target = obj
485     con.subtarget = definitions[4]
486
487     bpy.ops.object.mode_set(mode='EDIT')
488     return (uleg1_name, uleg2_name, lleg1_name, lleg2_name, foot_name, toe_name, None)
489
490
491
492
493 def main(obj, bone_definition, base_names, options):
494     bones_fk = fk(obj, bone_definition, base_names, options)
495     bones_ik = ik(obj, bone_definition, base_names, options)
496     deform(obj, bone_definition, base_names, options)
497     return bones_ik