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:
authorNathan Vegdahl <cessen@cessen.com>2010-04-07 18:46:06 +0400
committerNathan Vegdahl <cessen@cessen.com>2010-04-07 18:46:06 +0400
commit54b12df3bcd83e22fa187503cc2791fff2e2ef88 (patch)
tree6dba8258feb01dfa524e3845cb29cdf3ebc13807 /release
parent8bf6e2d09ce11176d374f371c4b7e8b89d9d05dd (diff)
Added tongue and neck rigs. The neck rig is quite solid, I think, and is working well in production on Durian. The tongue rig is a bit hacky, but I'm adding it for now since we're using it in Durian.
Also added pupil dilation to the eye rig type, and made the finger rig type work with two-digit fingers.
Diffstat (limited to 'release')
-rw-r--r--release/scripts/modules/rigify/eye_balls.py129
-rw-r--r--release/scripts/modules/rigify/finger_curl.py126
-rw-r--r--release/scripts/modules/rigify/neck.py344
-rw-r--r--release/scripts/modules/rigify/tongue.py361
4 files changed, 908 insertions, 52 deletions
diff --git a/release/scripts/modules/rigify/eye_balls.py b/release/scripts/modules/rigify/eye_balls.py
index c1302a5cbca..90e309bbc38 100644
--- a/release/scripts/modules/rigify/eye_balls.py
+++ b/release/scripts/modules/rigify/eye_balls.py
@@ -27,6 +27,85 @@ from rigify_utils import copy_bone_simple
#METARIG_NAMES = ("cpy",)
RIG_TYPE = "eye_balls"
+def addget_shape_key(obj, name="Key"):
+ """ Fetches a shape key, or creates it if it doesn't exist
+ """
+ # Create a shapekey set if it doesn't already exist
+ if obj.data.shape_keys is None:
+ shape = obj.add_shape_key(name="Basis", from_mix=False)
+ obj.active_shape_key_index = 0
+
+ # Get the shapekey, or create it if it doesn't already exist
+ if name in obj.data.shape_keys.keys:
+ shape_key = obj.data.shape_keys.keys[name]
+ else:
+ shape_key = obj.add_shape_key(name=name, from_mix=False)
+
+ return shape_key
+
+
+def addget_shape_key_driver(obj, name="Key"):
+ """ Fetches the driver for the shape key, or creates it if it doesn't
+ already exist.
+ """
+ driver_path = 'keys["' + name + '"].value'
+ fcurve = None
+ driver = None
+ new = False
+ if obj.data.shape_keys.animation_data is not None:
+ for driver_s in obj.data.shape_keys.animation_data.drivers:
+ if driver_s.data_path == driver_path:
+ fcurve = driver_s
+ if fcurve == None:
+ fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0)
+ fcurve.driver.type = 'AVERAGE'
+ new = True
+
+ return fcurve, new
+
+
+def create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression):
+ """ Creates/gets a shape key and sets up a driver for it.
+
+ obj = armature object
+ bone = driving bone name
+ meshes = list of meshes to create the shapekey/driver on
+ shape_name = name of the shape key
+ var_name = name of the driving variable
+ var_path = path to the property on the bone to drive with
+ expression = python expression for the driver
+ """
+ pb = obj.pose.bones
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ for mesh_name in meshes:
+ mesh_obj = bpy.data.objects[mesh_name]
+
+ # Add/get the shape key
+ shape = addget_shape_key(mesh_obj, name=shape_name)
+
+ # Add/get the shape key driver
+ fcurve, a = addget_shape_key_driver(mesh_obj, name=shape_name)
+
+ # Set up the driver
+ driver = fcurve.driver
+ driver.type = 'SCRIPTED'
+ driver.expression = expression
+
+ # Get the variable, or create it if it doesn't already exist
+ if var_name in driver.variables:
+ var = driver.variables[var_name]
+ else:
+ var = driver.variables.new()
+ var.name = var_name
+
+ # Set up the variable
+ var.type = "SINGLE_PROP"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = 'pose.bones["' + bone + '"]' + var_path
+
+
def mark_actions():
for action in bpy.data.actions:
action.tag = True
@@ -120,6 +199,12 @@ def control(obj, definitions, base_names, options):
head = definitions[0]
eye_target = definitions[1]
+ # Get list of pupil mesh objects
+ if "mesh" in options:
+ pupil_meshes = options["mesh"].replace(" ", "").split(",")
+ else:
+ pupil_meshes = []
+
# Get list of eyes
if "eyes" in options:
eye_base_names = options["eyes"].replace(" ", "").split(",")
@@ -246,6 +331,50 @@ def control(obj, definitions, base_names, options):
con.minimum = 0.0
con.maximum = 2.0
con.target_space = 'LOCAL'
+
+
+ # Get/create the shape keys and drivers for pupil dilation
+ shape_names = ["PUPILS-dilate_wide", "PUPILS-dilate_narrow"]
+ slider_name = "pupil_dilate"
+
+ # Set up the custom property on the bone
+ prop = rna_idprop_ui_prop_get(pb[target_ctrl], slider_name, create=True)
+ pb[target_ctrl][slider_name] = 0.0
+ prop["min"] = 0.0
+ prop["max"] = 1.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ if len(shape_names) > 1:
+ prop["min"] = -1.0
+ prop["soft_min"] = -1.0
+
+ # Add the shape drivers
+ # Positive
+ if shape_names[0] != "":
+ # Set up the variables for creating the shape key driver
+ shape_name = shape_names[0]
+ var_name = slider_name.replace(".", "_").replace("-", "_")
+ var_path = '["' + slider_name + '"]'
+ if slider_name + "_fac" in options:
+ fac = options[slider_name + "_fac"]
+ else:
+ fac = 1.0
+ expression = var_name + " * " + str(fac)
+ # Create the shape key driver
+ create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression)
+ # Negative
+ if shape_names[0] != "" and len(shape_names) > 1:
+ # Set up the variables for creating the shape key driver
+ shape_name = shape_names[1]
+ var_name = slider_name.replace(".", "_").replace("-", "_")
+ var_path = '["' + slider_name + '"]'
+ if slider_name + "_fac" in options:
+ fac = options[slider_name + "_fac"]
+ else:
+ fac = 1.0
+ expression = var_name + " * " + str(fac) + " * -1"
+ # Create the shape key driver
+ create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression)
diff --git a/release/scripts/modules/rigify/finger_curl.py b/release/scripts/modules/rigify/finger_curl.py
index 1f4d3e985f3..27ed437b5ac 100644
--- a/release/scripts/modules/rigify/finger_curl.py
+++ b/release/scripts/modules/rigify/finger_curl.py
@@ -57,31 +57,20 @@ def metarig_template():
def metarig_definition(obj, orig_bone_name):
'''
The bone given is the first in a chain
- Expects a chain of at least 2 children.
+ Expects a chain with at least 1 child of the same base name.
eg.
- finger -> finger_01 -> finger_02
+ finger_01 -> finger_02
'''
- bone_definition = []
-
orig_bone = obj.data.bones[orig_bone_name]
- bone_definition.append(orig_bone.name)
-
- bone = orig_bone
- chain = 0
- while chain < 2: # first 2 bones only have 1 child
- children = bone.children
-
- if len(children) != 1:
- raise RigifyError("expected the chain to have 2 children from bone '%s' without a fork" % orig_bone_name)
- bone = children[0]
- bone_definition.append(bone.name) # finger_02, finger_03
- chain += 1
-
- if len(bone_definition) != len(METARIG_NAMES):
- raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
-
+ bone_definition = [orig_bone.name]
+
+ bone_definition.extend([child.name for child in orig_bone.children_recursive_basename])
+
+ if len(bone_definition) < 2:
+ raise RigifyError("expected the chain to have at least 1 child from bone '%s' without the same base name" % orig_bone_name)
+
return bone_definition
@@ -90,6 +79,8 @@ def deform(obj, definitions, base_names, options):
"""
bpy.ops.object.mode_set(mode='EDIT')
+ three_digits = True if len(definitions) > 2 else False
+
# Create base digit bones: two bones, each half of the base digit.
f1a = copy_bone_simple(obj.data, definitions[0], "DEF-%s.01" % base_names[definitions[0]], parent=True)
f1b = copy_bone_simple(obj.data, definitions[0], "DEF-%s.02" % base_names[definitions[0]], parent=True)
@@ -102,13 +93,15 @@ def deform(obj, definitions, base_names, options):
# Create the other deform bones.
f2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s" % base_names[definitions[1]], parent=True)
- f3 = copy_bone_simple(obj.data, definitions[2], "DEF-%s" % base_names[definitions[2]], parent=True)
+ if three_digits:
+ f3 = copy_bone_simple(obj.data, definitions[2], "DEF-%s" % base_names[definitions[2]], parent=True)
# Store names before leaving edit mode
f1a_name = f1a.name
f1b_name = f1b.name
f2_name = f2.name
- f3_name = f3.name
+ if three_digits:
+ f3_name = f3.name
# Leave edit mode
bpy.ops.object.mode_set(mode='OBJECT')
@@ -117,7 +110,8 @@ def deform(obj, definitions, base_names, options):
f1a = obj.pose.bones[f1a_name]
f1b = obj.pose.bones[f1b_name]
f2 = obj.pose.bones[f2_name]
- f3 = obj.pose.bones[f3_name]
+ if three_digits:
+ f3 = obj.pose.bones[f3_name]
# Constrain the base digit's bones
con = f1a.constraints.new('DAMPED_TRACK')
@@ -141,15 +135,18 @@ def deform(obj, definitions, base_names, options):
con.target = obj
con.subtarget = definitions[1]
- con = f3.constraints.new('COPY_TRANSFORMS')
- con.name = "copy_transforms"
- con.target = obj
- con.subtarget = definitions[2]
+ if three_digits:
+ con = f3.constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_transforms"
+ con.target = obj
+ con.subtarget = definitions[2]
def main(obj, bone_definition, base_names, options):
# *** EDITMODE
bpy.ops.object.mode_set(mode='EDIT')
+
+ three_digits = True if len(bone_definition) > 2 else False
# get assosiated data
arm = obj.data
@@ -159,7 +156,8 @@ def main(obj, bone_definition, base_names, options):
org_f1 = bone_definition[0] # Original finger bone 01
org_f2 = bone_definition[1] # Original finger bone 02
- org_f3 = bone_definition[2] # Original finger bone 03
+ if three_digits:
+ org_f3 = bone_definition[2] # Original finger bone 03
# Check options
if "bend_ratio" in options:
@@ -179,7 +177,10 @@ def main(obj, bone_definition, base_names, options):
# Create the control bone
base_name = base_names[bone_definition[0]].split(".", 1)[0]
- tot_len = eb[org_f1].length + eb[org_f2].length + eb[org_f3].length
+ if three_digits:
+ tot_len = eb[org_f1].length + eb[org_f2].length + eb[org_f3].length
+ else:
+ tot_len = eb[org_f1].length + eb[org_f2].length
control = copy_bone_simple(arm, bone_definition[0], base_name + get_side_name(base_names[bone_definition[0]]), parent=True).name
eb[control].connected = eb[org_f1].connected
eb[control].parent = eb[org_f1].parent
@@ -188,26 +189,30 @@ def main(obj, bone_definition, base_names, options):
# Create secondary control bones
f1 = copy_bone_simple(arm, bone_definition[0], base_names[bone_definition[0]]).name
f2 = copy_bone_simple(arm, bone_definition[1], base_names[bone_definition[1]]).name
- f3 = copy_bone_simple(arm, bone_definition[2], base_names[bone_definition[2]]).name
+ if three_digits:
+ f3 = copy_bone_simple(arm, bone_definition[2], base_names[bone_definition[2]]).name
# Create driver bones
df1 = copy_bone_simple(arm, bone_definition[0], "MCH-" + base_names[bone_definition[0]]).name
eb[df1].length /= 2
df2 = copy_bone_simple(arm, bone_definition[1], "MCH-" + base_names[bone_definition[1]]).name
eb[df2].length /= 2
- df3 = copy_bone_simple(arm, bone_definition[2], "MCH-" + base_names[bone_definition[2]]).name
- eb[df3].length /= 2
+ if three_digits:
+ df3 = copy_bone_simple(arm, bone_definition[2], "MCH-" + base_names[bone_definition[2]]).name
+ eb[df3].length /= 2
# Set parents of the bones, interleaving the driver bones with the secondary control bones
- eb[f3].connected = False
- eb[df3].connected = False
+ if three_digits:
+ eb[f3].connected = False
+ eb[df3].connected = False
eb[f2].connected = False
eb[df2].connected = False
eb[f1].connected = False
eb[df1].connected = eb[org_f1].connected
- eb[f3].parent = eb[df3]
- eb[df3].parent = eb[f2]
+ if three_digits:
+ eb[f3].parent = eb[df3]
+ eb[df3].parent = eb[f2]
eb[f2].parent = eb[df2]
eb[df2].parent = eb[f1]
eb[f1].parent = eb[df1]
@@ -215,8 +220,8 @@ def main(obj, bone_definition, base_names, options):
# Set up bones for hinge
if make_hinge:
- socket = copy_bone_simple(arm, org_f1, "MCH-socket_" + control, parent=True).name
- hinge = copy_bone_simple(arm, eb[org_f1].parent.name, "MCH-hinge_" + control).name
+ socket = copy_bone_simple(arm, org_f1, "MCH-socket_"+control, parent=True).name
+ hinge = copy_bone_simple(arm, eb[org_f1].parent.name, "MCH-hinge_"+control).name
eb[control].connected = False
eb[control].parent = eb[hinge]
@@ -234,12 +239,15 @@ def main(obj, bone_definition, base_names, options):
pb[control].lock_scale = True, False, True
pb[f1].rotation_mode = 'YZX'
pb[f2].rotation_mode = 'YZX'
- pb[f3].rotation_mode = 'YZX'
+ if three_digits:
+ pb[f3].rotation_mode = 'YZX'
pb[f1].lock_location = True, True, True
pb[f2].lock_location = True, True, True
- pb[f3].lock_location = True, True, True
+ if three_digits:
+ pb[f3].lock_location = True, True, True
pb[df2].rotation_mode = 'YZX'
- pb[df3].rotation_mode = 'YZX'
+ if three_digits:
+ pb[df3].rotation_mode = 'YZX'
# Add the bend_ratio property to the control bone
pb[control]["bend_ratio"] = bend_ratio
@@ -271,9 +279,10 @@ def main(obj, bone_definition, base_names, options):
con.target = obj
con.subtarget = f2
- con = pb[org_f3].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = f3
+ if three_digits:
+ con = pb[org_f3].constraints.new('COPY_TRANSFORMS')
+ con.target = obj
+ con.subtarget = f3
if make_hinge:
con = pb[hinge].constraints.new('COPY_TRANSFORMS')
@@ -303,8 +312,13 @@ def main(obj, bone_definition, base_names, options):
# Create the drivers for the driver bones (control bone scale rotates driver bones)
controller_path = pb[control].path_from_id() # 'pose.bones["%s"]' % control_bone_name
+ if three_digits:
+ finger_digits = [df2, df3]
+ else:
+ finger_digits = [df2]
+
i = 0
- for bone in [df2, df3]:
+ for bone in finger_digits:
# XXX - todo, any number
if i == 2:
@@ -334,23 +348,31 @@ def main(obj, bone_definition, base_names, options):
var.targets[0].data_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'
+ if three_digits:
+ 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'
+ else:
+ driver.expression = driver.expression = '(-scale+1.0)*pi*2.0'
i += 1
# Last step setup layers
if "ex_layer" in options:
- layer = [n == options["ex_layer"] for n in range(0, 32)]
+ layer = [n==options["ex_layer"] for n in range(0,32)]
else:
layer = list(arm.bones[bone_definition[0]].layer)
- for bone_name in [f1, f2, f3]:
- arm.bones[bone_name].layer = layer
+ #for bone_name in [f1, f2, f3]:
+ # arm.bones[bone_name].layer = layer
+ arm.bones[f1].layer = layer
+ arm.bones[f2].layer = layer
+ if three_digits:
+ arm.bones[f3].layer = layer
layer = list(arm.bones[bone_definition[0]].layer)
bb[control].layer = layer
# no blending the result of this
return None
+
diff --git a/release/scripts/modules/rigify/neck.py b/release/scripts/modules/rigify/neck.py
new file mode 100644
index 00000000000..747e8397710
--- /dev/null
+++ b/release/scripts/modules/rigify/neck.py
@@ -0,0 +1,344 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from rigify import RigifyError
+from rigify_utils import bone_class_instance, copy_bone_simple
+from rna_prop_ui import rna_idprop_ui_prop_get
+
+
+
+def metarig_template():
+ # TODO:
+ ## generated by rigify.write_meta_rig
+ #bpy.ops.object.mode_set(mode='EDIT')
+ #obj = bpy.context.active_object
+ #arm = obj.data
+ #bone = arm.edit_bones.new('body')
+ #bone.head[:] = 0.0000, -0.0276, -0.1328
+ #bone.tail[:] = 0.0000, -0.0170, -0.0197
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone = arm.edit_bones.new('head')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, 0.0726, 0.1354
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['body']
+ #bone = arm.edit_bones.new('neck.01')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, -0.0099, 0.0146
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone.parent = arm.edit_bones['head']
+ #bone = arm.edit_bones.new('neck.02')
+ #bone.head[:] = 0.0000, -0.0099, 0.0146
+ #bone.tail[:] = 0.0000, -0.0242, 0.0514
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.01']
+ #bone = arm.edit_bones.new('neck.03')
+ #bone.head[:] = 0.0000, -0.0242, 0.0514
+ #bone.tail[:] = 0.0000, -0.0417, 0.0868
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.02']
+ #bone = arm.edit_bones.new('neck.04')
+ #bone.head[:] = 0.0000, -0.0417, 0.0868
+ #bone.tail[:] = 0.0000, -0.0509, 0.1190
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.03']
+ #bone = arm.edit_bones.new('neck.05')
+ #bone.head[:] = 0.0000, -0.0509, 0.1190
+ #bone.tail[:] = 0.0000, -0.0537, 0.1600
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.04']
+ #
+ #bpy.ops.object.mode_set(mode='OBJECT')
+ #pbone = obj.pose.bones['head']
+ #pbone['type'] = 'neck_flex'
+ pass
+
+
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is neck_01, its parent is the body
+ eg.
+ body -> neck_01 -> neck_02 -> neck_03.... etc
+ '''
+ arm = obj.data
+ neck = arm.bones[orig_bone_name]
+ body = neck.parent
+
+ bone_definition = [body.name, neck.name]
+ bone_definition.extend([child.name for child in neck.children_recursive_basename])
+ return bone_definition
+
+
+def deform(obj, definitions, base_names, options):
+ for org_bone_name in definitions[1:]:
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create deform bone.
+ bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True)
+
+ # Store name before leaving edit mode
+ bone_name = bone.name
+
+ # Leave edit mode
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Get the pose bone
+ bone = obj.pose.bones[bone_name]
+
+ # Constrain to the original bone
+ # XXX. Todo, is this needed if the bone is connected to its parent?
+ con = bone.constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_loc"
+ con.target = obj
+ con.subtarget = org_bone_name
+
+
+def main(obj, bone_definition, base_names, options):
+ from Mathutils import Vector
+
+ arm = obj.data
+ eb = obj.data.edit_bones
+ bb = obj.data.bones
+ pb = obj.pose.bones
+
+ body = bone_definition[0]
+
+ # Create the neck and head control bones
+ if "head_name" in options:
+ head_name = options["head_name"]
+ else:
+ head_name = "head"
+
+ neck_name = base_names[bone_definition[1]].split(".")[0]
+
+ neck_ctrl = copy_bone_simple(arm, bone_definition[1], neck_name).name
+ head_ctrl = copy_bone_simple(arm, bone_definition[len(bone_definition)-1], head_name).name
+ eb[head_ctrl].tail += eb[neck_ctrl].head - eb[head_ctrl].head
+ eb[head_ctrl].head = eb[neck_ctrl].head
+
+ # Create hinge and socket bones
+ neck_hinge = copy_bone_simple(arm, bone_definition[0], "MCH-" + neck_name + "_hinge").name
+ head_hinge = copy_bone_simple(arm, neck_ctrl, "MCH-" + head_name + "_hinge").name
+ eb[neck_hinge].tail += eb[neck_ctrl].head - eb[neck_hinge].head
+ eb[neck_hinge].head = eb[neck_ctrl].head
+ eb[head_hinge].tail += eb[neck_ctrl].head - eb[head_hinge].head
+ eb[head_hinge].head = eb[neck_ctrl].head
+
+ neck_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + neck_name + "_socket").name
+ head_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + head_name + "_socket").name
+
+ # Parent-child relationships between the body, hinges, controls, and sockets
+ eb[neck_ctrl].parent = eb[neck_hinge]
+ eb[head_ctrl].parent = eb[head_hinge]
+
+ eb[neck_socket].parent = eb[body]
+ eb[head_socket].parent = eb[body]
+
+ # Create neck bones
+ neck = [] # neck bones
+ neck_neck = [] # bones constrained to neck control
+ neck_head = [] # bones constrained to head control
+ for i in range(1, len(bone_definition)):
+ # Create bones
+ neck_bone = copy_bone_simple(arm, bone_definition[i], base_names[bone_definition[i]]).name
+ neck_neck_bone = copy_bone_simple(arm, neck_ctrl, "MCH-" + base_names[bone_definition[i]] + ".neck").name
+ neck_head_bone = copy_bone_simple(arm, head_ctrl, "MCH-" + base_names[bone_definition[i]] + ".head").name
+
+ # Move them all to the same place
+ eb[neck_neck_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head
+ eb[neck_head_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head
+ eb[neck_neck_bone].head = eb[neck_bone].head
+ eb[neck_head_bone].head = eb[neck_bone].head
+
+ # Parent/child relationships
+ eb[neck_bone].parent = eb[neck_head_bone]
+ eb[neck_head_bone].parent = eb[neck_neck_bone]
+
+ if i > 1:
+ eb[neck_neck_bone].parent = eb[neck[i-2]]
+ else:
+ eb[neck_neck_bone].parent = eb[body]
+
+ # Add them to the lists
+ neck += [neck_bone]
+ neck_neck += [neck_neck_bone]
+ neck_head += [neck_head_bone]
+
+ # Create deformation rig
+ deform(obj, bone_definition, base_names, options)
+
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Axis locks
+ pb[neck_ctrl].lock_location = True, True, True
+ pb[head_ctrl].lock_location = True, True, True
+
+ for bone in neck:
+ pb[bone].lock_location = True, True, True
+
+ # Neck hinge
+ prop = rna_idprop_ui_prop_get(pb[neck_ctrl], "hinge", create=True)
+ pb[neck_ctrl]["hinge"] = 0.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ prop["hard_min"] = 0.0
+ prop["hard_max"] = 1.0
+
+ con = pb[neck_hinge].constraints.new('COPY_LOCATION')
+ con.name = "socket"
+ con.target = obj
+ con.subtarget = neck_socket
+
+ con = pb[neck_hinge].constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = body
+
+ hinge_driver_path = pb[neck_ctrl].path_from_id() + '["hinge"]'
+
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = hinge_driver_path
+
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ # Head hinge
+ prop = rna_idprop_ui_prop_get(pb[head_ctrl], "hinge", create=True)
+ pb[head_ctrl]["hinge"] = 0.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ prop["hard_min"] = 0.0
+ prop["hard_max"] = 1.0
+
+ con = pb[head_hinge].constraints.new('COPY_LOCATION')
+ con.name = "socket"
+ con.target = obj
+ con.subtarget = head_socket
+
+ con = pb[head_hinge].constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = neck_ctrl
+
+ hinge_driver_path = pb[head_ctrl].path_from_id() + '["hinge"]'
+
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = hinge_driver_path
+
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ # Neck rotation constraints
+ for i in range(0, len(neck_neck)):
+ con = pb[neck_neck[i]].constraints.new('COPY_ROTATION')
+ con.name = "neck rotation"
+ con.target = obj
+ con.subtarget = neck_ctrl
+ con.influence = (i+1) / len(neck_neck)
+
+
+ # Head rotation constraints/drivers
+ prop = rna_idprop_ui_prop_get(pb[head_ctrl], "extent", create=True)
+ if "extent" in options:
+ pb[head_ctrl]["extent"] = options["extent"]
+ else:
+ pb[head_ctrl]["extent"] = 0.5
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ prop["hard_min"] = 0.0
+ prop["hard_max"] = 1.0
+
+ extent_prop_path = pb[head_ctrl].path_from_id() + '["extent"]'
+
+ for i in range(0, len(neck_head)):
+ con = pb[neck_head[i]].constraints.new('COPY_ROTATION')
+ con.name = "head rotation"
+ con.target = obj
+ con.subtarget = head_ctrl
+
+ if i < (len(neck_head)-1):
+ inf = (i+1) / len(neck_head)
+
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ var = driver.variables.new()
+ var.name = "ext"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = extent_prop_path
+
+ driver.expression = "0 if ext == 0 else (((%s-1)/ext)+1)" % inf
+ else:
+ con.influence = 1.0
+
+ # Constrain original bones to the neck bones
+ for i in range(0, len(neck)):
+ con = pb[bone_definition[i+1]].constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_transform"
+ con.target = obj
+ con.subtarget = neck[i]
+
+
+ # Set the controls' custom shapes to use other bones for transforms
+ pb[neck_ctrl].custom_shape_transform = pb[bone_definition[len(bone_definition)//2]]
+ pb[head_ctrl].custom_shape_transform = pb[bone_definition[len(bone_definition)-1]]
+
+
+ # last step setup layers
+ if "ex_layer" in options:
+ layer = [n==options["ex_layer"] for n in range(0,32)]
+ else:
+ layer = list(arm.bones[bone_definition[1]].layer)
+ for bone in neck:
+ bb[bone].layer = layer
+
+ layer = list(arm.bones[bone_definition[1]].layer)
+ bb[neck_ctrl].layer = layer
+ bb[head_ctrl].layer = layer
+
+
+ # no blending the result of this
+ return None
+
diff --git a/release/scripts/modules/rigify/tongue.py b/release/scripts/modules/rigify/tongue.py
new file mode 100644
index 00000000000..5e219309503
--- /dev/null
+++ b/release/scripts/modules/rigify/tongue.py
@@ -0,0 +1,361 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from rigify import RigifyError
+from rigify_utils import bone_class_instance, copy_bone_simple
+from rna_prop_ui import rna_idprop_ui_prop_get
+
+# not used, defined for completeness
+METARIG_NAMES = ("body", "head")
+
+
+def metarig_template():
+ # TODO:
+ ## generated by rigify.write_meta_rig
+ #bpy.ops.object.mode_set(mode='EDIT')
+ #obj = bpy.context.active_object
+ #arm = obj.data
+ #bone = arm.edit_bones.new('body')
+ #bone.head[:] = 0.0000, -0.0276, -0.1328
+ #bone.tail[:] = 0.0000, -0.0170, -0.0197
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone = arm.edit_bones.new('head')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, 0.0726, 0.1354
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['body']
+ #bone = arm.edit_bones.new('neck.01')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, -0.0099, 0.0146
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone.parent = arm.edit_bones['head']
+ #bone = arm.edit_bones.new('neck.02')
+ #bone.head[:] = 0.0000, -0.0099, 0.0146
+ #bone.tail[:] = 0.0000, -0.0242, 0.0514
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.01']
+ #bone = arm.edit_bones.new('neck.03')
+ #bone.head[:] = 0.0000, -0.0242, 0.0514
+ #bone.tail[:] = 0.0000, -0.0417, 0.0868
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.02']
+ #bone = arm.edit_bones.new('neck.04')
+ #bone.head[:] = 0.0000, -0.0417, 0.0868
+ #bone.tail[:] = 0.0000, -0.0509, 0.1190
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.03']
+ #bone = arm.edit_bones.new('neck.05')
+ #bone.head[:] = 0.0000, -0.0509, 0.1190
+ #bone.tail[:] = 0.0000, -0.0537, 0.1600
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.04']
+ #
+ #bpy.ops.object.mode_set(mode='OBJECT')
+ #pbone = obj.pose.bones['head']
+ #pbone['type'] = 'neck_flex'
+ pass
+
+
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is the tongue control, its parent is the body,
+ # its only child the first of a chain with matching basenames.
+ eg.
+ body -> tongue_control -> tongue_01 -> tongue_02 -> tongue_03.... etc
+ '''
+ arm = obj.data
+ tongue = arm.bones[orig_bone_name]
+ body = tongue.parent
+
+ children = tongue.children
+ if len(children) != 1:
+ raise RigifyError("expected the tongue bone '%s' to have only 1 child." % orig_bone_name)
+
+ child = children[0]
+ bone_definition = [body.name, tongue.name, child.name]
+ bone_definition.extend([child.name for child in child.children_recursive_basename])
+ return bone_definition
+
+
+def deform(obj, definitions, base_names, options):
+ for org_bone_name in definitions[2:]:
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create deform bone.
+ bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True)
+
+ # Store name before leaving edit mode
+ bone_name = bone.name
+
+ # Leave edit mode
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Get the pose bone
+ bone = obj.pose.bones[bone_name]
+
+ # Constrain to the original bone
+ # XXX. Todo, is this needed if the bone is connected to its parent?
+ con = bone.constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_loc"
+ con.target = obj
+ con.subtarget = org_bone_name
+
+
+# TODO: rename all of the head/neck references to tongue
+def main(obj, bone_definition, base_names, options):
+ from Mathutils import Vector
+
+ arm = obj.data
+
+ # Initialize container classes for convenience
+ mt = bone_class_instance(obj, ["body", "head"]) # meta
+ mt.body = bone_definition[0]
+ mt.head = bone_definition[1]
+ mt.update()
+
+ neck_chain = bone_definition[2:]
+
+ mt_chain = bone_class_instance(obj, [("neck_%.2d" % (i + 1)) for i in range(len(neck_chain))]) # 99 bones enough eh?
+ for i, attr in enumerate(mt_chain.attr_names):
+ setattr(mt_chain, attr, neck_chain[i])
+ mt_chain.update()
+
+ neck_chain_basename = base_names[mt_chain.neck_01_e.name].split(".")[0]
+ neck_chain_segment_length = mt_chain.neck_01_e.length
+
+ ex = bone_class_instance(obj, ["head", "head_hinge", "neck_socket", "head_ctrl"]) # hinge & extras
+
+ # Add the head hinge at the bodys location, becomes the parent of the original head
+
+ # apply everything to this copy of the chain
+ ex_chain = mt_chain.copy(base_names=base_names)
+ ex_chain.neck_01_e.parent = mt_chain.neck_01_e.parent
+
+
+ # Copy the head bone and offset
+ ex.head_e = copy_bone_simple(arm, mt.head, "MCH-%s" % base_names[mt.head], parent=True)
+ ex.head_e.connected = False
+ ex.head = ex.head_e.name
+ # offset
+ head_length = ex.head_e.length
+ ex.head_e.head.y += head_length / 2.0
+ ex.head_e.tail.y += head_length / 2.0
+
+ # Yes, use the body bone but call it a head hinge
+ ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH-%s_hinge" % base_names[mt.head], parent=False)
+ ex.head_hinge_e.connected = False
+ ex.head_hinge = ex.head_hinge_e.name
+ ex.head_hinge_e.head.y += head_length / 4.0
+ ex.head_hinge_e.tail.y += head_length / 4.0
+
+ # Insert the neck socket, the head copys this loation
+ ex.neck_socket_e = arm.edit_bones.new("MCH-%s_socked" % neck_chain_basename)
+ ex.neck_socket = ex.neck_socket_e.name
+ ex.neck_socket_e.connected = False
+ ex.neck_socket_e.parent = mt.body_e
+ ex.neck_socket_e.head = mt.head_e.head
+ ex.neck_socket_e.tail = mt.head_e.head - Vector(0.0, neck_chain_segment_length / 2.0, 0.0)
+ ex.neck_socket_e.roll = 0.0
+
+
+ # copy of the head for controling
+ ex.head_ctrl_e = copy_bone_simple(arm, mt.head, base_names[mt.head])
+ ex.head_ctrl = ex.head_ctrl_e.name
+ ex.head_ctrl_e.parent = ex.head_hinge_e
+
+ for i, attr in enumerate(ex_chain.attr_names):
+ neck_e = getattr(ex_chain, attr + "_e")
+
+ # dont store parent names, re-reference as each chain bones parent.
+ neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % base_names[getattr(mt_chain, attr)])
+ neck_e_parent.head = neck_e.head
+ neck_e_parent.tail = neck_e.head + (mt.head_e.vector.normalize() * neck_chain_segment_length / 2.0)
+ neck_e_parent.roll = mt.head_e.roll
+
+ orig_parent = neck_e.parent
+ neck_e.connected = False
+ neck_e.parent = neck_e_parent
+ neck_e_parent.connected = False
+
+ if i == 0:
+ neck_e_parent.parent = mt.body_e
+ else:
+ neck_e_parent.parent = orig_parent
+
+ deform(obj, bone_definition, base_names, options)
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ mt.update()
+ mt_chain.update()
+ ex_chain.update()
+ ex.update()
+
+ # Axis locks
+ ex.head_ctrl_p.lock_location = True, True, True
+ ex.head_ctrl_p.lock_scale = True, False, True
+
+ # Simple one off constraints, no drivers
+ con = ex.head_ctrl_p.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = ex.neck_socket
+
+ con = ex.head_p.constraints.new('COPY_ROTATION')
+ con.target = obj
+ con.subtarget = ex.head_ctrl
+
+ # driven hinge
+ prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, "hinge", create=True)
+ ex.head_ctrl_p["hinge"] = 0.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ con = ex.head_hinge_p.constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = mt.body
+
+ # add driver
+ hinge_driver_path = ex.head_ctrl_p.path_to_id() + '["hinge"]'
+
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = hinge_driver_path
+
+ #mod = fcurve_driver.modifiers.new('GENERATOR')
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ head_driver_path = ex.head_ctrl_p.path_to_id()
+
+ target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))]
+
+ ex.head_ctrl_p["bend_tot"] = 0.0
+ fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]', 0)
+ driver = fcurve.driver
+ driver.type = 'SUM'
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+ for i in range(len(neck_chain)):
+ var = driver.variables.new()
+ var.name = target_names[i]
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["bend_%.2d"]' % (i + 1))
+
+
+ for i, attr in enumerate(ex_chain.attr_names):
+ neck_p = getattr(ex_chain, attr + "_p")
+ neck_p.lock_location = True, True, True
+ neck_p.lock_location = True, True, True
+ neck_p.lock_rotations_4d = True
+
+ # Add bend prop
+ prop_name = "bend_%.2d" % (i + 1)
+ prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, prop_name, create=True)
+ ex.head_ctrl_p[prop_name] = 1.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ # add parent constraint
+ neck_p_parent = neck_p.parent
+
+ # add constraints
+ if i == 0:
+ con = neck_p.constraints.new('COPY_SCALE')
+ con.name = "Copy Scale"
+ con.target = obj
+ con.subtarget = ex.head_ctrl
+ con.owner_space = 'LOCAL'
+ con.target_space = 'LOCAL'
+
+ con = neck_p_parent.constraints.new('COPY_ROTATION')
+ con.name = "Copy Rotation"
+ con.target = obj
+ con.subtarget = ex.head
+ con.owner_space = 'LOCAL'
+ con.target_space = 'LOCAL'
+
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ driver.type = 'SCRIPTED'
+ driver.expression = "bend/bend_tot"
+
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+
+ # add target
+ var = driver.variables.new()
+ var.name = "bend_tot"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["bend_tot"]')
+
+ var = driver.variables.new()
+ var.name = "bend"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["%s"]' % prop_name)
+
+
+ # finally constrain the original bone to this one
+ orig_neck_p = getattr(mt_chain, attr + "_p")
+ con = orig_neck_p.constraints.new('COPY_TRANSFORMS')
+ con.target = obj
+ con.subtarget = neck_p.name
+
+
+ # Set the head control's custom shape to use the last
+ # org neck bone for its transform
+ ex.head_ctrl_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
+
+
+ # last step setup layers
+ if "ex_layer" in options:
+ layer = [n==options["ex_layer"] for n in range(0,32)]
+ else:
+ layer = list(arm.bones[bone_definition[1]].layer)
+ for attr in ex_chain.attr_names:
+ getattr(ex_chain, attr + "_b").layer = layer
+ for attr in ex.attr_names:
+ getattr(ex, attr + "_b").layer = layer
+
+ layer = list(arm.bones[bone_definition[1]].layer)
+ ex.head_ctrl_b.layer = layer
+
+
+ # no blending the result of this
+ return None
+