Changeset View
Changeset View
Standalone View
Standalone View
rigify/rig_ui_template.py
| Show All 12 Lines | |||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
| # | # | ||||
| #======================= END GPL LICENSE BLOCK ======================== | #======================= END GPL LICENSE BLOCK ======================== | ||||
| # <pep8 compliant> | # <pep8 compliant> | ||||
| UI_SLIDERS = ''' | UI_IMPORTS = [ | ||||
| import bpy | 'import bpy', | ||||
| from bpy.props import StringProperty | 'from bpy.props import StringProperty', | ||||
| from mathutils import Matrix, Vector | 'import math', | ||||
| from math import acos, pi, radians | 'from math import pi', | ||||
| 'from mathutils import Euler, Matrix, Quaternion, Vector', | |||||
| ] | |||||
| UI_BASE_UTILITIES = ''' | |||||
| rig_id = "%s" | rig_id = "%s" | ||||
| ############################ | ############################ | ||||
| ## Math utility functions ## | ## Math utility functions ## | ||||
| ############################ | ############################ | ||||
| def perpendicular_vector(v): | def perpendicular_vector(v): | ||||
| Show All 15 Lines | |||||
| def rotation_difference(mat1, mat2): | def rotation_difference(mat1, mat2): | ||||
| """ Returns the shortest-path rotational difference between two | """ Returns the shortest-path rotational difference between two | ||||
| matrices. | matrices. | ||||
| """ | """ | ||||
| q1 = mat1.to_quaternion() | q1 = mat1.to_quaternion() | ||||
| q2 = mat2.to_quaternion() | q2 = mat2.to_quaternion() | ||||
| angle = acos(min(1,max(-1,q1.dot(q2)))) * 2 | angle = math.acos(min(1,max(-1,q1.dot(q2)))) * 2 | ||||
| if angle > pi: | if angle > pi: | ||||
| angle = -angle + (2*pi) | angle = -angle + (2*pi) | ||||
| return angle | return angle | ||||
| def tail_distance(angle,bone_ik,bone_fk): | def tail_distance(angle,bone_ik,bone_fk): | ||||
| """ Returns the distance between the tails of two bones | """ Returns the distance between the tails of two bones | ||||
| after rotating bone_ik in AXIS_ANGLE mode. | after rotating bone_ik in AXIS_ANGLE mode. | ||||
| """ | """ | ||||
| ▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | def match_pole_target(ik_first, ik_last, pole, match_bone, length): | ||||
| pv2 = Matrix.Rotation(-angle, 4, ikv) @ pv | pv2 = Matrix.Rotation(-angle, 4, ikv) @ pv | ||||
| set_pole(pv2) | set_pole(pv2) | ||||
| ang2 = rotation_difference(ik_first.matrix, match_bone.matrix) | ang2 = rotation_difference(ik_first.matrix, match_bone.matrix) | ||||
| # Do the one with the smaller angle | # Do the one with the smaller angle | ||||
| if ang1 < ang2: | if ang1 < ang2: | ||||
| set_pole(pv1) | set_pole(pv1) | ||||
| ########## | |||||
| ## Misc ## | |||||
| ########## | |||||
| def parse_bone_names(names_string): | |||||
| if names_string[0] == '[' and names_string[-1] == ']': | |||||
| return eval(names_string) | |||||
| else: | |||||
| return names_string | |||||
| ''' | |||||
| UTILITIES_FUNC_ARM_FKIK = [''' | |||||
| ###################### | |||||
| ## IK Arm functions ## | |||||
| ###################### | |||||
| def fk2ik_arm(obj, fk, ik): | def fk2ik_arm(obj, fk, ik): | ||||
| """ Matches the fk bones in an arm rig to the ik bones. | """ Matches the fk bones in an arm rig to the ik bones. | ||||
| obj: armature object | obj: armature object | ||||
| fk: list of fk bone names | fk: list of fk bone names | ||||
| ik: list of ik bone names | ik: list of ik bone names | ||||
| """ | """ | ||||
| uarm = obj.pose.bones[fk[0]] | uarm = obj.pose.bones[fk[0]] | ||||
| ▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | else: | ||||
| match_pose_scale(handi, hand) | match_pose_scale(handi, hand) | ||||
| # Upper Arm position | # Upper Arm position | ||||
| match_pose_translation(uarmi, uarm) | match_pose_translation(uarmi, uarm) | ||||
| match_pose_rotation(uarmi, uarm) | match_pose_rotation(uarmi, uarm) | ||||
| match_pose_scale(uarmi, uarm) | match_pose_scale(uarmi, uarm) | ||||
| # Rotation Correction | # Rotation Correction | ||||
| correct_rotation(uarmi, uarm) | correct_rotation(uarmi, uarm) | ||||
| '''] | |||||
| UTILITIES_FUNC_LEG_FKIK = [''' | |||||
| ###################### | |||||
| ## IK Leg functions ## | |||||
| ###################### | |||||
| def fk2ik_leg(obj, fk, ik): | def fk2ik_leg(obj, fk, ik): | ||||
| """ Matches the fk bones in a leg rig to the ik bones. | """ Matches the fk bones in a leg rig to the ik bones. | ||||
| obj: armature object | obj: armature object | ||||
| fk: list of fk bone names | fk: list of fk bone names | ||||
| ik: list of ik bone names | ik: list of ik bone names | ||||
| """ | """ | ||||
| thigh = obj.pose.bones[fk[0]] | thigh = obj.pose.bones[fk[0]] | ||||
| ▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | else: | ||||
| set_pose_translation(footi, footmat) | set_pose_translation(footi, footmat) | ||||
| set_pose_rotation(footi, footmat) | set_pose_rotation(footi, footmat) | ||||
| set_pose_scale(footi, footmat) | set_pose_scale(footi, footmat) | ||||
| bpy.ops.object.mode_set(mode='OBJECT') | bpy.ops.object.mode_set(mode='OBJECT') | ||||
| bpy.ops.object.mode_set(mode='POSE') | bpy.ops.object.mode_set(mode='POSE') | ||||
| # Pole target position | # Pole target position | ||||
| match_pole_target(thighi, shini, pole, thigh, (thighi.length + shini.length)) | match_pole_target(thighi, shini, pole, thigh, (thighi.length + shini.length)) | ||||
| '''] | |||||
| UTILITIES_FUNC_POLE = [''' | |||||
| ################################ | ################################ | ||||
| ## IK Rotation-Pole functions ## | ## IK Rotation-Pole functions ## | ||||
| ################################ | ################################ | ||||
| def parse_bone_names(names_string): | |||||
| if names_string[0] == '[' and names_string[-1] == ']': | |||||
| return eval(names_string) | |||||
| else: | |||||
| return names_string | |||||
| def rotPoleToggle(rig, limb_type, controls, ik_ctrl, fk_ctrl, parent, pole): | def rotPoleToggle(rig, limb_type, controls, ik_ctrl, fk_ctrl, parent, pole): | ||||
| rig_id = rig.data['rig_id'] | rig_id = rig.data['rig_id'] | ||||
| leg_fk2ik = eval('bpy.ops.pose.rigify_leg_fk2ik_' + rig_id) | leg_fk2ik = eval('bpy.ops.pose.rigify_leg_fk2ik_' + rig_id) | ||||
| arm_fk2ik = eval('bpy.ops.pose.rigify_arm_fk2ik_' + rig_id) | arm_fk2ik = eval('bpy.ops.pose.rigify_arm_fk2ik_' + rig_id) | ||||
| leg_ik2fk = eval('bpy.ops.pose.rigify_leg_ik2fk_' + rig_id) | leg_ik2fk = eval('bpy.ops.pose.rigify_leg_ik2fk_' + rig_id) | ||||
| arm_ik2fk = eval('bpy.ops.pose.rigify_arm_ik2fk_' + rig_id) | arm_ik2fk = eval('bpy.ops.pose.rigify_arm_ik2fk_' + rig_id) | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | for b in pbones: | ||||
| 'foot_ik': controls[6], 'pole': pole, 'footroll': controls[5], 'mfoot_ik': ik_ctrl[2], | 'foot_ik': controls[6], 'pole': pole, 'footroll': controls[5], 'mfoot_ik': ik_ctrl[2], | ||||
| 'main_parent': parent} | 'main_parent': parent} | ||||
| func1(**kwargs1) | func1(**kwargs1) | ||||
| rig.pose.bones[parent]['pole_vector'] = new_pole_vector_value | rig.pose.bones[parent]['pole_vector'] = new_pole_vector_value | ||||
| func2(**kwargs2) | func2(**kwargs2) | ||||
| bpy.ops.pose.select_all(action='DESELECT') | bpy.ops.pose.select_all(action='DESELECT') | ||||
| '''] | |||||
| ############################## | REGISTER_OP_ARM_FKIK = ['Rigify_Arm_FK2IK', 'Rigify_Arm_IK2FK'] | ||||
| ## IK/FK snapping operators ## | |||||
| ############################## | UTILITIES_OP_ARM_FKIK = [''' | ||||
| ################################## | |||||
| ## IK/FK Arm snapping operators ## | |||||
| ################################## | |||||
| class Rigify_Arm_FK2IK(bpy.types.Operator): | class Rigify_Arm_FK2IK(bpy.types.Operator): | ||||
| """ Snaps an FK arm to an IK arm. | """ Snaps an FK arm to an IK arm. | ||||
| """ | """ | ||||
| bl_idname = "pose.rigify_arm_fk2ik_" + rig_id | bl_idname = "pose.rigify_arm_fk2ik_" + rig_id | ||||
| bl_label = "Rigify Snap FK arm to IK" | bl_label = "Rigify Snap FK arm to IK" | ||||
| bl_options = {'UNDO'} | bl_options = {'UNDO'} | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | class Rigify_Arm_IK2FK(bpy.types.Operator): | ||||
| def execute(self, context): | def execute(self, context): | ||||
| use_global_undo = context.preferences.edit.use_global_undo | use_global_undo = context.preferences.edit.use_global_undo | ||||
| context.preferences.edit.use_global_undo = False | context.preferences.edit.use_global_undo = False | ||||
| try: | try: | ||||
| ik2fk_arm(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, self.main_parent]) | ik2fk_arm(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, self.main_parent]) | ||||
| finally: | finally: | ||||
| context.preferences.edit.use_global_undo = use_global_undo | context.preferences.edit.use_global_undo = use_global_undo | ||||
| return {'FINISHED'} | return {'FINISHED'} | ||||
| '''] | |||||
| REGISTER_OP_LEG_FKIK = ['Rigify_Leg_FK2IK', 'Rigify_Leg_IK2FK'] | |||||
| UTILITIES_OP_LEG_FKIK = [''' | |||||
| ################################## | |||||
| ## IK/FK Leg snapping operators ## | |||||
| ################################## | |||||
| class Rigify_Leg_FK2IK(bpy.types.Operator): | class Rigify_Leg_FK2IK(bpy.types.Operator): | ||||
| """ Snaps an FK leg to an IK leg. | """ Snaps an FK leg to an IK leg. | ||||
| """ | """ | ||||
| bl_idname = "pose.rigify_leg_fk2ik_" + rig_id | bl_idname = "pose.rigify_leg_fk2ik_" + rig_id | ||||
| bl_label = "Rigify Snap FK leg to IK" | bl_label = "Rigify Snap FK leg to IK" | ||||
| bl_options = {'UNDO'} | bl_options = {'UNDO'} | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | class Rigify_Leg_IK2FK(bpy.types.Operator): | ||||
| def execute(self, context): | def execute(self, context): | ||||
| use_global_undo = context.preferences.edit.use_global_undo | use_global_undo = context.preferences.edit.use_global_undo | ||||
| context.preferences.edit.use_global_undo = False | context.preferences.edit.use_global_undo = False | ||||
| try: | try: | ||||
| ik2fk_leg(context.active_object, fk=[self.thigh_fk, self.shin_fk, self.mfoot_fk, self.foot_fk], ik=[self.thigh_ik, self.shin_ik, self.foot_ik, self.footroll, self.pole, self.mfoot_ik, self.main_parent]) | ik2fk_leg(context.active_object, fk=[self.thigh_fk, self.shin_fk, self.mfoot_fk, self.foot_fk], ik=[self.thigh_ik, self.shin_ik, self.foot_ik, self.footroll, self.pole, self.mfoot_ik, self.main_parent]) | ||||
| finally: | finally: | ||||
| context.preferences.edit.use_global_undo = use_global_undo | context.preferences.edit.use_global_undo = use_global_undo | ||||
| return {'FINISHED'} | return {'FINISHED'} | ||||
| '''] | |||||
| REGISTER_OP_POLE = ['Rigify_Rot2PoleSwitch'] | |||||
| UTILITIES_OP_POLE = [''' | |||||
| ########################### | ########################### | ||||
| ## IK Rotation Pole Snap ## | ## IK Rotation Pole Snap ## | ||||
| ########################### | ########################### | ||||
| class Rigify_Rot2PoleSwitch(bpy.types.Operator): | class Rigify_Rot2PoleSwitch(bpy.types.Operator): | ||||
| bl_idname = "pose.rigify_rot2pole_" + rig_id | bl_idname = "pose.rigify_rot2pole_" + rig_id | ||||
| bl_label = "Rotation - Pole toggle" | bl_label = "Rotation - Pole toggle" | ||||
| bl_description = "Toggles IK chain between rotation and pole target" | bl_description = "Toggles IK chain between rotation and pole target" | ||||
| Show All 10 Lines | def execute(self, context): | ||||
| rig = context.object | rig = context.object | ||||
| if self.bone_name: | if self.bone_name: | ||||
| bpy.ops.pose.select_all(action='DESELECT') | bpy.ops.pose.select_all(action='DESELECT') | ||||
| rig.pose.bones[self.bone_name].bone.select = True | rig.pose.bones[self.bone_name].bone.select = True | ||||
| rotPoleToggle(rig, self.limb_type, self.controls, self.ik_ctrl, self.fk_ctrl, self.parent, self.pole) | rotPoleToggle(rig, self.limb_type, self.controls, self.ik_ctrl, self.fk_ctrl, self.parent, self.pole) | ||||
| return {'FINISHED'} | return {'FINISHED'} | ||||
| '''] | |||||
| REGISTER_RIG_ARM = REGISTER_OP_ARM_FKIK + REGISTER_OP_POLE | |||||
| UTILITIES_RIG_ARM = [ | |||||
| *UTILITIES_FUNC_ARM_FKIK, | |||||
| *UTILITIES_FUNC_POLE, | |||||
| *UTILITIES_OP_ARM_FKIK, | |||||
| *UTILITIES_OP_POLE, | |||||
| ] | |||||
| REGISTER_RIG_LEG = REGISTER_OP_LEG_FKIK + REGISTER_OP_POLE | |||||
| UTILITIES_RIG_LEG = [ | |||||
| *UTILITIES_FUNC_LEG_FKIK, | |||||
| *UTILITIES_FUNC_POLE, | |||||
| *UTILITIES_OP_LEG_FKIK, | |||||
| *UTILITIES_OP_POLE, | |||||
| ] | |||||
| ############################## | |||||
| ## Default set of utilities ## | |||||
| ############################## | |||||
| UI_REGISTER = [ | |||||
| 'RigUI', | |||||
| 'RigLayers', | |||||
| *REGISTER_OP_ARM_FKIK, | |||||
| *REGISTER_OP_LEG_FKIK, | |||||
| ] | |||||
| # Include arm and leg utilities for now in case somebody wants to use | |||||
| # legacy limb rigs, which expect these to be available by default. | |||||
| UI_UTILITIES = [ | |||||
| *UTILITIES_FUNC_ARM_FKIK, | |||||
| *UTILITIES_FUNC_LEG_FKIK, | |||||
| *UTILITIES_OP_ARM_FKIK, | |||||
| *UTILITIES_OP_LEG_FKIK, | |||||
| ] | |||||
| UI_SLIDERS = ''' | |||||
| ################### | ################### | ||||
| ## Rig UI Panels ## | ## Rig UI Panels ## | ||||
| ################### | ################### | ||||
| class RigUI(bpy.types.Panel): | class RigUI(bpy.types.Panel): | ||||
| bl_space_type = 'VIEW_3D' | bl_space_type = 'VIEW_3D' | ||||
| bl_region_type = 'UI' | bl_region_type = 'UI' | ||||
| bl_label = "Rig Main Properties" | bl_label = "Rig Main Properties" | ||||
| ▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | ''' | ||||
| code += "\n row = col.row()" | code += "\n row = col.row()" | ||||
| code += "\n row.separator()" | code += "\n row.separator()" | ||||
| code += "\n row = col.row()" | code += "\n row = col.row()" | ||||
| code += "\n row.separator()\n" | code += "\n row.separator()\n" | ||||
| code += "\n row = col.row()\n" | code += "\n row = col.row()\n" | ||||
| code += " row.prop(context.active_object.data, 'layers', index=28, toggle=True, text='Root')\n" | code += " row.prop(context.active_object.data, 'layers', index=28, toggle=True, text='Root')\n" | ||||
| return code | return code | ||||
| UI_REGISTER = ''' | |||||
| classes = ( | |||||
| Rigify_Arm_FK2IK, | |||||
| Rigify_Arm_IK2FK, | |||||
| Rigify_Leg_FK2IK, | |||||
| Rigify_Leg_IK2FK, | |||||
| Rigify_Rot2PoleSwitch, | |||||
| RigUI, | |||||
| RigLayers, | |||||
| ) | |||||
| def register(): | |||||
| from bpy.utils import register_class | |||||
| for cls in classes: | |||||
| register_class(cls) | |||||
| def unregister(): | |||||
| from bpy.utils import unregister_class | |||||
| for cls in classes: | |||||
| unregister_class(cls) | |||||
| register() | |||||
| ''' | |||||