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