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