From f85cb5c36fb79629791d03a146c17370f9fd9f5f Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Tue, 8 Mar 2011 07:51:40 +0000 Subject: Beginnings of ik/fk snapping functions in Rigify. So far just IK->FK for biped.arm. --- rigify/rig_ui_template.py | 175 ++++++++++++++++++++++++++++++++++++-- rigify/rigs/biped/arm/__init__.py | 13 ++- rigify/rigs/biped/arm/ik.py | 2 +- 3 files changed, 180 insertions(+), 10 deletions(-) (limited to 'rigify') diff --git a/rigify/rig_ui_template.py b/rigify/rig_ui_template.py index d9469ad4..32b0d61c 100644 --- a/rigify/rig_ui_template.py +++ b/rigify/rig_ui_template.py @@ -16,12 +16,175 @@ # #======================= END GPL LICENSE BLOCK ======================== -UI_SLIDERS = """ +UI_SLIDERS = ''' import bpy rig_id = "%s" +def get_pose_matrix_in_other_space(pose_bone, pbs): + """ Returns the transform matrix of pose_bone relative to pbs's transform space. + In other words, you could take the matrix returned from this, slap + it into pbs, and it would have the same world transform as pb. + This is with constraints applied. + """ + mat = pose_bone.matrix.copy() + rest_inv = pbs.bone.matrix_local.inverted() + + if pbs.parent: + par_inv = pbs.parent.matrix.inverted() + par_rest = pbs.parent.bone.matrix_local.copy() + + smat = rest_inv * (par_rest * (par_inv * mat)) + else: + smat = rest_inv * mat + + return smat + + +def get_local_matrix_with_constraints(pose_bone): + """ Returns the local matrix of the given pose bone, with constraints + applied. + """ + return get_pose_matrix_in_other_space(pose_bone, pose_bone) + + +def set_pose_rotation(pb, mat): + """ Sets the pose bone's rotation to the same rotation as the given matrix. + Matrix should be given in local space. + """ + q = mat.to_quaternion() + + if pb.rotation_mode == 'QUATERNION': + pb.rotation_quaternion = q + elif pb.rotation_mode == 'AXIS_ANGLE': + pb.rotation_axis_angle[0] = q.angle + pb.rotation_axis_angle[1] = q.axis[0] + pb.rotation_axis_angle[2] = q.axis[1] + pb.rotation_axis_angle[3] = q.axis[2] + else: + pb.rotation_euler = q.to_euler(pb.rotation_mode) + + +def set_pose_scale(pb, mat): + """ Sets the pose bone's scale to the same scale as the given matrix. + Matrix should be given in local space. + """ + pb.scale = mat.to_scale() + + +def set_pose_translation(pb, mat): + """ Sets the pose bone's translation to the same translation as the given matrix. + Matrix should be given in local space. + """ + pb.location = mat.to_translation() + + +def fk2ik(obj, fk, ik): + """ Matches the fk bones in an arm rig to the ik bones. + """ + pb = obj.pose.bones + + uarm = pb[fk[0]] + farm = pb[fk[1]] + hand = pb[fk[2]] + + uarmi = pb[ik[0]] + farmi = pb[ik[1]] + handi = pb[ik[2]] + + uarmmat = get_pose_matrix_in_other_space(uarmi, uarm) + set_pose_rotation(uarm, uarmmat) + set_pose_scale(uarm, uarmmat) + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='POSE') + + farmmat = get_pose_matrix_in_other_space(farmi, farm) + set_pose_rotation(farm, farmmat) + set_pose_scale(farm, farmmat) + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='POSE') + + handmat = get_pose_matrix_in_other_space(handi, hand) + set_pose_rotation(hand, handmat) + set_pose_scale(hand, handmat) + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='POSE') + + +def ik2fk(obj, fk, ik): + """ Matches the ik bones in an arm rig to the fk bones. + """ + pb = obj.pose.bones + + uarm = pb[fk[0]] + farm = pb[fk[1]] + hand = pb[fk[2]] + + uarmi = pb[ik[0]] + farmi = pb[ik[1]] + handi = pb[ik[2]] + pole = pb[ik[3]] + + handmat = get_pose_matrix_in_other_space(hand, handi) + set_pose_translation(handi, handmat) + set_pose_rotation(handi, handmat) + set_pose_scale(handi, handmat) + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='POSE') + + +class Rigify_Arm_FK2IK(bpy.types.Operator): + """ Snaps an FK arm to an IK arm. + """ + bl_idname = "pose.rigify_arm_fk2ik" + bl_label = "Rigify Snap FK arm to IK" + + uarm_fk = bpy.props.StringProperty(name="Upper Arm FK Name") + farm_fk = bpy.props.StringProperty(name="Forerm FK Name") + hand_fk = bpy.props.StringProperty(name="Hand FK Name") + + uarm_ik = bpy.props.StringProperty(name="Upper Arm IK Name") + farm_ik = bpy.props.StringProperty(name="Forearm IK Name") + hand_ik = bpy.props.StringProperty(name="Hand IK Name") + + @classmethod + def poll(cls, context): + return (context.active_object != None and context.mode == 'POSE') + + def execute(self, context): + fk2ik(context.active_object, fk=[self.uarm_fk, self.farm_fk, self.hand_fk], ik=[self.uarm_ik, self.farm_ik, self.hand_ik]) + return {'FINISHED'} + + +class Rigify_Arm_IK2FK(bpy.types.Operator): + """ Snaps an IK arm to an FK arm. + """ + bl_idname = "pose.rigify_arm_ik2fk" + bl_label = "Snap IK arm to FK" + + uarm_fk = bpy.props.StringProperty(name="Upper Arm FK Name") + farm_fk = bpy.props.StringProperty(name="Forerm FK Name") + hand_fk = bpy.props.StringProperty(name="Hand FK Name") + + uarm_ik = bpy.props.StringProperty(name="Upper Arm IK Name") + farm_ik = bpy.props.StringProperty(name="Forearm IK Name") + hand_ik = bpy.props.StringProperty(name="Hand IK Name") + pole = bpy.props.StringProperty(name="Pole IK Name") + + @classmethod + def poll(cls, context): + return (context.active_object != None and context.mode == 'POSE') + + def execute(self, context): + ik2fk(context.active_object, fk=[self.uarm_fk, self.farm_fk, self.hand_fk], ik=[self.uarm_ik, self.farm_ik, self.hand_ik, self.pole]) + return {'FINISHED'} + + +bpy.utils.register_class(Rigify_Arm_FK2IK) +bpy.utils.register_class(Rigify_Arm_IK2FK) + + class RigUI(bpy.types.Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -57,14 +220,14 @@ class RigUI(bpy.types.Panel): return False -""" +''' def layers_ui(layers): """ Turn a list of booleans into a layer UI. """ - code = """ + code = ''' class RigLayers(bpy.types.Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -81,7 +244,7 @@ class RigLayers(bpy.types.Panel): def draw(self, context): layout = self.layout col = layout.column() -""" +''' i = 0 for layer in layers: if layer: @@ -95,12 +258,12 @@ class RigLayers(bpy.types.Panel): return code -UI_REGISTER = """ +UI_REGISTER = ''' def register(): bpy.utils.register_class(RigUI) bpy.utils.register_class(RigLayers) register() -""" +''' diff --git a/rigify/rigs/biped/arm/__init__.py b/rigify/rigs/biped/arm/__init__.py index 0fd2c43f..7d4214fd 100644 --- a/rigify/rigs/biped/arm/__init__.py +++ b/rigify/rigs/biped/arm/__init__.py @@ -27,9 +27,16 @@ imp.reload(deform) script = """ fk_arm = ["%s", "%s", "%s"] -ik_arm = ["%s", "%s"] +ik_arm = ["%s", "%s", "%s", "%s"] if is_selected(fk_arm+ik_arm): - layout.prop(pose_bones[ik_arm[0]], '["ikfk_switch"]', text="FK / IK (" + ik_arm[0] + ")", slider=True) + layout.prop(pose_bones[ik_arm[2]], '["ikfk_switch"]', text="FK / IK (" + ik_arm[2] + ")", slider=True) + p = layout.operator("pose.rigify_arm_fk2ik", text="Snap FK->IK (" + fk_arm[0] + ")") + p.uarm_fk = fk_arm[0] + p.farm_fk = fk_arm[1] + p.hand_fk = fk_arm[2] + p.uarm_ik = ik_arm[0] + p.farm_ik = ik_arm[1] + p.hand_ik = ik_arm[2] if is_selected(fk_arm): layout.prop(pose_bones[fk_arm[0]], '["isolate"]', text="Isolate Rotation (" + fk_arm[0] + ")", slider=True) """ @@ -64,7 +71,7 @@ class Rig: self.deform_rig.generate() fk_controls = self.fk_rig.generate() ik_controls = self.ik_rig.generate() - return [script % (fk_controls[0], fk_controls[1], fk_controls[2], ik_controls[0], ik_controls[1])] + return [script % (fk_controls[0], fk_controls[1], fk_controls[2], ik_controls[0], ik_controls[1], ik_controls[2], ik_controls[3])] @classmethod def add_parameters(self, group): diff --git a/rigify/rigs/biped/arm/ik.py b/rigify/rigs/biped/arm/ik.py index 403d1d0d..b16221d8 100644 --- a/rigify/rigs/biped/arm/ik.py +++ b/rigify/rigs/biped/arm/ik.py @@ -303,5 +303,5 @@ class Rig: mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 - return [hand, pole] + return [uarm, farm, hand, pole] -- cgit v1.2.3