Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'rigify/rig_ui_template.py')
-rw-r--r--rigify/rig_ui_template.py551
1 files changed, 551 insertions, 0 deletions
diff --git a/rigify/rig_ui_template.py b/rigify/rig_ui_template.py
new file mode 100644
index 00000000..db3bb6cb
--- /dev/null
+++ b/rigify/rig_ui_template.py
@@ -0,0 +1,551 @@
+#====================== 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+UI_SLIDERS = '''
+import bpy
+from mathutils import Matrix, Vector
+from math import acos
+
+rig_id = "%s"
+
+
+#########################################
+## "Visual Transform" helper functions ##
+#########################################
+
+def get_pose_matrix_in_other_space(mat, pose_bone):
+ """ Returns the transform matrix relative to pose_bone's current
+ transform space. In other words, presuming that mat is in
+ armature space, slapping the returned matrix onto pose_bone
+ should give it the armature-space transforms of mat.
+ TODO: try to handle cases with axis-scaled parents better.
+ """
+ rest = pose_bone.bone.matrix_local.copy()
+ rest_inv = rest.inverted()
+ if pose_bone.parent:
+ par_mat = pose_bone.parent.matrix.copy()
+ par_inv = par_mat.inverted()
+ par_rest = pose_bone.parent.bone.matrix_local.copy()
+ else:
+ par_mat = Matrix()
+ par_inv = Matrix()
+ par_rest = Matrix()
+
+ # Get matrix in bone's current transform space
+ smat = rest_inv * (par_rest * (par_inv * mat))
+
+ # Compensate for non-local location
+ #if not pose_bone.bone.use_local_location:
+ # loc = smat.to_translation() * (par_rest.inverted() * rest).to_quaternion()
+ # smat[3][0] = loc[0]
+ # smat[3][1] = loc[1]
+ # smat[3][2] = loc[2]
+
+ return smat
+
+
+def get_local_pose_matrix(pose_bone):
+ """ Returns the local transform matrix of the given pose bone.
+ """
+ return get_pose_matrix_in_other_space(pose_bone.matrix, pose_bone)
+
+
+def set_pose_translation(pose_bone, mat):
+ """ Sets the pose bone's translation to the same translation as the given matrix.
+ Matrix should be given in bone's local space.
+ """
+ if pose_bone.bone.use_local_location == True:
+ pose_bone.location = mat.to_translation()
+ else:
+ loc = mat.to_translation()
+
+ rest = pose_bone.bone.matrix_local.copy()
+ if pose_bone.bone.parent:
+ par_rest = pose_bone.bone.parent.matrix_local.copy()
+ else:
+ par_rest = Matrix()
+
+ q = (par_rest.inverted() * rest).to_quaternion()
+ pose_bone.location = loc * q
+
+
+def set_pose_rotation(pose_bone, mat):
+ """ Sets the pose bone's rotation to the same rotation as the given matrix.
+ Matrix should be given in bone's local space.
+ """
+ q = mat.to_quaternion()
+
+ if pose_bone.rotation_mode == 'QUATERNION':
+ pose_bone.rotation_quaternion = q
+ elif pose_bone.rotation_mode == 'AXIS_ANGLE':
+ pose_bone.rotation_axis_angle[0] = q.angle
+ pose_bone.rotation_axis_angle[1] = q.axis[0]
+ pose_bone.rotation_axis_angle[2] = q.axis[1]
+ pose_bone.rotation_axis_angle[3] = q.axis[2]
+ else:
+ pose_bone.rotation_euler = q.to_euler(pose_bone.rotation_mode)
+
+
+def set_pose_scale(pose_bone, mat):
+ """ Sets the pose bone's scale to the same scale as the given matrix.
+ Matrix should be given in bone's local space.
+ """
+ pose_bone.scale = mat.to_scale()
+
+
+def match_pose_translation(pose_bone, target_bone):
+ """ Matches pose_bone's visual translation to target_bone's visual
+ translation.
+ This function assumes you are in pose mode on the relevant armature.
+ """
+ mat = get_pose_matrix_in_other_space(target_bone.matrix, pose_bone)
+ set_pose_translation(pose_bone, mat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+
+def match_pose_rotation(pose_bone, target_bone):
+ """ Matches pose_bone's visual rotation to target_bone's visual
+ rotation.
+ This function assumes you are in pose mode on the relevant armature.
+ """
+ mat = get_pose_matrix_in_other_space(target_bone.matrix, pose_bone)
+ set_pose_rotation(pose_bone, mat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+
+def match_pose_scale(pose_bone, target_bone):
+ """ Matches pose_bone's visual scale to target_bone's visual
+ scale.
+ This function assumes you are in pose mode on the relevant armature.
+ """
+ mat = get_pose_matrix_in_other_space(target_bone.matrix, pose_bone)
+ set_pose_scale(pose_bone, mat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+
+##############################
+## IK/FK snapping functions ##
+##############################
+
+def match_pole_target(ik_first, ik_last, pole, match_bone, length):
+ """ Places an IK chain's pole target to match ik_first's
+ transforms to match_bone. All bones should be given as pose bones.
+ You need to be in pose mode on the relevant armature object.
+ ik_first: first bone in the IK chain
+ ik_last: last bone in the IK chain
+ pole: pole target bone for the IK chain
+ match_bone: bone to match ik_first to (probably first bone in a matching FK chain)
+ length: distance pole target should be placed from the chain center
+ """
+ a = ik_first.matrix.to_translation()
+ b = ik_last.matrix.to_translation() + ik_last.vector
+
+ # Vector from the head of ik_first to the
+ # tip of ik_last
+ ikv = b - a
+
+ # Create a vector that is not aligned with ikv.
+ # It doesn't matter what vector. Just any vector
+ # that's guaranteed to not be pointing in the same
+ # direction. In this case, we create a unit vector
+ # on the axis of the smallest component of ikv.
+ if abs(ikv[0]) < abs(ikv[1]) and abs(ikv[0]) < abs(ikv[2]):
+ v = Vector((1,0,0))
+ elif abs(ikv[1]) < abs(ikv[2]):
+ v = Vector((0,1,0))
+ else:
+ v = Vector((0,0,1))
+
+ # Get a vector perpendicular to ikv
+ pv = v.cross(ikv).normalized() * length
+
+ def set_pole(pvi):
+ """ Set pole target's position based on a vector
+ from the arm center line.
+ """
+ # Translate pvi into armature space
+ ploc = a + (ikv/2) + pvi
+
+ # Set pole target to location
+ mat = get_pose_matrix_in_other_space(Matrix.Translation(ploc), pole)
+ set_pose_translation(pole, mat)
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+ set_pole(pv)
+
+ # Get the rotation difference between ik_first and match_bone
+ q1 = ik_first.matrix.to_quaternion()
+ q2 = match_bone.matrix.to_quaternion()
+ angle = acos(min(1,max(-1,q1.dot(q2)))) * 2
+
+ # Compensate for the rotation difference
+ if angle > 0.0001:
+ pv *= Matrix.Rotation(angle, 4, ikv).to_quaternion()
+ set_pole(pv)
+
+ # Get rotation difference again, to see if we
+ # compensated in the right direction
+ q1 = ik_first.matrix.to_quaternion()
+ q2 = match_bone.matrix.to_quaternion()
+ angle2 = acos(min(1,max(-1,q1.dot(q2)))) * 2
+ if angle2 > 0.0001:
+ # Compensate in the other direction
+ pv *= Matrix.Rotation((angle*(-2)), 4, ikv).to_quaternion()
+ set_pole(pv)
+
+
+def fk2ik_arm(obj, fk, ik):
+ """ Matches the fk bones in an arm rig to the ik bones.
+ obj: armature object
+ fk: list of fk bone names
+ ik: list of ik bone names
+ """
+ uarm = obj.pose.bones[fk[0]]
+ farm = obj.pose.bones[fk[1]]
+ hand = obj.pose.bones[fk[2]]
+ uarmi = obj.pose.bones[ik[0]]
+ farmi = obj.pose.bones[ik[1]]
+ handi = obj.pose.bones[ik[2]]
+
+ # Upper arm position
+ match_pose_rotation(uarm, uarmi)
+ match_pose_scale(uarm, uarmi)
+
+ # Forearm position
+ match_pose_rotation(farm, farmi)
+ match_pose_scale(farm, farmi)
+
+ # Hand position
+ match_pose_rotation(hand, handi)
+ match_pose_scale(hand, handi)
+
+
+def ik2fk_arm(obj, fk, ik):
+ """ Matches the ik bones in an arm rig to the fk bones.
+ obj: armature object
+ fk: list of fk bone names
+ ik: list of ik bone names
+ """
+ uarm = obj.pose.bones[fk[0]]
+ farm = obj.pose.bones[fk[1]]
+ hand = obj.pose.bones[fk[2]]
+ uarmi = obj.pose.bones[ik[0]]
+ farmi = obj.pose.bones[ik[1]]
+ handi = obj.pose.bones[ik[2]]
+ pole = obj.pose.bones[ik[3]]
+
+ # Hand position
+ match_pose_translation(handi, hand)
+ match_pose_rotation(handi, hand)
+ match_pose_scale(handi, hand)
+
+ # Pole target position
+ match_pole_target(uarmi, farmi, pole, uarm, (uarmi.length + farmi.length))
+
+
+def fk2ik_leg(obj, fk, ik):
+ """ Matches the fk bones in a leg rig to the ik bones.
+ obj: armature object
+ fk: list of fk bone names
+ ik: list of ik bone names
+ """
+ thigh = obj.pose.bones[fk[0]]
+ shin = obj.pose.bones[fk[1]]
+ foot = obj.pose.bones[fk[2]]
+ mfoot = obj.pose.bones[fk[3]]
+ thighi = obj.pose.bones[ik[0]]
+ shini = obj.pose.bones[ik[1]]
+ mfooti = obj.pose.bones[ik[2]]
+
+ # Thigh position
+ match_pose_rotation(thigh, thighi)
+ match_pose_scale(thigh, thighi)
+
+ # Shin position
+ match_pose_rotation(shin, shini)
+ match_pose_scale(shin, shini)
+
+ # Foot position
+ mat = mfoot.bone.matrix_local.inverted() * foot.bone.matrix_local
+ footmat = get_pose_matrix_in_other_space(mfooti.matrix, foot) * mat
+ set_pose_rotation(foot, footmat)
+ set_pose_scale(foot, footmat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+
+def ik2fk_leg(obj, fk, ik):
+ """ Matches the ik bones in a leg rig to the fk bones.
+ obj: armature object
+ fk: list of fk bone names
+ ik: list of ik bone names
+ """
+ thigh = obj.pose.bones[fk[0]]
+ shin = obj.pose.bones[fk[1]]
+ mfoot = obj.pose.bones[fk[2]]
+ thighi = obj.pose.bones[ik[0]]
+ shini = obj.pose.bones[ik[1]]
+ footi = obj.pose.bones[ik[2]]
+ footroll = obj.pose.bones[ik[3]]
+ pole = obj.pose.bones[ik[4]]
+ mfooti = obj.pose.bones[ik[5]]
+
+ # Clear footroll
+ set_pose_rotation(footroll, Matrix())
+
+ # Foot position
+ mat = mfooti.bone.matrix_local.inverted() * footi.bone.matrix_local
+ footmat = get_pose_matrix_in_other_space(mfoot.matrix, footi) * mat
+ set_pose_translation(footi, footmat)
+ set_pose_rotation(footi, footmat)
+ set_pose_scale(footi, footmat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+ # Pole target position
+ match_pole_target(thighi, shini, pole, thigh, (thighi.length + shini.length))
+
+
+##############################
+## IK/FK snapping operators ##
+##############################
+
+class Rigify_Arm_FK2IK(bpy.types.Operator):
+ """ Snaps an FK arm to an IK arm.
+ """
+ bl_idname = "pose.rigify_arm_fk2ik_" + rig_id
+ bl_label = "Rigify Snap FK arm to IK"
+ bl_options = {'UNDO'}
+
+ 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):
+ use_global_undo = context.user_preferences.edit.use_global_undo
+ context.user_preferences.edit.use_global_undo = False
+ try:
+ fk2ik_arm(context.active_object, fk=[self.uarm_fk, self.farm_fk, self.hand_fk], ik=[self.uarm_ik, self.farm_ik, self.hand_ik])
+ finally:
+ context.user_preferences.edit.use_global_undo = use_global_undo
+ return {'FINISHED'}
+
+
+class Rigify_Arm_IK2FK(bpy.types.Operator):
+ """ Snaps an IK arm to an FK arm.
+ """
+ bl_idname = "pose.rigify_arm_ik2fk_" + rig_id
+ bl_label = "Rigify Snap IK arm to FK"
+ bl_options = {'UNDO'}
+
+ 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):
+ use_global_undo = context.user_preferences.edit.use_global_undo
+ context.user_preferences.edit.use_global_undo = False
+ 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])
+ finally:
+ context.user_preferences.edit.use_global_undo = use_global_undo
+ return {'FINISHED'}
+
+
+class Rigify_Leg_FK2IK(bpy.types.Operator):
+ """ Snaps an FK leg to an IK leg.
+ """
+ bl_idname = "pose.rigify_leg_fk2ik_" + rig_id
+ bl_label = "Rigify Snap FK leg to IK"
+ bl_options = {'UNDO'}
+
+ thigh_fk = bpy.props.StringProperty(name="Thigh FK Name")
+ shin_fk = bpy.props.StringProperty(name="Shin FK Name")
+ foot_fk = bpy.props.StringProperty(name="Foot FK Name")
+ mfoot_fk = bpy.props.StringProperty(name="MFoot FK Name")
+
+ thigh_ik = bpy.props.StringProperty(name="Thigh IK Name")
+ shin_ik = bpy.props.StringProperty(name="Shin IK Name")
+ mfoot_ik = bpy.props.StringProperty(name="MFoot IK Name")
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object != None and context.mode == 'POSE')
+
+ def execute(self, context):
+ use_global_undo = context.user_preferences.edit.use_global_undo
+ context.user_preferences.edit.use_global_undo = False
+ try:
+ fk2ik_leg(context.active_object, fk=[self.thigh_fk, self.shin_fk, self.foot_fk, self.mfoot_fk], ik=[self.thigh_ik, self.shin_ik, self.mfoot_ik])
+ finally:
+ context.user_preferences.edit.use_global_undo = use_global_undo
+ return {'FINISHED'}
+
+
+class Rigify_Leg_IK2FK(bpy.types.Operator):
+ """ Snaps an IK leg to an FK leg.
+ """
+ bl_idname = "pose.rigify_leg_ik2fk_" + rig_id
+ bl_label = "Rigify Snap IK leg to FK"
+ bl_options = {'UNDO'}
+
+ thigh_fk = bpy.props.StringProperty(name="Thigh FK Name")
+ shin_fk = bpy.props.StringProperty(name="Shin FK Name")
+ mfoot_fk = bpy.props.StringProperty(name="MFoot FK Name")
+
+ thigh_ik = bpy.props.StringProperty(name="Thigh IK Name")
+ shin_ik = bpy.props.StringProperty(name="Shin IK Name")
+ foot_ik = bpy.props.StringProperty(name="Foot IK Name")
+ footroll = bpy.props.StringProperty(name="Foot Roll Name")
+ pole = bpy.props.StringProperty(name="Pole IK Name")
+ mfoot_ik = bpy.props.StringProperty(name="MFoot IK Name")
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object != None and context.mode == 'POSE')
+
+ def execute(self, context):
+ use_global_undo = context.user_preferences.edit.use_global_undo
+ context.user_preferences.edit.use_global_undo = False
+ try:
+ ik2fk_leg(context.active_object, fk=[self.thigh_fk, self.shin_fk, self.mfoot_fk], ik=[self.thigh_ik, self.shin_ik, self.foot_ik, self.footroll, self.pole, self.mfoot_ik])
+ finally:
+ context.user_preferences.edit.use_global_undo = use_global_undo
+ return {'FINISHED'}
+
+
+###################
+## Rig UI Panels ##
+###################
+
+class RigUI(bpy.types.Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+ bl_label = "Rig Main Properties"
+ bl_idname = rig_id + "_PT_rig_ui"
+
+ @classmethod
+ def poll(self, context):
+ if context.mode != 'POSE':
+ return False
+ try:
+ return (context.active_object.data.get("rig_id") == rig_id)
+ except (AttributeError, KeyError, TypeError):
+ return False
+
+ def draw(self, context):
+ layout = self.layout
+ pose_bones = context.active_object.pose.bones
+ try:
+ selected_bones = [bone.name for bone in context.selected_pose_bones]
+ selected_bones += [context.active_pose_bone.name]
+ except (AttributeError, TypeError):
+ return
+
+ def is_selected(names):
+ # Returns whether any of the named bones are selected.
+ if type(names) == list:
+ for name in names:
+ if name in selected_bones:
+ return True
+ elif names in selected_bones:
+ return True
+ return False
+
+
+'''
+
+
+def layers_ui(layers):
+ """ Turn a list of booleans into a layer UI.
+ """
+
+ code = '''
+class RigLayers(bpy.types.Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+ bl_label = "Rig Layers"
+ bl_idname = rig_id + "_PT_rig_layers"
+
+ @classmethod
+ def poll(self, context):
+ try:
+ return (context.active_object.data.get("rig_id") == rig_id)
+ except (AttributeError, KeyError, TypeError):
+ return False
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column()
+'''
+ i = 0
+ for layer in layers:
+ if layer:
+ code += "\n row = col.row()\n"
+ if i == 28:
+ code += " row.prop(context.active_object.data, 'layers', index=%s, toggle=True, text='Root')\n" % (str(i))
+ else:
+ code += " row.prop(context.active_object.data, 'layers', index=%s, toggle=True, text='%s')\n" % (str(i), str(i + 1))
+ i += 1
+
+ return code
+
+
+UI_REGISTER = '''
+
+def register():
+ bpy.utils.register_class(Rigify_Arm_FK2IK)
+ bpy.utils.register_class(Rigify_Arm_IK2FK)
+ bpy.utils.register_class(Rigify_Leg_FK2IK)
+ bpy.utils.register_class(Rigify_Leg_IK2FK)
+ bpy.utils.register_class(RigUI)
+ bpy.utils.register_class(RigLayers)
+
+def unregister():
+ bpy.utils.unregister_class(Rigify_Arm_FK2IK)
+ bpy.utils.unregister_class(Rigify_Arm_IK2FK)
+ bpy.utils.unregister_class(Rigify_Leg_FK2IK)
+ bpy.utils.unregister_class(Rigify_Leg_IK2FK)
+ bpy.utils.unregister_class(RigUI)
+ bpy.utils.unregister_class(RigLayers)
+
+register()
+'''
+