Hello all. Recently I’ve decided to upgrade my sweet rig to have IK-FK snap function. After some googling i’ve found script that does job way I like it. I am not sure how excatly this script working cause scripting is not my strong side to say least. But it does what I need. It snapping IK and Pole Target bones to FK and vice versa via UI buttons. Also it has influence slider for IK constraint. All is good. But. This example script made only for single limb and I need at least two limbs - right and left. So I edited script to add needed classes and buttons for right limb. Way I’ve done it isn’t elegant or optimized but it works except one thing. Influence of constraint is working only for one IK chain, and I don’t know how to make this work for both. I know it’s stupid question but please bear with me.
This script is pretty huge (wasn’t expected snap feature is so complicated to script )
import bpy
import mathutils
########################### Left Hand #####################
num_bones = 2
armature_name = 'Armature'
ik_bone_name_L = 'forearm.L'
upper_arm_name_L = 'upper_arm.L'
ik_target_name_L = 'IK.L'
ik_pole_name_L = 'arm_pole.L'
def get_influece_data_path():
ik_bone = bpy.data.objects[armature_name].pose.bones[ik_bone_name_L]
return [ik_bone.constraints["IK"],'influence']
def get_ik_influence(data_path):
return exec("data_path[0].%s" % data_path[1])
def set_ik_influence(data_path, val):
exec("data_path[0].%s = %f" % (data_path[1], val))
def set_ik(data_path):
set_ik_influence(data_path, 1.0)
def set_fk(data_path):
set_ik_influence(data_path, 0.0)
def set_translation(matrix, loc):
trs = matrix.decompose()
rot = trs[1].to_matrix().to_4x4()
scale = mathutils.Matrix.Scale(1, 4, trs[2])
return mathutils.Matrix.Translation(loc) * (rot * scale)
######################### Right Hand #########################
num_bones = 2
armature_name = 'Armature'
ik_bone_name_R = 'forearm.R'
upper_arm_name_R = 'upper_arm.R'
ik_target_name_R = 'IK.R'
ik_pole_name_R = 'arm_pole.R'
def get_influece_data_path():
ik_bone = bpy.data.objects[armature_name].pose.bones[ik_bone_name_R]
return [ik_bone.constraints["IK"],'influence']
def get_ik_influence(data_path):
return exec("data_path[0].%s" % data_path[1])
def set_ik_influence(data_path, val):
exec("data_path[0].%s = %f" % (data_path[1], val))
def set_ik(data_path):
set_ik_influence(data_path, 1.0)
def set_fk(data_path):
set_ik_influence(data_path, 0.0)
def set_translation(matrix, loc):
trs = matrix.decompose()
rot = trs[1].to_matrix().to_4x4()
scale = mathutils.Matrix.Scale(1, 4, trs[2])
return mathutils.Matrix.Translation(loc) * (rot * scale)
################## UI for Left Hand ###########################
class IKFK_Snap(bpy.types.Panel):
bl_label = "IK/FK Snap Hands"
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = "Rig Options"
@classmethod
def poll(self, context):
return context.object and context.object.type == 'ARMATURE'
def draw(self, context):
l = self.layout
l.label(text="Left Hand:")
influence_data_path = get_influece_data_path()
l.prop(influence_data_path[0],influence_data_path[1], slider=True)
subrow = l.row(align=True)
subrow.operator('my.iktofk')
subrow = l.row(align=True)
subrow.operator('my.fktoik')
#l.operator('my.iktofk')
#l.operator('my.fktoik')
class IKtoFKButton(bpy.types.Operator):
bl_idname = "my.iktofk"
bl_label = "IK -> FK"
def execute(self, context):
amt = bpy.data.objects[armature_name]
ik_bone = amt.pose.bones[ik_bone_name_L]
upper_arm = amt.pose.bones[upper_arm_name_L]
ik_target = amt.pose.bones[ik_target_name_L]
ik_pole = amt.pose.bones[ik_pole_name_L]
#copy fk matrix
set_fk(get_influece_data_path())
#pose update
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
#set ik target
ik_target.matrix = set_translation(ik_target.matrix, ik_bone.tail)
#set pole target
ik_pole.matrix = set_translation(ik_pole.matrix, upper_arm.tail)
return {'FINISHED'}
class FKtoIKButton(bpy.types.Operator):
bl_idname = "my.fktoik"
bl_label = "FK -> IK"
def execute(self, context):
amt = bpy.data.objects[armature_name]
ik_bone = amt.pose.bones[ik_bone_name_L]
upper_arm = amt.pose.bones[upper_arm_name_L]
ik_target = amt.pose.bones[ik_target_name_L]
ik_pole = amt.pose.bones[ik_pole_name_L]
# copy ik matrix
set_ik(get_influece_data_path())
#pose update
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
ik_bone_matrixes = []
it = ik_bone
for i in range(num_bones):
ik_bone_matrixes.append(it.matrix)
it = ik_bone.parent
# set ik matrix to fk bone
set_fk(get_influece_data_path())
it = ik_bone
for i in range(num_bones):
it.matrix = ik_bone_matrixes[i]
it = it.parent
return {'FINISHED'}
############################## UI For Right Hand ##################
class IKFK_Snap_Right(bpy.types.Panel):
bl_label = "IK/FK Snap Hands"
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = "Rig Options"
@classmethod
def poll(self, context):
return context.object and context.object.type == 'ARMATURE'
def draw(self, context):
l = self.layout
l.label(text="Right Hand:")
influence_data_path = get_influece_data_path()
l.prop(influence_data_path[0],influence_data_path[1], slider=True)
subrow = l.row(align=True)
subrow.operator('right.iktofk')
subrow = l.row(align=True)
subrow.operator('right.fktoik')
#l.operator('my.iktofk')
#l.operator('my.fktoik')
class IKtoFKButton_Right(bpy.types.Operator):
bl_idname = "right.iktofk"
bl_label = "IK -> FK"
def execute(self, context):
amt = bpy.data.objects[armature_name]
ik_bone = amt.pose.bones[ik_bone_name_R]
upper_arm = amt.pose.bones[upper_arm_name_R]
ik_target = amt.pose.bones[ik_target_name_R]
ik_pole = amt.pose.bones[ik_pole_name_R]
#copy fk matrix
set_fk(get_influece_data_path())
#pose update
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
#set ik target
ik_target.matrix = set_translation(ik_target.matrix, ik_bone.tail)
#set pole target
ik_pole.matrix = set_translation(ik_pole.matrix, upper_arm.tail)
return {'FINISHED'}
class FKtoIKButton_Right(bpy.types.Operator):
bl_idname = "right.fktoik"
bl_label = "FK -> IK"
def execute(self, context):
amt = bpy.data.objects[armature_name]
ik_bone = amt.pose.bones[ik_bone_name_R]
upper_arm = amt.pose.bones[upper_arm_name_R]
ik_target = amt.pose.bones[ik_target_name_R]
ik_pole = amt.pose.bones[ik_pole_name_R]
# copy ik matrix
set_ik(get_influece_data_path())
#pose update
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
ik_bone_matrixes = []
it = ik_bone
for i in range(num_bones):
ik_bone_matrixes.append(it.matrix)
it = ik_bone.parent
# set ik matrix to fk bone
set_fk(get_influece_data_path())
it = ik_bone
for i in range(num_bones):
it.matrix = ik_bone_matrixes[i]
it = it.parent
return {'FINISHED'}
###################### Register ##########################
classes = (
IKFK_Snap,
IKtoFKButton,
FKtoIKButton,
IKFK_Snap_Right,
IKtoFKButton_Right,
FKtoIKButton_Right
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reverse(classes):
bpy.utils.unregister_class(cls)
if __name__ == "__main__":
register()
Any help is appreciated. maybe there is easier solution for this topic?
And here is example blend
ikfk_snap(Left-Right).blend (669.8 KB)