A field for an offset might be nice too, for shape keys driving multiple keys (looks like you could drive 2 keys with this, by negating the multiplier, but not more then that).
Joe On Wed, Feb 3, 2010 at 7:40 AM, Nathan Vegdahl <[email protected]> wrote: > Revision: 26582 > > http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=26582 > Author: cessen > Date: 2010-02-03 16:40:56 +0100 (Wed, 03 Feb 2010) > > Log Message: > ----------- > 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 > > Added Paths: > ----------- > trunk/blender/release/scripts/modules/rigify/shape_key_transforms.py > > Added: trunk/blender/release/scripts/modules/rigify/shape_key_transforms.py > =================================================================== > --- trunk/blender/release/scripts/modules/rigify/shape_key_transforms.py > (rev 0) > +++ trunk/blender/release/scripts/modules/rigify/shape_key_transforms.py > 2010-02-03 15:40:56 UTC (rev 26582) > @@ -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,) > + > > > _______________________________________________ > Bf-blender-cvs mailing list > [email protected] > http://lists.blender.org/mailman/listinfo/bf-blender-cvs > _______________________________________________ Bf-committers mailing list [email protected] http://lists.blender.org/mailman/listinfo/bf-committers
