diff options
author | Nathan Vegdahl <cessen@cessen.com> | 2010-01-19 22:07:09 +0300 |
---|---|---|
committer | Nathan Vegdahl <cessen@cessen.com> | 2010-01-19 22:07:09 +0300 |
commit | c54d54e8aeb386fd8f5cbd61d62fb5a490bb6ea8 (patch) | |
tree | 6a9fdb6aa9b7ddf4ae4c864bd42075efdc6ae3de /release | |
parent | 40fb29862ea06794d27378aaf64638d8c1f72121 (diff) |
Rigify:
- Added two driven-shape-key rig types that create and drive shape keys on a mesh/meshes based on the distance or rotation difference between two bones.
- Fixed bug in finger curl rig type where secondary finger controls were not created. Finger type can also now (optionally) have a hinge switch (useful when using it for wings).
- Changed the blending system in rigify_utils to use copy_transforms constraints instead of copy_loc+copy_rot.
- Finished the quadruped leg type. Now has both ik and fk control and ik/fk switching. Also uses a rotating bone to control the knee direction instead of a pole target (seems to work more consistently for quadruped setups). There's still one annoying bug regarding foot roll, but it's not blocking. I'll track it down later.
- Mouth rig now creates corrective shape keys on the face mesh for dealing with mouth corners when they spread open.
- Biped arm and leg types now cause mesh to scale when you scale the fk controls.
- Misc improvements to the rig types.
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/modules/rigify/arm_biped.py | 20 | ||||
-rw-r--r-- | release/scripts/modules/rigify/finger_curl.py | 236 | ||||
-rw-r--r-- | release/scripts/modules/rigify/leg_biped.py | 17 | ||||
-rw-r--r-- | release/scripts/modules/rigify/leg_quadruped.py | 281 | ||||
-rw-r--r-- | release/scripts/modules/rigify/mouth.py | 526 | ||||
-rw-r--r-- | release/scripts/modules/rigify/neck_flex.py | 3 | ||||
-rw-r--r-- | release/scripts/modules/rigify/palm_curl.py | 3 | ||||
-rw-r--r-- | release/scripts/modules/rigify/shape_key_distance.py | 176 | ||||
-rw-r--r-- | release/scripts/modules/rigify/shape_key_rotdiff.py | 176 | ||||
-rw-r--r-- | release/scripts/modules/rigify/spine_pivot_flex.py | 8 | ||||
-rw-r--r-- | release/scripts/modules/rigify_utils.py | 28 |
11 files changed, 1239 insertions, 235 deletions
diff --git a/release/scripts/modules/rigify/arm_biped.py b/release/scripts/modules/rigify/arm_biped.py index 26b56164b37..f3d449e5aff 100644 --- a/release/scripts/modules/rigify/arm_biped.py +++ b/release/scripts/modules/rigify/arm_biped.py @@ -223,6 +223,7 @@ def fk(obj, definitions, base_names, options): fk_chain.forearm_p.rotation_mode = 'XYZ' fk_chain.forearm_p.lock_rotation = (False, True, True) fk_chain.hand_p.rotation_mode = 'ZXY' + fk_chain.arm_p.lock_location = True, True, True con = fk_chain.arm_p.constraints.new('COPY_LOCATION') con.target = obj @@ -276,7 +277,14 @@ def fk(obj, definitions, base_names, options): fk_chain.arm_b.layer = layer fk_chain.forearm_b.layer = layer fk_chain.hand_b.layer = layer - + + # Forearm was getting wrong roll somehow. Hack to fix that. + bpy.ops.object.mode_set(mode='EDIT') + fk_chain.update() + mt.update() + fk_chain.forearm_e.roll = mt.forearm_e.roll + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='EDIT') return None, fk_chain.arm, fk_chain.forearm, fk_chain.hand @@ -338,6 +346,11 @@ def deform(obj, definitions, base_names, options): con.target = obj con.subtarget = definitions[2] + con = uarm1.constraints.new('COPY_SCALE') + con.name = "trackto" + con.target = obj + con.subtarget = definitions[1] + con = uarm2.constraints.new('COPY_ROTATION') con.name = "copy_rot" con.target = obj @@ -349,6 +362,11 @@ def deform(obj, definitions, base_names, options): con.target = obj con.subtarget = definitions[2] + con = farm1.constraints.new('COPY_SCALE') + con.name = "copy_rot" + con.target = obj + con.subtarget = definitions[2] + con = farm2.constraints.new('COPY_ROTATION') con.name = "copy_rot" con.target = obj diff --git a/release/scripts/modules/rigify/finger_curl.py b/release/scripts/modules/rigify/finger_curl.py index 085eba180fd..997ed889bb2 100644 --- a/release/scripts/modules/rigify/finger_curl.py +++ b/release/scripts/modules/rigify/finger_curl.py @@ -150,103 +150,171 @@ def deform(obj, definitions, base_names, options): def main(obj, bone_definition, base_names, options): # *** EDITMODE - + bpy.ops.object.mode_set(mode='EDIT') + # get assosiated data arm = obj.data - orig_ebone = arm.edit_bones[bone_definition[0]] - - obj.animation_data_create() # needed if its a new armature with no keys - - children = orig_ebone.children_recursive - tot_len = reduce(lambda f, ebone: f + ebone.length, children, orig_ebone.length) - - # FIXME, the line below is far too arbitrary - base_name = base_names[bone_definition[0]].rsplit(".", 2)[0] - - # first make a new bone at the location of the finger - #control_ebone = arm.edit_bones.new(base_name) - control_ebone = copy_bone_simple(arm, bone_definition[0], base_name + get_side_name(base_names[bone_definition[0]]), parent=True) - 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 - control_ebone.length = tot_len - - # now add bones inbetween this and its children recursively - - # switching modes so store names only! - children = [ebone.name for ebone in children] - - driver_bone_pairs = [] - - for child_bone_name in children: - child_ebone = arm.edit_bones[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 = copy_bone_simple(arm, child_ebone.name, driver_bone_name) - driver_ebone.length *= 0.5 - - # 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 + bb = obj.data.bones + eb = obj.data.edit_bones + pb = obj.pose.bones + + 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 + + # Check options + if "bend_ratio" in options: + bend_ratio = options["bend_ratio"] + else: + bend_ratio = 0.4 + + yes = [1, 1.0, True, "True", "true", "Yes", "yes"] + make_hinge = False + if ("hinge" in options) and (eb[org_f1].parent is not None): + if options["hinge"] in yes: + make_hinge = True + + # Needed if its a new armature with no keys + obj.animation_data_create() + + # 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 + 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 + eb[control].length = tot_len + + # 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 + + # 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 + + # Set parents of the bones, interleaving the driver bones with the secondary control bones + 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] + eb[f2].parent = eb[df2] + eb[df2].parent = eb[f1] + eb[f1].parent = eb[df1] + eb[df1].parent = eb[org_f1].parent + + # 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 + + eb[control].connected = False + eb[control].parent = eb[hinge] + + # Create the deform rig while we're still in edit mode deform(obj, bone_definition, base_names, options) - + + # *** POSEMODE bpy.ops.object.mode_set(mode='OBJECT') - - - orig_pbone = obj.pose.bones[bone_definition[0]] - control_pbone = obj.pose.bones[control_bone_name] - control_bbone = arm.bones[control_bone_name] - control_pbone.rotation_mode = obj.pose.bones[bone_definition[0]].rotation_mode - - - # 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) + + # Set rotation modes and axis locks + pb[control].rotation_mode = obj.pose.bones[bone_definition[0]].rotation_mode + pb[control].lock_location = True, True, True + pb[control].lock_scale = True, False, True + pb[f1].rotation_mode = 'YZX' + pb[f2].rotation_mode = 'YZX' + 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 + pb[df2].rotation_mode = 'YZX' + pb[df3].rotation_mode = 'YZX' + + # Add the bend_ratio property to the control bone + pb[control]["bend_ratio"] = bend_ratio + prop = rna_idprop_ui_prop_get(pb[control], "bend_ratio", create=True) prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 - - con = orig_pbone.constraints.new('COPY_LOCATION') + + # Add hinge property to the control bone + if make_hinge: + pb[control]["hinge"] = 0.0 + prop = rna_idprop_ui_prop_get(pb[control], "hinge", create=True) + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + + # Constraints + con = pb[df1].constraints.new('COPY_LOCATION') con.target = obj - con.subtarget = control_bone_name + con.subtarget = control - con = orig_pbone.constraints.new('COPY_ROTATION') + con = pb[df1].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. + con.subtarget = control + + con = pb[org_f1].constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = f1 + + con = pb[org_f2].constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = f2 + + con = pb[org_f3].constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = f3 + + if make_hinge: + con = pb[hinge].constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = bb[org_f1].parent.name + + hinge_driver_path = pb[control].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 - # drives the bones - controller_path = control_pbone.path_to_id() # 'pose.bones["%s"]' % control_bone_name + mod = fcurve.modifiers[0] + mod.poly_order = 1 + mod.coefficients[0] = 1.0 + mod.coefficients[1] = -1.0 + + con = pb[control].constraints.new('COPY_LOCATION') + con.target = obj + con.subtarget = socket + + # Create the drivers for the driver bones (control bone scale rotates driver bones) + controller_path = pb[control].path_to_id() # 'pose.bones["%s"]' % control_bone_name i = 0 - for child_bone_name, driver_bone_name in driver_bone_pairs: + for bone in [df2, df3]: # XXX - todo, any number if i == 2: break - driver_pbone = obj.pose.bones[driver_bone_name] + pbone = pb[bone] - driver_pbone.rotation_mode = 'YZX' - fcurve_driver = driver_pbone.driver_add("rotation_euler", 0) + pbone.rotation_mode = 'YZX' + fcurve_driver = pbone.driver_add("rotation_euler", 0) #obj.driver_add('pose.bones["%s"].scale', 1) #obj.animation_data.drivers[-1] # XXX, WATCH THIS @@ -272,24 +340,18 @@ def main(obj, bone_definition, base_names, options): elif i == 1: driver.expression = '(-scale+1.0)*pi*2.0*br' - child_pbone = obj.pose.bones[child_bone_name] - - # only allow X rotation - driver_pbone.lock_rotation = child_pbone.lock_rotation = (False, True, True) - i += 1 - - # last step setup layers + # 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[0]].layer) - for child_bone_name, driver_bone_name in driver_bone_pairs: - arm.bones[driver_bone_name].layer = layer + for bone_name in [f1, f2, f3]: + arm.bones[bone_name].layer = layer layer = list(arm.bones[bone_definition[0]].layer) - control_bbone.layer = layer + bb[control].layer = layer # no blending the result of this return None diff --git a/release/scripts/modules/rigify/leg_biped.py b/release/scripts/modules/rigify/leg_biped.py index 70be980d7b2..5c214cea362 100644 --- a/release/scripts/modules/rigify/leg_biped.py +++ b/release/scripts/modules/rigify/leg_biped.py @@ -219,6 +219,8 @@ def ik(obj, bone_definition, base_names, options): ik.foot_roll_p.lock_rotation = False, True, True ik_chain.toe_p.rotation_mode = 'YXZ' ik_chain.toe_p.lock_rotation = False, True, True + ik_chain.toe_p.lock_location = True, True, True + ik.foot_roll_p.lock_location = True, True, True # IK con = ik_chain.shin_p.constraints.new('IK') @@ -329,6 +331,7 @@ def fk(obj, bone_definition, base_names, options): foot_p.rotation_mode = 'YXZ' fk_chain.toe_p.rotation_mode = 'YXZ' fk_chain.toe_p.lock_rotation = False, True, True + fk_chain.thigh_p.lock_location = True, True, True con = fk_chain.thigh_p.constraints.new('COPY_LOCATION') con.target = obj @@ -336,7 +339,7 @@ def fk(obj, bone_definition, base_names, options): # hinge prop = rna_idprop_ui_prop_get(fk_chain.thigh_p, "hinge", create=True) - fk_chain.thigh_p["hinge"] = 0.5 + fk_chain.thigh_p["hinge"] = 0.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 @@ -441,6 +444,11 @@ def deform(obj, definitions, base_names, options): con.target = obj con.subtarget = definitions[2] + con = uleg1.constraints.new('COPY_SCALE') + con.name = "scale" + con.target = obj + con.subtarget = definitions[1] + con = uleg2.constraints.new('COPY_ROTATION') con.name = "copy_rot" con.target = obj @@ -452,6 +460,11 @@ def deform(obj, definitions, base_names, options): con.target = obj con.subtarget = definitions[2] + con = lleg1.constraints.new('COPY_SCALE') + con.name = "copy_rot" + con.target = obj + con.subtarget = definitions[2] + con = lleg2.constraints.new('COPY_ROTATION') con.name = "copy_rot" con.target = obj @@ -484,5 +497,5 @@ def main(obj, bone_definition, base_names, options): deform(obj, bone_definition, base_names, options) bpy.ops.object.mode_set(mode='OBJECT') - blend_bone_list(obj, bone_definition + [None], bones_fk, bones_ik, target_bone=bones_ik[6], target_prop="ik", blend_default=0.0) + blend_bone_list(obj, bone_definition + [None], bones_fk, bones_ik, target_bone=bones_ik[6], target_prop="ik", blend_default=1.0) diff --git a/release/scripts/modules/rigify/leg_quadruped.py b/release/scripts/modules/rigify/leg_quadruped.py index 49a404aef33..d1f74ca28bf 100644 --- a/release/scripts/modules/rigify/leg_quadruped.py +++ b/release/scripts/modules/rigify/leg_quadruped.py @@ -19,6 +19,8 @@ # <pep8 compliant> import bpy +from rna_prop_ui import rna_idprop_ui_prop_get +from math import pi from rigify import RigifyError from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone, get_side_name, get_base_name from Mathutils import Vector @@ -104,6 +106,8 @@ def metarig_definition(obj, orig_bone_name): def ik(obj, bone_definition, base_names, options): + eb = obj.data.edit_bones + pb = obj.pose.bones arm = obj.data bpy.ops.object.mode_set(mode='EDIT') @@ -114,13 +118,14 @@ def ik(obj, bone_definition, base_names, options): mt.attr_initialize(METARIG_NAMES, bone_definition) mt_chain.attr_initialize(METARIG_NAMES, bone_definition) - ik_chain = mt_chain.copy(to_fmt="%s", base_names=base_names) + ik_chain = mt_chain.copy(to_fmt="MCH-%s.ik", base_names=base_names) ik_chain.thigh_e.connected = False ik_chain.thigh_e.parent = mt.hips_e ik_chain.foot_e.parent = None - ik_chain.rename("foot", get_base_name(ik_chain.foot) + "_ik" + get_side_name(ik_chain.foot)) + ik_chain.rename("foot", get_base_name(base_names[bone_definition[3]]) + "_ik" + get_side_name(base_names[bone_definition[3]])) + ik_chain.rename("toe", get_base_name(base_names[bone_definition[4]]) + "_ik" + get_side_name(base_names[bone_definition[4]])) # keep the foot_ik as the parent ik_chain.toe_e.connected = False @@ -129,21 +134,29 @@ def ik(obj, bone_definition, base_names, options): ik_chain.foot_e.align_orientation(mt_chain.toe_e) # children of ik_foot - ik = bone_class_instance(obj, ["foot_roll", "foot_roll_01", "foot_roll_02", "knee_target", "foot_target"]) - - ik.knee_target = add_pole_target_bone(obj, mt_chain.shin, "knee_target" + get_side_name(base_names[mt_chain.foot])) #XXX - pick a better name - ik.update() - ik.knee_target_e.parent = mt.hips_e + ik = bone_class_instance(obj, ["foot_roll", "foot_roll_01", "foot_roll_02", "foot_target"]) + + # knee rotator + knee_rotator = copy_bone_simple(arm, mt_chain.toe, "knee_rotator" + get_side_name(base_names[mt_chain.foot]), parent=True).name + eb[knee_rotator].connected = False + eb[knee_rotator].parent = eb[mt.hips] + eb[knee_rotator].head = eb[ik_chain.thigh].head + eb[knee_rotator].tail = eb[knee_rotator].head + eb[mt_chain.toe].vector + eb[knee_rotator].length = eb[ik_chain.thigh].length / 2 + eb[knee_rotator].roll += pi/2 + + # parent ik leg to the knee rotator + eb[ik_chain.thigh].parent = eb[knee_rotator] # foot roll is an interesting one! # plot a vector from the toe bones head, bactwards to the length of the foot # then align it with the foot but reverse direction. ik.foot_roll_e = copy_bone_simple(arm, mt_chain.toe, get_base_name(base_names[mt_chain.foot]) + "_roll" + get_side_name(base_names[mt_chain.foot])) ik.foot_roll = ik.foot_roll_e.name + ik.foot_roll_e.connected = False ik.foot_roll_e.parent = ik_chain.foot_e - ik.foot_roll_e.translate(- (mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length)) - ik.foot_roll_e.align_orientation(mt_chain.foot_e) - ik.foot_roll_e.tail = ik.foot_roll_e.head - ik.foot_roll_e.vector # flip + ik.foot_roll_e.head -= mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length + ik.foot_roll_e.tail = ik.foot_roll_e.head - (mt_chain.foot_e.vector.normalize() * mt_chain.toe_e.length) ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotationPart() * Vector(0.0, 0.0, -1.0)) # MCH-foot @@ -173,23 +186,74 @@ def ik(obj, bone_definition, base_names, options): mt_chain.update() ik.update() ik_chain.update() + + # Set rotation modes and axis locks + #pb[knee_rotator].rotation_mode = 'YXZ' + #pb[knee_rotator].lock_rotation = False, True, False + pb[knee_rotator].lock_location = True, True, True + pb[ik.foot_roll].rotation_mode = 'XYZ' + pb[ik.foot_roll].lock_rotation = False, True, True + pb[ik_chain.toe].rotation_mode = 'XYZ' + pb[ik_chain.toe].lock_rotation = False, True, True + + # IK switch property + prop = rna_idprop_ui_prop_get(pb[ik_chain.foot], "ik", create=True) + pb[ik_chain.foot]["ik"] = 1.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + prop["min"] = 0.0 + prop["max"] = 1.0 + + ik_driver_path = pb[ik_chain.foot].path_to_id() + '["ik"]' # simple constraining of orig bones con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik_chain.thigh + 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 = ik_driver_path con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik_chain.shin + 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 = ik_driver_path con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik.foot_roll_02 + 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 = ik_driver_path con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik_chain.toe + 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 = ik_driver_path # others... con = ik.foot_roll_01_p.constraints.new('COPY_ROTATION') @@ -211,8 +275,7 @@ def ik(obj, bone_definition, base_names, options): con.target = obj con.subtarget = ik.foot_target - con.pole_target = obj - con.pole_subtarget = ik.knee_target + con.pole_target = None ik.update() ik_chain.update() @@ -226,12 +289,204 @@ def ik(obj, bone_definition, base_names, options): obj.data.bones[getattr(ik_chain, attr)].layer = layer for attr in ik.attr_names: obj.data.bones[getattr(ik, attr)].layer = layer + obj.data.bones[knee_rotator].layer = layer + + return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe - return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe +def fk(obj, bone_definition, base_names, options): + eb = obj.data.edit_bones + pb = obj.pose.bones + arm = obj.data + bpy.ops.object.mode_set(mode='EDIT') + + # setup the existing bones, use names from METARIG_NAMES + mt = bone_class_instance(obj, ["hips"]) + mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"]) + + mt.attr_initialize(METARIG_NAMES, bone_definition) + mt_chain.attr_initialize(METARIG_NAMES, bone_definition) + + fk_chain = mt_chain.copy(to_fmt="%s", base_names=base_names) + + # Create the socket + socket = copy_bone_simple(arm, mt_chain.thigh, "MCH-leg_socket").name + eb[socket].parent = eb[mt.hips] + eb[socket].length = eb[mt_chain.thigh].length / 4 + + # Create the hinge + hinge = copy_bone_simple(arm, mt.hips, "MCH-leg_hinge").name + eb[hinge].length = eb[mt.hips].length / 2 + + # Make leg child of hinge + eb[fk_chain.thigh].connected = False + eb[fk_chain.thigh].parent = eb[hinge] + + + bpy.ops.object.mode_set(mode='OBJECT') + + # Set rotation modes and axis locks + pb[fk_chain.shin].rotation_mode = 'XYZ' + pb[fk_chain.shin].lock_rotation = False, True, True + + # Constrain original bones to control bones + con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = fk_chain.thigh + + con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = fk_chain.shin + + con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = fk_chain.foot + + con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = fk_chain.toe + + # Socket constraint + con = pb[fk_chain.thigh].constraints.new('COPY_LOCATION') + con.target = obj + con.subtarget = socket + + # Hinge constraint + con = pb[hinge].constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = mt.hips + + prop = rna_idprop_ui_prop_get(pb[fk_chain.thigh], "hinge", create=True) + pb[fk_chain.thigh]["hinge"] = 0.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + prop["min"] = 0.0 + prop["max"] = 1.0 + + hinge_driver_path = pb[fk_chain.thigh].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.modifiers[0] + mod.poly_order = 1 + mod.coefficients[0] = 1.0 + mod.coefficients[1] = -1.0 + + return None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe + + + + +def deform(obj, definitions, base_names, options): + bpy.ops.object.mode_set(mode='EDIT') + + # Create upper leg bones: two bones, each half of the upper leg. + uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True) + uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True) + uleg1.connected = False + uleg2.connected = False + uleg2.parent = uleg1 + center = uleg1.center + uleg1.tail = center + uleg2.head = center + + # Create lower leg bones: two bones, each half of the lower leg. + lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True) + lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True) + lleg1.connected = False + lleg2.connected = False + lleg2.parent = lleg1 + center = lleg1.center + lleg1.tail = center + lleg2.head = center + + # Create a bone for the second lower leg deform bone to twist with + twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist") + twist.length /= 4 + twist.connected = False + twist.parent = obj.data.edit_bones[definitions[3]] + + # Create foot bone + foot = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True) + + # Create toe bone + toe = copy_bone_simple(obj.data, definitions[4], "DEF-%s" % base_names[definitions[4]], parent=True) + + # Store names before leaving edit mode + uleg1_name = uleg1.name + uleg2_name = uleg2.name + lleg1_name = lleg1.name + lleg2_name = lleg2.name + twist_name = twist.name + foot_name = foot.name + toe_name = toe.name + + # Leave edit mode + bpy.ops.object.mode_set(mode='OBJECT') + + # Get the pose bones + uleg1 = obj.pose.bones[uleg1_name] + uleg2 = obj.pose.bones[uleg2_name] + lleg1 = obj.pose.bones[lleg1_name] + lleg2 = obj.pose.bones[lleg2_name] + foot = obj.pose.bones[foot_name] + toe = obj.pose.bones[toe_name] + + # Upper leg constraints + con = uleg1.constraints.new('DAMPED_TRACK') + con.name = "trackto" + con.target = obj + con.subtarget = definitions[2] + + con = uleg2.constraints.new('COPY_ROTATION') + con.name = "copy_rot" + con.target = obj + con.subtarget = definitions[1] + + # Lower leg constraints + con = lleg1.constraints.new('COPY_ROTATION') + con.name = "copy_rot" + con.target = obj + con.subtarget = definitions[2] + + con = lleg2.constraints.new('COPY_ROTATION') + con.name = "copy_rot" + con.target = obj + con.subtarget = twist_name + + con = lleg2.constraints.new('DAMPED_TRACK') + con.name = "trackto" + con.target = obj + con.subtarget = definitions[3] + + # Foot constraint + con = foot.constraints.new('COPY_ROTATION') + con.name = "copy_rot" + con.target = obj + con.subtarget = definitions[3] + + # Toe constraint + con = toe.constraints.new('COPY_ROTATION') + con.name = "copy_rot" + con.target = obj + con.subtarget = definitions[4] + + bpy.ops.object.mode_set(mode='EDIT') + return (uleg1_name, uleg2_name, lleg1_name, lleg2_name, foot_name, toe_name, None) + + def main(obj, bone_definition, base_names, options): + bones_fk = fk(obj, bone_definition, base_names, options) bones_ik = ik(obj, bone_definition, base_names, options) + deform(obj, bone_definition, base_names, options) return bones_ik diff --git a/release/scripts/modules/rigify/mouth.py b/release/scripts/modules/rigify/mouth.py index b22df918675..e2ca1ab4d0c 100644 --- a/release/scripts/modules/rigify/mouth.py +++ b/release/scripts/modules/rigify/mouth.py @@ -19,15 +19,69 @@ # <pep8 compliant> import bpy -from math import acos +from rna_prop_ui import rna_idprop_ui_prop_get +from math import acos, pi from Mathutils import Vector -from rigify import get_layer_dict +from rigify import get_layer_dict, RigifyError from rigify_utils import bone_class_instance, copy_bone_simple #METARIG_NAMES = ("cpy",) RIG_TYPE = "mouth" +def mark_actions(): + for action in bpy.data.actions: + action.tag = True + +def get_unmarked_action(): + for action in bpy.data.actions: + if action.tag != True: + return action + return None + +def add_action(name=None): + mark_actions() + bpy.ops.action.new() + action = get_unmarked_action() + if name is not None: + action.name = name + return action + +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 + 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' + + return fcurve + + def metarig_template(): # generated by rigify.write_meta_rig bpy.ops.object.mode_set(mode='EDIT') @@ -49,7 +103,7 @@ def metarig_definition(obj, orig_bone_name): chain = [] try: - chain += [bone.parent.name, bone.parent.parent.name, bone.name] + chain += [bone.parent.parent.name, bone.parent.name, bone.name] except AttributeError: raise RigifyError("'%s' rig type requires a chain of two parents (bone: %s)" % (RIG_TYPE, base_names[0])) @@ -67,62 +121,70 @@ def deform(obj, definitions, base_names, options): eb = obj.data.edit_bones pb = obj.pose.bones + print("YAHOO") + + # 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]])) + + print("YAHOO2") + + meshes = options["mesh"].replace(" ", "").split(",") + # Upper lip MCH - lip1 = make_lip_stretch_bone(obj, "MCH-lip", definitions[2], definitions[3], 1.0) - lip2 = make_lip_stretch_bone(obj, "MCH-lip", definitions[3], definitions[4], 1.0) - lip22 = make_lip_stretch_bone(obj, "MCH-lip", definitions[4], definitions[5], 1.0) - lip33 = make_lip_stretch_bone(obj, "MCH-lip", definitions[4], definitions[3], 1.0) - lip3 = make_lip_stretch_bone(obj, "MCH-lip", definitions[5], definitions[4], 1.0) - lip4 = make_lip_stretch_bone(obj, "MCH-lip", definitions[6], definitions[5], 1.0) - - dlip22 = copy_bone_simple(obj.data, lip22, "MCH-lip", parent=True).name - dlip33 = copy_bone_simple(obj.data, lip33, "MCH-lip", parent=True).name - eb[dlip22].bbone_segments = 8 - eb[dlip33].bbone_segments = 8 - - eb[lip1].parent = eb[definitions[2]] - eb[lip2].parent = eb[definitions[3]] - eb[lip22].parent = eb[definitions[4]] - eb[lip33].parent = eb[definitions[4]] - eb[lip3].parent = eb[definitions[5]] - eb[lip4].parent = eb[definitions[6]] + lip1 = make_lip_stretch_bone(obj, "MCH-lip", definitions[3], definitions[2], 0.0) + lip2 = make_lip_stretch_bone(obj, "MCH-lip", definitions[4], definitions[3], 0.0) + lip22 = make_lip_stretch_bone(obj, "MCH-lip", definitions[5], definitions[4], 0.0) + lip33 = make_lip_stretch_bone(obj, "MCH-lip", definitions[3], definitions[4], 0.0) + lip3 = make_lip_stretch_bone(obj, "MCH-lip", definitions[4], definitions[5], 0.0) + lip4 = make_lip_stretch_bone(obj, "MCH-lip", definitions[5], definitions[6], 0.0) + + eb[lip1].parent = eb[definitions[3]] + eb[lip2].parent = eb[definitions[4]] + eb[lip22].parent = eb[definitions[5]] + eb[lip33].parent = eb[definitions[3]] + eb[lip3].parent = eb[definitions[4]] + eb[lip4].parent = eb[definitions[5]] + + eb[lip22].bbone_segments = 8 + eb[lip33].bbone_segments = 8 # Lower lip MCH - lip5 = make_lip_stretch_bone(obj, "MCH-lip", definitions[6], definitions[7], 1.0) - lip6 = make_lip_stretch_bone(obj, "MCH-lip", definitions[7], definitions[8], 1.0) - lip66 = make_lip_stretch_bone(obj, "MCH-lip", definitions[8], definitions[9], 1.0) - lip77 = make_lip_stretch_bone(obj, "MCH-lip", definitions[8], definitions[7], 1.0) - lip7 = make_lip_stretch_bone(obj, "MCH-lip", definitions[9], definitions[8], 1.0) - lip8 = make_lip_stretch_bone(obj, "MCH-lip", definitions[2], definitions[9], 1.0) - - dlip66 = copy_bone_simple(obj.data, lip66, "MCH-lip", parent=True).name - dlip77 = copy_bone_simple(obj.data, lip77, "MCH-lip", parent=True).name - eb[dlip66].bbone_segments = 8 - eb[dlip77].bbone_segments = 8 - - eb[lip5].parent = eb[definitions[6]] - eb[lip6].parent = eb[definitions[7]] - eb[lip66].parent = eb[definitions[8]] - eb[lip77].parent = eb[definitions[8]] - eb[lip7].parent = eb[definitions[9]] - eb[lip8].parent = eb[definitions[2]] + lip5 = make_lip_stretch_bone(obj, "MCH-lip", definitions[7], definitions[6], 0.0) + lip6 = make_lip_stretch_bone(obj, "MCH-lip", definitions[8], definitions[7], 0.0) + lip66 = make_lip_stretch_bone(obj, "MCH-lip", definitions[9], definitions[8], 0.0) + lip77 = make_lip_stretch_bone(obj, "MCH-lip", definitions[7], definitions[8], 0.0) + lip7 = make_lip_stretch_bone(obj, "MCH-lip", definitions[8], definitions[9], 0.0) + lip8 = make_lip_stretch_bone(obj, "MCH-lip", definitions[9], definitions[2], 0.0) + + eb[lip5].parent = eb[definitions[7]] + eb[lip6].parent = eb[definitions[8]] + eb[lip66].parent = eb[definitions[9]] + eb[lip77].parent = eb[definitions[7]] + eb[lip7].parent = eb[definitions[8]] + eb[lip8].parent = eb[definitions[9]] + + eb[lip66].bbone_segments = 8 + eb[lip77].bbone_segments = 8 # Upper lip DEF - dlip1 = copy_bone_simple(obj.data, lip1, "DEF-lip", parent=True).name - dlip2 = copy_bone_simple(obj.data, lip2, "DEF-lip", parent=True).name - dlip3 = copy_bone_simple(obj.data, lip3, "DEF-lip", parent=True).name - dlip4 = copy_bone_simple(obj.data, lip4, "DEF-lip", parent=True).name + dlip1 = copy_bone_simple(obj.data, lip1, "DEF-" + base_names[definitions[4]] + ".01.R", parent=True).name + dlip2 = copy_bone_simple(obj.data, lip2, "DEF-" + base_names[definitions[4]] + ".02.R", parent=True).name + dlip3 = copy_bone_simple(obj.data, lip3, "DEF-" + base_names[definitions[4]] + ".02.L", parent=True).name + dlip4 = copy_bone_simple(obj.data, lip4, "DEF-" + base_names[definitions[4]] + ".01.L", parent=True).name - eb[dlip2].parent = eb[dlip1] - eb[dlip22].parent = eb[dlip2] + eb[dlip1].parent = eb[dlip2] + eb[dlip2].parent = eb[lip22] - eb[dlip3].parent = eb[dlip4] - eb[dlip33].parent = eb[dlip3] + eb[dlip4].parent = eb[dlip3] + eb[dlip3].parent = eb[lip33] - eb[dlip2].connected = True - eb[dlip22].connected = True - eb[dlip3].connected = True - eb[dlip33].connected = True + eb[dlip1].connected = True + eb[dlip2].connected = True + eb[dlip4].connected = True + eb[dlip3].connected = True eb[dlip1].bbone_segments = 8 eb[dlip2].bbone_segments = 8 @@ -130,43 +192,37 @@ def deform(obj, definitions, base_names, options): eb[dlip4].bbone_segments = 8 # Lower lip DEF - dlip5 = copy_bone_simple(obj.data, lip5, "DEF-lip", parent=True).name - dlip6 = copy_bone_simple(obj.data, lip6, "DEF-lip", parent=True).name - dlip7 = copy_bone_simple(obj.data, lip7, "DEF-lip", parent=True).name - dlip8 = copy_bone_simple(obj.data, lip8, "DEF-lip", parent=True).name + dlip8 = copy_bone_simple(obj.data, lip8, "DEF-" + base_names[definitions[8]] + ".01.R", parent=True).name + dlip7 = copy_bone_simple(obj.data, lip7, "DEF-" + base_names[definitions[8]] + ".02.R", parent=True).name + dlip6 = copy_bone_simple(obj.data, lip6, "DEF-" + base_names[definitions[8]] + ".02.L", parent=True).name + dlip5 = copy_bone_simple(obj.data, lip5, "DEF-" + base_names[definitions[8]] + ".01.L", parent=True).name - eb[dlip6].parent = eb[dlip5] - eb[dlip66].parent = eb[dlip6] - eb[dlip7].parent = eb[dlip8] - eb[dlip77].parent = eb[dlip7] + eb[dlip5].parent = eb[dlip6] + eb[dlip6].parent = eb[lip66] + eb[dlip8].parent = eb[dlip7] + eb[dlip7].parent = eb[lip77] + + eb[dlip5].connected = True eb[dlip6].connected = True - eb[dlip66].connected = True + eb[dlip8].connected = True eb[dlip7].connected = True - eb[dlip77].connected = True eb[dlip5].bbone_segments = 8 eb[dlip6].bbone_segments = 8 eb[dlip7].bbone_segments = 8 eb[dlip8].bbone_segments = 8 - + print("OBJECT MODE1") bpy.ops.object.mode_set(mode='OBJECT') + print("OBJECT MODE2") # Constraints con = pb[dlip1].constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = lip1 - con = pb[dlip22].constraints.new('COPY_TRANSFORMS') - con.target = obj - con.subtarget = lip22 - - con = pb[dlip33].constraints.new('COPY_TRANSFORMS') - con.target = obj - con.subtarget = lip33 - con = pb[dlip2].constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = lip2 @@ -187,14 +243,6 @@ def deform(obj, definitions, base_names, options): con.target = obj con.subtarget = lip6 - con = pb[dlip66].constraints.new('COPY_TRANSFORMS') - con.target = obj - con.subtarget = lip66 - - con = pb[dlip77].constraints.new('COPY_TRANSFORMS') - con.target = obj - con.subtarget = lip77 - con = pb[dlip7].constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = lip7 @@ -203,6 +251,90 @@ def deform(obj, definitions, base_names, options): con.target = obj con.subtarget = lip8 + # Corrective shape keys for the corners of the mouth. + bpy.ops.object.mode_set(mode='EDIT') + + # Calculate the rotation difference between the bones + rotdiff_r = acos(eb[lip1].matrix.toQuat() * eb[lip8].matrix.toQuat()) * 2 + rotdiff_l = acos(eb[lip4].matrix.toQuat() * eb[lip5].matrix.toQuat()) * 2 + + print (rotdiff_l) + + bpy.ops.object.mode_set(mode='OBJECT') + + + + # Left side + for mesh_name in meshes: + mesh_obj = bpy.data.objects[mesh_name] + shape_key_name = "COR-" + base_names[definitions[4]] + ".L.spread" + + # Add/get the shape key + shape_key = addget_shape_key(mesh_obj, name=shape_key_name) + + # Add/get the shape key driver + fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name) + driver = fcurve.driver + + # Get the variable, or create it if it doesn't already exist + var_name = base_names[definitions[6]] + 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 = "ROTATION_DIFF" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].bone_target = lip4 + var.targets[1].id_type = 'OBJECT' + var.targets[1].id = obj + var.targets[1].bone_target = lip5 + + # Set fcurve offset + mod = fcurve.modifiers[0] + if rotdiff_l != pi: + mod.coefficients[0] = -rotdiff_l / (pi-rotdiff_l) + mod.coefficients[1] = 1 / (pi-rotdiff_l) + + # Right side + for mesh_name in meshes: + mesh_obj = bpy.data.objects[mesh_name] + shape_key_name = "COR-" + base_names[definitions[4]] + ".R.spread" + + # Add/get the shape key + shape_key = addget_shape_key(mesh_obj, name=shape_key_name) + + # Add/get the shape key driver + fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name) + driver = fcurve.driver + + # Get the variable, or create it if it doesn't already exist + var_name = base_names[definitions[2]] + 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 = "ROTATION_DIFF" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].bone_target = lip1 + var.targets[1].id_type = 'OBJECT' + var.targets[1].id = obj + var.targets[1].bone_target = lip8 + + # Set fcurve offset + mod = fcurve.modifiers[0] + if rotdiff_r != pi: + mod.coefficients[0] = -rotdiff_r / (pi-rotdiff_r) + mod.coefficients[1] = 1 / (pi-rotdiff_r) + + return (None,) @@ -217,6 +349,7 @@ def control(obj, definitions, base_names, options): head_e = eb[definitions[0]] jaw_e = eb[definitions[1]] + jaw = definitions[1] # Head lips hlip1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]+".head").name @@ -285,14 +418,14 @@ def control(obj, definitions, base_names, options): eb[lip7].roll = 0 eb[lip8].roll = 0 - eb[lip1].parent = eb[jlip1] - eb[lip2].parent = eb[jlip2] - eb[lip3].parent = eb[jlip3] - eb[lip4].parent = eb[jlip4] - eb[lip5].parent = eb[jlip5] - eb[lip6].parent = eb[jlip6] - eb[lip7].parent = eb[jlip7] - eb[lip8].parent = eb[jlip8] + eb[lip1].parent = eb[hlip1] + eb[lip2].parent = eb[hlip2] + eb[lip3].parent = eb[hlip3] + eb[lip4].parent = eb[hlip4] + eb[lip5].parent = eb[hlip5] + eb[lip6].parent = eb[hlip6] + eb[lip7].parent = eb[hlip7] + eb[lip8].parent = eb[hlip8] # Link lips llip1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]+".link").name @@ -313,53 +446,84 @@ def control(obj, definitions, base_names, options): eb[llip7].parent = eb[lip7] eb[llip8].parent = eb[lip8] + # Jaw open tracker + jopent = copy_bone_simple(obj.data, jaw_e.name, "MCH-"+base_names[jaw_e.name]+".track", parent=True).name + eb[jopent].connected = False + eb[jopent].tail = jaw_e.tail + Vector(0,0,jaw_e.length) + eb[jopent].head = jaw_e.tail bpy.ops.object.mode_set(mode='OBJECT') + # Add eye close action if it doesn't already exist + action_name = "mouth_open" + if action_name in bpy.data.actions: + open_action = bpy.data.actions[action_name] + else: + open_action = add_action(name=action_name) + + # Add close property (useful when making the animation in the action) + prop_name = "open_action" + prop = rna_idprop_ui_prop_get(pb[lip1], prop_name, create=True) + pb[lip1][prop_name] = 1.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + prop["min"] = 0.0 + prop["max"] = 1.0 + + open_driver_path = pb[lip1].path_to_id() + '["open_action"]' + # Constraints - # Jaw lips to head lips - influence = [0.0, 0.1, 0.5] + # Jaw open tracker stretches to jaw tip + con = pb[jopent].constraints.new('STRETCH_TO') + con.target = obj + con.subtarget = jaw + con.head_tail = 1.0 + con.original_length = bb[jopent].length + con.volume = 'NO_VOLUME' + + # Head lips to jaw lips + influence = [0.0, 0.1, 0.5, 0.25, 0.0] - con = pb[jlip1].constraints.new('COPY_TRANSFORMS') + con = pb[hlip1].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip1 + con.subtarget = jlip1 con.influence = influence[2] - con = pb[jlip2].constraints.new('COPY_TRANSFORMS') + con = pb[hlip2].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip2 + con.subtarget = jlip2 con.influence = influence[1] - con = pb[jlip3].constraints.new('COPY_TRANSFORMS') + con = pb[hlip3].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip3 + con.subtarget = jlip3 con.influence = influence[0] - con = pb[jlip4].constraints.new('COPY_TRANSFORMS') + con = pb[hlip4].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip4 + con.subtarget = jlip4 con.influence = influence[1] - con = pb[jlip5].constraints.new('COPY_TRANSFORMS') + con = pb[hlip5].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip5 + con.subtarget = jlip5 con.influence = influence[2] - con = pb[jlip6].constraints.new('COPY_TRANSFORMS') + con = pb[hlip6].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip6 - con.influence = 1.0 - influence[1] + con.subtarget = jlip6 + con.influence = 1.0 - influence[3] - con = pb[jlip7].constraints.new('COPY_TRANSFORMS') + con = pb[hlip7].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip7 - con.influence = 1.0 - influence[0] + con.subtarget = jlip7 + con.influence = 1.0 - influence[4] - con = pb[jlip8].constraints.new('COPY_TRANSFORMS') + con = pb[hlip8].constraints.new('COPY_TRANSFORMS') con.target = obj - con.subtarget = hlip8 - con.influence = 1.0 - influence[1] + con.subtarget = jlip8 + con.influence = 1.0 - influence[3] # ORG bones to link lips con = pb[definitions[2]].constraints.new('COPY_TRANSFORMS') @@ -394,6 +558,151 @@ def control(obj, definitions, base_names, options): con.target = obj con.subtarget = llip8 + # Action constraints for open mouth + con = pb[lip1].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + + con = pb[lip2].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + + con = pb[lip3].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + + con = pb[lip4].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + + con = pb[lip5].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + + con = pb[lip6].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + + con = pb[lip7].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + + con = pb[lip8].constraints.new('ACTION') + con.target = obj + con.subtarget = jopent + con.action = open_action + con.transform_channel = 'SCALE_Y' + con.start_frame = 0 + con.end_frame = 60 + con.minimum = 0.0 + con.maximum = 1.0 + con.target_space = 'LOCAL' + fcurve = con.driver_add("influence", 0) + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = open_driver_path + # Set layers layer = list(bb[definitions[2]].layer) @@ -414,9 +723,12 @@ def control(obj, definitions, base_names, options): def main(obj, bone_definition, base_names, options): # Create control rig + print("CONTROL") control(obj, bone_definition, base_names, options) + print("DEFORM") # Create deform rig deform(obj, bone_definition, base_names, options) + print("DONE") return (None,) diff --git a/release/scripts/modules/rigify/neck_flex.py b/release/scripts/modules/rigify/neck_flex.py index f9b7a9ae99d..d26510f49b2 100644 --- a/release/scripts/modules/rigify/neck_flex.py +++ b/release/scripts/modules/rigify/neck_flex.py @@ -213,6 +213,9 @@ def main(obj, bone_definition, base_names, options): ex_chain.update() ex.update() + # Axis locks + ex.head_ctrl_p.lock_location = True, True, True + # Simple one off constraints, no drivers con = ex.head_ctrl_p.constraints.new('COPY_LOCATION') con.target = obj diff --git a/release/scripts/modules/rigify/palm_curl.py b/release/scripts/modules/rigify/palm_curl.py index 9e60bc9dc22..b231919823b 100644 --- a/release/scripts/modules/rigify/palm_curl.py +++ b/release/scripts/modules/rigify/palm_curl.py @@ -152,6 +152,7 @@ def main(obj, bone_definition, base_names, options): control_pbone.rotation_mode = 'YZX' control_pbone.lock_rotation = False, True, True + control_pbone.lock_location = True, True, True driver_fcurves = pinky_pbone.driver_add("rotation_euler") @@ -163,6 +164,8 @@ def main(obj, bone_definition, base_names, options): prop = rna_idprop_ui_prop_get(control_pbone, "spread", create=True) prop["soft_min"] = -1.0 prop["soft_max"] = 1.0 + prop["min"] = -1.0 + prop["max"] = 1.0 # ***** diff --git a/release/scripts/modules/rigify/shape_key_distance.py b/release/scripts/modules/rigify/shape_key_distance.py new file mode 100644 index 00000000000..7701e725ea9 --- /dev/null +++ b/release/scripts/modules/rigify/shape_key_distance.py @@ -0,0 +1,176 @@ +# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get +from math import acos +from Mathutils import Vector +from rigify import get_layer_dict +from rigify_utils import bone_class_instance, copy_bone_simple + +#METARIG_NAMES = ("cpy",) +RIG_TYPE = "shape_key_distance" + + +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 + 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' + + return fcurve + + + + +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' + + +def metarig_definition(obj, orig_bone_name): + bone = obj.data.bones[orig_bone_name] + return [bone.name] + + +def deform(obj, definitions, base_names, options): + bpy.ops.object.mode_set(mode='EDIT') + eb = obj.data.edit_bones + + bone_from = definitions[0] + + + # Options + req_options = ["to", "mesh", "shape_key"] + 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]])) + + bone_to = "ORG-" + options["to"] + meshes = options["mesh"].replace(" ", "").split(",") + shape_key_name = options["shape_key"] + + if "dmul" in options: + shape_blend_fac = options["dmul"] + else: + shape_blend_fac = 1.0 + + + # Calculate the distance between the bones + distance = (eb[bone_from].head - eb[bone_to].head).length + + bpy.ops.object.mode_set(mode='OBJECT') + + # For every listed mesh object + for mesh_name in meshes: + mesh_obj = bpy.data.objects[mesh_name] + + # Add/get the shape key + shape_key = addget_shape_key(mesh_obj, name=shape_key_name) + + # Add/get the shape key driver + fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name) + driver = fcurve.driver + + # Get the variable, or create it if it doesn't already exist + var_name = base_names[bone_from] + 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 = "LOC_DIFF" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].bone_target = bone_from + var.targets[1].id_type = 'OBJECT' + var.targets[1].id = obj + var.targets[1].bone_target = bone_to + + # Set fcurve offset, so zero is at the rest distance + + mod = fcurve.modifiers[0] + if distance > 0.00001: + mod.coefficients[0] = -shape_blend_fac + mod.coefficients[1] = shape_blend_fac / distance + + return (None,) + + + + +def control(obj, definitions, base_names, options): + """ options: + mesh: name of mesh object with the shape key + shape_key: name of shape key + to: name of bone to measure distance from + """ + pass + + + + +def main(obj, bone_definition, base_names, options): + # Create control rig + #control(obj, bone_definition, base_names, options) + # Create deform rig + deform(obj, bone_definition, base_names, options) + + return (None,) + diff --git a/release/scripts/modules/rigify/shape_key_rotdiff.py b/release/scripts/modules/rigify/shape_key_rotdiff.py new file mode 100644 index 00000000000..98ab1bd16b7 --- /dev/null +++ b/release/scripts/modules/rigify/shape_key_rotdiff.py @@ -0,0 +1,176 @@ +# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get +from math import acos +from Mathutils import Vector +from rigify import get_layer_dict +from rigify_utils import bone_class_instance, copy_bone_simple + +#METARIG_NAMES = ("cpy",) +RIG_TYPE = "shape_key_rotdiff" + + +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 + 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' + + return fcurve + + + + +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' + + +def metarig_definition(obj, orig_bone_name): + bone = obj.data.bones[orig_bone_name] + return [bone.name] + + +def deform(obj, definitions, base_names, options): + bpy.ops.object.mode_set(mode='EDIT') + eb = obj.data.edit_bones + + bone_from = definitions[0] + + + # Options + req_options = ["to", "mesh", "shape_key"] + 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]])) + + bone_to = "ORG-" + options["to"] + meshes = options["mesh"].replace(" ", "").split(",") + shape_key_name = options["shape_key"] + + if "dmul" in options: + shape_blend_fac = options["dmul"] + else: + shape_blend_fac = 1.0 + + + # Calculate the rotation difference between the bones + rotdiff = (eb[bone_from].matrix.toQuat() * eb[bone_to].matrix.toQuat()) * 2 + + bpy.ops.object.mode_set(mode='OBJECT') + + # For every listed mesh object + for mesh_name in meshes: + mesh_obj = bpy.data.objects[mesh_name] + + # Add/get the shape key + shape_key = addget_shape_key(mesh_obj, name=shape_key_name) + + # Add/get the shape key driver + fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name) + driver = fcurve.driver + + # Get the variable, or create it if it doesn't already exist + var_name = base_names[bone_from] + 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 = "ROTATION_DIFF" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].bone_target = bone_from + var.targets[1].id_type = 'OBJECT' + var.targets[1].id = obj + var.targets[1].bone_target = bone_to + + # Set fcurve offset, so zero is at the rest distance + + mod = fcurve.modifiers[0] + if rotdiff > 0.00001: + mod.coefficients[0] = -shape_blend_fac + mod.coefficients[1] = shape_blend_fac / rotdiff + + return (None,) + + + + +def control(obj, definitions, base_names, options): + """ options: + mesh: name of mesh object with the shape key + shape_key: name of shape key + to: name of bone to measure distance from + """ + pass + + + + +def main(obj, bone_definition, base_names, options): + # Create control rig + #control(obj, bone_definition, base_names, options) + # Create deform rig + deform(obj, bone_definition, base_names, options) + + return (None,) + diff --git a/release/scripts/modules/rigify/spine_pivot_flex.py b/release/scripts/modules/rigify/spine_pivot_flex.py index 6d01e0263eb..20935b0bc6c 100644 --- a/release/scripts/modules/rigify/spine_pivot_flex.py +++ b/release/scripts/modules/rigify/spine_pivot_flex.py @@ -304,6 +304,9 @@ def main(obj, bone_definition, base_names, options): mt_chain.update() ex_chain.update() rv_chain.update() + + # Axis locks + ex.ribcage_copy_p.lock_location = True, True, True # df.pelvis_p / DEF-wgt_pelvis con = df.pelvis_p.constraints.new('COPY_LOCATION') @@ -437,7 +440,10 @@ def main(obj, bone_definition, base_names, options): # Add bend prop prop_name = "bend_%.2d" % i prop = rna_idprop_ui_prop_get(ex.ribcage_copy_p, prop_name, create=True) - ex.ribcage_copy_p[prop_name] = 1.0 + if ("bend_%.2d" % i) in options: + ex.ribcage_copy_p[prop_name] = options["bend_%.2d" % i] + else: + ex.ribcage_copy_p[prop_name] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 diff --git a/release/scripts/modules/rigify_utils.py b/release/scripts/modules/rigify_utils.py index 2a1c92534a0..e45f0dbc63a 100644 --- a/release/scripts/modules/rigify_utils.py +++ b/release/scripts/modules/rigify_utils.py @@ -145,28 +145,12 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta var.targets[0].id = obj var.targets[0].data_path = driver_path - def blend_location(new_pbone, from_bone_name, to_bone_name): - con = new_pbone.constraints.new('COPY_LOCATION') + def blend_transforms(new_pbone, from_bone_name, to_bone_name): + con = new_pbone.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = from_bone_name - con = new_pbone.constraints.new('COPY_LOCATION') - con.target = obj - con.subtarget = to_bone_name - - fcurve = con.driver_add("influence", 0) - driver = fcurve.driver - driver.type = 'AVERAGE' - fcurve.modifiers.remove(0) # grr dont need a modifier - - blend_target(driver) - - def blend_rotation(new_pbone, from_bone_name, to_bone_name): - con = new_pbone.constraints.new('COPY_ROTATION') - con.target = obj - con.subtarget = from_bone_name - - con = new_pbone.constraints.new('COPY_ROTATION') + con = new_pbone.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = to_bone_name @@ -187,12 +171,8 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta new_pbone = obj.pose.bones[new_bone_name] - # if the bone is connected or its location is totally locked then dont add location blending. - if not (new_pbone.bone.connected or (False not in new_pbone.lock_location)): - blend_location(new_pbone, from_bone_name, to_bone_name) + blend_transforms(new_pbone, from_bone_name, to_bone_name) - if not (False not in new_pbone.lock_rotation): # TODO. 4D chech? - blend_rotation(new_pbone, from_bone_name, to_bone_name) def add_pole_target_bone(obj, base_bone_name, name, mode='CROSS'): |