Newer
Older
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
('PTongue', (0,0.0))],
'SH' : [('PMouth', (-0.6,0)),
('PUpLip', (0,-0.5)),
('PLoLip', (0,0.5)),
('PJaw', (0,0)),
('PTongue', (0,0.0))],
'EE' : [('PMouth', (0.3,0)),
('PUpLip', (0,-0.3)),
('PLoLip', (0,0.3)),
('PJaw', (0,0.025)),
('PTongue', (0,0.0))],
'AH' : [('PMouth', (-0.1,0)),
('PUpLip', (0,-0.4)),
('PLoLip', (0,0)),
('PJaw', (0,0.35)),
('PTongue', (0,0.0))],
'EH' : [('PMouth', (0.1,0)),
('PUpLip', (0,-0.2)),
('PLoLip', (0,0.2)),
('PJaw', (0,0.2)),
('PTongue', (0,0.0))],
'TH' : [('PMouth', (0,0)),
('PUpLip', (0,-0.5)),
('PLoLip', (0,0.5)),
('PJaw', (-0.2,0.1)),
('PTongue', (0,-0.6))],
'L' : [('PMouth', (0,0)),
('PUpLip', (0,-0.2)),
('PLoLip', (0,0.2)),
('PJaw', (0.2,0.2)),
('PTongue', (0,-0.8))],
'G' : [('PMouth', (0,0)),
('PUpLip', (0,-0.1)),
('PLoLip', (0,0.1)),
('PJaw', (-0.3,0.1)),
('PTongue', (0,-0.6))],
'Blink' : [('PUpLid', (0,1.0)), ('PLoLid', (0,-1.0))],
'Unblink' : [('PUpLid', (0,0)), ('PLoLid', (0,0))],
})
Thomas Larsson
committed
"""
bodyLanguageVisemes = ({
'Rest' : [
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0.6),
('UpLipsMidHeight', 0),
('LoLipsMidHeight', 0),
('LoLipsIn', 0),
('MouthOpen', 0),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0.4),
('UpLipsMidHeight', 0),
('LoLipsMidHeight', 0),
('LoLipsIn', 0),
('MouthOpen', 0),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0),
('UpLipsMidHeight', 0),
('LoLipsMidHeight', 0),
('LoLipsIn', 0),
('MouthOpen', 0),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 1.0),
('MouthNarrow_R', 1.0),
('LipsPart', 0),
('UpLipsMidHeight', 0),
('LoLipsMidHeight', 0),
('LoLipsIn', 0),
('MouthOpen', 0.4),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0.9),
('MouthNarrow_R', 0.9),
('LipsPart', 0),
('UpLipsMidHeight', 0),
('LoLipsMidHeight', 0),
('LoLipsIn', 0),
('MouthOpen', 0.8),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0.5),
('MouthNarrow_R', 0.5),
('LipsPart', 0),
('UpLipsMidHeight', 0.2),
('LoLipsMidHeight', -0.2),
('LoLipsIn', 0),
('MouthOpen', 0),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0.2),
('MouthWidth_R', 0.2),
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
Thomas Larsson
committed
('LipsPart', 1.0),
('UpLipsMidHeight', 0),
('LoLipsMidHeight', 0.3),
('LoLipsIn', 0.6),
('MouthOpen', 0),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0),
('UpLipsMidHeight', 0.5),
('LoLipsMidHeight', -0.7),
('LoLipsIn', 0),
('MouthOpen', 0),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0.8),
('MouthWidth_R', 0.8),
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
Thomas Larsson
committed
('LipsPart', 0),
('UpLipsMidHeight', 1.0),
('LoLipsMidHeight', 0),
Thomas Larsson
committed
('LoLipsIn', 0),
('MouthOpen', 0),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0.2),
('MouthWidth_R', 0.2),
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
Thomas Larsson
committed
('LipsPart', 0),
('UpLipsMidHeight', 0.6),
('LoLipsMidHeight', -0.6),
('LoLipsIn', 0),
('MouthOpen', 0.5),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0),
('UpLipsMidHeight', 0.4),
('LoLipsMidHeight', 0),
('LoLipsIn', 0),
('MouthOpen', 0.7),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0),
('UpLipsMidHeight', 0.5),
('LoLipsMidHeight', -0.6),
('LoLipsIn', 0),
('MouthOpen', 0.25),
('TongueBackHeight', 0),
('TongueHeight', 0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0),
('UpLipsMidHeight', 0),
('LoLipsMidHeight', 0),
('LoLipsIn', 0),
('MouthOpen', 0.2),
('TongueBackHeight', 1.0),
('TongueHeight', 1.0)
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0),
('UpLipsMidHeight', 0.5),
('LoLipsMidHeight', -0.5),
('LoLipsIn', 0),
('MouthOpen', -0.2),
('TongueBackHeight', 1.0),
('TongueHeight', 1.0),
],
('MouthWidth_L', 0),
('MouthWidth_R', 0),
Thomas Larsson
committed
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
('MouthNarrow_L', 0),
('MouthNarrow_R', 0),
('LipsPart', 0),
('UpLipsMidHeight', 0.5),
('LoLipsMidHeight', -0.5),
('LoLipsIn', 0),
('MouthOpen', -0.2),
('TongueBackHeight', 1.0),
('TongueHeight', 0),
],
'Blink' : [
('UpLidUp_L', 1),
('UpLidUp_R', 1),
('LoLidDown_L', 1),
('LoLidDown_R', 1)
],
'Unblink' : [
('UpLidUp_L', 0),
('UpLidUp_R', 0),
('LoLidDown_L', 0),
('LoLidDown_R', 0)
],
Thomas Larsson
committed
VisemePanelBones = {
'MouthOpen' : ('PJaw', (0,0.25)),
'UpLipsMidHeight' : ('PUpLipMid', (0,-0.25)),
'LoLipsMidHeight' : ('PLoLipMid', (0,-0.25)),
'LoLipsIn': ('PLoLipMid', (-0.25,0)),
'MouthWidth_L' : ('PMouth_L', (0.25,0)),
'MouthWidth_R' : ('PMouth_R', (-0.25,0)),
Thomas Larsson
committed
'MouthNarrow_L' : ('PMouth_L', (-0.25,0)),
'MouthNarrow_R' : ('PMouth_R', (0.25,0)),
'LipsPart' : ('PMouthMid', (0, -0.25)),
'TongueBackHeight': ('PTongue', (-0.25, 0)),
'TongueHeight' : ('PTongue', (0, -0.25)),
'UpLidUp_L' : ('PUpLid_L', (0,1.0)),
'UpLidUp_R' : ('PUpLid_R', (0,1.0)),
'LoLidDown_L' : ('PLoLid_L', (0,-1.0)),
'LoLidDown_R' : ('PLoLid_R', (0,-1.0)),
}
VisemeList = [
('Rest', 'Etc', 'AH'),
('MBP', 'OO', 'O'),
('R', 'FV', 'S'),
('SH', 'EE', 'EH'),
('TH', 'L', 'G')
]
#
# makeVisemes(ob, scn):
# class VIEW3D_OT_MhxMakeVisemesButton(bpy.types.Operator):
#
def makeVisemes(ob, scn):
if ob.type != 'MESH':
print("Active object %s is not a mesh" % ob)
return
if not ob.data.shape_keys:
print("%s has no shapekeys" % ob)
return
try:
ob.data.shape_keys.key_blocks["VIS_Rest"]
print("Visemes already created")
return
except:
pass
verts = ob.data.vertices
for (vis,shapes) in bodyLanguageVisemes.items():
if vis in ['Blink', 'Unblink']:
continue
vkey = ob.shape_key_add(name="VIS_%s" % vis)
print(vkey.name)
for n,v in enumerate(verts):
vkey.data[n].co = v.co
for (name,value) in shapes:
if name[-2:] == "_R":
continue
skey = ob.data.shape_keys.key_blocks[name]
factor = 0.75*value
for n,v in enumerate(verts):
vkey.data[n].co += factor*(skey.data[n].co - v.co)
print("Visemes made")
return
class VIEW3D_OT_MhxMakeVisemesButton(bpy.types.Operator):
bl_idname = "mhx.make_visemes"
bl_label = "Generate viseme shapekeys"
def execute(self, context):
makeVisemes(context.object, context.scene)
return{'FINISHED'}
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
#
# mohoVisemes
# magpieVisemes
#
mohoVisemes = dict({
'rest' : 'Rest',
'etc' : 'Etc',
'AI' : 'AH',
'O' : 'O',
'U' : 'OO',
'WQ' : 'AH',
'L' : 'L',
'E' : 'EH',
'MBP' : 'MBP',
'FV' : 'FV',
})
magpieVisemes = dict({
"CONS" : "t,d,k,g,T,D,s,z,S,Z,h,n,N,j,r,tS",
"AI" : "i,&,V,aU,I,0,@,aI",
"E" : "eI,3,e",
"O" : "O,@U,oI",
"UW" : "U,u,w",
"MBP" : "m,b,p",
"L" : "l",
"FV" : "f,v",
"Sh" : "dZ",
})
#
# setViseme(context, vis, setKey, frame):
# setBoneLocation(context, pbone, loc, mirror, setKey, frame):
# class VIEW3D_OT_MhxVisemeButton(bpy.types.Operator):
#
def getVisemeSet(context, rig):
try:
visset = rig['MhxVisemeSet']
except:
return bodyLanguageVisemes
if visset == 'StopStaring':
return stopStaringVisemes
elif visset == 'BodyLanguage':
return bodyLanguageVisemes
else:
raise MhxError("Unknown viseme set %s" % visset)
Thomas Larsson
committed
def setViseme(context, vis, setKey, frame):
Thomas Larsson
committed
(rig, mesh) = getMhxRigMesh(context.object)
isPanel = False
isProp = False
shapekeys = None
scale = 0.75
Thomas Larsson
committed
scale *= rig.pose.bones['PFace'].bone.length
isPanel = True
Thomas Larsson
committed
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
isProp = True
elif mesh:
shapekeys = mesh.data.shape_keys.key_blocks
visemes = getVisemeSet(context, rig)
for (skey, value) in visemes[vis]:
if isPanel:
(b, (x,z)) = VisemePanelBones[skey]
loc = mathutils.Vector((float(x*value),0,float(z*value)))
pb = rig.pose.bones[b]
pb.location = loc*scale
if setKey or context.tool_settings.use_keyframe_insert_auto:
for n in range(3):
pb.keyframe_insert('location', index=n, frame=frame, group=pb.name)
elif isProp:
skey = '&_' + skey
try:
prop = rig[skey]
except:
continue
rig[skey] = value*scale
if setKey or context.tool_settings.use_keyframe_insert_auto:
rig.keyframe_insert('["%s"]' % skey, frame=frame, group="Visemes")
elif shapekeys:
try:
shapekeys[skey].value = value*scale
except:
continue
if setKey or context.tool_settings.use_keyframe_insert_auto:
shapekeys[skey].keyframe_insert("value", frame=frame)
Thomas Larsson
committed
class VIEW3D_OT_MhxVisemeButton(bpy.types.Operator):
bl_idname = 'mhx.pose_viseme'
bl_label = 'Viseme'
viseme = StringProperty()
def invoke(self, context, event):
setViseme(context, self.viseme, False, context.scene.frame_current)
return{'FINISHED'}
#
# openFile(context, filepath):
# readMoho(context, filepath, offs):
# readMagpie(context, filepath, offs):
#
def openFile(context, filepath):
(path, fileName) = os.path.split(filepath)
(name, ext) = os.path.splitext(fileName)
return open(filepath, "rU")
def readMoho(context, filepath, offs):
Thomas Larsson
committed
(rig, mesh) = getMhxRigMesh(context.object)
context.scene.objects.active = rig
bpy.ops.object.mode_set(mode='POSE')
fp = openFile(context, filepath)
for line in fp:
words= line.split()
if len(words) < 2:
pass
else:
vis = mohoVisemes[words[1]]
setViseme(context, vis, True, int(words[0])+offs)
fp.close()
setInterpolation(rig)
print("Moho file %s loaded" % filepath)
return
def readMagpie(context, filepath, offs):
Thomas Larsson
committed
rig,mesh = getMhxRigMesh(context.object)
context.scene.objects.active = rig
bpy.ops.object.mode_set(mode='POSE')
fp = openFile(context, filepath)
for line in fp:
words= line.split()
if len(words) < 3:
pass
elif words[2] == 'X':
vis = magpieVisemes[words[3]]
setViseme(context, vis, True, int(words[0])+offs)
fp.close()
setInterpolation(rig)
print("Magpie file %s loaded" % filepath)
return
#
# class VIEW3D_OT_MhxLoadMohoButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxLoadMohoButton(bpy.types.Operator):
bl_idname = "mhx.pose_load_moho"
bl_label = "Moho (.dat)"
filepath = StringProperty(subtype='FILE_PATH')
startFrame = IntProperty(name="Start frame", description="First frame to import", default=1)
def execute(self, context):
import bpy, os, mathutils
readMoho(context, self.properties.filepath, self.properties.startFrame-1)
return{'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
#
# class VIEW3D_OT_MhxLoadMagpieButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxLoadMagpieButton(bpy.types.Operator):
bl_idname = "mhx.pose_load_magpie"
bl_label = "Magpie (.mag)"
filepath = StringProperty(subtype='FILE_PATH')
startFrame = IntProperty(name="Start frame", description="First frame to import", default=1)
def execute(self, context):
import bpy, os, mathutils
readMagpie(context, self.properties.filepath, self.properties.startFrame-1)
return{'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
#
# class MhxLipsyncPanel(bpy.types.Panel):
#
class MhxLipsyncPanel(bpy.types.Panel):
bl_label = "MHX Lipsync"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
def draw(self, context):
Thomas Larsson
committed
rig,mesh = getMhxRigMesh(context.object)
if not rig:
return
layout = self.layout
layout.label(text="Visemes")
for (vis1, vis2, vis3) in VisemeList:
row = layout.row()
row.operator("mhx.pose_viseme", text=vis1).viseme = vis1
row.operator("mhx.pose_viseme", text=vis2).viseme = vis2
row.operator("mhx.pose_viseme", text=vis3).viseme = vis3
layout.separator()
row = layout.row()
row.operator("mhx.pose_viseme", text="Blink").viseme = 'Blink'
row.operator("mhx.pose_viseme", text="Unblink").viseme = 'Unblink'
layout.label(text="Load file")
row = layout.row()
row.operator("mhx.pose_load_moho")
row.operator("mhx.pose_load_magpie")
layout.operator("mhx.update")
layout.separator()
layout.operator("mhx.make_visemes")
#
# class VIEW3D_OT_MhxUpdateButton(bpy.types.Operator):
#
def updatePose(context):
scn = context.scene
Thomas Larsson
committed
scn.frame_current = scn.frame_current
bpy.ops.object.posemode_toggle()
bpy.ops.object.posemode_toggle()
return
class VIEW3D_OT_MhxUpdateButton(bpy.types.Operator):
bl_idname = "mhx.update"
bl_label = "Update"
def execute(self, context):
return{'FINISHED'}
###################################################################################
#
# Expression panel
#
###################################################################################
#
# class VIEW3D_OT_MhxResetExpressionsButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxResetExpressionsButton(bpy.types.Operator):
bl_idname = "mhx.pose_reset_expressions"
bl_label = "Reset expressions"
def execute(self, context):
Thomas Larsson
committed
rig,mesh = getMhxRigMesh(context.object)
props = getShapeProps(rig)
for (prop, name) in props:
rig[prop] = 0.0
return{'FINISHED'}
#
# class VIEW3D_OT_MhxKeyExpressionButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxKeyExpressionsButton(bpy.types.Operator):
bl_idname = "mhx.pose_key_expressions"
bl_label = "Key expressions"
def execute(self, context):
Thomas Larsson
committed
rig,mesh = getMhxRigMesh(context.object)
props = getShapeProps(rig)
frame = context.scene.frame_current
for (prop, name) in props:
rig.keyframe_insert('["%s"]' % prop, frame=frame)
return{'FINISHED'}
#
# class VIEW3D_OT_MhxPinExpressionButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxPinExpressionButton(bpy.types.Operator):
bl_idname = "mhx.pose_pin_expression"
bl_label = "Pin"
expression = StringProperty()
def execute(self, context):
Thomas Larsson
committed
rig,mesh = getMhxRigMesh(context.object)
props = getShapeProps(rig)
if context.tool_settings.use_keyframe_insert_auto:
frame = context.scene.frame_current
for (prop, name) in props:
old = rig[prop]
if prop == self.expression:
rig[prop] = 1.0
else:
rig[prop] = 0.0
if abs(rig[prop] - old) > 1e-3:
rig.keyframe_insert('["%s"]' % prop, frame=frame)
else:
for (prop, name) in props:
if prop == self.expression:
rig[prop] = 1.0
else:
rig[prop] = 0.0
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
return{'FINISHED'}
#
# getShapeProps(ob):
#
def getShapeProps(rig):
props = []
plist = list(rig.keys())
plist.sort()
for prop in plist:
if prop[0] == '*':
props.append((prop, prop[1:]))
return props
#
# class MhxExpressionsPanel(bpy.types.Panel):
#
class MhxExpressionsPanel(bpy.types.Panel):
bl_label = "MHX Expressions"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
def draw(self, context):
Thomas Larsson
committed
layout = self.layout
rig,mesh = getMhxRigMesh(context.object)
Thomas Larsson
committed
print("No MHX rig found")
return
Thomas Larsson
committed
layout.label("No shapekey drivers.")
layout.label("Set expression values in mesh context instead")
return
props = getShapeProps(rig)
if not props:
return
layout.label(text="Expressions")
layout.operator("mhx.pose_reset_expressions")
layout.operator("mhx.pose_key_expressions")
#layout.operator("mhx.update")
layout.separator()
for (prop, name) in props:
Thomas Larsson
committed
row = layout.split(0.85)
row.prop(rig, '["%s"]' % prop, text=name)
Thomas Larsson
committed
row.operator("mhx.pose_pin_expression", text="", icon='UNPINNED').expression = prop
Thomas Larsson
committed
#########################################
#
Thomas Larsson
committed
#
#########################################
def getPoseMatrix(mat, pb):
restInv = pb.bone.matrix_local.inverted()
parInv = pb.parent.matrix.inverted()
parRest = pb.parent.bone.matrix_local
return restInv * (parRest * (parInv * mat))
Thomas Larsson
committed
else:
Thomas Larsson
committed
def getGlobalMatrix(mat, pb):
gmat = pb.bone.matrix_local * mat
if pb.parent:
parMat = pb.parent.matrix
parRest = pb.parent.bone.matrix_local
return parMat * (parRest.inverted() * gmat)
else:
return gmat
Thomas Larsson
committed
def matchPoseTranslation(pb, fkPb, auto):
mat = getPoseMatrix(fkPb.matrix, pb)
insertLocation(pb, mat, auto)
Thomas Larsson
committed
def insertLocation(pb, mat, auto):
pb.location = mat.to_translation()
if auto:
pb.keyframe_insert("location", group=pb.name)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
Thomas Larsson
committed
def matchPoseRotation(pb, fkPb, auto):
mat = getPoseMatrix(fkPb.matrix, pb)
insertRotation(pb, mat, auto)
Thomas Larsson
committed
def insertRotation(pb, mat, auto):
Thomas Larsson
committed
q = mat.to_quaternion()
if pb.rotation_mode == 'QUATERNION':
pb.rotation_quaternion = q
if auto:
pb.keyframe_insert("rotation_quaternion", group=pb.name)
Thomas Larsson
committed
else:
pb.rotation_euler = q.to_euler(pb.rotation_mode)
if auto:
pb.keyframe_insert("rotation_euler", group=pb.name)
Thomas Larsson
committed
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
def matchPoseReverse(pb, fkPb, auto):
Thomas Larsson
committed
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
gmat = fkPb.matrix * Matrix.Rotation(math.pi, 4, 'Z')
offs = pb.bone.length * fkPb.matrix.col[1]
gmat[0][3] += offs[0]
gmat[1][3] += offs[1]
gmat[2][3] += offs[2]
mat = getPoseMatrix(gmat, pb)
pb.matrix_basis = mat
insertLocation(pb, mat, auto)
insertRotation(pb, mat, auto)
Thomas Larsson
committed
def matchPoseScale(pb, fkPb, auto):
mat = getPoseMatrix(fkPb.matrix, pb)
pb.scale = mat.to_scale()
if auto:
pb.keyframe_insert("scale", group=pb.name)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
Thomas Larsson
committed
def fk2ikArm(context, suffix):
rig = context.object
auto = context.scene.tool_settings.use_keyframe_insert_auto
print("Snap FK Arm%s" % suffix)
(uparmIk, loarmIk, elbow, elbowPt, wrist) = getSnapBones(rig, "ArmIK", suffix)
(uparmFk, loarmFk, elbowPtFk, handFk) = getSnapBones(rig, "ArmFK", suffix)
Thomas Larsson
committed
matchPoseRotation(uparmFk, uparmFk, auto)
matchPoseScale(uparmFk, uparmFk, auto)
Thomas Larsson
committed
matchPoseRotation(loarmFk, loarmFk, auto)
matchPoseScale(loarmFk, loarmFk, auto)
Thomas Larsson
committed
if rig["&HandFollowsWrist" + suffix]:
matchPoseRotation(handFk, wrist, auto)
matchPoseScale(handFk, wrist, auto)
Thomas Larsson
committed
return
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["&ElbowFollowsShoulder" + suffix] = False
#rig["&ElbowFollowsWrist" + 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)
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
(uplegIk, lolegIk, kneePt, ankleIk, legIk, legFk, footIk, toeIk) = getSnapBones(rig, "LegIK", suffix)
(uplegFk, lolegFk, kneePtFk, footFk, toeFk) = getSnapBones(rig, "LegFK", suffix)
#rig["&KneeFollowsHip" + suffix] = False
#rig["&KneeFollowsFoot" + suffix] = False
legIkToAnkle = rig["&LegIkToAnkle" + suffix]
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)
if prop[:4] == "&Arm":
fk2ikArm(context, prop[-2:])
elif prop[:4] == "&Leg":
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)
if prop[:4] == "&Arm":
ik2fkArm(context, prop[-2:])
elif prop[:4] == "&Leg":
ik2fkLeg(context, prop[-2:])
restoreSnapProp(rig, prop, old, context)
Thomas Larsson
committed
return{'FINISHED'}
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]