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:
authorThomas Larsson <thomas_larsson_01@hotmail.com>2012-03-24 12:08:48 +0400
committerThomas Larsson <thomas_larsson_01@hotmail.com>2012-03-24 12:08:48 +0400
commitb6d1cb0afaf8d0f3d8d15dd8eced37958dd77803 (patch)
tree0a3fda0a3476da239208574b0c970ae88ec61e84 /io_import_scene_mhx.py
parent1bafadf7cd5beb8c65ebbd2b3e70d4baa3b794b9 (diff)
MHX importer: Multiple UV maps now work correctly with Bmesh. Added FK-IK snapping, stolen from Rigify.
Diffstat (limited to 'io_import_scene_mhx.py')
-rw-r--r--io_import_scene_mhx.py315
1 files changed, 311 insertions, 4 deletions
diff --git a/io_import_scene_mhx.py b/io_import_scene_mhx.py
index b954f6c9..e07e0734 100644
--- a/io_import_scene_mhx.py
+++ b/io_import_scene_mhx.py
@@ -61,7 +61,9 @@ BLENDER_VERSION = (2, 59, 2)
import bpy
import os
import time
+import math
import mathutils
+from mathutils import Vector, Matrix
from bpy.props import *
MHX249 = False
@@ -1342,11 +1344,10 @@ def parseFaces2(tokens, me):
def parseUvTexture(args, tokens, me):
name = args[0]
- uvtex = me.uv_textures.new(name = name)
- uvtex.active = True
+ bpy.ops.mesh.uv_texture_add()
+ uvtex = me.uv_textures[-1]
+ uvtex.name = name
uvloop = me.uv_loop_layers[-1]
- #print("UV", name, uvtex)
- #print(" ", uvloop, uvloop.data)
loadedData['MeshTextureFaceLayer'][name] = uvloop
for (key, val, sub) in tokens:
if key == 'Data':
@@ -3537,6 +3538,312 @@ class MhxExpressionsPanel(bpy.types.Panel):
row.operator("mhx.pose_pin_expression", text="", icon='UNPINNED').expression = prop
return
+#########################################
+#
+# FK-IK snapping panel.
+# The bulk of this code was shamelessly stolen from Rigify.
+#
+#########################################
+
+def getPoseMatrixInOtherSpace(mat, pb):
+ rest = pb.bone.matrix_local.copy()
+ restInv = rest.inverted()
+ if pb.parent:
+ parMat = pb.parent.matrix.copy()
+ parInv = parMat.inverted()
+ parRest = pb.parent.bone.matrix_local.copy()
+ else:
+ parMat = Matrix()
+ parInv = Matrix()
+ parRest = Matrix()
+
+ # Get matrix in bone's current transform space
+ smat = restInv * (parRest * (parInv * mat))
+ return smat
+
+
+def getLocalPoseMatrix(pb):
+ return getPoseMatrixInOtherSpace(pb.matrix, pb)
+
+
+def setPoseTranslation(pb, mat):
+ if pb.bone.use_local_location == True:
+ pb.location = mat.to_translation()
+ else:
+ loc = mat.to_translation()
+
+ rest = pb.bone.matrix_local.copy()
+ if pb.bone.parent:
+ parRest = pb.bone.parent.matrix_local.copy()
+ else:
+ parRest = Matrix()
+
+ q = (parRest.inverted() * rest).to_quaternion()
+ pb.location = q * loc
+
+
+def setPoseRotation(pb, mat):
+ 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 setPoseScale(pb, mat):
+ pb.scale = mat.to_scale()
+
+def matchPoseTranslation(pb, tarPb):
+ mat = getPoseMatrixInOtherSpace(tarPb.matrix, pb)
+ setPoseTranslation(pb, mat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+def matchPoseRotation(pb, tarPb):
+ mat = getPoseMatrixInOtherSpace(tarPb.matrix, pb)
+ setPoseRotation(pb, mat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+def matchPoseScale(pb, tarPb):
+ mat = getPoseMatrixInOtherSpace(tarPb.matrix, pb)
+ setPoseScale(pb, mat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+
+def matchPoleTarget(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 = getPoseMatrixInOtherSpace(Matrix.Translation(ploc), pole)
+ setPoseTranslation(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 = math.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() * pv
+ 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 = math.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() * pv
+ set_pole(pv)
+
+
+def fk2ikArm(context, suffix):
+ rig = context.object
+ print("FK -> IK Arm")
+ (uparmIk, loarmIk, elbowPt, wrist) = getSnapBones(rig, "ArmIK", suffix)
+ (uparmFk, loarmFk, handFk) = getSnapBones(rig, "ArmFK", suffix)
+
+ matchPoseRotation(uparmFk, uparmIk)
+ matchPoseScale(uparmFk, uparmIk)
+
+ matchPoseRotation(loarmFk, loarmIk)
+ matchPoseScale(loarmFk, loarmIk)
+
+ if rig["&HandFollowsWrist" + suffix]:
+ matchPoseRotation(handFk, wrist)
+ matchPoseScale(handFk, wrist)
+ return
+
+
+def ik2fkArm(context, suffix):
+ rig = context.object
+ (uparmIk, loarmIk, elbowPt, wrist) = getSnapBones(rig, "ArmIK", suffix)
+ (uparmFk, loarmFk, handFk) = getSnapBones(rig, "ArmFK", suffix)
+
+ matchPoseTranslation(wrist, handFk)
+ matchPoseRotation(wrist, handFk)
+ matchPoseScale(wrist, handFk)
+
+ matchPoleTarget(uparmIk, loarmIk, elbowPt, uparmFk, (uparmIk.length + loarmIk.length))
+ return
+
+
+def fk2ikLeg(context, suffix):
+ rig = context.object
+ (uplegIk, lolegIk, kneePt, ankleIk, legIk, legFk) = getSnapBones(rig, "LegIK", suffix)
+ (uplegFk, lolegFk, footFk) = getSnapBones(rig, "LegFK", suffix)
+
+ matchPoseRotation(uplegFk, uplegIk)
+ matchPoseScale(uplegFk, uplegIk)
+
+ matchPoseRotation(lolegFk, lolegIk)
+ matchPoseScale(lolegFk, lolegIk)
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
+ return
+
+def ik2fkLeg(context, suffix):
+ rig = context.object
+ (uplegIk, lolegIk, kneePt, ankleIk, legIk, legFk) = getSnapBones(rig, "LegIK", suffix)
+ (uplegFk, lolegFk, footFk) = getSnapBones(rig, "LegFK", suffix)
+
+ legIkToAngle = "&LegIkToAnkle" + suffix
+ oldLegIkToAnkle = rig[legIkToAngle]
+
+ if True or oldLegIkToAnkle > 0.9:
+ matchPoseTranslation(ankleIk, footFk)
+ else:
+ childof = None
+ for cns in ankleIk.constraints:
+ if cns.type == 'CHILD_OF':
+ childof = cns
+ print("Found Child-of constraint", childof)
+ break
+ if not childof:
+ raise NameError("Something is wrong. Cannot find Child-of constraint")
+
+ oldActive = rig.data.bones.active
+ rig.data.bones.active = ankleIk.bone
+ rig[legIkToAngle] = 1.0
+ bpy.ops.constraint.childof_set_inverse(constraint=childof.name, owner='BONE')
+ matchPoseTranslation(ankleIk, footFk)
+ matchPoseTranslation(legIk, legFk)
+ matchPoseRotation(legIk, legFk)
+ matchPoseScale(legIk, legFk)
+ rig.data.bones.active = ankleIk.bone
+ rig[legIkToAngle] = oldLegIkToAnkle
+ halt
+ bpy.ops.constraint.childof_set_inverse(constraint=childof.name, owner='BONE')
+ rig.data.bones.active = oldActive
+
+ matchPoleTarget(uplegIk, lolegIk, kneePt, uplegFk, (uplegIk.length + lolegIk.length))
+ return
+
+SnapBones = {
+ "ArmFK" : ["UpArm", "LoArm", "Hand"],
+ "ArmIK" : ["UpArmIK", "LoArmIK", "ElbowPT", "Wrist"],
+ "LegFK" : ["UpLeg", "LoLeg", "Foot"],
+ "LegIK" : ["UpLegIK", "LoLegIK", "KneePT", "Ankle", "LegIK", "LegFK"],
+}
+
+def getSnapBones(rig, key, suffix):
+ names = SnapBones[key]
+ pbones = []
+ for name in names:
+ pb = rig.pose.bones[name+suffix]
+ pbones.append(pb)
+ return tuple(pbones)
+
+class VIEW3D_OT_MhxSnapFk2IkButton(bpy.types.Operator):
+ bl_idname = "mhx.snap_fk_ik"
+ bl_label = "Set FK"
+ bone = StringProperty()
+
+ def execute(self, context):
+ bpy.ops.object.mode_set(mode='POSE')
+ if self.bone[:3] == "Arm":
+ fk2ikArm(context, self.bone[-2:])
+ elif self.bone[:3] == "Leg":
+ fk2ikLeg(context, self.bone[-2:])
+ return{'FINISHED'}
+
+class VIEW3D_OT_MhxSnapIk2FkButton(bpy.types.Operator):
+ bl_idname = "mhx.snap_ik_fk"
+ bl_label = "Set IK"
+ bone = StringProperty()
+
+ def execute(self, context):
+ bpy.ops.object.mode_set(mode='POSE')
+ if self.bone[:3] == "Arm":
+ ik2fkArm(context, self.bone[-2:])
+ elif self.bone[:3] == "Leg":
+ ik2fkLeg(context, self.bone[-2:])
+ return{'FINISHED'}
+
+class MhxSnappingPanel(bpy.types.Panel):
+ bl_label = "MHX Snapping"
+ bl_space_type = "VIEW_3D"
+ bl_region_type = "UI"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return pollMhxRig(context.object)
+
+ def draw(self, context):
+ ob = context.object
+ layout = self.layout
+
+ row = layout.row()
+ row.label("Left arm")
+ row.operator("mhx.snap_fk_ik").bone = "Arm_L"
+ row.operator("mhx.snap_ik_fk").bone = "Arm_L"
+
+ row = layout.row()
+ row.label("Right arm")
+ row.operator("mhx.snap_fk_ik").bone = "Arm_R"
+ row.operator("mhx.snap_ik_fk").bone = "Arm_R"
+
+ row = layout.row()
+ row.label("Left leg")
+ row.operator("mhx.snap_fk_ik").bone = "Leg_L"
+ row.operator("mhx.snap_ik_fk").bone = "Leg_L"
+
+ row = layout.row()
+ row.label("Right arm")
+ row.operator("mhx.snap_fk_ik").bone = "Leg_R"
+ row.operator("mhx.snap_ik_fk").bone = "Leg_R"
+
###################################################################################
#
# Posing panel