edits to the bone copy metarig type from Cessen, pointcache warning fix
[blender.git] / release / scripts / modules / rigify / finger_curl.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 RigifyError, get_layer_dict
23 from rigify_utils import copy_bone_simple, get_side_name
24 from rna_prop_ui import rna_idprop_ui_prop_get
25 from functools import reduce
26
27 METARIG_NAMES = "finger_01", "finger_02", "finger_03"
28
29
30 def metarig_template():
31     bpy.ops.object.mode_set(mode='EDIT')
32     obj = bpy.context.active_object
33     arm = obj.data
34     bone = arm.edit_bones.new('finger.01')
35     bone.head[:] = 0.0000, 0.0000, 0.0000
36     bone.tail[:] = 0.8788, -0.4584, -0.1327
37     bone.roll = -2.8722
38     bone.connected = False
39     bone = arm.edit_bones.new('finger.02')
40     bone.head[:] = 0.8788, -0.4584, -0.1327
41     bone.tail[:] = 1.7483, -0.9059, -0.3643
42     bone.roll = -2.7099
43     bone.connected = True
44     bone.parent = arm.edit_bones['finger.01']
45     bone = arm.edit_bones.new('finger.03')
46     bone.head[:] = 1.7483, -0.9059, -0.3643
47     bone.tail[:] = 2.2478, -1.1483, -0.7408
48     bone.roll = -2.1709
49     bone.connected = True
50     bone.parent = arm.edit_bones['finger.02']
51
52     bpy.ops.object.mode_set(mode='OBJECT')
53     pbone = obj.pose.bones['finger.01']
54     pbone['type'] = 'finger_curl'
55
56
57 def metarig_definition(obj, orig_bone_name):
58     '''
59     The bone given is the first in a chain
60     Expects a chain of at least 2 children.
61     eg.
62         finger -> finger_01 -> finger_02
63     '''
64
65     bone_definition = []
66
67     orig_bone = obj.data.bones[orig_bone_name]
68
69     bone_definition.append(orig_bone.name)
70
71     bone = orig_bone
72     chain = 0
73     while chain < 2: # first 2 bones only have 1 child
74         children = bone.children
75
76         if len(children) != 1:
77             raise RigifyError("expected the chain to have 2 children from bone '%s' without a fork" % orig_bone_name)
78         bone = children[0]
79         bone_definition.append(bone.name) # finger_02, finger_03
80         chain += 1
81
82     if len(bone_definition) != len(METARIG_NAMES):
83         raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
84
85     return bone_definition
86
87
88 def main(obj, bone_definition, base_names, options):
89     # *** EDITMODE
90
91     # get assosiated data
92     arm = obj.data
93     orig_ebone = arm.edit_bones[bone_definition[0]]
94
95     obj.animation_data_create() # needed if its a new armature with no keys
96
97     children = orig_ebone.children_recursive
98     tot_len = reduce(lambda f, ebone: f + ebone.length, children, orig_ebone.length)
99
100     # FIXME, the line below is far too arbitrary
101     base_name = base_names[bone_definition[0]].rsplit(".", 2)[0]
102
103     # first make a new bone at the location of the finger
104     #control_ebone = arm.edit_bones.new(base_name)
105     control_ebone = copy_bone_simple(arm, bone_definition[0], base_name + get_side_name(base_names[bone_definition[0]]), parent=True)
106     control_bone_name = control_ebone.name # we dont know if we get the name requested
107
108     control_ebone.connected = orig_ebone.connected
109     control_ebone.parent = orig_ebone.parent
110     control_ebone.length = tot_len
111
112     # now add bones inbetween this and its children recursively
113
114     # switching modes so store names only!
115     children = [ebone.name for ebone in children]
116
117     driver_bone_pairs = []
118
119     for child_bone_name in children:
120         child_ebone = arm.edit_bones[child_bone_name]
121
122         # finger.02 --> finger_driver.02
123         driver_bone_name = child_bone_name.split('.')
124         driver_bone_name = driver_bone_name[0] + "_driver." + ".".join(driver_bone_name[1:])
125
126         driver_ebone = copy_bone_simple(arm, child_ebone.name, driver_bone_name)
127         driver_ebone.length *= 0.5
128
129         # Insert driver_ebone in the chain without connected parents
130         driver_ebone.connected = False
131         driver_ebone.parent = child_ebone.parent
132
133         child_ebone.connected = False
134         child_ebone.parent = driver_ebone
135
136         # Add the drivers to these when in posemode.
137         driver_bone_pairs.append((child_bone_name, driver_bone_name))
138
139     del control_ebone
140
141
142     # *** POSEMODE
143     bpy.ops.object.mode_set(mode='OBJECT')
144
145
146     orig_pbone = obj.pose.bones[bone_definition[0]]
147     control_pbone = obj.pose.bones[control_bone_name]
148
149
150     # only allow Y scale
151     control_pbone.lock_scale = (True, False, True)
152
153     control_pbone["bend_ratio"] = 0.4
154     prop = rna_idprop_ui_prop_get(control_pbone, "bend_ratio", create=True)
155     prop["soft_min"] = 0.0
156     prop["soft_max"] = 1.0
157
158     con = orig_pbone.constraints.new('COPY_LOCATION')
159     con.target = obj
160     con.subtarget = control_bone_name
161
162     con = orig_pbone.constraints.new('COPY_ROTATION')
163     con.target = obj
164     con.subtarget = control_bone_name
165
166
167
168     # setup child drivers on each new smaller bone added. assume 2 for now.
169
170     # drives the bones
171     controller_path = control_pbone.path_to_id() # 'pose.bones["%s"]' % control_bone_name
172
173     i = 0
174     for child_bone_name, driver_bone_name in driver_bone_pairs:
175
176         # XXX - todo, any number
177         if i == 2:
178             break
179
180         driver_pbone = obj.pose.bones[driver_bone_name]
181
182         driver_pbone.rotation_mode = 'YZX'
183         fcurve_driver = driver_pbone.driver_add("rotation_euler", 0)
184
185         #obj.driver_add('pose.bones["%s"].scale', 1)
186         #obj.animation_data.drivers[-1] # XXX, WATCH THIS
187         driver = fcurve_driver.driver
188
189         # scale target
190         tar = driver.targets.new()
191         tar.name = "scale"
192         tar.id_type = 'OBJECT'
193         tar.id = obj
194         tar.data_path = controller_path + '.scale[1]'
195
196         # bend target
197         tar = driver.targets.new()
198         tar.name = "br"
199         tar.id_type = 'OBJECT'
200         tar.id = obj
201         tar.data_path = controller_path + '["bend_ratio"]'
202
203         # XXX - todo, any number
204         if i == 0:
205             driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)'
206         elif i == 1:
207             driver.expression = '(-scale+1.0)*pi*2.0*br'
208
209         child_pbone = obj.pose.bones[child_bone_name]
210
211         # only allow X rotation
212         driver_pbone.lock_rotation = child_pbone.lock_rotation = (False, True, True)
213
214         i += 1
215
216
217     # last step setup layers
218     layers = get_layer_dict(options)
219     lay = layers["extra"]
220     for child_bone_name, driver_bone_name in driver_bone_pairs:
221         arm.bones[driver_bone_name].layer = lay
222
223     lay = layers["main"]
224     arm.bones[control_bone_name].layer = lay
225
226     # no blending the result of this
227     return None