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