You may want to try this: http://pasteall.org/384523/python
It's an addon. You'll have to put it in your %appdata%\Blender Foundation\Blender\2.78\scripts\addons
folder or the equivalent in your platform and enable it in Blender. It adds a button to the constraints panel for each IK constraint it finds. The button puts the right number in the pole angle box.
I took @jerryno's solution and coded an addon around it, so, thank him. It's not the most elegant solution around, but it did the trick for my pipeline.
EDIT: as pointed out in the comments, I'm inserting the code inline so it stays here once the pastebin turns to dust.
bl_info = {
"name": "Bone Panel extension",
"author": "Fernando D'Andrea - Rockhead Studios (thanks to Jerryno for the angle calculation code)",
"version": (0, 1),
"blender": (2, 78, 0),
"location": "Properties > Bone Constraints > Inverse Kinematics",
"description": "Extends IK panel funcionality",
"warning": "",
"wiki_url": "",
"category": "Rigging"
}
import bpy
import mathutils
import bmesh
def dandrea_IKConstraint_panel(self, context):
_bone = context.pose_bone #context.object.pose.bones
#self.layout.label(str(_bone.name))
#self.layout.label(str(_bone.constraints))
#self.layout.label(str(len(_bone.constraints)))
for cons in _bone.constraints:
if cons.type=='IK':
self.layout.operator("constraint.dandrea_adjust_pole", icon = 'OUTLINER_OB_ARMATURE', text='Adjust Pole Angle: ' + _bone.name + ' ("'+ cons.name +'")').constraint = cons.name
class dandrea_adjust_pole(bpy.types.Operator):
"""Adds functionality to the IK constraint panel."""
bl_idname = "constraint.dandrea_adjust_pole"
bl_label = "Adjust IK Pole Angle"
bl_icon = 'OUTLINER_OB_ARMATURE'
constraint = bpy.props.StringProperty(name="IK Name", description="IK constraint name to set", default="")
@classmethod
def poll(cls, context):
#implement poll
return True
def execute(self, context):
def signed_angle(vector_u, vector_v, normal):
# Normal specifies orientation
angle = vector_u.angle(vector_v)
if vector_u.cross(vector_v).angle(normal) < 1:
angle = -angle
return angle
def get_pole_angle(base_bone, ik_bone, pole_location):
pole_normal = (ik_bone.tail - base_bone.head).cross(pole_location - base_bone.head)
projected_pole_axis = pole_normal.cross(base_bone.tail - base_bone.head)
return signed_angle(base_bone.x_axis, projected_pole_axis, base_bone.tail - base_bone.head)
context_mode = context.mode
bpy.ops.object.mode_set(mode='POSE')
ik_bone = context.pose_bone
print (ik_bone)
cons = ik_bone.constraints[self.constraint]
if cons is None:
return {'CANCELLED'}
cons_mute = cons.mute
base_bone = ik_bone
for i in range(1, cons.chain_count):
base_bone = base_bone.parent
if base_bone is None:
return {'CANCELLED'}
pole_bone = cons.pole_target
if pole_bone is None:
return {'CANCELLED'}
if pole_bone.type == 'ARMATURE':
pole_bone = context.object.pose.bones[cons.pole_subtarget]
if pole_bone is None:
return {'CANCELLED'}
print(pole_bone)
if (base_bone is not None) and (pole_bone is not None):
cons.mute = False
bpy.ops.object.mode_set(mode='EDIT')
pole_angle_in_radians = get_pole_angle(base_bone,ik_bone,pole_bone.matrix.translation)
pole_angle_in_deg = round(180*pole_angle_in_radians/3.141592, 3)
print(pole_angle_in_deg)
cons.mute = cons_mute
bpy.ops.object.mode_set(mode=context_mode)
cons.pole_angle = pole_angle_in_radians
return {'FINISHED'}
def register():
bpy.utils.register_class(dandrea_adjust_pole)
bpy.types.BONE_PT_constraints.append(dandrea_IKConstraint_panel)
def unregister():
bpy.utils.unregister_class(dandrea_adjust_pole)
bpy.types.BONE_PT_constraints.remove(dandrea_IKConstraint_panel)
if __name__ == "__main__":
unregister()
register()