68501ac829b10a75a229172b6e9cda7f13aa79d8
[blender-staging.git] / release / scripts / modules / rigify / shape_key_distance.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
24 #METARIG_NAMES = ("cpy",)
25 RIG_TYPE = "shape_key_distance"
26
27
28 def addget_shape_key(obj, name="Key"):
29     """ Fetches a shape key, or creates it if it doesn't exist
30     """
31     # Create a shapekey set if it doesn't already exist
32     if obj.data.shape_keys is None:
33         shape = obj.add_shape_key(name="Basis", from_mix=False)
34         obj.active_shape_key_index = 0
35
36     # Get the shapekey, or create it if it doesn't already exist
37     if name in obj.data.shape_keys.keys:
38         shape_key = obj.data.shape_keys.keys[name]
39     else:
40         shape_key = obj.add_shape_key(name=name, from_mix=False)
41
42     return shape_key
43
44
45 def addget_shape_key_driver(obj, name="Key"):
46     """ Fetches the driver for the shape key, or creates it if it doesn't
47         already exist.
48     """
49     driver_path = 'keys["' + name + '"].value'
50     fcurve = None
51     driver = None
52     if obj.data.shape_keys.animation_data is not None:
53         for driver_s in obj.data.shape_keys.animation_data.drivers:
54             if driver_s.data_path == driver_path:
55                 fcurve = driver_s
56     if fcurve == None:
57         fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0)
58     fcurve.driver.type = 'AVERAGE'
59
60     return fcurve
61
62
63
64
65 def metarig_template():
66     # generated by rigify.write_meta_rig
67     bpy.ops.object.mode_set(mode='EDIT')
68     obj = bpy.context.active_object
69     arm = obj.data
70     bone = arm.edit_bones.new('Bone')
71     bone.head[:] = 0.0000, 0.0000, 0.0000
72     bone.tail[:] = 0.0000, 0.0000, 1.0000
73     bone.roll = 0.0000
74     bone.connected = False
75
76     bpy.ops.object.mode_set(mode='OBJECT')
77     pbone = obj.pose.bones['Bone']
78     pbone['type'] = 'copy'
79
80
81 def metarig_definition(obj, orig_bone_name):
82     bone = obj.data.bones[orig_bone_name]
83     return [bone.name]
84
85
86 def deform(obj, definitions, base_names, options):
87     bpy.ops.object.mode_set(mode='EDIT')
88     eb = obj.data.edit_bones
89
90     bone_from = definitions[0]
91
92
93     # Options
94     req_options = ["to", "mesh", "shape_key"]
95     for option in req_options:
96         if option not in options:
97             raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
98
99     bone_to = "ORG-" + options["to"]
100     meshes = options["mesh"].replace(" ", "").split(",")
101     shape_key_name = options["shape_key"]
102
103     if "dmul" in options:
104         shape_blend_fac = options["dmul"]
105     else:
106         shape_blend_fac = 1.0
107
108
109     # Calculate the distance between the bones
110     distance = (eb[bone_from].head - eb[bone_to].head).length
111
112     bpy.ops.object.mode_set(mode='OBJECT')
113
114     # For every listed mesh object
115     for mesh_name in meshes:
116         mesh_obj = bpy.data.objects[mesh_name]
117
118         # Add/get the shape key
119         shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
120
121         # Add/get the shape key driver
122         fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name)
123         driver = fcurve.driver
124
125         # Get the variable, or create it if it doesn't already exist
126         var_name = base_names[bone_from]
127         if var_name in driver.variables:
128             var = driver.variables[var_name]
129         else:
130             var = driver.variables.new()
131             var.name = var_name
132
133         # Set up the variable
134         var.type = "LOC_DIFF"
135         var.targets[0].id_type = 'OBJECT'
136         var.targets[0].id = obj
137         var.targets[0].bone_target = bone_from
138         var.targets[1].id_type = 'OBJECT'
139         var.targets[1].id = obj
140         var.targets[1].bone_target = bone_to
141
142         # Set fcurve offset, so zero is at the rest distance
143
144         mod = fcurve.modifiers[0]
145         if distance > 0.00001:
146             mod.coefficients[0] = -shape_blend_fac
147             mod.coefficients[1] = shape_blend_fac / distance
148
149     return (None,)
150
151
152
153
154 def control(obj, definitions, base_names, options):
155     """ options:
156         mesh: name of mesh object with the shape key
157         shape_key: name of shape key
158         to: name of bone to measure distance from
159     """
160     pass
161
162
163
164
165 def main(obj, bone_definition, base_names, options):
166     # Create control rig
167     #control(obj, bone_definition, base_names, options)
168     # Create deform rig
169     deform(obj, bone_definition, base_names, options)
170
171     return (None,)
172