Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-11-30 15:31:11 +0300
committerCampbell Barton <ideasman42@gmail.com>2009-11-30 15:31:11 +0300
commita2140192fe0784538c9b9e905d0672b05ec00b5d (patch)
tree2dddde08af285745ba5093fd34e3d6297262535a /release/scripts
parent679da5eb50651f9000333df424fbcdd73d129fc0 (diff)
convert rigify into a package. advantage is new types can be added into the package without modifying any existing files, the bone 'type' property will find the matching submodule
Diffstat (limited to 'release/scripts')
-rw-r--r--release/scripts/modules/rigify.py888
-rw-r--r--release/scripts/modules/rigify/__init__.py236
-rw-r--r--release/scripts/modules/rigify/arm.py315
-rw-r--r--release/scripts/modules/rigify/delta.py109
-rw-r--r--release/scripts/modules/rigify/finger.py173
-rw-r--r--release/scripts/modules/rigify/palm.py130
6 files changed, 963 insertions, 888 deletions
diff --git a/release/scripts/modules/rigify.py b/release/scripts/modules/rigify.py
deleted file mode 100644
index 3cdd2baa0dd..00000000000
--- a/release/scripts/modules/rigify.py
+++ /dev/null
@@ -1,888 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-import bpy
-from functools import reduce
-from Mathutils import Vector
-
-# TODO, have these in a more general module
-from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
-
-empty_layer = [False] * 16
-
-def auto_class(slots, name="ContainerClass"):
- return type(name, (object,), {"__slots__":tuple(slots)})
-
-def auto_class_instance(slots, name="ContainerClass"):
- return auto_class(slots, name)()
-
-
-
-def bone_class_instance(obj, slots, name="BoneContainer"):
- for member in slots[:]:
- slots.append(member + "_b") # bone bone
- slots.append(member + "_p") # pose bone
- slots.append(member + "_e") # edit bone
-
- slots.extend(["obj", "update"])
-
- instance = auto_class_instance(slots, name)
-
- def update():
- '''
- Re-Assigns bones from the blender data
- '''
- arm = obj.data
-
- bbones = arm.bones
- pbones = obj.pose.bones
- ebones = arm.edit_bones
-
- for member in slots:
-
- if member in ("update", "obj"):
- continue
-
- if not member[-2] == "_":
- name = getattr(instance, member, None)
- if name is not None:
- setattr(instance, member + "_b", bbones.get(name, None))
- setattr(instance, member + "_p", pbones.get(name, None))
- setattr(instance, member + "_e", ebones.get(name, None))
-
- instance.update = update
-
- return instance
-
-def gen_none(obj, orig_bone_name):
- pass
-
-def get_bone_data(obj, bone_name):
- arm = obj.data
- pbone = obj.pose.bones[bone_name]
- if obj.mode == 'EDIT':
- bone = arm.edit_bones[bone_name]
- else:
- bone = arm.bones[bone_name]
-
- return arm, pbone, bone
-
-def bone_basename(name):
- return name.split(".")[0]
-
-def copy_bone_simple(arm, from_bone, name, parent=False):
- ebone = arm.edit_bones[from_bone]
- ebone_new = arm.edit_bones.new(name)
-
- if parent:
- ebone_new.connected = ebone.connected
- ebone_new.parent = ebone.parent
-
- ebone_new.head = ebone.head
- ebone_new.tail = ebone.tail
- ebone_new.roll = ebone.roll
- return ebone_new
-
-
-def add_stretch_to(obj, from_name, to_name, name):
- '''
- Adds a bone that stretches from one to another
- '''
-
- mode_orig = obj.mode
- bpy.ops.object.mode_set(mode='EDIT')
-
- arm = obj.data
- stretch_ebone = arm.edit_bones.new(name)
- stretch_name = stretch_ebone.name
- del name
-
- head = stretch_ebone.head = arm.edit_bones[from_name].head.copy()
- #tail = stretch_ebone.tail = arm.edit_bones[to_name].head.copy()
-
- # annoying exception for zero length bones, since its using stretch_to the rest pose doesnt really matter
- #if (head - tail).length < 0.1:
- if 1:
- tail = stretch_ebone.tail = arm.edit_bones[from_name].tail.copy()
-
-
- # Now for the constraint
- bpy.ops.object.mode_set(mode='OBJECT')
- from_pbone = obj.pose.bones[from_name]
- to_pbone = obj.pose.bones[to_name]
-
- stretch_pbone = obj.pose.bones[stretch_name]
-
- con = stretch_pbone.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = from_name
-
- con = stretch_pbone.constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = to_name
- con.original_length = (head - tail).length
- con.keep_axis = 'PLANE_X'
- con.volume = 'NO_VOLUME'
-
- bpy.ops.object.mode_set(mode=mode_orig)
-
-
-def add_pole_target_bone(obj, base_name, name, mode='CROSS'):
- '''
- Does not actually create a poll target, just the bone to use as a poll target
- '''
- mode_orig = obj.mode
- bpy.ops.object.mode_set(mode='EDIT')
-
- arm = obj.data
-
- poll_ebone = arm.edit_bones.new(base_name + "_poll")
- base_ebone = arm.edit_bones[base_name]
- poll_name = poll_ebone.name
- parent_ebone = base_ebone.parent
-
- base_head = base_ebone.head.copy()
- base_tail = base_ebone.tail.copy()
- base_dir = base_head - base_tail
-
- parent_head = parent_ebone.head.copy()
- parent_tail = parent_ebone.tail.copy()
- parent_dir = parent_head - parent_tail
-
- distance = (base_dir.length + parent_dir.length)
-
- if mode == 'CROSS':
- offset = base_dir.copy().normalize() - parent_dir.copy().normalize()
- offset.length = distance
- else:
- offset = Vector(0,0,0)
- if mode[0]=="+":
- val = distance
- else:
- val = -distance
-
- setattr(offset, mode[1].lower(), val)
-
- poll_ebone.head = base_head + offset
- poll_ebone.tail = base_head + (offset * (1.0 - (1.0 / 4.0)))
-
- bpy.ops.object.mode_set(mode=mode_orig)
-
- return poll_name
-
-
-def gen_finger(obj, orig_bone_name):
-
- # *** EDITMODE
-
- # get assosiated data
- arm, orig_pbone, orig_ebone = get_bone_data(obj, orig_bone_name)
-
- obj.animation_data_create() # needed if its a new armature with no keys
-
- arm.layer[0] = arm.layer[8] = True
-
- children = orig_pbone.children_recursive
- tot_len = reduce(lambda f, pbone: f + pbone.bone.length, children, orig_pbone.bone.length)
-
- base_name = bone_basename(orig_pbone.name)
-
- # first make a new bone at the location of the finger
- control_ebone = arm.edit_bones.new(base_name)
- control_bone_name = control_ebone.name # we dont know if we get the name requested
-
- control_ebone.connected = orig_ebone.connected
- control_ebone.parent = orig_ebone.parent
-
- # Place the finger bone
- head = orig_ebone.head.copy()
- tail = orig_ebone.tail.copy()
-
- control_ebone.head = head
- control_ebone.tail = head + ((tail - head).normalize() * tot_len)
- control_ebone.roll = orig_ebone.roll
-
- # now add bones inbetween this and its children recursively
-
- # switching modes so store names only!
- children = [pbone.name for pbone in children]
-
- # set an alternate layer for driver bones
- other_layer = empty_layer[:]
- other_layer[8] = True
-
-
- driver_bone_pairs = []
-
- for child_bone_name in children:
- arm, pbone_child, child_ebone = get_bone_data(obj, child_bone_name)
-
- # finger.02 --> finger_driver.02
- driver_bone_name = child_bone_name.split('.')
- driver_bone_name = driver_bone_name[0] + "_driver." + ".".join(driver_bone_name[1:])
-
- driver_ebone = arm.edit_bones.new(driver_bone_name)
- driver_bone_name = driver_ebone.name # cant be too sure!
- driver_ebone.layer = other_layer
-
- new_len = pbone_child.bone.length / 2.0
-
- head = child_ebone.head.copy()
- tail = child_ebone.tail.copy()
-
- driver_ebone.head = head
- driver_ebone.tail = head + ((tail - head).normalize() * new_len)
- driver_ebone.roll = child_ebone.roll
-
- # Insert driver_ebone in the chain without connected parents
- driver_ebone.connected = False
- driver_ebone.parent = child_ebone.parent
-
- child_ebone.connected = False
- child_ebone.parent = driver_ebone
-
- # Add the drivers to these when in posemode.
- driver_bone_pairs.append((child_bone_name, driver_bone_name))
-
- del control_ebone
-
-
- # *** POSEMODE
- bpy.ops.object.mode_set(mode='OBJECT')
-
-
- arm, orig_pbone, orig_bone = get_bone_data(obj, orig_bone_name)
- arm, control_pbone, control_bone= get_bone_data(obj, control_bone_name)
-
-
- # only allow Y scale
- control_pbone.lock_scale = (True, False, True)
-
- control_pbone["bend_ratio"] = 0.4
- prop = rna_idprop_ui_prop_get(control_pbone, "bend_ratio", create=True)
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- con = orig_pbone.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = control_bone_name
-
- con = orig_pbone.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = control_bone_name
-
-
-
- # setup child drivers on each new smaller bone added. assume 2 for now.
-
- # drives the bones
- controller_path = control_pbone.path_to_id() # 'pose.bones["%s"]' % control_bone_name
-
- i = 0
- for child_bone_name, driver_bone_name in driver_bone_pairs:
-
- # XXX - todo, any number
- if i==2:
- break
-
- arm, driver_pbone, driver_bone = get_bone_data(obj, driver_bone_name)
-
- driver_pbone.rotation_mode = 'YZX'
- fcurve_driver = driver_pbone.driver_add("rotation_euler", 0)
-
- #obj.driver_add('pose.bones["%s"].scale', 1)
- #obj.animation_data.drivers[-1] # XXX, WATCH THIS
- driver = fcurve_driver.driver
-
- # scale target
- tar = driver.targets.new()
- tar.name = "scale"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = controller_path + '.scale[1]'
-
- # bend target
- tar = driver.targets.new()
- tar.name = "br"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = controller_path + '["bend_ratio"]'
-
- # XXX - todo, any number
- if i==0:
- driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)'
- elif i==1:
- driver.expression = '(-scale+1.0)*pi*2.0*br'
-
- arm, child_pbone, child_bone = get_bone_data(obj, child_bone_name)
-
- # only allow X rotation
- driver_pbone.lock_rotation = child_pbone.lock_rotation = (False, True, True)
-
- i += 1
-
-
-def gen_delta(obj, delta_name):
- '''
- Use this bone to define a delta thats applied to its child in pose mode.
- '''
-
- arm = obj.data
-
- mode_orig = obj.mode
- bpy.ops.object.mode_set(mode='OBJECT')
-
- delta_pbone = obj.pose.bones[delta_name]
- children = delta_pbone.children
-
- if len(children) != 1:
- print("only 1 child supported for delta")
-
- child_name = children[0].name
- arm, child_pbone, child_bone = get_bone_data(obj, child_name)
-
- delta_phead = delta_pbone.head.copy()
- delta_ptail = delta_pbone.tail.copy()
- delta_pmatrix = delta_pbone.matrix.copy()
-
- child_phead = child_pbone.head.copy()
- child_ptail = child_pbone.tail.copy()
- child_pmatrix = child_pbone.matrix.copy()
-
-
- children = delta_pbone.children
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- delta_ebone = arm.edit_bones[delta_name]
- child_ebone = arm.edit_bones[child_name]
-
- delta_head = delta_ebone.head.copy()
- delta_tail = delta_ebone.tail.copy()
-
- # arm, parent_pbone, parent_bone = get_bone_data(obj, delta_name)
- child_head = child_ebone.head.copy()
- child_tail = child_ebone.tail.copy()
-
- arm.edit_bones.remove(delta_ebone)
- del delta_ebone # cant use thz
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
-
- # Move the child bone to the deltas location
- obj.animation_data_create()
- child_pbone = obj.pose.bones[child_name]
-
- # ------------------- drivers
-
- child_pbone.rotation_mode = 'XYZ'
-
- rot = delta_pmatrix.invert().rotationPart() * child_pmatrix.rotationPart()
- rot = rot.invert().toEuler()
-
- fcurve_drivers = child_pbone.driver_add("rotation_euler", -1)
- for i, fcurve_driver in enumerate(fcurve_drivers):
- driver = fcurve_driver.driver
- driver.type = 'AVERAGE'
- #mod = fcurve_driver.modifiers.new('GENERATOR')
- mod = fcurve_driver.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = rot[i]
- mod.coefficients[1] = 0.0
-
- # tricky, find the transform to drive the bone to this location.
- delta_head_offset = child_pmatrix.rotationPart() * (delta_phead - child_phead)
-
- fcurve_drivers = child_pbone.driver_add("location", -1)
- for i, fcurve_driver in enumerate(fcurve_drivers):
- driver = fcurve_driver.driver
- driver.type = 'AVERAGE'
- #mod = fcurve_driver.modifiers.new('GENERATOR')
- mod = fcurve_driver.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = delta_head_offset[i]
- mod.coefficients[1] = 0.0
-
-
- # arm, parent_pbone, parent_bone = get_bone_data(obj, delta_name)
- bpy.ops.object.mode_set(mode='EDIT')
-
- bpy.ops.object.mode_set(mode=mode_orig)
-
-
-def gen_arm(obj, orig_bone_name):
- """
- the bone with the 'arm' property is the upper arm, this assumes a chain as follows.
- [shoulder, upper_arm, forearm, hand]
- ...where this bone is 'upper_arm'
-
- there are 3 chains
- - Original
- - IK, MCH-%s_ik
- - IKSwitch, MCH-%s ()
- """
-
- # Since there are 3 chains, this gets confusing so divide into 3 chains
- # Initialize container classes for convenience
- mt = bone_class_instance(obj, ["shoulder", "arm", "forearm", "hand"]) # meta
- ik = bone_class_instance(obj, ["arm", "forearm", "pole", "hand"]) # ik
- sw = bone_class_instance(obj, ["socket", "shoulder", "arm", "forearm", "hand"]) # hinge
- ex = bone_class_instance(obj, ["arm_hinge"]) # hinge & extras
-
-
- def chain_init():
- '''
- Sanity check and return the arm as a list of bone names.
- '''
- # do a sanity check
- mt.arm = orig_bone_name
- mt.update()
-
- mt.shoulder_p = mt.arm_p.parent
- mt.shoulder = mt.shoulder_p.name
-
- if not mt.shoulder_p:
- print("could not find 'arm' parent, skipping:", orig_bone_name)
- return
-
- # We could have some bones attached, find the bone that has this as its 2nd parent
- hands = []
- for pbone in obj.pose.bones:
- index = pbone.parent_index(mt.arm_p)
- if index == 2:
- hands.append(pbone)
-
- if len(hands) > 1:
- print("more then 1 hand found on:", orig_bone_name)
- return
-
- # first add the 2 new bones
- mt.hand_p = hands[0]
- mt.hand = mt.hand_p.name
-
- mt.forearm_p = mt.hand_p.parent
- mt.forearm = mt.forearm_p.name
-
- arm = obj.data
-
-
- def chain_ik(prefix="MCH-%s_ik"):
-
- mt.update()
-
- # Add the edit bones
- ik.hand_e = copy_bone_simple(arm, mt.hand, prefix % mt.hand)
- ik.hand = ik.hand_e.name
-
- ik.arm_e = copy_bone_simple(arm, mt.arm, prefix % mt.arm)
- ik.arm = ik.arm_e.name
-
- ik.forearm_e = copy_bone_simple(arm, mt.forearm, prefix % mt.forearm)
- ik.forearm = ik.forearm_e.name
-
- ik.arm_e.parent = mt.arm_e.parent
- ik.forearm_e.connected = mt.arm_e.connected
-
- ik.forearm_e.parent = ik.arm_e
- ik.forearm_e.connected = True
-
-
- # Add the bone used for the arms poll target
- ik.pole = add_pole_target_bone(obj, mt.forearm, "elbow_poll", mode='+Z')
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- ik.update()
-
- con = ik.forearm_p.constraints.new('IK')
- con.target = obj
- con.subtarget = ik.hand
- con.pole_target = obj
- con.pole_subtarget = ik.pole
-
- con.use_tail = True
- con.use_stretch = True
- con.use_target = True
- con.use_rotation = False
- con.chain_length = 2
- con.pole_angle = -90.0 # XXX, RAD2DEG
-
- # ID Propery on the hand for IK/FK switch
-
- prop = rna_idprop_ui_prop_get(ik.hand_p, "ik", create=True)
- ik.hand_p["ik"] = 0.5
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- ik.arm = ik.arm
- ik.forearm = ik.forearm
- ik.hand = ik.hand
- ik.pole = ik.pole
-
- def chain_switch(prefix="MCH-%s"):
-
- sw.update()
- mt.update()
-
- sw.shoulder_e = copy_bone_simple(arm, mt.shoulder, prefix % mt.shoulder)
- sw.shoulder = sw.shoulder_e.name
- sw.shoulder_e.parent = mt.shoulder_e.parent
- sw.shoulder_e.connected = mt.shoulder_e.connected
-
- sw.arm_e = copy_bone_simple(arm, mt.arm, prefix % mt.arm)
- sw.arm = sw.arm_e.name
- sw.arm_e.parent = sw.shoulder_e
- sw.arm_e.connected = arm.edit_bones[mt.shoulder].connected
-
- sw.forearm_e = copy_bone_simple(arm, mt.forearm, prefix % mt.forearm)
- sw.forearm = sw.forearm_e.name
- sw.forearm_e.parent = sw.arm_e
- sw.forearm_e.connected = arm.edit_bones[mt.forearm].connected
-
- sw.hand_e = copy_bone_simple(arm, mt.hand, prefix % mt.hand)
- sw.hand = sw.hand_e.name
- sw.hand_e.parent = sw.forearm_e
- sw.hand_e.connected = arm.edit_bones[mt.hand].connected
-
- # The sw.hand_e needs to own all the children on the metarig's hand
- for child in mt.hand_e.children:
- child.parent = sw.hand_e
-
-
- # These are made the children of sw.shoulder_e
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Add constraints
- sw.update()
-
- #dummy, ik.arm, ik.forearm, ik.hand, ik.pole = ik_chain_tuple
-
- ik_driver_path = obj.pose.bones[ik.hand].path_to_id() + '["ik"]'
-
-
- def ik_fk_driver(con):
- '''
- 3 bones use this for ik/fk switching
- '''
- fcurve = con.driver_add("influence", 0)
- driver = fcurve.driver
- tar = driver.targets.new()
- driver.type = 'AVERAGE'
- tar.name = "ik"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = ik_driver_path
-
- # ***********
- con = sw.arm_p.constraints.new('COPY_ROTATION')
- con.name = "FK"
- con.target = obj
- con.subtarget = mt.arm
-
- con = sw.arm_p.constraints.new('COPY_ROTATION')
-
- con.target = obj
- con.subtarget = ik.arm
- con.influence = 0.5
- ik_fk_driver(con)
-
- # ***********
- con = sw.forearm_p.constraints.new('COPY_ROTATION')
- con.name = "FK"
- con.target = obj
- con.subtarget = mt.forearm
-
- con = sw.forearm_p.constraints.new('COPY_ROTATION')
- con.name = "IK"
- con.target = obj
- con.subtarget = ik.forearm
- con.influence = 0.5
- ik_fk_driver(con)
-
- # ***********
- con = sw.hand_p.constraints.new('COPY_ROTATION')
- con.name = "FK"
- con.target = obj
- con.subtarget = mt.hand
-
- con = sw.hand_p.constraints.new('COPY_ROTATION')
- con.name = "IK"
- con.target = obj
- con.subtarget = ik.hand
- con.influence = 0.5
- ik_fk_driver(con)
-
-
- add_stretch_to(obj, sw.forearm, ik.pole, "VIS-elbow_ik_poll")
- add_stretch_to(obj, sw.hand, ik.hand, "VIS-hand_ik")
-
- bpy.ops.object.mode_set(mode='EDIT')
-
-
- def chain_shoulder(prefix="MCH-%s"):
-
- sw.socket_e = copy_bone_simple(arm, mt.arm, (prefix % mt.arm) + "_socket")
- sw.socket = sw.socket_e.name
- sw.socket_e.tail = arm.edit_bones[mt.shoulder].tail
-
-
- # Set the shoulder as parent
- ik.update()
- sw.update()
- mt.update()
-
- sw.socket_e.parent = sw.shoulder_e
- ik.arm_e.parent = sw.shoulder_e
-
-
- # ***** add the shoulder hinge
- # yes this is correct, the shoulder copy gets the arm's name
- ex.arm_hinge_e = copy_bone_simple(arm, mt.shoulder, (prefix % mt.arm) + "_hinge")
- ex.arm_hinge = ex.arm_hinge_e.name
- offset = ex.arm_hinge_e.length / 2.0
-
- ex.arm_hinge_e.head.y += offset
- ex.arm_hinge_e.tail.y += offset
-
- # Note: meta arm becomes child of hinge
- mt.arm_e.parent = ex.arm_hinge_e
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- ex.update()
-
- con = mt.arm_p.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = sw.socket
-
-
- # Hinge constraint & driver
- con = ex.arm_hinge_p.constraints.new('COPY_ROTATION')
- con.name = "hinge"
- con.target = obj
- con.subtarget = sw.shoulder
- driver_fcurve = con.driver_add("influence", 0)
- driver = driver_fcurve.driver
-
-
- controller_path = mt.arm_p.path_to_id()
- # add custom prop
- mt.arm_p["hinge"] = 0.0
- prop = rna_idprop_ui_prop_get(mt.arm_p, "hinge", create=True)
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
-
- # *****
- driver = driver_fcurve.driver
- driver.type = 'AVERAGE'
-
- tar = driver.targets.new()
- tar.name = "hinge"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = controller_path + '["hinge"]'
-
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- # remove the shoulder and re-parent
-
-
-
- chain_init()
- chain_ik()
- chain_switch()
- chain_shoulder()
-
- # Shoulder with its delta and hinge.
-
-
-
-
-
-def gen_palm(obj, orig_bone_name):
- arm, palm_pbone, palm_ebone = get_bone_data(obj, orig_bone_name)
- children = [ebone.name for ebone in palm_ebone.children]
- children.sort() # simply assume the pinky has the lowest name
-
- # Make a copy of the pinky
- pinky_ebone = arm.edit_bones[children[0]]
- control_ebone = copy_bone_simple(arm, pinky_ebone.name, "palm_control", parent=True)
- control_name = control_ebone.name
-
- offset = (arm.edit_bones[children[0]].head - arm.edit_bones[children[1]].head)
-
- control_ebone.head += offset
- control_ebone.tail += offset
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
-
- arm, control_pbone, control_ebone = get_bone_data(obj, control_name)
- arm, pinky_pbone, pinky_ebone = get_bone_data(obj, children[0])
-
- control_pbone.rotation_mode = 'YZX'
- control_pbone.lock_rotation = False, True, True
-
- driver_fcurves = pinky_pbone.driver_add("rotation_euler")
-
-
- controller_path = control_pbone.path_to_id()
-
- # add custom prop
- control_pbone["spread"] = 0.0
- prop = rna_idprop_ui_prop_get(control_pbone, "spread", create=True)
- prop["soft_min"] = -1.0
- prop["soft_max"] = 1.0
-
-
- # *****
- driver = driver_fcurves[0].driver
- driver.type = 'AVERAGE'
-
- tar = driver.targets.new()
- tar.name = "x"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = controller_path + ".rotation_euler[0]"
-
-
- # *****
- driver = driver_fcurves[1].driver
- driver.expression = "-x/4.0"
-
- tar = driver.targets.new()
- tar.name = "x"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = controller_path + ".rotation_euler[0]"
-
-
- # *****
- driver = driver_fcurves[2].driver
- driver.expression = "(1.0-cos(x))-s"
- tar = driver.targets.new()
- tar.name = "x"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = controller_path + ".rotation_euler[0]"
-
- tar = driver.targets.new()
- tar.name = "s"
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = controller_path + '["spread"]'
-
-
- for i, child_name in enumerate(children):
- child_pbone = obj.pose.bones[child_name]
- child_pbone.rotation_mode = 'YZX'
-
- if child_name != children[-1] and child_name != children[0]:
-
- # this is somewhat arbitrary but seems to look good
- inf = i / (len(children)+1)
- inf = 1.0 - inf
- inf = ((inf * inf) + inf) / 2.0
-
- # used for X/Y constraint
- inf_minor = inf * inf
-
- con = child_pbone.constraints.new('COPY_ROTATION')
- con.name = "Copy Z Rot"
- con.target = obj
- con.subtarget = children[0] # also pinky_pbone
- con.owner_space = con.target_space = 'LOCAL'
- con.use_x, con.use_y, con.use_z = False, False, True
- con.influence = inf
-
- con = child_pbone.constraints.new('COPY_ROTATION')
- con.name = "Copy XY Rot"
- con.target = obj
- con.subtarget = children[0] # also pinky_pbone
- con.owner_space = con.target_space = 'LOCAL'
- con.use_x, con.use_y, con.use_z = True, True, False
- con.influence = inf_minor
-
-
- child_pbone = obj.pose.bones[children[-1]]
- child_pbone.rotation_mode = 'QUATERNION'
-
-
-gen_table = {
- "":gen_none, \
- "finger":gen_finger, \
- "delta":gen_delta, \
- "arm":gen_arm, \
- "palm":gen_palm, \
-}
-
-def generate_rig(context, ob):
-
- global_undo = context.user_preferences.edit.global_undo
- context.user_preferences.edit.global_undo = False
-
- # add_stretch_to(ob, "a", "b", "c")
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
-
- # copy object and data
- ob.selected = False
- ob_new = ob.copy()
- ob_new.data = ob.data.copy()
- scene = context.scene
- scene.objects.link(ob_new)
- scene.objects.active = ob_new
- ob_new.selected = True
-
- # enter armature editmode
-
-
- for pbone_name in ob_new.pose.bones.keys():
- bone_type = ob_new.pose.bones[pbone_name].get("type", "")
-
- try:
- func = gen_table[bone_type]
- except KeyError:
- print("\tunknown type '%s', bone '%s'" % (bone_type, pbone_name))
-
-
- # Toggle editmode so the pose data is always up to date
- bpy.ops.object.mode_set(mode='EDIT')
- func(ob_new, pbone_name)
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # needed to update driver deps
- # context.scene.update()
-
- # Only for demo'ing
- ob.restrict_view = True
- ob_new.data.draw_axes = False
-
- context.user_preferences.edit.global_undo = global_undo
-
-if __name__ == "__main__":
- generate_rig(bpy.context, bpy.context.object)
diff --git a/release/scripts/modules/rigify/__init__.py b/release/scripts/modules/rigify/__init__.py
new file mode 100644
index 00000000000..fa2a8040d01
--- /dev/null
+++ b/release/scripts/modules/rigify/__init__.py
@@ -0,0 +1,236 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+from Mathutils import Vector
+
+# TODO, have these in a more general module
+from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
+
+empty_layer = [False] * 32
+
+def auto_class(slots, name="ContainerClass"):
+ return type(name, (object,), {"__slots__":tuple(slots)})
+
+def auto_class_instance(slots, name="ContainerClass"):
+ return auto_class(slots, name)()
+
+def bone_class_instance(obj, slots, name="BoneContainer"):
+ for member in slots[:]:
+ slots.append(member + "_b") # bone bone
+ slots.append(member + "_p") # pose bone
+ slots.append(member + "_e") # edit bone
+
+ slots.extend(["obj", "update"])
+
+ instance = auto_class_instance(slots, name)
+
+ def update():
+ '''
+ Re-Assigns bones from the blender data
+ '''
+ arm = obj.data
+
+ bbones = arm.bones
+ pbones = obj.pose.bones
+ ebones = arm.edit_bones
+
+ for member in slots:
+
+ if member in ("update", "obj"):
+ continue
+
+ if not member[-2] == "_":
+ name = getattr(instance, member, None)
+ if name is not None:
+ setattr(instance, member + "_b", bbones.get(name, None))
+ setattr(instance, member + "_p", pbones.get(name, None))
+ setattr(instance, member + "_e", ebones.get(name, None))
+
+ instance.update = update
+
+ return instance
+
+def gen_none(obj, orig_bone_name):
+ pass
+
+def get_bone_data(obj, bone_name):
+ arm = obj.data
+ pbone = obj.pose.bones[bone_name]
+ if obj.mode == 'EDIT':
+ bone = arm.edit_bones[bone_name]
+ else:
+ bone = arm.bones[bone_name]
+
+ return arm, pbone, bone
+
+def bone_basename(name):
+ return name.split(".")[0]
+
+def copy_bone_simple(arm, from_bone, name, parent=False):
+ ebone = arm.edit_bones[from_bone]
+ ebone_new = arm.edit_bones.new(name)
+
+ if parent:
+ ebone_new.connected = ebone.connected
+ ebone_new.parent = ebone.parent
+
+ ebone_new.head = ebone.head
+ ebone_new.tail = ebone.tail
+ ebone_new.roll = ebone.roll
+ return ebone_new
+
+
+def add_stretch_to(obj, from_name, to_name, name):
+ '''
+ Adds a bone that stretches from one to another
+ '''
+
+ mode_orig = obj.mode
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ arm = obj.data
+ stretch_ebone = arm.edit_bones.new(name)
+ stretch_name = stretch_ebone.name
+ del name
+
+ head = stretch_ebone.head = arm.edit_bones[from_name].head.copy()
+ #tail = stretch_ebone.tail = arm.edit_bones[to_name].head.copy()
+
+ # annoying exception for zero length bones, since its using stretch_to the rest pose doesnt really matter
+ #if (head - tail).length < 0.1:
+ if 1:
+ tail = stretch_ebone.tail = arm.edit_bones[from_name].tail.copy()
+
+
+ # Now for the constraint
+ bpy.ops.object.mode_set(mode='OBJECT')
+ from_pbone = obj.pose.bones[from_name]
+ to_pbone = obj.pose.bones[to_name]
+
+ stretch_pbone = obj.pose.bones[stretch_name]
+
+ con = stretch_pbone.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = from_name
+
+ con = stretch_pbone.constraints.new('STRETCH_TO')
+ con.target = obj
+ con.subtarget = to_name
+ con.original_length = (head - tail).length
+ con.keep_axis = 'PLANE_X'
+ con.volume = 'NO_VOLUME'
+
+ bpy.ops.object.mode_set(mode=mode_orig)
+
+
+def add_pole_target_bone(obj, base_name, name, mode='CROSS'):
+ '''
+ Does not actually create a poll target, just the bone to use as a poll target
+ '''
+ mode_orig = obj.mode
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ arm = obj.data
+
+ poll_ebone = arm.edit_bones.new(base_name + "_poll")
+ base_ebone = arm.edit_bones[base_name]
+ poll_name = poll_ebone.name
+ parent_ebone = base_ebone.parent
+
+ base_head = base_ebone.head.copy()
+ base_tail = base_ebone.tail.copy()
+ base_dir = base_head - base_tail
+
+ parent_head = parent_ebone.head.copy()
+ parent_tail = parent_ebone.tail.copy()
+ parent_dir = parent_head - parent_tail
+
+ distance = (base_dir.length + parent_dir.length)
+
+ if mode == 'CROSS':
+ offset = base_dir.copy().normalize() - parent_dir.copy().normalize()
+ offset.length = distance
+ else:
+ offset = Vector(0,0,0)
+ if mode[0]=="+":
+ val = distance
+ else:
+ val = -distance
+
+ setattr(offset, mode[1].lower(), val)
+
+ poll_ebone.head = base_head + offset
+ poll_ebone.tail = base_head + (offset * (1.0 - (1.0 / 4.0)))
+
+ bpy.ops.object.mode_set(mode=mode_orig)
+
+ return poll_name
+
+
+def generate_rig(context, ob):
+
+ global_undo = context.user_preferences.edit.global_undo
+ context.user_preferences.edit.global_undo = False
+
+ # add_stretch_to(ob, "a", "b", "c")
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+ # copy object and data
+ ob.selected = False
+ ob_new = ob.copy()
+ ob_new.data = ob.data.copy()
+ scene = context.scene
+ scene.objects.link(ob_new)
+ scene.objects.active = ob_new
+ ob_new.selected = True
+
+ # enter armature editmode
+
+
+ for pbone_name in ob_new.pose.bones.keys():
+ bone_type = ob_new.pose.bones[pbone_name].get("type", "")
+
+ if bone_type == "":
+ continue
+
+ # submodule = getattr(self, bone_type)
+ # exec("from rigify import %s as submodule")
+ submodule = __import__(name="%s.%s" % (__package__, bone_type), fromlist=[bone_type])
+
+ reload(submodule) # XXX, dev only
+
+
+ # Toggle editmode so the pose data is always up to date
+ bpy.ops.object.mode_set(mode='EDIT')
+ submodule.main(ob_new, pbone_name)
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # needed to update driver deps
+ # context.scene.update()
+
+ # Only for demo'ing
+ ob.restrict_view = True
+ ob_new.data.draw_axes = False
+
+ context.user_preferences.edit.global_undo = global_undo
+
+if __name__ == "__main__":
+ generate_rig(bpy.context, bpy.context.object)
diff --git a/release/scripts/modules/rigify/arm.py b/release/scripts/modules/rigify/arm.py
new file mode 100644
index 00000000000..d2c9208d4ff
--- /dev/null
+++ b/release/scripts/modules/rigify/arm.py
@@ -0,0 +1,315 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+from rigify import bone_class_instance, copy_bone_simple, add_pole_target_bone, add_stretch_to
+from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
+
+
+def main(obj, orig_bone_name):
+ """
+ the bone with the 'arm' property is the upper arm, this assumes a chain as follows.
+ [shoulder, upper_arm, forearm, hand]
+ ...where this bone is 'upper_arm'
+
+ there are 3 chains
+ - Original
+ - IK, MCH-%s_ik
+ - IKSwitch, MCH-%s ()
+ """
+
+ # Since there are 3 chains, this gets confusing so divide into 3 chains
+ # Initialize container classes for convenience
+ mt = bone_class_instance(obj, ["shoulder", "arm", "forearm", "hand"]) # meta
+ ik = bone_class_instance(obj, ["arm", "forearm", "pole", "hand"]) # ik
+ sw = bone_class_instance(obj, ["socket", "shoulder", "arm", "forearm", "hand"]) # hinge
+ ex = bone_class_instance(obj, ["arm_hinge"]) # hinge & extras
+
+
+ def chain_init():
+ '''
+ Sanity check and return the arm as a list of bone names.
+ '''
+ # do a sanity check
+ mt.arm = orig_bone_name
+ mt.update()
+
+ mt.shoulder_p = mt.arm_p.parent
+ mt.shoulder = mt.shoulder_p.name
+
+ if not mt.shoulder_p:
+ print("could not find 'arm' parent, skipping:", orig_bone_name)
+ return
+
+ # We could have some bones attached, find the bone that has this as its 2nd parent
+ hands = []
+ for pbone in obj.pose.bones:
+ index = pbone.parent_index(mt.arm_p)
+ if index == 2:
+ hands.append(pbone)
+
+ if len(hands) > 1:
+ print("more then 1 hand found on:", orig_bone_name)
+ return
+
+ # first add the 2 new bones
+ mt.hand_p = hands[0]
+ mt.hand = mt.hand_p.name
+
+ mt.forearm_p = mt.hand_p.parent
+ mt.forearm = mt.forearm_p.name
+
+ arm = obj.data
+
+
+ def chain_ik(prefix="MCH-%s_ik"):
+
+ mt.update()
+
+ # Add the edit bones
+ ik.hand_e = copy_bone_simple(arm, mt.hand, prefix % mt.hand)
+ ik.hand = ik.hand_e.name
+
+ ik.arm_e = copy_bone_simple(arm, mt.arm, prefix % mt.arm)
+ ik.arm = ik.arm_e.name
+
+ ik.forearm_e = copy_bone_simple(arm, mt.forearm, prefix % mt.forearm)
+ ik.forearm = ik.forearm_e.name
+
+ ik.arm_e.parent = mt.arm_e.parent
+ ik.forearm_e.connected = mt.arm_e.connected
+
+ ik.forearm_e.parent = ik.arm_e
+ ik.forearm_e.connected = True
+
+
+ # Add the bone used for the arms poll target
+ ik.pole = add_pole_target_bone(obj, mt.forearm, "elbow_poll", mode='+Z')
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ ik.update()
+
+ con = ik.forearm_p.constraints.new('IK')
+ con.target = obj
+ con.subtarget = ik.hand
+ con.pole_target = obj
+ con.pole_subtarget = ik.pole
+
+ con.use_tail = True
+ con.use_stretch = True
+ con.use_target = True
+ con.use_rotation = False
+ con.chain_length = 2
+ con.pole_angle = -90.0 # XXX, RAD2DEG
+
+ # ID Propery on the hand for IK/FK switch
+
+ prop = rna_idprop_ui_prop_get(ik.hand_p, "ik", create=True)
+ ik.hand_p["ik"] = 0.5
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ ik.arm = ik.arm
+ ik.forearm = ik.forearm
+ ik.hand = ik.hand
+ ik.pole = ik.pole
+
+ def chain_switch(prefix="MCH-%s"):
+
+ sw.update()
+ mt.update()
+
+ sw.shoulder_e = copy_bone_simple(arm, mt.shoulder, prefix % mt.shoulder)
+ sw.shoulder = sw.shoulder_e.name
+ sw.shoulder_e.parent = mt.shoulder_e.parent
+ sw.shoulder_e.connected = mt.shoulder_e.connected
+
+ sw.arm_e = copy_bone_simple(arm, mt.arm, prefix % mt.arm)
+ sw.arm = sw.arm_e.name
+ sw.arm_e.parent = sw.shoulder_e
+ sw.arm_e.connected = arm.edit_bones[mt.shoulder].connected
+
+ sw.forearm_e = copy_bone_simple(arm, mt.forearm, prefix % mt.forearm)
+ sw.forearm = sw.forearm_e.name
+ sw.forearm_e.parent = sw.arm_e
+ sw.forearm_e.connected = arm.edit_bones[mt.forearm].connected
+
+ sw.hand_e = copy_bone_simple(arm, mt.hand, prefix % mt.hand)
+ sw.hand = sw.hand_e.name
+ sw.hand_e.parent = sw.forearm_e
+ sw.hand_e.connected = arm.edit_bones[mt.hand].connected
+
+ # The sw.hand_e needs to own all the children on the metarig's hand
+ for child in mt.hand_e.children:
+ child.parent = sw.hand_e
+
+
+ # These are made the children of sw.shoulder_e
+
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Add constraints
+ sw.update()
+
+ #dummy, ik.arm, ik.forearm, ik.hand, ik.pole = ik_chain_tuple
+
+ ik_driver_path = obj.pose.bones[ik.hand].path_to_id() + '["ik"]'
+
+
+ def ik_fk_driver(con):
+ '''
+ 3 bones use this for ik/fk switching
+ '''
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ tar = driver.targets.new()
+ driver.type = 'AVERAGE'
+ tar.name = "ik"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = ik_driver_path
+
+ # ***********
+ con = sw.arm_p.constraints.new('COPY_ROTATION')
+ con.name = "FK"
+ con.target = obj
+ con.subtarget = mt.arm
+
+ con = sw.arm_p.constraints.new('COPY_ROTATION')
+
+ con.target = obj
+ con.subtarget = ik.arm
+ con.influence = 0.5
+ ik_fk_driver(con)
+
+ # ***********
+ con = sw.forearm_p.constraints.new('COPY_ROTATION')
+ con.name = "FK"
+ con.target = obj
+ con.subtarget = mt.forearm
+
+ con = sw.forearm_p.constraints.new('COPY_ROTATION')
+ con.name = "IK"
+ con.target = obj
+ con.subtarget = ik.forearm
+ con.influence = 0.5
+ ik_fk_driver(con)
+
+ # ***********
+ con = sw.hand_p.constraints.new('COPY_ROTATION')
+ con.name = "FK"
+ con.target = obj
+ con.subtarget = mt.hand
+
+ con = sw.hand_p.constraints.new('COPY_ROTATION')
+ con.name = "IK"
+ con.target = obj
+ con.subtarget = ik.hand
+ con.influence = 0.5
+ ik_fk_driver(con)
+
+
+ add_stretch_to(obj, sw.forearm, ik.pole, "VIS-elbow_ik_poll")
+ add_stretch_to(obj, sw.hand, ik.hand, "VIS-hand_ik")
+
+ bpy.ops.object.mode_set(mode='EDIT')
+
+
+ def chain_shoulder(prefix="MCH-%s"):
+
+ sw.socket_e = copy_bone_simple(arm, mt.arm, (prefix % mt.arm) + "_socket")
+ sw.socket = sw.socket_e.name
+ sw.socket_e.tail = arm.edit_bones[mt.shoulder].tail
+
+
+ # Set the shoulder as parent
+ ik.update()
+ sw.update()
+ mt.update()
+
+ sw.socket_e.parent = sw.shoulder_e
+ ik.arm_e.parent = sw.shoulder_e
+
+
+ # ***** add the shoulder hinge
+ # yes this is correct, the shoulder copy gets the arm's name
+ ex.arm_hinge_e = copy_bone_simple(arm, mt.shoulder, (prefix % mt.arm) + "_hinge")
+ ex.arm_hinge = ex.arm_hinge_e.name
+ offset = ex.arm_hinge_e.length / 2.0
+
+ ex.arm_hinge_e.head.y += offset
+ ex.arm_hinge_e.tail.y += offset
+
+ # Note: meta arm becomes child of hinge
+ mt.arm_e.parent = ex.arm_hinge_e
+
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ ex.update()
+
+ con = mt.arm_p.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = sw.socket
+
+
+ # Hinge constraint & driver
+ con = ex.arm_hinge_p.constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = sw.shoulder
+ driver_fcurve = con.driver_add("influence", 0)
+ driver = driver_fcurve.driver
+
+
+ controller_path = mt.arm_p.path_to_id()
+ # add custom prop
+ mt.arm_p["hinge"] = 0.0
+ prop = rna_idprop_ui_prop_get(mt.arm_p, "hinge", create=True)
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+
+ # *****
+ driver = driver_fcurve.driver
+ driver.type = 'AVERAGE'
+
+ tar = driver.targets.new()
+ tar.name = "hinge"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + '["hinge"]'
+
+
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # remove the shoulder and re-parent
+
+
+
+ chain_init()
+ chain_ik()
+ chain_switch()
+ chain_shoulder()
+
+ # Shoulder with its delta and hinge.
+
diff --git a/release/scripts/modules/rigify/delta.py b/release/scripts/modules/rigify/delta.py
new file mode 100644
index 00000000000..a8458537c12
--- /dev/null
+++ b/release/scripts/modules/rigify/delta.py
@@ -0,0 +1,109 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+from rigify import get_bone_data
+
+def main(obj, delta_name):
+ '''
+ Use this bone to define a delta thats applied to its child in pose mode.
+ '''
+
+ arm = obj.data
+
+ mode_orig = obj.mode
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ delta_pbone = obj.pose.bones[delta_name]
+ children = delta_pbone.children
+
+ if len(children) != 1:
+ print("only 1 child supported for delta")
+
+ child_name = children[0].name
+ arm, child_pbone, child_bone = get_bone_data(obj, child_name)
+
+ delta_phead = delta_pbone.head.copy()
+ delta_ptail = delta_pbone.tail.copy()
+ delta_pmatrix = delta_pbone.matrix.copy()
+
+ child_phead = child_pbone.head.copy()
+ child_ptail = child_pbone.tail.copy()
+ child_pmatrix = child_pbone.matrix.copy()
+
+
+ children = delta_pbone.children
+
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ delta_ebone = arm.edit_bones[delta_name]
+ child_ebone = arm.edit_bones[child_name]
+
+ delta_head = delta_ebone.head.copy()
+ delta_tail = delta_ebone.tail.copy()
+
+ # arm, parent_pbone, parent_bone = get_bone_data(obj, delta_name)
+ child_head = child_ebone.head.copy()
+ child_tail = child_ebone.tail.copy()
+
+ arm.edit_bones.remove(delta_ebone)
+ del delta_ebone # cant use thz
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+ # Move the child bone to the deltas location
+ obj.animation_data_create()
+ child_pbone = obj.pose.bones[child_name]
+
+ # ------------------- drivers
+
+ child_pbone.rotation_mode = 'XYZ'
+
+ rot = delta_pmatrix.invert().rotationPart() * child_pmatrix.rotationPart()
+ rot = rot.invert().toEuler()
+
+ fcurve_drivers = child_pbone.driver_add("rotation_euler", -1)
+ for i, fcurve_driver in enumerate(fcurve_drivers):
+ driver = fcurve_driver.driver
+ driver.type = 'AVERAGE'
+ #mod = fcurve_driver.modifiers.new('GENERATOR')
+ mod = fcurve_driver.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = rot[i]
+ mod.coefficients[1] = 0.0
+
+ # tricky, find the transform to drive the bone to this location.
+ delta_head_offset = child_pmatrix.rotationPart() * (delta_phead - child_phead)
+
+ fcurve_drivers = child_pbone.driver_add("location", -1)
+ for i, fcurve_driver in enumerate(fcurve_drivers):
+ driver = fcurve_driver.driver
+ driver.type = 'AVERAGE'
+ #mod = fcurve_driver.modifiers.new('GENERATOR')
+ mod = fcurve_driver.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = delta_head_offset[i]
+ mod.coefficients[1] = 0.0
+
+
+ # arm, parent_pbone, parent_bone = get_bone_data(obj, delta_name)
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ bpy.ops.object.mode_set(mode=mode_orig)
+
diff --git a/release/scripts/modules/rigify/finger.py b/release/scripts/modules/rigify/finger.py
new file mode 100644
index 00000000000..a5e8f2d0ea1
--- /dev/null
+++ b/release/scripts/modules/rigify/finger.py
@@ -0,0 +1,173 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+from rigify import get_bone_data, bone_basename, empty_layer
+from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
+from functools import reduce
+
+def main(obj, orig_bone_name):
+
+ # *** EDITMODE
+
+ # get assosiated data
+ arm, orig_pbone, orig_ebone = get_bone_data(obj, orig_bone_name)
+
+ obj.animation_data_create() # needed if its a new armature with no keys
+
+ arm.layer[0] = arm.layer[8] = True
+
+ children = orig_pbone.children_recursive
+ tot_len = reduce(lambda f, pbone: f + pbone.bone.length, children, orig_pbone.bone.length)
+
+ base_name = bone_basename(orig_pbone.name)
+
+ # first make a new bone at the location of the finger
+ control_ebone = arm.edit_bones.new(base_name)
+ control_bone_name = control_ebone.name # we dont know if we get the name requested
+
+ control_ebone.connected = orig_ebone.connected
+ control_ebone.parent = orig_ebone.parent
+
+ # Place the finger bone
+ head = orig_ebone.head.copy()
+ tail = orig_ebone.tail.copy()
+
+ control_ebone.head = head
+ control_ebone.tail = head + ((tail - head).normalize() * tot_len)
+ control_ebone.roll = orig_ebone.roll
+
+ # now add bones inbetween this and its children recursively
+
+ # switching modes so store names only!
+ children = [pbone.name for pbone in children]
+
+ # set an alternate layer for driver bones
+ other_layer = empty_layer[:]
+ other_layer[8] = True
+
+
+ driver_bone_pairs = []
+
+ for child_bone_name in children:
+ arm, pbone_child, child_ebone = get_bone_data(obj, child_bone_name)
+
+ # finger.02 --> finger_driver.02
+ driver_bone_name = child_bone_name.split('.')
+ driver_bone_name = driver_bone_name[0] + "_driver." + ".".join(driver_bone_name[1:])
+
+ driver_ebone = arm.edit_bones.new(driver_bone_name)
+ driver_bone_name = driver_ebone.name # cant be too sure!
+ driver_ebone.layer = other_layer
+
+ new_len = pbone_child.bone.length / 2.0
+
+ head = child_ebone.head.copy()
+ tail = child_ebone.tail.copy()
+
+ driver_ebone.head = head
+ driver_ebone.tail = head + ((tail - head).normalize() * new_len)
+ driver_ebone.roll = child_ebone.roll
+
+ # Insert driver_ebone in the chain without connected parents
+ driver_ebone.connected = False
+ driver_ebone.parent = child_ebone.parent
+
+ child_ebone.connected = False
+ child_ebone.parent = driver_ebone
+
+ # Add the drivers to these when in posemode.
+ driver_bone_pairs.append((child_bone_name, driver_bone_name))
+
+ del control_ebone
+
+
+ # *** POSEMODE
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+ arm, orig_pbone, orig_bone = get_bone_data(obj, orig_bone_name)
+ arm, control_pbone, control_bone= get_bone_data(obj, control_bone_name)
+
+
+ # only allow Y scale
+ control_pbone.lock_scale = (True, False, True)
+
+ control_pbone["bend_ratio"] = 0.4
+ prop = rna_idprop_ui_prop_get(control_pbone, "bend_ratio", create=True)
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ con = orig_pbone.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = control_bone_name
+
+ con = orig_pbone.constraints.new('COPY_ROTATION')
+ con.target = obj
+ con.subtarget = control_bone_name
+
+
+
+ # setup child drivers on each new smaller bone added. assume 2 for now.
+
+ # drives the bones
+ controller_path = control_pbone.path_to_id() # 'pose.bones["%s"]' % control_bone_name
+
+ i = 0
+ for child_bone_name, driver_bone_name in driver_bone_pairs:
+
+ # XXX - todo, any number
+ if i==2:
+ break
+
+ arm, driver_pbone, driver_bone = get_bone_data(obj, driver_bone_name)
+
+ driver_pbone.rotation_mode = 'YZX'
+ fcurve_driver = driver_pbone.driver_add("rotation_euler", 0)
+
+ #obj.driver_add('pose.bones["%s"].scale', 1)
+ #obj.animation_data.drivers[-1] # XXX, WATCH THIS
+ driver = fcurve_driver.driver
+
+ # scale target
+ tar = driver.targets.new()
+ tar.name = "scale"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + '.scale[1]'
+
+ # bend target
+ tar = driver.targets.new()
+ tar.name = "br"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + '["bend_ratio"]'
+
+ # XXX - todo, any number
+ if i==0:
+ driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)'
+ elif i==1:
+ driver.expression = '(-scale+1.0)*pi*2.0*br'
+
+ arm, child_pbone, child_bone = get_bone_data(obj, child_bone_name)
+
+ # only allow X rotation
+ driver_pbone.lock_rotation = child_pbone.lock_rotation = (False, True, True)
+
+ i += 1
+
diff --git a/release/scripts/modules/rigify/palm.py b/release/scripts/modules/rigify/palm.py
new file mode 100644
index 00000000000..f6f55541c64
--- /dev/null
+++ b/release/scripts/modules/rigify/palm.py
@@ -0,0 +1,130 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+from rigify import get_bone_data, copy_bone_simple
+from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
+
+def main(obj, orig_bone_name):
+ arm, palm_pbone, palm_ebone = get_bone_data(obj, orig_bone_name)
+ children = [ebone.name for ebone in palm_ebone.children]
+ children.sort() # simply assume the pinky has the lowest name
+
+ # Make a copy of the pinky
+ pinky_ebone = arm.edit_bones[children[0]]
+ control_ebone = copy_bone_simple(arm, pinky_ebone.name, "palm_control", parent=True)
+ control_name = control_ebone.name
+
+ offset = (arm.edit_bones[children[0]].head - arm.edit_bones[children[1]].head)
+
+ control_ebone.head += offset
+ control_ebone.tail += offset
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+ arm, control_pbone, control_ebone = get_bone_data(obj, control_name)
+ arm, pinky_pbone, pinky_ebone = get_bone_data(obj, children[0])
+
+ control_pbone.rotation_mode = 'YZX'
+ control_pbone.lock_rotation = False, True, True
+
+ driver_fcurves = pinky_pbone.driver_add("rotation_euler")
+
+
+ controller_path = control_pbone.path_to_id()
+
+ # add custom prop
+ control_pbone["spread"] = 0.0
+ prop = rna_idprop_ui_prop_get(control_pbone, "spread", create=True)
+ prop["soft_min"] = -1.0
+ prop["soft_max"] = 1.0
+
+
+ # *****
+ driver = driver_fcurves[0].driver
+ driver.type = 'AVERAGE'
+
+ tar = driver.targets.new()
+ tar.name = "x"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + ".rotation_euler[0]"
+
+
+ # *****
+ driver = driver_fcurves[1].driver
+ driver.expression = "-x/4.0"
+
+ tar = driver.targets.new()
+ tar.name = "x"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + ".rotation_euler[0]"
+
+
+ # *****
+ driver = driver_fcurves[2].driver
+ driver.expression = "(1.0-cos(x))-s"
+ tar = driver.targets.new()
+ tar.name = "x"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + ".rotation_euler[0]"
+
+ tar = driver.targets.new()
+ tar.name = "s"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + '["spread"]'
+
+
+ for i, child_name in enumerate(children):
+ child_pbone = obj.pose.bones[child_name]
+ child_pbone.rotation_mode = 'YZX'
+
+ if child_name != children[-1] and child_name != children[0]:
+
+ # this is somewhat arbitrary but seems to look good
+ inf = i / (len(children)+1)
+ inf = 1.0 - inf
+ inf = ((inf * inf) + inf) / 2.0
+
+ # used for X/Y constraint
+ inf_minor = inf * inf
+
+ con = child_pbone.constraints.new('COPY_ROTATION')
+ con.name = "Copy Z Rot"
+ con.target = obj
+ con.subtarget = children[0] # also pinky_pbone
+ con.owner_space = con.target_space = 'LOCAL'
+ con.use_x, con.use_y, con.use_z = False, False, True
+ con.influence = inf
+
+ con = child_pbone.constraints.new('COPY_ROTATION')
+ con.name = "Copy XY Rot"
+ con.target = obj
+ con.subtarget = children[0] # also pinky_pbone
+ con.owner_space = con.target_space = 'LOCAL'
+ con.use_x, con.use_y, con.use_z = True, True, False
+ con.influence = inf_minor
+
+
+ child_pbone = obj.pose.bones[children[-1]]
+ child_pbone.rotation_mode = 'QUATERNION'
+