Newer
Older
Thomas Larsson
committed
def ik2fkArm(context, suffix):
rig = context.object
scn = context.scene
auto = scn.tool_settings.use_keyframe_insert_auto
print("Snap IK Arm%s" % suffix)
(uparmIk, loarmIk, elbow, elbowPt, wrist) = getSnapBones(rig, "ArmIK", suffix)
(uparmFk, loarmFk, elbowPtFk, handFk) = getSnapBones(rig, "ArmFK", suffix)
Thomas Larsson
committed
#rig["MhaElbowFollowsShoulder" + suffix] = False
#rig["MhaElbowFollowsWrist" + suffix] = False
matchPoseTranslation(wrist, handFk, auto)
matchPoseRotation(wrist, handFk, auto)
matchPoseTranslation(elbow, elbowPtFk, auto)
matchPoseTranslation(elbowPt, elbowPtFk, auto)
setInverse(rig, elbowPt)
Thomas Larsson
committed
return
def fk2ikLeg(context, suffix):
rig = context.object
auto = context.scene.tool_settings.use_keyframe_insert_auto
print("Snap FK Leg%s" % suffix)
(uplegIk, lolegIk, kneePt, ankleIk, legIk, legFk, footIk, toeIk) = getSnapBones(rig, "LegIK", suffix)
(uplegFk, lolegFk, kneePtFk, footFk, toeFk) = getSnapBones(rig, "LegFK", suffix)
Thomas Larsson
committed
matchPoseRotation(uplegFk, uplegFk, auto)
matchPoseScale(uplegFk, uplegFk, auto)
Thomas Larsson
committed
matchPoseRotation(lolegFk, lolegFk, auto)
matchPoseScale(lolegFk, lolegFk, auto)
Thomas Larsson
committed
return
Thomas Larsson
committed
def ik2fkLeg(context, suffix):
rig = context.object
scn = context.scene
auto = scn.tool_settings.use_keyframe_insert_auto
print("Snap IK Leg%s" % suffix)
(uplegIk, lolegIk, kneePt, ankleIk, legIk, legFk, footIk, toeIk) = getSnapBones(rig, "LegIK", suffix)
(uplegFk, lolegFk, kneePtFk, footFk, toeFk) = getSnapBones(rig, "LegFK", suffix)
#rig["MhaKneeFollowsHip" + suffix] = False
#rig["MhaKneeFollowsFoot" + suffix] = False
Thomas Larsson
committed
legIkToAnkle = rig["MhaLegIkToAnkle" + suffix]
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
if legIkToAnkle:
matchPoseTranslation(ankleIk, footFk, auto)
matchPoseTranslation(legIk, legFk, auto)
matchPoseRotation(legIk, legFk, auto)
matchPoseReverse(toeIk, toeFk, auto)
matchPoseReverse(footIk, footFk, auto)
setInverse(rig, ankleIk)
matchPoseTranslation(kneePt, kneePtFk, auto)
setInverse(rig, kneePt)
if not legIkToAnkle:
matchPoseTranslation(ankleIk, footFk, auto)
return
#
# setInverse(rig, pb):
#
def setInverse(rig, pb):
rig.data.bones.active = pb.bone
pb.bone.select = True
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
for cns in pb.constraints:
if cns.type == 'CHILD_OF':
bpy.ops.constraint.childof_set_inverse(constraint=cns.name, owner='BONE')
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
return
def clearInverse(rig, pb):
rig.data.bones.active = pb.bone
pb.bone.select = True
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
for cns in pb.constraints:
if cns.type == 'CHILD_OF':
bpy.ops.constraint.childof_clear_inverse(constraint=cns.name, owner='BONE')
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
return
Thomas Larsson
committed
def fixAnkle(rig, suffix, scn):
layers = list(rig.data.layers)
Thomas Larsson
committed
try:
rig.data.layers = 32*[True]
setInverse(rig, rig.pose.bones["Ankle" + suffix])
scn.frame_current = scn.frame_current
finally:
rig.data.layers = layers
return
Thomas Larsson
committed
def clearAnkle(rig, suffix, scn):
layers = list(rig.data.layers)
try:
rig.data.layers = 32*[True]
clearInverse(rig, rig.pose.bones["Ankle" + suffix])
scn.frame_current = scn.frame_current
finally:
rig.data.layers = layers
Thomas Larsson
committed
return
class VIEW3D_OT_FixAnkleButton(bpy.types.Operator):
bl_idname = "mhx.fix_ankle"
bl_label = "Fix ankle"
bl_description = "Set inverse for ankle Child-of constraints"
suffix = StringProperty()
def execute(self, context):
fixAnkle(context.object, self.suffix, context.scene)
return{'FINISHED'}
class VIEW3D_OT_ClearAnkleButton(bpy.types.Operator):
bl_idname = "mhx.clear_ankle"
bl_label = "Clear ankle"
bl_description = "Clear inverse for ankle Child-of constraints"
suffix = StringProperty()
def execute(self, context):
clearAnkle(context.object, self.suffix, context.scene)
return{'FINISHED'}
Thomas Larsson
committed
SnapBones = {
"ArmFK" : ["UpArm", "LoArm", "ElbowPTFK", "Hand"],
"ArmIK" : ["UpArmIK", "LoArmIK", "Elbow", "ElbowPT", "Wrist"],
"LegFK" : ["UpLeg", "LoLeg", "KneePTFK", "Foot", "Toe"],
"LegIK" : ["UpLegIK", "LoLegIK", "KneePT", "Ankle", "LegIK", "LegFK", "FootRev", "ToeRev"],
Thomas Larsson
committed
}
Thomas Larsson
committed
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)
Thomas Larsson
committed
class VIEW3D_OT_MhxSnapFk2IkButton(bpy.types.Operator):
bl_idname = "mhx.snap_fk_ik"
Thomas Larsson
committed
def execute(self, context):
bpy.ops.object.mode_set(mode='POSE')
rig = context.object
(prop, old) = setSnapProp(rig, self.data, 1.0, context, False)
Thomas Larsson
committed
if prop[:6] == "MhaArm":
fk2ikArm(context, prop[-2:])
Thomas Larsson
committed
elif prop[:6] == "MhaLeg":
fk2ikLeg(context, prop[-2:])
restoreSnapProp(rig, prop, old, context)
Thomas Larsson
committed
return{'FINISHED'}
Thomas Larsson
committed
class VIEW3D_OT_MhxSnapIk2FkButton(bpy.types.Operator):
bl_idname = "mhx.snap_ik_fk"
Thomas Larsson
committed
def execute(self, context):
bpy.ops.object.mode_set(mode='POSE')
rig = context.object
(prop, old) = setSnapProp(rig, self.data, 0.0, context, True)
Thomas Larsson
committed
if prop[:6] == "MhaArm":
ik2fkArm(context, prop[-2:])
Thomas Larsson
committed
elif prop[:6] == "MhaLeg":
ik2fkLeg(context, prop[-2:])
restoreSnapProp(rig, prop, old, context)
Thomas Larsson
committed
return{'FINISHED'}
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
def setSnapProp(rig, data, value, context, isIk):
words = data.split()
prop = words[0]
oldValue = rig[prop]
rig[prop] = value
ik = int(words[1])
fk = int(words[2])
extra = int(words[3])
oldIk = rig.data.layers[ik]
oldFk = rig.data.layers[fk]
oldExtra = rig.data.layers[extra]
rig.data.layers[ik] = True
rig.data.layers[fk] = True
rig.data.layers[extra] = True
updatePose(context)
if isIk:
oldValue = 1.0
oldIk = True
oldFk = False
else:
oldValue = 0.0
oldIk = False
oldFk = True
oldExtra = False
return (prop, (oldValue, ik, fk, extra, oldIk, oldFk, oldExtra))
def restoreSnapProp(rig, prop, old, context):
updatePose(context)
(oldValue, ik, fk, extra, oldIk, oldFk, oldExtra) = old
rig[prop] = oldValue
rig.data.layers[ik] = oldIk
rig.data.layers[fk] = oldFk
rig.data.layers[extra] = oldExtra
return
Thomas Larsson
committed
class VIEW3D_OT_MhxToggleFkIkButton(bpy.types.Operator):
bl_idname = "mhx.toggle_fk_ik"
bl_label = "FK - IK"
Thomas Larsson
committed
toggle = StringProperty()
def execute(self, context):
words = self.toggle.split()
rig = context.object
prop = words[0]
value = float(words[1])
onLayer = int(words[2])
offLayer = int(words[3])
rig.data.layers[onLayer] = True
rig.data.layers[offLayer] = False
rig[prop] = value
# Don't do autokey - confusing.
#if context.tool_settings.use_keyframe_insert_auto:
# rig.keyframe_insert('["%s"]' % prop, frame=scn.frame_current)
updatePose(context)
Thomas Larsson
committed
return{'FINISHED'}
#
# MHX FK/IK Switch panel
#
Thomas Larsson
committed
class MhxFKIKPanel(bpy.types.Panel):
bl_label = "MHX FK/IK Switch"
Thomas Larsson
committed
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
#bl_options = {'DEFAULT_CLOSED'}
Thomas Larsson
committed
@classmethod
def poll(cls, context):
return (context.object and context.object.MhxRig == 'MHX')
Thomas Larsson
committed
def draw(self, context):
Thomas Larsson
committed
rig = context.object
layout = self.layout
row = layout.row()
row.label("")
row.label("Left")
row.label("Right")
Thomas Larsson
committed
layout.label("FK/IK switch")
Thomas Larsson
committed
row = layout.row()
row.label("Arm")
Thomas Larsson
committed
self.toggleButton(row, rig, "MhaArmIk_L", " 3", " 2")
self.toggleButton(row, rig, "MhaArmIk_R", " 19", " 18")
Thomas Larsson
committed
row = layout.row()
row.label("Leg")
Thomas Larsson
committed
self.toggleButton(row, rig, "MhaLegIk_L", " 5", " 4")
self.toggleButton(row, rig, "MhaLegIk_R", " 21", " 20")
Thomas Larsson
committed
try:
ok = (rig["MhxVersion"] >= 12)
except:
ok = False
if not ok:
layout.label("Snapping only works with MHX version 1.12 and later.")
return
layout.label("Snap Arm bones")
Thomas Larsson
committed
row = layout.row()
Thomas Larsson
committed
row.operator("mhx.snap_fk_ik", text="Snap L FK Arm").data = "MhaArmIk_L 2 3 12"
row.operator("mhx.snap_fk_ik", text="Snap R FK Arm").data = "MhaArmIk_R 18 19 28"
Thomas Larsson
committed
row = layout.row()
Thomas Larsson
committed
row.operator("mhx.snap_ik_fk", text="Snap L IK Arm").data = "MhaArmIk_L 2 3 12"
row.operator("mhx.snap_ik_fk", text="Snap R IK Arm").data = "MhaArmIk_R 18 19 28"
Thomas Larsson
committed
layout.label("Snap Leg bones")
Thomas Larsson
committed
row = layout.row()
Thomas Larsson
committed
row.operator("mhx.snap_fk_ik", text="Snap L FK Leg").data = "MhaLegIk_L 4 5 12"
row.operator("mhx.snap_fk_ik", text="Snap R FK Leg").data = "MhaLegIk_R 20 21 28"
row = layout.row()
row.label("IK Leg")
Thomas Larsson
committed
row.operator("mhx.snap_ik_fk", text="Snap L IK Leg").data = "MhaLegIk_L 4 5 12"
row.operator("mhx.snap_ik_fk", text="Snap R IK Leg").data = "MhaLegIk_R 20 21 28"
row.label("Ankle")
row.operator("mhx.fix_ankle", text="Fix L Ankle").suffix = "_L"
row.operator("mhx.fix_ankle", text="Fix R Ankle").suffix = "_R"
Thomas Larsson
committed
row = layout.row()
row.label("")
row.operator("mhx.clear_ankle", text="Clear L Ankle").suffix = "_L"
row.operator("mhx.clear_ankle", text="Clear R Ankle").suffix = "_R"
Thomas Larsson
committed
Thomas Larsson
committed
def toggleButton(self, row, rig, prop, fk, ik):
if rig[prop] > 0.5:
row.operator("mhx.toggle_fk_ik", text="IK").toggle = prop + " 0" + fk + ik
else:
row.operator("mhx.toggle_fk_ik", text="FK").toggle = prop + " 1" + ik + fk
###################################################################################
#
# Posing panel
#
###################################################################################
#
# class MhxDriversPanel(bpy.types.Panel):
#
class MhxDriversPanel(bpy.types.Panel):
bl_label = "MHX Drivers"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object and context.object.MhxRig)
def draw(self, context):
Thomas Larsson
committed
lrProps = []
Thomas Larsson
committed
lrFaceProps = []
faceProps = []
plist = list(context.object.keys())
plist.sort()
for prop in plist:
if prop[0:3] == 'Mha':
if prop[-2:] == '_L':
Thomas Larsson
committed
lrProps.append(prop[:-2])
Thomas Larsson
committed
props.append(prop)
elif prop[0:3] == 'Mhf':
if prop[-2:] == '_L':
lrFaceProps.append(prop[:-2])
elif prop[-2:] != '_R':
faceProps.append(prop)
Thomas Larsson
committed
ob = context.object
layout = self.layout
Thomas Larsson
committed
for prop in props:
layout.prop(ob, prop, text=prop[3:])
layout.separator()
row = layout.row()
row.label("Left")
row.label("Right")
for prop in lrProps:
row = layout.row()
row.prop(ob, prop+"_L", text=prop[3:])
row.prop(ob, prop+"_R", text=prop[3:])
if faceProps:
layout.separator()
layout.label("Face shapes")
Thomas Larsson
committed
for prop in faceProps:
Thomas Larsson
committed
layout.separator()
row = layout.row()
row.label("Left")
row.label("Right")
for prop in lrFaceProps:
row = layout.row()
row.prop(ob, prop+"_L", text=prop[3:])
row.prop(ob, prop+"_R", text=prop[3:])
Thomas Larsson
committed
###################################################################################
#
# Visibility panel
#
###################################################################################
#
# class MhxVisibilityPanel(bpy.types.Panel):
#
class MhxVisibilityPanel(bpy.types.Panel):
bl_label = "MHX Visibility"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object and context.object.MhxRig)
def draw(self, context):
ob = context.object
Thomas Larsson
committed
layout = self.layout
props = list(ob.keys())
props.sort()
for prop in props:
Thomas Larsson
committed
if prop[0:3] == "Mhh":
layout.prop(ob, prop, text="Hide %s" % prop[3:])
Thomas Larsson
committed
layout.separator()
layout.operator("mhx.update_textures")
layout.separator()
layout.operator("mhx.add_hiders")
layout.operator("mhx.remove_hiders")
Thomas Larsson
committed
class VIEW3D_OT_MhxUpdateTexturesButton(bpy.types.Operator):
bl_idname = "mhx.update_textures"
bl_label = "Update"
Thomas Larsson
committed
def execute(self, context):
scn = context.scene
for mat in bpy.data.materials:
if mat.animation_data:
try:
mat["MhxDriven"]
except:
continue
for driver in mat.animation_data.drivers:
prop = mat.path_resolve(driver.data_path)
value = driver.evaluate(scn.frame_current)
#print("Update %s[%d] = %s" % (driver.data_path, driver.array_index, value))
prop[driver.array_index] = value
return{'FINISHED'}
class VIEW3D_OT_MhxAddHidersButton(bpy.types.Operator):
bl_idname = "mhx.add_hiders"
bl_label = "Add Hide Property"
def execute(self, context):
rig = context.object
for ob in context.scene.objects:
if ob.select and ob != rig:
Thomas Larsson
committed
prop = "Mhh%s" % ob.name
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
rig[prop] = False
addHider(ob, "hide", rig, prop)
addHider(ob, "hide_render", rig, prop)
return{'FINISHED'}
def addHider(ob, attr, rig, prop):
fcu = ob.driver_add(attr)
drv = fcu.driver
drv.type = 'SCRIPTED'
drv.expression = "x"
drv.show_debug_info = True
var = drv.variables.new()
var.name = "x"
targ = var.targets[0]
targ.id = rig
targ.data_path = '["%s"]' % prop
return
class VIEW3D_OT_MhxRemoveHidersButton(bpy.types.Operator):
bl_idname = "mhx.remove_hiders"
bl_label = "Remove Hide Property"
Thomas Larsson
committed
def execute(self, context):
rig = context.object
for ob in context.scene.objects:
if ob.select and ob != rig:
ob.driver_remove("hide")
ob.driver_remove("hide_render")
Thomas Larsson
committed
del rig["Mhh%s" % ob.name]
###################################################################################
#
# Layers panel
#
###################################################################################
MhxLayers = [
(( 0, 'Root', 'MhxRoot'),
( 8, 'Face', 'MhxFace')),
(( 9, 'Tweak', 'MhxTweak'),
(10, 'Head', 'MhxHead')),
(( 1, 'FK Spine', 'MhxFKSpine'),
(17, 'IK Spine', 'MhxIKSpine')),
((13, 'Inv FK Spine', 'MhxInvFKSpine'),
(16, 'Clothes', 'MhxClothes')),
('Left', 'Right'),
(( 2, 'IK Arm', 'MhxIKArm'),
(18, 'IK Arm', 'MhxIKArm')),
(( 3, 'FK Arm', 'MhxFKArm'),
(19, 'FK Arm', 'MhxFKArm')),
(( 4, 'IK Leg', 'MhxIKLeg'),
(20, 'IK Leg', 'MhxIKLeg')),
(( 5, 'FK Leg', 'MhxFKLeg'),
(21, 'FK Leg', 'MhxFKLeg')),
((12, 'Extra', 'MhxExtra'),
(28, 'Extra', 'MhxExtra')),
(( 6, 'Fingers', 'MhxFingers'),
(22, 'Fingers', 'MhxFingers')),
(( 7, 'Links', 'MhxLinks'),
(23, 'Links', 'MhxLinks')),
((11, 'Palm', 'MhxPalm'),
(27, 'Palm', 'MhxPalm')),
]
#
# class MhxLayersPanel(bpy.types.Panel):
#
class MhxLayersPanel(bpy.types.Panel):
bl_label = "MHX Layers"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
#bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.object
if (ob and ob.MhxRig == 'MHX'):
return True
return False
def draw(self, context):
layout = self.layout
Thomas Larsson
committed
layout.operator("mhx.pose_enable_all_layers")
layout.operator("mhx.pose_disable_all_layers")
amt = context.object.data
for (left,right) in MhxLayers:
row = layout.row()
if type(left) == str:
row.label(left)
row.label(right)
else:
for (n, name, prop) in [left,right]:
row.prop(amt, "layers", index=n, toggle=True, text=name)
return
Thomas Larsson
committed
class VIEW3D_OT_MhxEnableAllLayersButton(bpy.types.Operator):
bl_idname = "mhx.pose_enable_all_layers"
bl_label = "Enable all layers"
def execute(self, context):
Thomas Larsson
committed
rig,mesh = getMhxRigMesh(context.object)
for (left,right) in MhxLayers:
if type(left) != str:
for (n, name, prop) in [left,right]:
Thomas Larsson
committed
rig.data.layers[n] = True
return{'FINISHED'}
class VIEW3D_OT_MhxDisableAllLayersButton(bpy.types.Operator):
bl_idname = "mhx.pose_disable_all_layers"
bl_label = "Disable all layers"
Thomas Larsson
committed
def execute(self, context):
Thomas Larsson
committed
rig,mesh = getMhxRigMesh(context.object)
Thomas Larsson
committed
layers = 32*[False]
pb = context.active_pose_bone
if pb:
for n in range(32):
if pb.bone.layers[n]:
layers[n] = True
break
else:
layers[0] = True
rig.data.layers = layers
return{'FINISHED'}
###################################################################################
#
# Common functions
#
###################################################################################
#
Thomas Larsson
committed
# getMhxRigMesh(ob):
def pollMhx(ob):
if not ob:
return False
elif ob.type == 'ARMATURE':
return ob.MhxRig
elif ob.type == 'MESH':
par = ob.parent
return (par and (par.type == 'ARMATURE') and par.MhxRig)
else:
return False
Thomas Larsson
committed
def getMhxRigMesh(ob):
if ob.type == 'ARMATURE':
for mesh in ob.children:
if mesh.MhxMesh and ob.MhxRig:
return (ob, mesh)
return (ob, None)
elif ob.type == 'MESH':
par = ob.parent
if (par and par.type == 'ARMATURE' and par.MhxRig):
if ob.MhxMesh:
return (par, ob)
else:
return (par, None)
else:
Thomas Larsson
committed
return (None, None)
return (None, None)
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
#
# setInterpolation(rig):
#
def setInterpolation(rig):
if not rig.animation_data:
return
act = rig.animation_data.action
if not act:
return
for fcu in act.fcurves:
for pt in fcu.keyframe_points:
pt.interpolation = 'LINEAR'
fcu.extrapolation = 'CONSTANT'
return
###################################################################################
#
# initialize and register
#
###################################################################################
def menu_func(self, context):
self.layout.operator(ImportMhx.bl_idname, text="MakeHuman (.mhx)...")
bpy.types.Object.MhxMesh = BoolProperty(default=False)
bpy.types.Object.MhxRig = StringProperty(default="")
bpy.types.Object.MhxRigify = BoolProperty(default=False)
bpy.types.Object.MhxShapekeyDrivers = BoolProperty(default=True)
Thomas Larsson
committed
bpy.types.Object.MhxStrength = FloatProperty(
name = "Expression strength",
description = "Multiply expression with this factor",
default=1.0, min=-1.0, max=2.0
)
Campbell Barton
committed
bpy.utils.register_module(__name__)
Thomas Larsson
committed
bpy.utils.unregister_module(__name__)
Thomas Larsson
committed
try:
bpy.types.INFO_MT_file_import.remove(menu_func)
except:
pass
if __name__ == "__main__":
unregister()