514d443a1f92e5fa48cce2ac83c91fb2e668fdd3
[blender-staging.git] / release / scripts / modules / rigify / neck_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., 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 rigify import RigifyError
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 = ("body", "head")
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('body')
36     bone.head[:] = 0.0000, -0.0276, -0.1328
37     bone.tail[:] = 0.0000, -0.0170, -0.0197
38     bone.roll = 0.0000
39     bone.connected = False
40     bone = arm.edit_bones.new('head')
41     bone.head[:] = 0.0000, -0.0170, -0.0197
42     bone.tail[:] = 0.0000, 0.0726, 0.1354
43     bone.roll = 0.0000
44     bone.connected = True
45     bone.parent = arm.edit_bones['body']
46     bone = arm.edit_bones.new('neck.01')
47     bone.head[:] = 0.0000, -0.0170, -0.0197
48     bone.tail[:] = 0.0000, -0.0099, 0.0146
49     bone.roll = 0.0000
50     bone.connected = False
51     bone.parent = arm.edit_bones['head']
52     bone = arm.edit_bones.new('neck.02')
53     bone.head[:] = 0.0000, -0.0099, 0.0146
54     bone.tail[:] = 0.0000, -0.0242, 0.0514
55     bone.roll = 0.0000
56     bone.connected = True
57     bone.parent = arm.edit_bones['neck.01']
58     bone = arm.edit_bones.new('neck.03')
59     bone.head[:] = 0.0000, -0.0242, 0.0514
60     bone.tail[:] = 0.0000, -0.0417, 0.0868
61     bone.roll = 0.0000
62     bone.connected = True
63     bone.parent = arm.edit_bones['neck.02']
64     bone = arm.edit_bones.new('neck.04')
65     bone.head[:] = 0.0000, -0.0417, 0.0868
66     bone.tail[:] = 0.0000, -0.0509, 0.1190
67     bone.roll = 0.0000
68     bone.connected = True
69     bone.parent = arm.edit_bones['neck.03']
70     bone = arm.edit_bones.new('neck.05')
71     bone.head[:] = 0.0000, -0.0509, 0.1190
72     bone.tail[:] = 0.0000, -0.0537, 0.1600
73     bone.roll = 0.0000
74     bone.connected = True
75     bone.parent = arm.edit_bones['neck.04']
76
77     bpy.ops.object.mode_set(mode='OBJECT')
78     pbone = obj.pose.bones['head']
79     pbone['type'] = 'neck_flex'
80
81
82 def metarig_definition(obj, orig_bone_name):
83     '''
84     The bone given is the head, its parent is the body,
85     # its only child the first of a chain with matching basenames.
86     eg.
87         body -> head -> neck_01 -> neck_02 -> neck_03.... etc
88     '''
89     arm = obj.data
90     head = arm.bones[orig_bone_name]
91     body = head.parent
92
93     children = head.children
94     if len(children) != 1:
95         raise RigifyError("expected the head bone '%s' to have only 1 child." % orig_bone_name)
96
97     child = children[0]
98     bone_definition = [body.name, head.name, child.name]
99     bone_definition.extend([child.name for child in child.children_recursive_basename])
100     return bone_definition
101
102
103 def deform(obj, definitions, base_names, options):
104     for org_bone_name in definitions[2:]:
105         bpy.ops.object.mode_set(mode='EDIT')
106
107         # Create deform bone.
108         bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True)
109
110         # Store name before leaving edit mode
111         bone_name = bone.name
112
113         # Leave edit mode
114         bpy.ops.object.mode_set(mode='OBJECT')
115
116         # Get the pose bone
117         bone = obj.pose.bones[bone_name]
118
119         # Constrain to the original bone
120         # XXX. Todo, is this needed if the bone is connected to its parent?
121         con = bone.constraints.new('COPY_TRANSFORMS')
122         con.name = "copy_loc"
123         con.target = obj
124         con.subtarget = org_bone_name
125
126
127 def main(obj, bone_definition, base_names, options):
128     from mathutils import Vector
129
130     arm = obj.data
131
132     # Initialize container classes for convenience
133     mt = bone_class_instance(obj, ["body", "head"]) # meta
134     mt.body = bone_definition[0]
135     mt.head = bone_definition[1]
136     mt.update()
137
138     neck_chain = bone_definition[2:]
139
140     mt_chain = bone_class_instance(obj, [("neck_%.2d" % (i + 1)) for i in range(len(neck_chain))]) # 99 bones enough eh?
141     for i, attr in enumerate(mt_chain.attr_names):
142         setattr(mt_chain, attr, neck_chain[i])
143     mt_chain.update()
144
145     neck_chain_basename = base_names[mt_chain.neck_01_e.name].split(".")[0]
146     neck_chain_segment_length = mt_chain.neck_01_e.length
147
148     ex = bone_class_instance(obj, ["head", "head_hinge", "neck_socket", "head_ctrl"]) # hinge & extras
149
150     # Add the head hinge at the bodys location, becomes the parent of the original head
151
152     # apply everything to this copy of the chain
153     ex_chain = mt_chain.copy(base_names=base_names)
154     ex_chain.neck_01_e.parent = mt_chain.neck_01_e.parent
155
156
157     # Copy the head bone and offset
158     ex.head_e = copy_bone_simple(arm, mt.head, "MCH-%s" % base_names[mt.head], parent=True)
159     ex.head_e.connected = False
160     ex.head = ex.head_e.name
161     # offset
162     head_length = ex.head_e.length
163     ex.head_e.head.y += head_length / 2.0
164     ex.head_e.tail.y += head_length / 2.0
165
166     # Yes, use the body bone but call it a head hinge
167     ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH-%s_hinge" % base_names[mt.head], parent=False)
168     ex.head_hinge_e.connected = False
169     ex.head_hinge = ex.head_hinge_e.name
170     ex.head_hinge_e.head.y += head_length / 4.0
171     ex.head_hinge_e.tail.y += head_length / 4.0
172
173     # Insert the neck socket, the head copys this loation
174     ex.neck_socket_e = arm.edit_bones.new("MCH-%s_socked" % neck_chain_basename)
175     ex.neck_socket = ex.neck_socket_e.name
176     ex.neck_socket_e.connected = False
177     ex.neck_socket_e.parent = mt.body_e
178     ex.neck_socket_e.head = mt.head_e.head
179     ex.neck_socket_e.tail = mt.head_e.head - Vector(0.0, neck_chain_segment_length / 2.0, 0.0)
180     ex.neck_socket_e.roll = 0.0
181
182
183     # copy of the head for controling
184     ex.head_ctrl_e = copy_bone_simple(arm, mt.head, base_names[mt.head])
185     ex.head_ctrl = ex.head_ctrl_e.name
186     ex.head_ctrl_e.parent = ex.head_hinge_e
187
188     for i, attr in enumerate(ex_chain.attr_names):
189         neck_e = getattr(ex_chain, attr + "_e")
190
191         # dont store parent names, re-reference as each chain bones parent.
192         neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % base_names[getattr(mt_chain, attr)])
193         neck_e_parent.head = neck_e.head
194         neck_e_parent.tail = neck_e.head + (mt.head_e.vector.normalize() * neck_chain_segment_length / 2.0)
195         neck_e_parent.roll = mt.head_e.roll
196
197         orig_parent = neck_e.parent
198         neck_e.connected = False
199         neck_e.parent = neck_e_parent
200         neck_e_parent.connected = False
201
202         if i == 0:
203             neck_e_parent.parent = mt.body_e
204         else:
205             neck_e_parent.parent = orig_parent
206
207     deform(obj, bone_definition, base_names, options)
208
209     bpy.ops.object.mode_set(mode='OBJECT')
210
211     mt.update()
212     mt_chain.update()
213     ex_chain.update()
214     ex.update()
215
216     # Axis locks
217     ex.head_ctrl_p.lock_location = True, True, True
218
219     # Simple one off constraints, no drivers
220     con = ex.head_ctrl_p.constraints.new('COPY_LOCATION')
221     con.target = obj
222     con.subtarget = ex.neck_socket
223
224     con = ex.head_p.constraints.new('COPY_ROTATION')
225     con.target = obj
226     con.subtarget = ex.head_ctrl
227
228     # driven hinge
229     prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, "hinge", create=True)
230     ex.head_ctrl_p["hinge"] = 0.0
231     prop["soft_min"] = 0.0
232     prop["soft_max"] = 1.0
233
234     con = ex.head_hinge_p.constraints.new('COPY_ROTATION')
235     con.name = "hinge"
236     con.target = obj
237     con.subtarget = mt.body
238
239     # add driver
240     hinge_driver_path = ex.head_ctrl_p.path_from_id() + '["hinge"]'
241
242     fcurve = con.driver_add("influence", 0)
243     driver = fcurve.driver
244     var = driver.variables.new()
245     driver.type = 'AVERAGE'
246     var.name = "var"
247     var.targets[0].id_type = 'OBJECT'
248     var.targets[0].id = obj
249     var.targets[0].data_path = hinge_driver_path
250
251     #mod = fcurve_driver.modifiers.new('GENERATOR')
252     mod = fcurve.modifiers[0]
253     mod.poly_order = 1
254     mod.coefficients[0] = 1.0
255     mod.coefficients[1] = -1.0
256
257     head_driver_path = ex.head_ctrl_p.path_from_id()
258
259     target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))]
260
261     ex.head_ctrl_p["bend_tot"] = 0.0
262     fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]', 0)
263     driver = fcurve.driver
264     driver.type = 'SUM'
265     fcurve.modifiers.remove(0) # grr dont need a modifier
266
267     for i in range(len(neck_chain)):
268         var = driver.variables.new()
269         var.name = target_names[i]
270         var.targets[0].id_type = 'OBJECT'
271         var.targets[0].id = obj
272         var.targets[0].data_path = head_driver_path + ('["bend_%.2d"]' % (i + 1))
273
274
275     for i, attr in enumerate(ex_chain.attr_names):
276         neck_p = getattr(ex_chain, attr + "_p")
277         neck_p.lock_location = True, True, True
278         neck_p.lock_location = True, True, True
279         neck_p.lock_rotations_4d = True
280
281         # Add bend prop
282         prop_name = "bend_%.2d" % (i + 1)
283         prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, prop_name, create=True)
284         ex.head_ctrl_p[prop_name] = 1.0
285         prop["soft_min"] = 0.0
286         prop["soft_max"] = 1.0
287
288         # add parent constraint
289         neck_p_parent = neck_p.parent
290
291         # add constraint
292         con = neck_p_parent.constraints.new('COPY_ROTATION')
293         con.name = "Copy Rotation"
294         con.target = obj
295         con.subtarget = ex.head
296         con.owner_space = 'LOCAL'
297         con.target_space = 'LOCAL'
298
299         fcurve = con.driver_add("influence", 0)
300         driver = fcurve.driver
301         driver.type = 'SCRIPTED'
302         driver.expression = "bend/bend_tot"
303
304         fcurve.modifiers.remove(0) # grr dont need a modifier
305
306
307         # add target
308         var = driver.variables.new()
309         var.name = "bend_tot"
310         var.targets[0].id_type = 'OBJECT'
311         var.targets[0].id = obj
312         var.targets[0].data_path = head_driver_path + ('["bend_tot"]')
313
314         var = driver.variables.new()
315         var.name = "bend"
316         var.targets[0].id_type = 'OBJECT'
317         var.targets[0].id = obj
318         var.targets[0].data_path = head_driver_path + ('["%s"]' % prop_name)
319
320
321         # finally constrain the original bone to this one
322         orig_neck_p = getattr(mt_chain, attr + "_p")
323         con = orig_neck_p.constraints.new('COPY_ROTATION')
324         con.target = obj
325         con.subtarget = neck_p.name
326
327
328     # Set the head control's custom shape to use the last
329     # org neck bone for its transform
330     ex.head_ctrl_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
331
332
333     # last step setup layers
334     if "ex_layer" in options:
335         layer = [n == options["ex_layer"] for n in range(0, 32)]
336     else:
337         layer = list(arm.bones[bone_definition[1]].layer)
338     for attr in ex_chain.attr_names:
339         getattr(ex_chain, attr + "_b").layer = layer
340     for attr in ex.attr_names:
341         getattr(ex, attr + "_b").layer = layer
342
343     layer = list(arm.bones[bone_definition[1]].layer)
344     ex.head_ctrl_b.layer = layer
345
346
347     # no blending the result of this
348     return None