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-02-03 18:40:56 +0300
committerNathan Vegdahl <cessen@cessen.com>2010-02-03 18:40:56 +0300
commit11ce6eb4d46ac99adab073047d041b8bf104967b (patch)
tree3839df9a1130ba54afbaa3c1fcfe47cc2beb5cd4 /release/scripts/modules
parent1f3e277121795aaa37b7b719a0b5d0b8185b0d1c (diff)
Added a new rig type "shape_key_transforms" that drives shape keys based on the local transforms of a single bone. Quite useful in a variety of situations.
Required options: mesh: name of mesh object(s) to add/get shapekeys to/from (if multiple objects, make a comma-separated list) Optional options: loc_<x/y/z>: name of the shape key to tie to translation of the bone loc_<x/y/z>_fac: default multiplier of the bone influence on the shape key rot_<x/y/z>: name of the shape key to tie to rotation of the bone rot_<x/y/z>_fac: default multiplier of the bone influence on the shape key scale_<x/y/z>: name of the shape key to tie to scale of the bone scale_<x/y/z>_fac: default multiplier of the bone influence on the shape key
Diffstat (limited to 'release/scripts/modules')
-rw-r--r--release/scripts/modules/rigify/shape_key_transforms.py263
1 files changed, 263 insertions, 0 deletions
diff --git a/release/scripts/modules/rigify/shape_key_transforms.py b/release/scripts/modules/rigify/shape_key_transforms.py
new file mode 100644
index 00000000000..8e81776bf0c
--- /dev/null
+++ b/release/scripts/modules/rigify/shape_key_transforms.py
@@ -0,0 +1,263 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+from rigify import RigifyError
+from rigify_utils import copy_bone_simple
+from rna_prop_ui import rna_idprop_ui_prop_get
+
+#METARIG_NAMES = ("cpy",)
+RIG_TYPE = "shape_key_transforms"
+
+
+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
+
+
+# TODO:
+def metarig_template():
+ # 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('Bone')
+ #bone.head[:] = 0.0000, 0.0000, 0.0000
+ #bone.tail[:] = 0.0000, 0.0000, 1.0000
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #
+ #bpy.ops.object.mode_set(mode='OBJECT')
+ #pbone = obj.pose.bones['Bone']
+ #pbone['type'] = 'copy'
+ pass
+
+
+def metarig_definition(obj, orig_bone_name):
+ bone = obj.data.bones[orig_bone_name]
+ return [bone.name]
+
+
+def main(obj, definitions, base_names, options):
+ """ A rig that drives shape keys with the local transforms of a single bone.
+
+ Required options:
+ mesh: name of mesh object(s) to add/get shapekeys to/from
+ (if multiple objects, make a comma-separated list)
+ Optional options:
+ loc_<x/y/z>: name of the shape key to tie to translation of the bone
+ loc_<x/y/z>_fac: default multiplier of the bone influence on the shape key
+ rot_<x/y/z>: name of the shape key to tie to rotation of the bone
+ rot_<x/y/z>_fac: default multiplier of the bone influence on the shape key
+ scale_<x/y/z>: name of the shape key to tie to scale of the bone
+ scale_<x/y/z>_fac: default multiplier of the bone influence on the shape key
+ """
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ eb = obj.data.edit_bones
+ pb = obj.pose.bones
+
+ org_bone = definitions[0]
+
+ # Options
+ req_options = ["mesh"]
+ for option in req_options:
+ if option not in options:
+ raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
+
+ meshes = options["mesh"].replace(" ", "").split(",")
+
+ bone = copy_bone_simple(obj.data, org_bone, base_names[org_bone], parent=True).name
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Set rotation mode and axis locks
+ pb[bone].rotation_mode = pb[org_bone].rotation_mode
+ pb[bone].lock_location = tuple(pb[org_bone].lock_location)
+ pb[bone].lock_rotation = tuple(pb[org_bone].lock_rotation)
+ pb[bone].lock_rotation_w = pb[org_bone].lock_rotation_w
+ pb[bone].lock_rotations_4d = pb[org_bone].lock_rotations_4d
+ pb[bone].lock_scale = tuple(pb[org_bone].lock_scale)
+
+ # List of rig options for specifying shape keys
+ # Append '_fac' to the end for the name of the correspond 'factor default'
+ # option for that shape
+ shape_key_options = ["loc_x",
+ "loc_y",
+ "loc_z",
+ "rot_x",
+ "rot_y",
+ "rot_z",
+ "scale_x",
+ "scale_y",
+ "scale_z"]
+
+ driver_paths = {"loc_x":".location[0]",
+ "loc_y":".location[1]",
+ "loc_z":".location[2]",
+ "rot_x":".rotation_euler[0]",
+ "rot_y":".rotation_euler[1]",
+ "rot_z":".rotation_euler[2]",
+ "qrot_x":".rotation_quaternion[1]",
+ "qrot_y":".rotation_quaternion[2]",
+ "qrot_z":".rotation_quaternion[3]",
+ "scale_x":".scale[0]",
+ "scale_y":".scale[1]",
+ "scale_z":".scale[2]"}
+
+ # Create the shape keys and drivers
+ shape_info = []
+ for option in shape_key_options:
+ if option in options:
+ shape_name = options[option]
+
+ var_name = bone + "_" + option
+ # Different paths for euler vs quat
+ if option in shape_key_options[3:6] and pb[bone].rotation_mode == 'QUATERNION':
+ var_path = driver_paths['q' + option]
+ else:
+ var_path = driver_paths[option]
+
+ fac_name = option + "_factor"
+ if (option+"_fac") in options:
+ fac_default = options[option+"_fac"]
+ else:
+ fac_default = 1.0
+
+ # Different expressions for loc/rot/scale
+ if option in shape_key_options[:3]:
+ expression = var_name + " * " + fac_name
+ elif option in shape_key_options[:6]:
+ # Different expressions for euler vs quats
+ if pb[bone].rotation_mode == 'QUATERNION':
+ expression = "2 * asin(" + var_name + ") * " + fac_name
+ else:
+ expression = var_name + " * " + fac_name
+ else:
+ expression = "(1.0 - " + var_name + ") * " + fac_name + " * -2"
+
+ create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, fac_name, fac_default, expression)
+
+ return (None,)
+
+
+def create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, fac_name, fac_default, 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
+ fac_name = name of the "factor" custom property on the bone
+ fac_default = default starting value of the factor property
+ expression = python expression for the driver
+ """
+ pb = obj.pose.bones
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Set up the "factor" custom property on the bone
+ prop = rna_idprop_ui_prop_get(pb[bone], fac_name, create=True)
+ pb[bone][fac_name] = fac_default
+ prop["min"] = -1000.0
+ prop["max"] = 1000.0
+ prop["soft_min"] = -1000.0
+ prop["soft_max"] = 1000.0
+
+ 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
+
+ # Get the fac variable, or create it if it doesn't already exist
+ if fac_name in driver.variables:
+ var_fac = driver.variables[fac_name]
+ else:
+ var_fac = driver.variables.new()
+ var_fac.name = fac_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
+
+ # Set up the fac variable
+ var_fac.type = "SINGLE_PROP"
+ var_fac.targets[0].id_type = 'OBJECT'
+ var_fac.targets[0].id = obj
+ var_fac.targets[0].data_path = 'pose.bones["' + bone + '"]["' + fac_name + '"]'
+
+
+def main(obj, bone_definition, base_names, options):
+ control(obj, bone_definition, base_names, options)
+
+
+ return (None,)
+