split up metarig hierarchy evaluation and modifying the metarig into 2 steps,
[blender.git] / release / scripts / modules / rigify / spine.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 import bpy
20 from rigify import bone_class_instance, copy_bone_simple
21 from rna_prop_ui import rna_idprop_ui_prop_get
22
23 # not used, defined for completeness
24 METARIG_NAMES = ("pelvis", "ribcage")
25
26 def metarig_template():
27     bpy.ops.object.mode_set(mode='EDIT')
28     obj = bpy.context.object
29     arm = obj.data
30     bone = arm.edit_bones.new('pelvis')
31     bone.head[:] = -0.0000, -0.2559, 0.8673
32     bone.tail[:] = -0.0000, -0.2559, -0.1327
33     bone.roll = 0.0000
34     bone.connected = False
35     bone = arm.edit_bones.new('rib_cage')
36     bone.head[:] = -0.0000, -0.2559, 0.8673
37     bone.tail[:] = -0.0000, -0.2559, 1.8673
38     bone.roll = -0.0000
39     bone.connected = False
40     bone.parent = arm.edit_bones['pelvis']
41     bone = arm.edit_bones.new('spine.01')
42     bone.head[:] = -0.0000, -0.0000, 0.0000
43     bone.tail[:] = -0.0000, -0.2559, 0.8673
44     bone.roll = -0.0000
45     bone.connected = False
46     bone.parent = arm.edit_bones['rib_cage']
47     bone = arm.edit_bones.new('spine.02')
48     bone.head[:] = -0.0000, -0.2559, 0.8673
49     bone.tail[:] = -0.0000, -0.3321, 1.7080
50     bone.roll = -0.0000
51     bone.connected = True
52     bone.parent = arm.edit_bones['spine.01']
53     bone = arm.edit_bones.new('spine.03')
54     bone.head[:] = -0.0000, -0.3321, 1.7080
55     bone.tail[:] = -0.0000, -0.0787, 2.4160
56     bone.roll = 0.0000
57     bone.connected = True
58     bone.parent = arm.edit_bones['spine.02']
59     bone = arm.edit_bones.new('spine.04')
60     bone.head[:] = -0.0000, -0.0787, 2.4160
61     bone.tail[:] = -0.0000, 0.2797, 3.0016
62     bone.roll = 0.0000
63     bone.connected = True
64     bone.parent = arm.edit_bones['spine.03']
65     bone = arm.edit_bones.new('spine.05')
66     bone.head[:] = -0.0000, 0.2797, 3.0016
67     bone.tail[:] = -0.0000, 0.4633, 3.6135
68     bone.roll = 0.0000
69     bone.connected = True
70     bone.parent = arm.edit_bones['spine.04']
71     bone = arm.edit_bones.new('spine.06')
72     bone.head[:] = -0.0000, 0.4633, 3.6135
73     bone.tail[:] = -0.0000, 0.3671, 4.3477
74     bone.roll = -0.0000
75     bone.connected = True
76     bone.parent = arm.edit_bones['spine.05']
77     bone = arm.edit_bones.new('spine.07')
78     bone.head[:] = -0.0000, 0.3671, 4.3477
79     bone.tail[:] = -0.0000, 0.0175, 5.0033
80     bone.roll = -0.0000
81     bone.connected = True
82     bone.parent = arm.edit_bones['spine.06']
83
84     bpy.ops.object.mode_set(mode='OBJECT')
85     pbone = obj.pose.bones['rib_cage']
86     pbone['type'] = 'spine'
87
88
89 def metarig_definition(obj, orig_bone_name):
90     '''
91     The bone given is the second in a chain.
92     Expects at least 1 parent and a chain of children withe the same basename
93     eg.
94         pelvis -> rib_cage -> spine.01 -> spine.02 -> spine.03
95
96     note: same as neck.
97     '''
98     arm = obj.data
99     ribcage = arm.bones[orig_bone_name]
100     pelvis = ribcage.parent
101     
102     children = ribcage.children
103     if len(children) != 1:
104         print("expected the ribcage to have only 1 child.")
105
106     child = children[0]
107     bone_definition = [pelvis.name, ribcage.name, child.name]
108     bone_definition.extend([child.name for child in child.children_recursive_basename])
109     return bone_definition
110
111 def fk(*args):
112     main(*args)
113
114 def main(obj, bone_definition, base_names):
115     from Mathutils import Vector, Matrix, RotationMatrix
116     from math import radians, pi
117
118     arm = obj.data
119
120     # Initialize container classes for convenience
121     mt = bone_class_instance(obj, ["pelvis", "ribcage"]) # meta
122     mt.pelvis = bone_definition[0]
123     mt.ribcage = bone_definition[1]
124     mt.update()
125
126     spine_chain_orig = bone_definition[2:]
127     spine_chain = [arm.edit_bones[child_name] for child_name in spine_chain_orig]
128     spine_chain_basename = base_names[spine_chain[0].name].rsplit(".", 1) # probably 'ORG-spine.01' -> 'spine'
129     spine_chain_len = len(spine_chain_orig)
130
131     '''
132     children = mt.ribcage_e.children
133     child = children[0] # validate checks for 1 only.
134     spine_chain_basename = child.basename # probably 'spine'
135     spine_chain_segment_length = child.length
136     spine_chain = [child] + child.children_recursive_basename
137     spine_chain_orig = [child.name for child in spine_chain]
138     '''
139     
140     child = spine_chain[0]
141     spine_chain_segment_length = child.length
142     child.parent = mt.pelvis_e # was mt.ribcage
143     
144     # The first bone in the chain happens to be the basis of others, create them now
145     ex = bone_class_instance(obj, ["pelvis", "ribcage", "ribcage_hinge", "spine_rotate"])
146     df = bone_class_instance(obj, ["pelvis", "ribcage"]) # DEF-wgt_pelvis, DEF-wgt_rib_cage
147
148
149     # copy the pelvis, offset to make MCH-spine_rotate and MCH-ribcage_hinge
150     ex.ribcage_hinge_e = copy_bone_simple(arm, mt.pelvis, "MCH-%s_hinge" % mt.ribcage)
151     ex.ribcage_hinge = ex.ribcage_hinge_e.name
152     ex.ribcage_hinge_e.translate(Vector(0.0, spine_chain_segment_length / 4.0, 0.0))
153     mt.ribcage_e.parent = ex.ribcage_hinge_e
154     
155     ex.spine_rotate_e = copy_bone_simple(arm, mt.pelvis, "MCH-%s_rotate" % spine_chain_basename)
156     ex.spine_rotate = ex.spine_rotate_e.name
157     ex.spine_rotate_e.translate(Vector(0.0, spine_chain_segment_length / 2.0, 0.0))
158     # swap head/tail
159     ex.spine_rotate_e.head, ex.spine_rotate_e.tail = ex.spine_rotate_e.tail.copy(), ex.spine_rotate_e.head.copy()
160     ex.spine_rotate_e.parent = mt.pelvis_e
161     
162     df.pelvis_e = copy_bone_simple(arm, child.name, "DEF-wgt_%s" % mt.pelvis)
163     df.pelvis = df.pelvis_e.name
164     df.pelvis_e.translate(Vector(spine_chain_segment_length * 2.0, -spine_chain_segment_length, 0.0))
165
166     ex.pelvis_e = copy_bone_simple(arm, child.name, "MCH-wgt_%s" % mt.pelvis)
167     ex.pelvis = ex.pelvis_e.name
168     ex.pelvis_e.translate(Vector(0.0, -spine_chain_segment_length, 0.0))
169     ex.pelvis_e.parent = mt.pelvis_e
170
171     # Copy the last bone now
172     child = spine_chain[-1]
173     
174     df.ribcage_e = copy_bone_simple(arm, child.name, "DEF-wgt_%s" % mt.ribcage)
175     df.ribcage = df.ribcage_e.name
176     df.ribcage_e.translate(Vector(spine_chain_segment_length * 2.0, -df.ribcage_e.length / 2.0, 0.0))
177     
178     ex.ribcage_e = copy_bone_simple(arm, child.name, "MCH-wgt_%s" % mt.ribcage)
179     ex.ribcage = ex.ribcage_e.name
180     ex.ribcage_e.translate(Vector(0.0, -ex.ribcage_e.length / 2.0, 0.0))
181     ex.ribcage_e.parent = mt.ribcage_e
182
183     # rename!
184     for child in spine_chain:
185         child.name = "ORG-" + child.name
186
187     spine_chain = [child.name for child in spine_chain]
188
189     # We have 3 spine chains
190     # - original (ORG_*)
191     # - copy (*use original name*)
192     # - reverse (MCH-rev_*)
193     spine_chain_attrs = [("spine_%.2d" % (i + 1)) for i in range(spine_chain_len)]
194
195     mt_chain = bone_class_instance(obj, spine_chain_attrs) # ORG_*
196     rv_chain = bone_class_instance(obj, spine_chain_attrs) # *
197     ex_chain = bone_class_instance(obj, spine_chain_attrs) # MCH-rev_*
198     del spine_chain_attrs
199     
200     for i, child_name in enumerate(spine_chain):
201         child_name_orig = spine_chain_orig[i]
202
203         attr = mt_chain.attr_names[i] # eg. spine_04
204
205         setattr(mt_chain, attr, spine_chain[i]) # use the new name
206
207         ebone = copy_bone_simple(arm, child_name, child_name_orig) # use the original name
208         setattr(ex_chain, attr, ebone.name)
209
210         ebone = copy_bone_simple(arm, child_name, "MCH-rev_%s" % child_name_orig)
211         setattr(rv_chain, attr, ebone.name)
212         ebone.connected = False
213
214     mt_chain.update()
215     ex_chain.update()
216     rv_chain.update()
217
218     # Now we need to re-parent these chains
219     for i, child_name in enumerate(spine_chain_orig):        
220         attr = ex_chain.attr_names[i] + "_e"
221         
222         if i == 0:
223             getattr(ex_chain, attr).parent = mt.pelvis_e
224         else:
225             attr_parent = ex_chain.attr_names[i-1] + "_e"
226             getattr(ex_chain, attr).parent = getattr(ex_chain, attr_parent)
227         
228         # intentional! get the parent from the other paralelle chain member
229         getattr(rv_chain, attr).parent = getattr(ex_chain, attr)
230     
231     
232     # ex_chain needs to interlace bones!
233     # Note, skip the first bone
234     for i in range(1, spine_chain_len): # similar to neck
235         child_name_orig = spine_chain_orig[i]
236         spine_e = getattr(mt_chain, mt_chain.attr_names[i] + "_e")
237         
238         # dont store parent names, re-reference as each chain bones parent.
239         spine_e_parent = arm.edit_bones.new("MCH-rot_%s" % child_name_orig)
240         spine_e_parent.head = spine_e.head
241         spine_e_parent.tail = spine_e.head + Vector(0.0, 0.0, spine_chain_segment_length / 2.0)
242         spine_e_parent.roll = 0.0
243         
244         spine_e = getattr(ex_chain, ex_chain.attr_names[i] + "_e")
245         orig_parent = spine_e.parent
246         spine_e.connected = False
247         spine_e.parent = spine_e_parent
248         spine_e_parent.connected = False
249
250         spine_e_parent.parent = orig_parent
251         
252
253     # Rotate the rev chain 180 about the by the first bones center point
254     pivot = (rv_chain.spine_01_e.head + rv_chain.spine_01_e.tail) * 0.5
255     matrix = RotationMatrix(radians(180), 3, 'X')
256     for i, attr in enumerate(rv_chain.attr_names): # similar to neck
257         spine_e = getattr(rv_chain, attr + "_e")
258         # use the first bone as the pivot
259
260         spine_e.head = ((spine_e.head - pivot) * matrix) + pivot
261         spine_e.tail = ((spine_e.tail - pivot) * matrix) + pivot
262         spine_e.roll += pi # 180d roll
263         del spine_e
264     
265     
266     bpy.ops.object.mode_set(mode='OBJECT')
267     
268     # refresh pose bones
269     mt.update()
270     ex.update()
271     df.update()
272     mt_chain.update()
273     ex_chain.update()
274     rv_chain.update()
275     
276     # df.pelvis_p / DEF-wgt_pelvis
277     con = df.pelvis_p.constraints.new('COPY_LOCATION')
278     con.target = obj
279     con.subtarget = ex.pelvis
280     con.owner_space = 'LOCAL'
281     con.target_space = 'LOCAL'
282     
283     con = df.pelvis_p.constraints.new('COPY_ROTATION')
284     con.target = obj
285     con.subtarget = ex.pelvis
286     con.owner_space = 'LOCAL'
287     con.target_space = 'LOCAL'    
288     
289     # df.ribcage_p / DEF-wgt_rib_cage
290     con = df.ribcage_p.constraints.new('COPY_ROTATION')
291     con.target = obj
292     con.subtarget = ex.ribcage
293     con.owner_space = 'LOCAL'
294     con.target_space = 'LOCAL'
295     
296     con = df.ribcage_p.constraints.new('COPY_LOCATION')
297     con.target = obj
298     con.subtarget = ex.ribcage
299     con.owner_space = 'LOCAL'
300     con.target_space = 'LOCAL'
301     
302     con = ex.ribcage_hinge_p.constraints.new('COPY_ROTATION')
303     con.name = "hinge"
304     con.target = obj
305     con.subtarget = mt.pelvis
306     
307     # add driver
308     hinge_driver_path = mt.ribcage_p.path_to_id() + '["hinge"]'
309     
310     fcurve = con.driver_add("influence", 0)
311     driver = fcurve.driver
312     tar = driver.targets.new()
313     driver.type = 'AVERAGE'
314     tar.name = "var"
315     tar.id_type = 'OBJECT'
316     tar.id = obj
317     tar.rna_path = hinge_driver_path
318     
319     mod = fcurve.modifiers[0]
320     mod.poly_order = 1
321     mod.coefficients[0] = 1.0
322     mod.coefficients[1] = -1.0
323     
324     
325     
326     con = ex.spine_rotate_p.constraints.new('COPY_ROTATION')
327     con.target = obj
328     con.subtarget = mt.ribcage
329
330
331     # ex.pelvis_p / MCH-wgt_pelvis
332     con = ex.pelvis_p.constraints.new('COPY_LOCATION')
333     con.target = obj
334     con.subtarget = mt_chain.spine_01
335
336     con = ex.pelvis_p.constraints.new('COPY_ROTATION')
337     con.target = obj
338     con.subtarget = mt_chain.spine_01
339     
340     # ex.ribcage_p / MCH-wgt_rib_cage
341     con = ex.ribcage_p.constraints.new('COPY_LOCATION')
342     con.target = obj
343     con.subtarget = getattr(mt_chain, mt_chain.attr_names[-1])
344     con.head_tail = 0.0
345
346     con = ex.ribcage_p.constraints.new('COPY_ROTATION')
347     con.target = obj
348     con.subtarget = getattr(mt_chain, mt_chain.attr_names[-1])    
349     
350     # mt.pelvis_p / rib_cage
351     con = mt.ribcage_p.constraints.new('COPY_LOCATION')
352     con.target = obj
353     con.subtarget = mt.pelvis
354     con.head_tail = 0.0
355     
356     # This stores all important ID props
357     prop = rna_idprop_ui_prop_get(mt.ribcage_p, "hinge", create=True)
358     mt.ribcage_p["hinge"] = 1.0
359     prop["soft_min"] = 0.0
360     prop["soft_max"] = 1.0
361     
362     prop = rna_idprop_ui_prop_get(mt.ribcage_p, "pivot_slide", create=True)
363     mt.ribcage_p["pivot_slide"] = 0.5
364     prop["soft_min"] = 1.0 / spine_chain_len
365     prop["soft_max"] = 1.0
366     
367     for i in range(spine_chain_len - 1):
368         prop_name = "bend_%.2d" % (i + 1)
369         prop = rna_idprop_ui_prop_get(mt.ribcage_p, prop_name, create=True)
370         mt.ribcage_p[prop_name] = 1.0
371         prop["soft_min"] = 0.0
372         prop["soft_max"] = 1.0
373     
374     # Create a fake connected parent/child relationship with bone location constraints
375     # positioned at the tip.
376     
377     # reverse bones / MCH-rev_spine.##
378     for i in range(1, spine_chain_len):
379         spine_p = getattr(rv_chain, rv_chain.attr_names[i] + "_p")
380         spine_fake_parent_name = getattr(rv_chain, rv_chain.attr_names[i - 1])
381         
382         con = spine_p.constraints.new('COPY_LOCATION')
383         con.target = obj
384         con.subtarget = spine_fake_parent_name
385         con.head_tail = 1.0
386         del spine_p, spine_fake_parent_name, con
387     
388     
389     # Constrain 'inbetween' bones
390     
391     # b01/max(0.001,b01+b02+b03+b04+b05)
392     target_names = [("b%.2d" % (i + 1)) for i in range(spine_chain_len - 1)]
393     expression_suffix = "/max(0.001,%s)" % "+".join(target_names)
394     
395     rib_driver_path = mt.ribcage_p.path_to_id()
396     
397     for i in range(1, spine_chain_len):
398         
399         spine_p = getattr(ex_chain, ex_chain.attr_names[i] + "_p")
400         spine_p_parent = spine_p.parent # interlaced bone
401
402         con = spine_p_parent.constraints.new('COPY_ROTATION')
403         con.target = obj
404         con.subtarget = ex.spine_rotate
405         con.owner_space = 'LOCAL'
406         con.target_space = 'LOCAL'
407         del spine_p
408         
409         # add driver
410         fcurve = con.driver_add("influence", 0)
411         driver = fcurve.driver
412         driver.type = 'SCRIPTED'
413         # b01/max(0.001,b01+b02+b03+b04+b05)
414         driver.expression = target_names[i - 1] + expression_suffix
415         fcurve.modifiers.remove(0) # grr dont need a modifier
416
417         for j in range(spine_chain_len - 1):
418             tar = driver.targets.new()
419             tar.name = target_names[j]
420             tar.id_type = 'OBJECT'
421             tar.id = obj
422             tar.rna_path = rib_driver_path + ('["bend_%.2d"]' % (j + 1))
423     
424     
425     # original bone drivers
426     # note: the first bone has a lot more constraints, but also this simple one is first.
427     for i in attr, enumerate(mt_chain.attr_names):
428         spine_p = getattr(mt_chain, attr + "_p")
429         
430         con = spine_p.constraints.new('COPY_ROTATION')
431         con.target = obj
432         con.subtarget = getattr(ex_chain, attr) # lock to the copy's rotation
433         del spine_p
434     
435     # pivot slide: - lots of copy location constraints.
436     
437     con = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
438     con.name = "base"
439     con.target = obj
440     con.subtarget = rv_chain.spine_01 # lock to the reverse location
441     
442     for i in range(1, spine_chain_len + 1):
443         con = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
444         con.name = "slide_%d" % i
445         con.target = obj
446         
447         if i == spine_chain_len:
448             attr = mt_chain.attr_names[i - 1]
449         else:
450             attr = mt_chain.attr_names[i]
451
452         con.subtarget = getattr(rv_chain, attr) # lock to the reverse location
453         
454         if i == spine_chain_len:
455             con.head_tail = 1.0
456
457         fcurve = con.driver_add("influence", 0)
458         driver = fcurve.driver
459         tar = driver.targets.new()
460         driver.type = 'AVERAGE'
461         tar.name = "var"
462         tar.id_type = 'OBJECT'
463         tar.id = obj
464         tar.rna_path = rib_driver_path + '["pivot_slide"]'
465         
466         mod = fcurve.modifiers[0]
467         mod.poly_order = 1
468         mod.coefficients[0] = - (i - 1)
469         mod.coefficients[1] = spine_chain_len
470     
471     # no support for blending chains
472     return None
473