This commit is contained in:
Jeffreytsai1004 2025-01-14 03:07:03 +08:00
parent 5c8bc871af
commit de7ea0e64f
28 changed files with 8451 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 yxnhyxnh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,236 @@
# -*- coding: utf-8 -*-
'''
this plugin is created for use with autodesk maya 2018+.
(because it import pyside2 module,and i don't know in which version maya would update this.)
'''
import sys
import maya.api.OpenMaya as om
import mocaphelperui
import mocaphelpersaccore
import mocaphelperfacore
import mocaphelperutility
import PySide2.QtWidgets
from PySide2 import QtCore
version = 1.44
ui = None
translator = QtCore.QTranslator()
def maya_useNewAPI():
"""
The presence of this function tells Maya that the plugin produces, and
expects to be passed, objects created using the Maya Python API 2.0.
"""
pass
# Initialize the plug-in
def initializePlugin(plugin):
pluginFn = om.MFnPlugin(plugin)
try:
pluginFn.registerCommand(
mocaphelpersaccore.SmoothAnimCurve.kPluginCmdName, mocaphelpersaccore.SmoothAnimCurve.cmdCreator,mocaphelpersaccore.syntaxCreator
)
except:
sys.stderr.write(
"Failed to register command: %s\n" % mocaphelpersaccore.SmoothAnimCurve.kPluginCmdName
)
raise
try:
pluginFn.registerCommand(
openui.kPluginCmdName, openui.cmdCreator,openuiSyntaxCreator
)
except:
sys.stderr.write(
"Failed to register command: %s\n" % openui.kPluginCmdName
)
raise
try:
pluginFn.registerCommand(
mocaphelperfacore.FrameAlign.kPluginCmdName, mocaphelperfacore.FrameAlign.cmdCreator,mocaphelperfacore.syntaxCreator
)
except:
sys.stderr.write(
"Failed to register command: %s\n" % mocaphelperfacore.FrameAlign.kPluginCmdName
)
raise
try:
pluginFn.registerCommand(
Eval.kPluginCmdName, Eval.cmdCreator,evalSyntaxCreator
)
except:
sys.stderr.write(
"Failed to register command: %s\n" % Eval.kPluginCmdName
)
raise
# Uninitialize the plug-in
def uninitializePlugin(plugin):
pluginFn = om.MFnPlugin(plugin)
try:
pluginFn.deregisterCommand(mocaphelpersaccore.SmoothAnimCurve.kPluginCmdName)
except:
sys.stderr.write(
"Failed to unregister command: %s\n" % mocaphelpersaccore.SmoothAnimCurve.kPluginCmdName
)
raise
try:
pluginFn.deregisterCommand(openui.kPluginCmdName)
except:
sys.stderr.write(
"Failed to unregister command: %s\n" % openui.kPluginCmdName
)
raise
try:
pluginFn.deregisterCommand(mocaphelperfacore.FrameAlign.kPluginCmdName)
except:
sys.stderr.write(
"Failed to unregister command: %s\n" % mocaphelperfacore.FrameAlign.kPluginCmdName
)
raise
try:
pluginFn.deregisterCommand(Eval.kPluginCmdName)
except:
sys.stderr.write(
"Failed to unregister command: %s\n" % Eval.kPluginCmdName
)
raise
# command
class openui(om.MPxCommand):
kPluginCmdName = "moCapHelper_showUi"
uiLanguageFlagShortName = "lan"
uiLanguageFlagLongName = "language"
lang = None
def __init__(self):
om.MPxCommand.__init__(self)
@staticmethod
def cmdCreator():
return openui()
def parseArguments(self,args):
argdata = om.MArgParser(self.syntax(),args)
if argdata.isFlagSet( self.uiLanguageFlagShortName ):
self.lang = argdata.flagArgumentString(self.uiLanguageFlagShortName,0)
else:
self.lang = None
def doIt(self, args):
self.parseArguments(args)
global ui
if ui != None:
print("saved ui ref:",ui)
print("closing ui:--------",ui.destroy(True,True))
app = PySide2.QtWidgets.QApplication.instance()
app.installTranslator(translator)
dir = mocaphelperutility.getDir()
# translate:
if self.lang == "CN":
translator.load("ui_CN",dir)
ui = mocaphelperui.MoCapHelperUI()
ui.setWindowTitle('动补助手 v'+str(version))
# print(translator.filePath())
# print(translator.translate())
# mocaphelperui.translateUi(ui.ui,ui.ui)
else:
translator.load("")
ui = mocaphelperui.MoCapHelperUI()
ui.show()
def openuiSyntaxCreator():
syntax = om.MSyntax()
syntax.addFlag( openui.uiLanguageFlagShortName, openui.uiLanguageFlagLongName, om.MSyntax.kString )
return syntax
class Eval(om.MPxCommand):
kPluginCmdName = "moCapHelper_eval"
strFlagShortName = "s"
strFlagLongName = "string"
cmd = ""
def __init__(self):
om.MPxCommand.__init__(self)
def parseArguments(self,args):
argdata = om.MArgParser(self.syntax(),args)
if argdata.isFlagSet( self.strFlagShortName ):
self.cmd = argdata.flagArgumentString(self.strFlagShortName,0)
else:
raise Exception("no str input")
@staticmethod
def cmdCreator():
return Eval()
def doIt(self, args):
self.parseArguments(args)
print(self.cmd)
global ui
if ui != None:
exec(self.cmd)
else:
raise Exception("please create ui first.")
def evalSyntaxCreator():
syntax = om.MSyntax()
syntax.addFlag( Eval.strFlagShortName, Eval.strFlagLongName, om.MSyntax.kString )
return syntax

View File

@ -0,0 +1,217 @@
# -*- coding: utf-8 -*-
import maya.cmds as cmds
import maya.mel as mel
import mocaphelperutility
import math
def createLoc(strname,cd = (0,0,0),rot = (0,0,0),roo = "xyz"):
locname = cmds.spaceLocator(name = strname)
mocaphelperutility.setWorldPos(locname,cd)
mocaphelperutility.setWorldRot(locname,rot,roo)
return locname
def reposition(objA,objB):
tempp = mocaphelperutility.getWorldPos(objB)
tempr = mocaphelperutility.getWorldRot(objB)
temproo = mocaphelperutility.getRotOrder(objB)
mocaphelperutility.setWorldPos(objA,tempp)
mocaphelperutility.setWorldRot(objA,tempr,temproo)
def checkConstraint(obj):
parent = cmds.parentConstraint(obj, targetList = True ,q = True )
point = cmds.pointConstraint(obj, targetList = True ,q = True )
orient = cmds.orientConstraint(obj, targetList = True ,q = True )
if parent == None and point == None and orient == None:
return False
else:
conslist = [parent,point,orient]
return conslist
def deleteAllConstraint(obj):
cmds.delete(obj,cn=True)
def createPointConstraint(ctrlobj,targetobj,maintainoffset = False):
name = cmds.pointConstraint(ctrlobj,targetobj,mo = maintainoffset)
return name
def createOrientConstraint(ctrlobj,targetobj,maintainoffset = False):
name = cmds.orientConstraint(ctrlobj,targetobj,mo = maintainoffset)
return name
def createParentConstraint(ctrlobj,targetobj,maintainoffset = False):
name = cmds.parentConstraint(ctrlobj,targetobj,mo = maintainoffset)
return name
'''
def deletePointConstraint(ctrlobj,targetobj):
cmds.pointConstraint(ctrlobj,targetobj,remove = True)
def deleteParentConstraint(ctrlobj,targetobj):
cmds.parentConstraint(ctrlobj,targetobj,remove = True)
def deleteOrientConstraint(ctrlobj,targetobj):
cmds.orientConstraint(ctrlobj,targetobj,remove = True)
'''
def bake(objs,mintime,maxtime,type = "all"):
# if smartbake == True:
if type == "all":
cmds.bakeResults(objs,t =(mintime,maxtime),simulation = True)
else:
if type == "parent":
atb = ["tx","ty","tz","sx","sy","sz","rx","ry","rz"]
elif type == "point":
atb = ["tx","ty","tz"]
elif type == "orient":
atb = ["rx","ry","rz"]
elif type == "onlyscale":
atb = ["sx","sy","sz"]
else:
raise Exception("bake error:type unidentified:",type)
cmds.bakeResults(objs,t =(mintime,maxtime),at = atb)
def smartbake(objs,mintime,maxtime,type = "all"):
if type == "all":
cmds.bakeResults(objs,t =(mintime,maxtime),smart = True,simulation = True)
else:
if type == "parent":
atb = ["tx","ty","tz","sx","sy","sz","rx","ry","rz"]
elif type == "point":
atb = ["tx","ty","tz"]
elif type == "orient":
atb = ["rx","ry","rz"]
elif type == "onlyscale":
atb = ["sx","sy","sz"]
else:
raise Exception("bake error:type unidentified")
cmds.bakeResults(objs,t =(mintime,maxtime),smart = True,at = atb)
def deleteInrange(objs,start,end):
if cmds.keyframe(objs,q = True) == None :
raise Exception("ref has no keys!")
else:
mocaphelperutility.cutKey(objs,start+0.01,end-0.01)
# mocaphelperutility.autoKetTangent(objs,start,start)
# mocaphelperutility.autoKetTangent(objs,end,end)
def deleteOutrange(objs,start,end):
if cmds.keyframe(objs,q = True) == None :
raise Exception("ref has no keys!")
framelist = set(cmds.keyframe(objs,q = True))
minframe = min(framelist)
maxframe = max(framelist)
if minframe < start:
mocaphelperutility.cutKey(objs,minframe,start-0.01)
# mocaphelperutility.autoKetTangent(objs,start,start)
if maxframe > end:
mocaphelperutility.cutKey(objs,end+0.01,maxframe)
# mocaphelperutility.autoKetTangent(objs,end,end)
def offsetFrame(objs,offset):
cmds.keyframe(objs,e = True,tc = float(offset),o = "over",relative = True)
def stickyDelete(ui):
objs = mocaphelperutility.getSelectedNodes()
fromframe = eval(ui.ui.arb_fromEdit.text())
curframe = mocaphelperutility.getCurrentFrame()
if fromframe != curframe:
mocaphelperutility.cutKey(objs,fromframe,curframe,True)
mocaphelperutility.autoKetTangent(objs,fromframe,curframe)
ui.ui.arb_fromEdit.setText(str(curframe))
ui.ui.arb_toEdit.setText(str(curframe))
else:
raise Exception("from == curframe")
def bakeAtoB(A,B,start,end,type,maintainoffset = False,smart = False):
print("type == ",type)
if type == "parent" or type == "all":
cons = createParentConstraint(A,B,maintainoffset)
elif type == "point":
cons = createPointConstraint(A,B,maintainoffset)
elif type == "orient":
cons = createOrientConstraint(A,B,maintainoffset)
elif type == "onlyscale":
cons = createParentConstraint(A,B,maintainoffset)
if smart:
smartbake(B,start,end,type)
else:
bake(B,start,end,type)
mocaphelperutility.deleteObj(cons)
def pinCurPos(objs,mintime,maxtime):
min = mintime
max = maxtime
if min > max:
min = maxtime
max = mintime
if min == max:
raise Exception("min == max.")
cdlist = []
# cmds.currentTime(min)
for obj in objs:
pos = mocaphelperutility.getWorldPos(obj)
rot = mocaphelperutility.getWorldRot(obj)
cdlist.append([pos,rot])
for i in range(int(math.floor(min)),int(math.ceil(max)+1)):
cmds.currentTime(float(i))
cmds.setKeyframe(objs,at = ["tx","ty","tz","rx","ry","rz"])
for i in range(len(objs)):
pos = cdlist[i][0]
rot = cdlist[i][1]
cmds.xform(objs[i],ws = True,translation = pos,rotation = rot)
def pinParentPos(objs,mintime,maxtime):
leng = len(objs)
if leng <= 1:
raise Exception("not enough obj selected,at least 2.")
min = mintime
max = maxtime
if min > max:
min = maxtime
max = mintime
if min == max:
raise Exception("min == max.")
# cmds.currentTime(min)
consobj = objs[:-1]
beconsobj = objs[-1]
pos = mocaphelperutility.getWorldPos(beconsobj)
rot = mocaphelperutility.getWorldRot(beconsobj)
roo = mocaphelperutility.getRotOrder(beconsobj)
loc = createLoc("mocaphelper_arb_pinparent_temp_loc",pos,rot,roo)[0]
createParentConstraint(consobj,loc,True)
bake(loc,min,max,type="parent")
for i in range(int(math.floor(min)),int(math.ceil(max)+1)):
cmds.currentTime(float(i))
cmds.setKeyframe(beconsobj,at = ["tx","ty","tz","rx","ry","rz"])
reposition(beconsobj,loc)
mocaphelperutility.deleteObj(loc)
mocaphelperutility.selectNodes(beconsobj)

View File

@ -0,0 +1,100 @@
import maya.api.OpenMaya as om
import maya.api.OpenMayaAnim as omani
import maya.cmds as cmds
import maya.mel as mel
import mocaphelperutility
refobjsShortFlagName = "-ref"
refobjsLongFlagName = "-refobjs"
def syntaxCreator():
syntax = om.MSyntax()
syntax.addFlag( refobjsShortFlagName, refobjsLongFlagName, om.MSyntax.kString )
return syntax
class FrameAlign(om.MPxCommand):
kPluginCmdName = "moCapHelper_frameAlign"
ref = ""
animcruvechanage = None
def __init__(self):
om.MPxCommand.__init__(self)
@staticmethod
def cmdCreator():
return FrameAlign()
def parseArguments(self,args):
argdata = om.MArgParser(self.syntax(),args)
if argdata.isFlagSet( refobjsShortFlagName ):
self.ref = argdata.flagArgumentString(refobjsShortFlagName,0)
else:
raise Exception("No refence argument!")
def isUndoable(self):
return True
def doIt(self,args):
self.animcruvechanage = omani.MAnimCurveChange()
self.parseArguments(args)
# start = cmds.playbackOptions( q=True,min=True )
# end = cmds.playbackOptions( q=True,max=True )
if mocaphelperutility.objExist(self.ref) == False:
raise Exception("ref obj does not exist!")
selectedobjs = mocaphelperutility.getSelectedNodes()
print(self.ref)
if cmds.keyframe(self.ref,q = True) == None :
raise Exception("ref has no keys!")
else:
framelist = set(cmds.keyframe(self.ref,q = True))
for frame in framelist:
cmds.setKeyframe(selectedobjs,t = (frame,frame),rk= True,hierarchy = "none",i = True,itt = "auto")
for obj in selectedobjs:
objframelist = set(cmds.keyframe(obj,q = True))
for objframe in objframelist:
if objframe in framelist:
continue
else:
mocaphelperutility.cutKey(obj,objframe,objframe)
def undoIt(self):
if self.animcruvechanage != None :
self.animcruvechanage.undoIt()
print("undo success")
else:
print("undo failed:self.animcruvechanage == None")
def redoIt(self):
if self.animcruvechanage != None :
self.animcruvechanage.redoIt()
print("redo success")
else:
print("redo failed:self.animcruvechanage == None")
# def cutlist(sourcelist,splitlist):
# backindex = 0
# forwardindex = 0
# for i in len(sourcelist):
# if sourcelist[i] in splitlist:
# def fastRecord(obj):
# pos = mocaphelperutility.getWorldPos(obj)
# loc = mocaphelperarbcore.createLoc("mocaphelper_fa_temp_loc")

View File

@ -0,0 +1,53 @@
import datetime
import getpass
import glob
import os
import shutil
import subprocess
import maya.cmds as cmds
import maya.mel as mel
PREV_DIR_ENV = "Mocaphelper_Playblast_Path"
def get_prev_path():
if cmds.optionVar(exists=PREV_DIR_ENV):
return cmds.optionVar(q=PREV_DIR_ENV)
else:
return None
def set_prev_path(dir_path):
cmds.optionVar(sv=(PREV_DIR_ENV, dir_path))
def getMagicMaskNode():
magic_mask_nodes = cmds.ls(type='magicMask')
if magic_mask_nodes == None:
return None
else:
return magic_mask_nodes[0]
def resetHUD():
mel.eval('source "initHUD";')
def removeHUD():
default_hud_list = cmds.headsUpDisplay(lh=True)
if default_hud_list:
for default_hud in default_hud_list:
cmds.headsUpDisplay(default_hud, rem=True)
# cmds.setAttr('%s.displayFilmGate' % main_cam, 0)
# cmds.setAttr('%s.displayResolution' % main_cam, 0)
def moCapHelper_Playblast(cam,filepath,offscreen):
pass

View File

@ -0,0 +1,168 @@
import maya.api.OpenMaya as om
import maya.cmds as cmds
import maya.mel as mel
import re
import mocaphelperutility
def retestlist(strlist,exp,casecheck = False):
matchlist = []
pyVersion = mocaphelperutility.getPythonVersion()
if pyVersion < 3:
if (type(exp)== unicode ):
raw_exp = repr(exp)[2:-1]
elif (type(exp)== str ):
raw_exp = exp
else:
raise Exception("unidentified string format input!")
else:
raw_exp = exp
print("convert---"+exp+"---to---"+raw_exp)
for longname in strlist:
shortname = longname2shortname(longname)[0]
print("checking:---exp---"+raw_exp+"---objname---"+shortname)
if casecheck == False:
if re.search(raw_exp,shortname,re.I) != None:
matchlist.append(longname)
print("succeed")
else:
print("failed")
continue
else:
if re.search(raw_exp,shortname) != None:
matchlist.append(longname)
print("succeed")
else:
print("failed")
continue
if len(matchlist) == 0:
print("no obj match expression!")
return None
else:
return matchlist
def expCreateDisplayLayer(exp,name,prefix = "",casecheck = False,childcheck = True,nodetype = "all"):
selected = mocaphelperutility.getSelectedNodes()
if childcheck:
untestlist = mocaphelperutility.getChildNodes(selected,nodetype=nodetype)
else:
untestlist = selected
combinelist = []
#check for multiple exp exist
if exp.find(";") != -1 or name.find(";") != -1:
splitedexplist = exp.split(";")
splitednamelist = name.split(";")
if len(splitedexplist) != len(splitednamelist):
raise Exception("name and exp count not match!")
else:
for i in range(len(splitedexplist)):
combinelist.append([splitedexplist[i],splitednamelist[i]])
else:
combinelist =[[exp,name]]
for combine in combinelist:
matchlist = retestlist(untestlist,combine[0],casecheck)
print("matchlist:",matchlist)
createDisplayLayer(prefix+combine[1],matchlist)
def createDisplayLayer(name,objlist):
cmds.createDisplayLayer(n= name,nr = True,empty = True)
cmds.editDisplayLayerMembers(name,objlist,nr = True)
def extractLayerInfo(ui):
name = cmds.editDisplayLayerGlobals( query=True, cdl=True )
members =cmds.editDisplayLayerMembers( name, query=True )
exp = ""
for member in members:
noPrefixMember = deleteRigPrefix(member)
if noPrefixMember[1] == True:
exp = exp+"."+ noPrefixMember[0] +"|"
else:
exp = exp+ noPrefixMember[0] +"|"
# remove last "|",cause it will match all name str.
exp = exp[0:-1]
ui.ui.re_layerNameEdit.setText(name)
ui.ui.re_expEdit.setText(exp)
return
def selMainCtrl():
# main name:
# ".MainExtra2" ".wenchangtai" ".Main_all"
curves = cmds.ls(type = "dagNode")
curves = mocaphelperutility.filterCertainTypeInList(curves,type = "nurbsCurve")
matchlist = []
a = retestlist(curves,".MainExtra2$|.wenchangtai$|.Main_all$")
if a != None:
matchlist += a
cmds.select(cl = True)
cmds.select(matchlist)
def longname2shortname(name):
id = name.rfind("|")
if id == -1:
return name,False
else:
return name[id+1:],True
def deleteRigPrefix(name):
id = name.rfind(":")
if id == -1:
return name,False
else:
return name[id:],True
def presetfileRebuild(filepath,backupfilepath):
backupstr = presetFileRead(backupfilepath)
presetFileWrite(filepath,backupstr)
def rawStrBuild(rawstr):
split = rawstr.split("\n")
newlist = []
for i in range(int(len(split)/2)):
name = split[2*i]
exp = split[2*i+1]
newlist.append([name,exp])
if len(newlist) == 0:
raise Exception("split list is empty!")
else:
return newlist
def strAppend(oristr,line1,line2):
newstr = oristr+"\n"+str(line1)+"\n"+str(line2)
return newstr
def presetFileRead(filepath):
file = open(filepath,mode ="r+")
file.seek(0,0)
raw = file.read()
file.close()
return raw
def presetFileWrite(filepath,str):
print("writing file:\n"+str)
file = open(filepath,mode ="w+")
file.seek(0,0)
file.write(str)
file.close()

View File

@ -0,0 +1,278 @@
import maya.api.OpenMaya as om
import maya.api.OpenMayaAnim as omani
import maya.cmds as cmds
import maya.mel as mel
import math
# selectionList = om.MGlobal.getActiveSelectionList()
# iterator = om.MItSelectionList( selectionList, om.MFn.kDagNode )
methodShortFlagName = "-m"
methodLongFlagName = "-method"
iterShortFlagName = "-i"
iterLongFlagName = "-iteration"
intensityShortFlagName = "-in"
intensityLongFlagName = "-intensity"
seltypeShortFlagName = "-sel"
seltypeLongFlagName = "-selecttype"
useTimeShortFlagName = "-u"
useTimeLongFlagName = "-usetime"
timeUnitShortFlagName = "-tu"
timeUnitLongFlagName = "-timeunit"
def syntaxCreator():
syntax = om.MSyntax()
syntax.addFlag( methodShortFlagName, methodLongFlagName, om.MSyntax.kString )
syntax.addFlag( iterShortFlagName, iterLongFlagName, om.MSyntax.kLong )
syntax.addFlag( intensityShortFlagName, intensityLongFlagName, om.MSyntax.kDouble )
syntax.addFlag( seltypeShortFlagName, seltypeLongFlagName, om.MSyntax.kLong )
syntax.addFlag( useTimeShortFlagName, useTimeLongFlagName, om.MSyntax.kBoolean )
syntax.addFlag( timeUnitShortFlagName, timeUnitLongFlagName, om.MSyntax.kDouble )
return syntax
class SmoothAnimCurve(om.MPxCommand):
kPluginCmdName = "moCapHelper_smoothAniCurve"
method = 0
iteration = 1
intensity = 1.0
seltype = 0
useTime = True
timeUnit = 5.0
animcruvechanage = None
def __init__(self):
om.MPxCommand.__init__(self)
def parseArguments(self,args):
argdata = om.MArgParser(self.syntax(),args)
if argdata.isFlagSet( methodShortFlagName ):
if argdata.flagArgumentString(methodShortFlagName,0) == "3linear":
self.method = 0
elif argdata.flagArgumentString(methodShortFlagName,0) == "3bell":
self.method = 1
elif argdata.flagArgumentString(methodShortFlagName,0) == "3ham":
self.method = 2
elif argdata.flagArgumentString(methodShortFlagName,0) == "5quad":
self.method = 10
elif argdata.flagArgumentString(methodShortFlagName,0) == "5bell":
self.method = 11
elif argdata.flagArgumentString(methodShortFlagName,0) == "5ham":
self.method = 12
else:
raise Exception("input method argument is not vaild!"+str(argdata.flagArgumentString(methodShortFlagName,0)))
else:
raise Exception("no input method argument")
if argdata.isFlagSet( iterShortFlagName ):
if argdata.flagArgumentInt(iterShortFlagName,0) <= 100:
self.iteration = argdata.flagArgumentInt(iterShortFlagName,0)
else:
raise Exception("iteration is bigger than 100,little bit too high,right?")
if argdata.isFlagSet( intensityShortFlagName ):
self.intensity = argdata.flagArgumentFloat(intensityShortFlagName,0)
if argdata.isFlagSet( seltypeShortFlagName ):
self.seltype = argdata.flagArgumentInt(seltypeShortFlagName,0)
if argdata.isFlagSet( useTimeShortFlagName ):
self.useTime = argdata.flagArgumentBool(useTimeShortFlagName,0)
if argdata.isFlagSet( timeUnitShortFlagName ):
self.timeUnit = argdata.flagArgumentFloat(timeUnitShortFlagName,0)
@staticmethod
def cmdCreator():
return SmoothAnimCurve()
def doIt(self, args):
self.animcruvechanage = omani.MAnimCurveChange()
self.parseArguments(args)
animcurves = self.getanimcurves()
for iter in range(self.iteration):
for cv in animcurves:
keylist = self.getkeylist(cv)
templist = self.smoothkeylistvalue(cv,keylist)
print(templist)
mslist = om.MGlobal.getSelectionListByName(repr(cv)[2:-1])
mit = om.MItSelectionList(mslist)
mobj = mit.getDependNode()
manimcurve = omani.MFnAnimCurve(mobj)
curveisangular = False
if manimcurve.animCurveType == manimcurve.kAnimCurveTA or manimcurve.animCurveType == manimcurve.kAnimCurveUA :
curveisangular = True
for i in templist:
if curveisangular:
value = math.radians(i[1])
else:
value = i[1]
manimcurve.setValue(i[0],value,self.animcruvechanage)
pass
print("using smoothanimcurve cmd with argument:\nselect type:",self.seltype,"\niteration:",self.iteration,"\nintensity:",self.intensity,"\nusetime:",self.useTime,"\ntimeunit:",self.timeUnit,"\nmethod:",self.method)
def undoIt(self):
if self.animcruvechanage != None :
self.animcruvechanage.undoIt()
print("undo success")
else:
print("undo failed:self.animcruvechanage == None")
def redoIt(self):
if self.animcruvechanage != None :
self.animcruvechanage.redoIt()
print("redo success")
else:
print("redo failed:self.animcruvechanage == None")
def isUndoable(self):
return True
def getanimcurves(self):
selectflag = cmds.animCurveEditor("graphEditor1GraphEd",query = True,areCurvesSelected = True)
showncurves = cmds.animCurveEditor("graphEditor1GraphEd",query = True,curvesShown = True)
selectedcurves = cmds.keyframe(q = True,s = True,name = True)
isoflag = 0
if showncurves == None:
raise Exception("plugin can't find any curve in graph editor,no curve shown or selected.")
else:
isoflag = len(showncurves) != len(selectedcurves)
if selectflag:
return selectedcurves
if isoflag:
self.seltype == 0
return showncurves
else:
raise Exception("plugin can't find any curve in graph editor,no curve shown or selected.")
# if selectflag:
# return selectedcurves
# else:
# return showncurves
# print(showncurves)
# print("----------------")
# print(selectedcurves)
def getkeylist(self,animcurve):
numkeys = cmds.keyframe(animcurve,q = True,keyframeCount = True)
keylist = []
#seltype == 0 :all keys on curves
if self.seltype == 0:
for i in range(numkeys):
keylist.append([i,0.0])
#seltype == 1 :selected keys only
elif self.seltype == 1:
numselkeyindexlist = cmds.keyframe(animcurve,sl = True,q=True,indexValue = True)
for index in numselkeyindexlist:
keylist.append([int(index),0.0])
return keylist
def smoothkeylistvalue(self,curve,keylist):
flag5pt = False
compareint = 0
if self.method>=9:
compareint = 1
flag5pt = True
numkeys = cmds.keyframe(curve,q = True,keyframeCount = True)
for key in keylist:
time = getkeytime(curve,key[0])
value = getkeyvalue(curve,time)
if key[0] <=compareint or numkeys-key[0]<=compareint+1:
key[1] = value
else:
pretime2 = 0
prevalue2 = 0
nexttime2 = 0
nextvalue2 = 0
pretime = getkeytime(curve,key[0]-1)
nexttime = getkeytime(curve,key[0]+1)
if self.useTime:
pretime = time - self.timeUnit
nexttime = time + self.timeUnit
else:
pass
prevalue = getkeyvalue(curve,pretime)
nextvalue = getkeyvalue(curve,nexttime)
if flag5pt:
pretime2 = getkeytime(curve,key[0]-2)
nexttime2 = getkeytime(curve,key[0]+2)
if self.useTime:
pretime2 = time - self.timeUnit*2
nexttime2 = time + self.timeUnit*2
else:
pass
prevalue2 = getkeyvalue(curve,pretime2)
nextvalue2 = getkeyvalue(curve,nexttime2)
if self.method == 0:
tempvalue = value+prevalue+nextvalue
key[1] = lerp(value,tempvalue/3,self.intensity)
elif self.method == 1:
tempvalue = 0.576*value+0.212*prevalue+0.212*nextvalue
key[1] = lerp(value,tempvalue,self.intensity)
elif self.method == 2:
tempvalue = 0.86*value+0.07*prevalue+0.07*nextvalue
key[1] = lerp(value,tempvalue,self.intensity)
elif self.method == 10:
tempvalue = 12*prevalue+nextvalue-3*prevalue2+nextvalue2+17*value
key[1] = lerp(value,tempvalue/35,self.intensity)
elif self.method == 11:
tempvalue = 0.11*(prevalue2+nextvalue2)+0.24*(prevalue+nextvalue)+0.3*(value)
key[1] = lerp(value,tempvalue,self.intensity)
elif self.method == 12:
tempvalue = 0.04*(prevalue2+nextvalue2)+0.24*(prevalue+nextvalue)+0.44*(value)
key[1] = lerp(value,tempvalue,self.intensity)
else:
raise Exception("method error while using smoothkeylistvalue()")
return keylist
def getkeytime(curve,id):
time = cmds.keyframe(curve,index=(id,id),q=True)[0]
return time
def getkeyvalue(curve,time):
value = cmds.keyframe(curve,t = (time,time),ev = True , q = True )[0]
return value
def lerp(originvalue,newvalue,intensity):
temp = newvalue-originvalue
return originvalue+temp*intensity

View File

@ -0,0 +1,661 @@
# coding=utf-8
# -*- coding: utf-8 -*-
import os
from mocaphelper import version
import mocaphelperutility
import mocaphelperrecore
import mocaphelperarbcore
from maya import cmds
from maya import mel
from maya import OpenMayaUI as omui
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PySide2.QtUiTools import *
from shiboken2 import wrapInstance
mayaMainWindowPtr = omui.MQtUtil.mainWindow()
pyVersion = mocaphelperutility.getPythonVersion()
if pyVersion < 3:
mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QWidget)
else:
mayaMainWindow = wrapInstance(int(mayaMainWindowPtr), QWidget)
class MoCapHelperUI(QWidget):
#sac:
sac_iteration = 1
sac_intensity = 1.0
sac_useTime = True
sac_method = "3linear"
sac_selType = "curves"
sac_timeUnit = 5.0
#fa:
fa_refobjs = None
#re:
re_exp = ""
re_name = ""
re_caseCheck = False
re_prefix = ""
#arb:
arb_fromtime = 10.0
arb_totime = 11.0
def __init__(self, *args, **kwargs):
super(MoCapHelperUI, self).__init__(*args, **kwargs)
self.setParent(mayaMainWindow)
self.setWindowFlags(Qt.Window)
self.setObjectName('mocaphelperui')
self.setWindowTitle('moCapHelper v'+str(version))
self.loadUI()
self.initSac()
self.initFa()
self.initre()
self.intiArb()
self.re_exp = self.ui.re_expEdit.text()
# self.arb_syncRange()
def loadUI(self):
loader = QUiLoader()
currentDir = os.path.dirname(__file__)
file = QFile(currentDir+"/mocaphelperui.ui")
file.open(QFile.ReadOnly)
try:
self.ui = loader.load(file, parentWidget=self)
finally:
file.close()
layout = QVBoxLayout()
layout.addWidget(self.ui)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
self.setLayout(layout)
#sac:
def initSac(self):
self.ui.sac_itEdit.textEdited.connect(self.on_sac_itEditEdited)
self.ui.sac_inEdit.textEdited.connect(self.on_sac_inEditEdited)
self.ui.sac_utCheckBox.stateChanged.connect(self.on_sac_utCheckBoxChanged)
self.ui.sac_tuEdit.textEdited.connect(self.on_sac_tuEditEdited)
self.ui.sac_selTypeComboBox.activated[str].connect(self.on_sac_selTypeComboBoxChanged)
self.ui.sac_smoothMethodComboBox.activated[str].connect(self.on_sac_smoothMethodComboBoxChanged)
self.ui.sac_cmdButton.clicked.connect(self.on_sac_cmdButtonClicked)
def on_sac_itEditEdited(self):
self.sac_iteration = int(eval(self.ui.sac_itEdit.text()))
def on_sac_inEditEdited(self):
self.sac_intensity = float(eval(self.ui.sac_inEdit.text()))
def on_sac_utCheckBoxChanged(self):
self.sac_useTime = self.ui.sac_utCheckBox.isChecked()
def on_sac_tuEditEdited(self):
self.sac_timeUnit = float(eval(self.ui.sac_tuEdit.text()))
def on_sac_selTypeComboBoxChanged(self, text):
self.sac_selType = text
def on_sac_smoothMethodComboBoxChanged(self, text):
self.sac_method = text
def on_sac_cmdButtonClicked(self):
seltype = 0
if self.sac_selType == 'selected keys' :
seltype = 1
cmds.moCapHelper_smoothAniCurve( method = self.sac_method , i = self.sac_iteration , intensity = self.sac_intensity , sel = seltype , u = self.sac_useTime , tu = self.sac_timeUnit )
#fa:
def initFa(self):
self.ui.fa_assignButton.clicked.connect(self.on_fa_assignButtonClicked)
self.ui.fa_cmdButton.clicked.connect(self.on_fa_cmdButtonClicked)
self.ui.fa_fastRecordButton.clicked.connect(self.on_fa_fastRecordButtonClicked)
def on_fa_assignButtonClicked(self):
curnode = mocaphelperutility.getSelectedNodes()[0]
self.ui.fa_refEdit.setText(curnode)
def on_fa_cmdButtonClicked(self):
if self.ui.fa_refEdit.text() =="":
raise Exception("no ref obj in ui!")
else:
#cmds.moCapHelper_frameAlign(ref = self.fa_refobjs)
mel.eval("moCapHelper_frameAlign -ref "+self.ui.fa_refEdit.text())
def on_fa_fastRecordButtonClicked(self):
obj = mocaphelperutility.getSelectedNodes()[0]
loc = mocaphelperarbcore.createLoc("mocaphelper_fa_temp_loc")[0]
cmds.setKeyframe(loc,at = ["tx"])
self.ui.fa_refEdit.setText(obj)
mocaphelperutility.selectNodes(loc)
self.on_fa_cmdButtonClicked()
self.ui.fa_refEdit.setText(loc)
#re:
def initre(self):
currentDir = os.path.dirname(__file__)
self.re_presetFilePath = currentDir+"\\re_exp_preset.txt"
self.re_backupPresetFilePath = currentDir+"\\re_exp_preset_backup.txt"
if os.path.exists(self.re_presetFilePath) == False:
mocaphelperrecore.presetfileRebuild(self.re_presetFilePath,self.re_backupPresetFilePath)
self.ui.re_expPresetComboBox.currentIndexChanged.connect(self.on_re_expPresetComboBoxChanged)
self.re_reloadPreset()
self.ui.re_reloadButton.clicked.connect(self.on_re_reloadButtonClicked)
self.ui.re_openFileButton.clicked.connect(self.on_re_openFileButtonClicked)
self.ui.re_assignButton.clicked.connect(self.on_re_assignButtonClicked)
self.ui.re_recordButton.clicked.connect(self.on_re_recordButtonClicked)
self.ui.re_layerNameEdit.setText("layername")
self.ui.re_prefixEdit.textChanged.connect(self.on_re_layerPrefixEditEdited)
self.ui.re_prefixEdit.textEdited.connect(self.on_re_layerPrefixEditEdited)
self.ui.re_layerNameEdit.textChanged.connect(self.on_re_layerNameEditEdited)
self.ui.re_layerNameEdit.textEdited.connect(self.on_re_layerNameEditEdited)
self.ui.re_expEdit.textChanged.connect(self.on_re_expEditEdited)
self.ui.re_expEdit.textEdited.connect(self.on_re_expEditEdited)
self.ui.re_selectMainCtrlButton.clicked.connect(self.on_re_selectMainCtrlButtonClicked)
self.ui.re_selectChildButton.clicked.connect(self.on_re_selectChildButtonClicked)
self.ui.re_selectChildCtrlButton.clicked.connect(self.on_re_selectChildCtrlButtonClicked)
self.ui.re_selectVisChildCtrlButton.clicked.connect(self.on_re_selectVisChildCtrlButtonClicked)
self.ui.re_expSelectButton.clicked.connect(self.on_re_expSelectButtonClicked)
self.ui.re_expCreateLayerButton.clicked.connect(self.on_re_expcreateLayerButtonClicked)
self.ui.re_selectedCreateLayerButton.clicked.connect(self.on_re_selcreateLayerButtonClicked)
self.ui.re_caseCheckCheckBox.stateChanged.connect(self.on_re_caseCheckCheckBoxChanged)
self.ui.re_extractLayerInfoButton.clicked.connect(self.on_re_extractLayerInfoButtonClicked)
def on_re_layerPrefixEditEdited(self):
self.re_prefix = self.ui.re_prefixEdit.text()
def on_re_layerNameEditEdited(self):
self.re_name = self.ui.re_layerNameEdit.text()
def on_re_expEditEdited(self):
self.re_exp = self.ui.re_expEdit.text()
def on_re_selectChildButtonClicked(self):
selectednodes = mocaphelperutility.getSelectedNodes()
children = mocaphelperutility.getChildNodes(selectednodes,nodetype="all")
mocaphelperutility.selectNodes(children)
print("objs selected: ",children)
def on_re_selectChildCtrlButtonClicked(self):
selectednodes = mocaphelperutility.getSelectedNodes()
children = mocaphelperutility.getChildNodes(selectednodes,nodetype="nurbsCurve")
mocaphelperutility.selectNodes(children)
print("objs selected: ",children)
def on_re_selectVisChildCtrlButtonClicked(self):
selectednodes = mocaphelperutility.getSelectedNodes()
children = mocaphelperutility.getChildNodes(selectednodes,nodetype="nurbsCurve")
mocaphelperutility.selectNodes(children,visible=True)
print("objs selected: ",children)
def on_re_selectMainCtrlButtonClicked(self):
mocaphelperrecore.selMainCtrl()
def on_re_expSelectButtonClicked(self):
actOnType = getReActOnType(self)
childcheck = self.ui.re_childCheckBox.isChecked()
seltednodes = mocaphelperutility.getSelectedNodes()
if childcheck:
ctrls = mocaphelperutility.getChildNodes(seltednodes,nodetype=actOnType)
else:
ctrls = seltednodes
matchlist = mocaphelperrecore.retestlist(ctrls,self.re_exp,self.re_caseCheck)
mocaphelperutility.selectNodes(matchlist)
print("objs selected: ",matchlist)
def on_re_selcreateLayerButtonClicked(self):
sel = mocaphelperutility.getSelectedNodes()
mocaphelperrecore.createDisplayLayer(self.re_prefix+self.re_name,sel)
def on_re_expcreateLayerButtonClicked(self):
actOnType = getReActOnType(self)
childcheck = self.ui.re_childCheckBox.isChecked()
mocaphelperutility.openUndoChunk()
try:
mocaphelperrecore.expCreateDisplayLayer(self.re_exp,self.re_name,self.re_prefix,self.re_caseCheck,childcheck = childcheck ,nodetype = actOnType)
finally:
mocaphelperutility.closeUndoChunk()
def on_re_extractLayerInfoButtonClicked(self):
mocaphelperrecore.extractLayerInfo(self)
def on_re_caseCheckCheckBoxChanged(self):
self.re_caseCheck = self.ui.re_caseCheckCheckBox.isChecked()
def on_re_expPresetComboBoxChanged(self):
pass
def on_re_assignButtonClicked(self):
index = self.ui.re_expPresetComboBox.currentIndex()
self.ui.re_layerNameEdit.setText(self.re_itemlist[index][0])
self.ui.re_expEdit.setText(self.re_itemlist[index][1])
def on_re_recordButtonClicked(self):
self.re_rawstr = mocaphelperrecore.strAppend(self.re_rawstr,self.re_name,self.re_exp)
self.re_itemlist = mocaphelperrecore.rawStrBuild(self.re_rawstr)
mocaphelperrecore.presetfileRebuild(self.re_presetFilePath,self.re_backupPresetFilePath)
mocaphelperrecore.presetFileWrite(self.re_presetFilePath,self.re_rawstr)
self.re_reloadPreset()
def on_re_openFileButtonClicked(self):
os.startfile(self.re_presetFilePath)
def on_re_reloadButtonClicked(self):
self.re_reloadPreset()
def re_expPresetComboBoxRebuild(self):
self.ui.re_expPresetComboBox.clear()
for item in self.re_itemlist:
convertedstr = "\""+item[0]+"\"\""+item[1]+"\""
self.ui.re_expPresetComboBox.addItem( convertedstr )
self.ui.re_expPresetComboBox.setCurrentIndex(0)
def re_reloadPreset(self):
if os.path.exists(self.re_presetFilePath) == False:
mocaphelperrecore.presetfileRebuild(self.re_presetFilePath,self.re_backupPresetFilePath)
self.re_rawstr = mocaphelperrecore.presetFileRead(self.re_presetFilePath)
self.re_itemlist = mocaphelperrecore.rawStrBuild(self.re_rawstr)
self.re_expPresetComboBoxRebuild()
# arb:
def intiArb(self):
# timerange
self.ui.arb_setFromButton.clicked.connect(self.arb_setFrom)
self.ui.arb_setToButton.clicked.connect(self.arb_setTo)
self.ui.arb_syncRangeButton.clicked.connect(self.arb_syncRange)
self.ui.arb_delInRangeButton.clicked.connect(self.on_arb_delInRangeButtonClicked)
self.ui.arb_delOutRangeButton.clicked.connect(self.on_arb_delOutRangeButtonClicked)
self.ui.arb_offsetFrameButton.clicked.connect(self.on_arb_offsetFrameButtonClicked)
self.ui.arb_stickyDelButton.clicked.connect(self.on_arb_stickyDelButtonClicked)
self.ui.arb_fromEdit.textChanged.connect(self.on_arb_fromEditEdited)
self.ui.arb_fromEdit.textEdited.connect(self.on_arb_fromEditEdited)
self.ui.arb_toEdit.textChanged.connect(self.on_arb_toEditEdited)
self.ui.arb_toEdit.textEdited.connect(self.on_arb_toEditEdited)
# basic
self.ui.arb_createLocButton.clicked.connect(self.on_arb_createLocButtonClicked)
self.ui.arb_rePosButton.clicked.connect(self.on_arb_rePosButtonClicked)
self.ui.arb_pointConstraintButton.clicked.connect(self.on_arb_pointConstraintButtonClicked)
self.ui.arb_orientConstraintButton.clicked.connect(self.on_arb_orientConstraintButtonClicked)
self.ui.arb_parentConstraintButton.clicked.connect(self.on_arb_parentConstraintButtonClicked)
self.ui.arb_delConstraintButton.clicked.connect(self.on_arb_delConstraintButtonClicked)
self.ui.arb_bakeButton.clicked.connect(self.on_arb_bakeButtonClicked)
# simplebake
self.ui.arb_simpleBakeAAssignButton.clicked.connect(self.on_arb_simpleBakeAAssignButtonClicked)
self.ui.arb_simpleBakeBAssignButton.clicked.connect(self.on_arb_simpleBakeBAssignButtonClicked)
self.ui.arb_simpleBakeToLocButton.clicked.connect(self.on_arb_simpleBakeToLocButtonClicked)
self.ui.arb_simpleBakeAToBButton.clicked.connect(self.on_arb_simpleBakeAToBButtonClicked)
self.ui.arb_simpleBakeBToAButton.clicked.connect(self.on_arb_simpleBakeBToAButtonClicked)
# fk2ik
self.ui.arb_fk2ikEndCtrlAssignButton.clicked.connect(self.on_arb_fk2ikEndCtrlAssignButtonClicked)
self.ui.arb_fk2ikCtrlRefAssignButton.clicked.connect(self.on_arb_fk2ikCtrlRefAssignButtonClicked)
self.ui.arb_fk2ikTwistAssignButton.clicked.connect(self.on_arb_fk2ikTwistAssignButtonClicked)
self.ui.arb_fk2ikTwistRefAssignButton.clicked.connect(self.on_arb_fk2ikTwistRefAssignButtonClicked)
self.ui.arb_fk2ikConvertButton.clicked.connect(self.on_arb_fk2ikConvertButtonClicked)
# pinpos
self.ui.arb_pinPosPinCurButton.clicked.connect(self.on_arb_pinPosPinCurButtonClicked)
self.ui.arb_pinPosPinParentButton.clicked.connect(self.on_arb_pinPosPinParentButtonClicked)
self.arb_syncRange()
def on_arb_fromEditEdited(self):
print("setfrom:",eval(self.ui.arb_fromEdit.text()))
self.arb_fromtime = float(eval(self.ui.arb_fromEdit.text()))
def on_arb_toEditEdited(self):
print("setto:",eval(self.ui.arb_toEdit.text()))
self.arb_totime = float(eval(self.ui.arb_toEdit.text()))
# print("setto:",self.ui.arb_toEdit.text(),self.arb_totime)
def arb_syncRange(self):
timerange = mocaphelperutility.getTimeRange()
print("syncrangeresult:",timerange)
self.ui.arb_fromEdit.setText(str(timerange[0]))
self.ui.arb_toEdit.setText(str(timerange[1]))
def arb_setFrom(self):
time = mocaphelperutility.getCurrentFrame()
self.ui.arb_fromEdit.setText(str(time))
def arb_setTo(self):
time = mocaphelperutility.getCurrentFrame()
self.ui.arb_toEdit.setText(str(time))
def on_arb_delInRangeButtonClicked(self):
objs = mocaphelperutility.getSelectedNodes()
print("delete inrange",self.arb_fromtime,self.arb_totime)
mocaphelperarbcore.deleteInrange(objs,self.arb_fromtime,self.arb_totime)
def on_arb_delOutRangeButtonClicked(self):
if self.arb_fromtime>self.arb_totime:
raise Exception("fromtime > totime")
else:
objs = mocaphelperutility.getSelectedNodes()
print("delete outrange",self.arb_fromtime,self.arb_totime)
mocaphelperarbcore.deleteOutrange(objs,self.arb_fromtime,self.arb_totime)
def on_arb_offsetFrameButtonClicked(self):
if self.arb_fromtime==self.arb_totime:
raise Exception("fromtime == totime")
else:
offsettime = self.arb_totime-self.arb_fromtime
objs = mocaphelperutility.getSelectedNodes()
mocaphelperarbcore.offsetFrame(objs,offsettime)
def on_arb_stickyDelButtonClicked(self):
mocaphelperarbcore.stickyDelete(self)
def on_arb_createLocButtonClicked(self):
objs = mocaphelperutility.getSelectedNodes()
if len(objs) == 0:
cmds.warning("No nodes selected")
return
pos = mocaphelperutility.getWorldPos(objs[0])
rot = mocaphelperutility.getWorldRot(objs[0])
roo = mocaphelperutility.getRotOrder(objs[0])
mocaphelperarbcore.createLoc("c_loc_"+objs[0],pos,rot,roo)
def on_arb_rePosButtonClicked(self):
objs = mocaphelperutility.getSelectedNodes()
if len(objs) == 0:
cmds.warning("No nodes selected")
return
mocaphelperarbcore.reposition(objs[0],objs[1])
def on_arb_pointConstraintButtonClicked(self):
objs = mocaphelperutility.getSelectedNodes()
ctrlobj = objs[:-1]
targetobj = objs[-1]
mocaphelperarbcore.createPointConstraint(ctrlobj,targetobj,maintainoffset=self.ui.arb_maintainOffsetCheckBox.isChecked())
def on_arb_orientConstraintButtonClicked(self):
objs = mocaphelperutility.getSelectedNodes()
ctrlobj = objs[:-1]
targetobj = objs[-1]
mocaphelperarbcore.createOrientConstraint(ctrlobj,targetobj,maintainoffset=self.ui.arb_maintainOffsetCheckBox.isChecked())
def on_arb_parentConstraintButtonClicked(self):
objs = mocaphelperutility.getSelectedNodes()
ctrlobj = objs[:-1]
targetobj = objs[-1]
mocaphelperarbcore.createParentConstraint(ctrlobj,targetobj,maintainoffset=self.ui.arb_maintainOffsetCheckBox.isChecked())
def on_arb_delConstraintButtonClicked(self):
objs = mocaphelperutility.getSelectedNodes()
mocaphelperarbcore.deleteAllConstraint(objs)
# for obj in objs:
# check = mocaphelperarbcore.checkConstraint(obj)
# if check != False:
# if check[0] != None:
# mocaphelperarbcore.deleteParentConstraint(check[0],obj)
# elif check[1] != None :
# mocaphelperarbcore.deletePointConstraint(check[1],obj)
# elif check[2] != None :
# mocaphelperarbcore.deleteOrientConstraint(check[2],obj)
# else:
# raise Exception("delconstraint error: constraint list out of range!")
# else:
# point = cmds.listRelatives(obj,children = True,type = "pointConstraint")
# orient = cmds.listRelatives(obj,children = True,type = "orientConstraint")
def on_arb_bakeButtonClicked(self):
mintime = self.arb_fromtime
maxtime = self.arb_totime
objs = mocaphelperutility.getSelectedNodes()
singleobj = objs[0]
check = mocaphelperarbcore.checkConstraint(singleobj)
smartbake = self.ui.arb_smartBakeCheckBox.isChecked()
if len(objs) == 1 and self.ui.arb_onlyBakeConstraintCheckBox.isChecked() and check != False:
type = "all"
if check[0] != None:
type = "parent"
elif check[1] != None :
type = "point"
elif check[2] != None :
type = "orient"
else:
type = "parent"
if smartbake:
mocaphelperarbcore.smartbake(objs,mintime,maxtime,type)
else:
mocaphelperarbcore.bake(objs,mintime,maxtime,type)
def on_arb_simpleBakeAAssignButtonClicked(self):
obj = mocaphelperutility.getSelectedNodes()[0]
self.ui.arb_simpleBakeAEdit.setText(obj)
def on_arb_simpleBakeBAssignButtonClicked(self):
obj = mocaphelperutility.getSelectedNodes()[0]
self.ui.arb_simpleBakeBEdit.setText(obj)
def on_arb_simpleBakeToLocButtonClicked(self):
mintime = self.arb_fromtime
maxtime = self.arb_totime
targetA = self.ui.arb_simpleBakeAEdit.text()
mocaphelperutility.openUndoChunk()
try:
# obj = mocaphelperutility.getSelectedNodes()[0]
locA = mocaphelperarbcore.createLoc(targetA +"_loc")
mocaphelperarbcore.createParentConstraint(targetA,locA,False)
mocaphelperarbcore.bake(locA,mintime,maxtime,"all")
mocaphelperarbcore.deleteAllConstraint(locA)
self.ui.arb_simpleBakeBEdit.setText(locA[0])
finally:
mocaphelperutility.closeUndoChunk()
def on_arb_simpleBakeAToBButtonClicked(self):
targetA = self.ui.arb_simpleBakeAEdit.text()
targetB = self.ui.arb_simpleBakeBEdit.text()
maintainoffset=self.ui.arb_maintainOffsetCheckBox.isChecked()
mocaphelperutility.openUndoChunk()
try:
check = mocaphelperarbcore.checkConstraint(targetB)
if check != False:
raise Exception("obj B has constraint already!")
else:
mintime = self.arb_fromtime
maxtime = self.arb_totime
type = getArbType(self)
mocaphelperarbcore.bakeAtoB(targetA,targetB,mintime,maxtime,type,maintainoffset,smart = self.ui.arb_smartBakeCheckBox.isChecked())
finally:
mocaphelperutility.closeUndoChunk()
def on_arb_simpleBakeBToAButtonClicked(self):
targetA = self.ui.arb_simpleBakeAEdit.text()
targetB = self.ui.arb_simpleBakeBEdit.text()
maintainoffset=self.ui.arb_maintainOffsetCheckBox.isChecked()
mocaphelperutility.openUndoChunk()
try:
check = mocaphelperarbcore.checkConstraint(targetA)
if check != False:
raise Exception("obj A has constraint already!")
else:
mintime = self.arb_fromtime
maxtime = self.arb_totime
type = getArbType(self)
mocaphelperarbcore.bakeAtoB(targetB,targetA,mintime,maxtime,type,maintainoffset,smart = self.ui.arb_smartBakeCheckBox.isChecked())
finally:
mocaphelperutility.closeUndoChunk()
def on_arb_fk2ikEndCtrlAssignButtonClicked(self):
obj = mocaphelperutility.getSelectedNodes()[0]
self.ui.arb_fk2ikEndCtrlEdit.setText(obj)
def on_arb_fk2ikCtrlRefAssignButtonClicked(self):
obj = mocaphelperutility.getSelectedNodes()[0]
self.ui.arb_fk2ikCtrlRefEdit.setText(obj)
def on_arb_fk2ikTwistAssignButtonClicked(self):
obj = mocaphelperutility.getSelectedNodes()[0]
self.ui.arb_fk2ikTwistEdit.setText(obj)
def on_arb_fk2ikTwistRefAssignButtonClicked(self):
obj = mocaphelperutility.getSelectedNodes()[0]
self.ui.arb_fk2ikTwistRefEdit.setText(obj)
def on_arb_fk2ikConvertButtonClicked(self):
mintime = self.arb_fromtime
maxtime = self.arb_totime
maintainoffset=self.ui.arb_maintainOffsetCheckBox.isChecked()
smartbake = self.ui.arb_smartBakeCheckBox.isChecked()
endctrl = self.ui.arb_fk2ikEndCtrlEdit.text()
ctrlref = self.ui.arb_fk2ikCtrlRefEdit.text()
twist = self.ui.arb_fk2ikTwistEdit.text()
twistref = self.ui.arb_fk2ikTwistRefEdit.text()
mocaphelperutility.openUndoChunk()
try:
if mocaphelperutility.objExist(endctrl) == False:
endctrl = ""
if mocaphelperutility.objExist(ctrlref) == False:
ctrlref = ""
if mocaphelperutility.objExist(twist) == False:
twist = ""
if mocaphelperutility.objExist(twistref) == False:
twistref = ""
check = mocaphelperarbcore.checkConstraint(endctrl)
if check != False:
raise Exception("endctrl has constraint already!")
if mocaphelperutility.objExist(twist) == True:
check = mocaphelperarbcore.checkConstraint(twist)
if check != False:
raise Exception("twist has constraint already!")
if endctrl== "" or ctrlref =="":
raise Exception("endctrl or ctrlref not set or not exist")
else:
if twist == "" or twistref == "":
mocaphelperarbcore.bakeAtoB(ctrlref,endctrl,mintime,maxtime,"parent",maintainoffset,smartbake)
else:
mocaphelperarbcore.bakeAtoB(ctrlref,endctrl,mintime,maxtime,"parent",maintainoffset,smartbake)
twistpos = mocaphelperutility.getWorldPos(twist)
twistrot = mocaphelperutility.getWorldRot(twist)
twistroo = mocaphelperutility.getRotOrder(twist)
twistloc = mocaphelperarbcore.createLoc("temp_twist_loc",twistpos,twistrot,twistroo)
cons1 = mocaphelperarbcore.createParentConstraint(twistref,twistloc,True)
cons2 = mocaphelperarbcore.createPointConstraint(twistloc,twist,False)
if smartbake:
mocaphelperarbcore.smartbake(twist,mintime,maxtime,"point")
else:
mocaphelperarbcore.bake(twist,mintime,maxtime,"point")
mocaphelperutility.deleteObj(cons1)
mocaphelperutility.deleteObj(cons2)
mocaphelperutility.deleteObj(twistloc)
finally:
mocaphelperutility.closeUndoChunk()
def on_arb_pinPosPinCurButtonClicked(self):
mintime = self.arb_fromtime
maxtime = self.arb_totime
mocaphelperutility.openUndoChunk()
try:
objs = mocaphelperutility.getSelectedNodes()
mocaphelperarbcore.pinCurPos(objs,mintime,maxtime)
finally:
mocaphelperutility.closeUndoChunk()
def on_arb_pinPosPinParentButtonClicked(self):
mintime = self.arb_fromtime
maxtime = self.arb_totime
mocaphelperutility.openUndoChunk()
try:
objs = mocaphelperutility.getSelectedNodes()
mocaphelperarbcore.pinParentPos(objs,mintime,maxtime)
finally:
mocaphelperutility.closeUndoChunk()
def getArbType(obj):
index = obj.ui.arb_simpleBakeTypeComboBox.currentIndex()
# type = mocaphelperutility.unicodeToStr(type)
# enList = ["all","parent","point","orient","onlyscale"]
# cnList = ["平移旋转","平移","旋转","所有属性"]
type = None
if index == 0:
type = "all"
elif index == 1:
type = "parent"
elif index == 2:
type = "point"
elif index == 3:
type = "orient"
else:
raise Exception("id out of range")
print("index is now:",index,".type is now:",type)
return type
def getReActOnType(obj):
index = obj.ui.re_actTypeComboBox.currentIndex()
type = None
if index == 0:
type = "all"
elif index == 1:
type = "nurbsCurve"
print("index is now:",index,".type is now:",type)
return type

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
import maya.api.OpenMaya as om
import maya.cmds as cmds
import maya.mel as mel
import os
from sys import version as sysver
def getPythonVersion():
return int(sysver[0])
def selectNodes(nodelist,visible = False):
cmds.select(cl=True)
if visible == True:
cmds.select(nodelist,vis = True)
else:
cmds.select(nodelist)
def addSelectNodes(nodelist):
for node in nodelist:
cmds.select(node,add = True)
def orderSelectNodes(nodelist):
cmds.select(cl=True)
for node in nodelist:
cmds.select(node,add = True)
def getSelectedNodes(nodetype = "all",longname = True):
selectednodes = cmds.ls(selection = True,type = "dagNode",long = longname)
if nodetype != "all":
selectednodes = filterCertainTypeInList(selectednodes,nodetype)
return selectednodes
def getChildNodes(parents,nodetype = "all",combine = True):
list = []
for parent in parents:
childlist = cmds.listRelatives(parent, ad=True, type = "transform",fullPath = True)
if childlist == None:
continue
else:
if nodetype == "all":
list += childlist
else:
list += filterCertainTypeInList(childlist,nodetype)
if list != None:
if combine == True:
return list+parents
else:
return list
else:
raise Exception("error when getting child")
def filterCertainTypeInList(list,type = "nurbsCurve"):
matchlist = []
for node in list:
if getShapeType(node) == type:
matchlist.append(node)
return matchlist
def getShapeType( node = "" ):
shape = cmds.listRelatives(node,shapes = True,fullPath = True)
if shape != None:
shape = shape[0]
return cmds.nodeType(shape)
else:
return None
def objExist(obj):
if len(cmds.ls(obj)) == 0:
return False
else:
return True
def getCurrentFrame():
return cmds.currentTime(q = True)
def getTimeRange(local = False):
#local means time slider range in maya time line
if local == True:
return cmds.playbackOptions(q = True,min = True),cmds.playbackOptions(q = True,max = True)
else:
return cmds.playbackOptions(q = True,ast = True),cmds.playbackOptions(q = True,aet = True)
def getWorldPos(obj):
return cmds.xform(obj,q = True,ws = True,t = True)
def getWorldRot(obj):
return cmds.xform(obj,q = True,ws = True,ro = True)
def getRotOrder(obj):
return cmds.xform(obj,q = True,roo = True)
def setWorldPos(obj,cd = (0.0,0.0,0.0)):
cmds.xform(obj,ws = True,t = cd)
def setWorldRot(obj,rot = (0.0,0.0,0.0),targetRotOrder = "xyz"):
originOrder = cmds.xform(obj,q = True,roo = True)
if originOrder == targetRotOrder:
cmds.xform(obj,ws = True,ro = rot)
else:
if targetRotOrder in ['xyz', 'yzx','zxy','xzy','yxz','zyx']:
cmds.xform(obj,ws = True,ro = rot,roo = targetRotOrder)
cmds.xform(obj,ws = True,roo = originOrder)
else:
raise Exception("rot order does not exist.")
def cutKey(objlist,mintime,maxtime,insertside = False):
if insertside:
cmds.cutKey(objlist,t =(mintime,maxtime),cl = True,option = "curve")
else:
cmds.cutKey(objlist,t =(mintime,maxtime),cl = True)
def autoKetTangent(objs,mintime,maxtime):
cmds.keyTangent(objs,e = True,itt="auto", ott="auto", t=(mintime,maxtime))
def deleteObj(obj):
cmds.delete(obj)
def unicodeToStr(str):
return repr(str)[2:-1]
def getDir():
dir = os.path.dirname(__file__)
return dir
def openUndoChunk():
return cmds.undoInfo(openChunk=True)
def closeUndoChunk():
return cmds.undoInfo(closeChunk=True)

View File

@ -0,0 +1,13 @@
torso
.ctrl.torso.
torso
.torso.ctrl.
l_arm
.ctrl.l.arm.
l_hand;l_arm
.:FKIndexFinger2_L|.:FKIndexFinger1_L|.:FKIndexFinger3_L|.:FKMiddleFinger1_L|.:FKMiddleFinger2_L|.:FKMiddleFinger3_L|.:FKRingFinger1_L|.:FKPinkyFinger1_L|.:FKPinkyFinger2_L|.:FKPinkyFinger3_L|.:FKThumbFinger2_L|.:FKThumbFinger3_L|.:FKThumbFinger1_L;.:FKElbow_L|.:FKWrist_L|.:FKShoulder_L
.
.

View File

@ -0,0 +1,8 @@
torso
.ctrl.torso.
torso
.torso.ctrl.
l_arm
.ctrl.l.arm.
r_arm
.l.arm.ctrl.

View File

@ -0,0 +1,500 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN" sourcelanguage="en">
<context>
<name>moCapHelper</name>
<message>
<source>Form</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="81"/>
<source>SAC/FA/RE</source>
<oldsource>SAC/FA/DLC</oldsource>
<translation>线//</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="130"/>
<source>smoothAnim</source>
<translation>线</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="151"/>
<source>iteration:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="158"/>
<source>1</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="165"/>
<source>intensity:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="172"/>
<source>1.0</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="179"/>
<source>use time unit</source>
<translation>使</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="189"/>
<source>timeunit:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="196"/>
<source>5.0</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="203"/>
<source>perform on:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="211"/>
<source>curves</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="216"/>
<source>selected keys</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="224"/>
<source>smooth method:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="235"/>
<source>3linear</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="240"/>
<source>3bell</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="245"/>
<source>3ham</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="250"/>
<source>5quad</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="255"/>
<source>5bell</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="260"/>
<source>5ham</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="271"/>
<source>smooth</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="288"/>
<source>frameAlign</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="314"/>
<source>fast record selected</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="328"/>
<source>ref obj:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="345"/>
<source>assign obj</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="359"/>
<source>align selection</source>
<translation></translation>
</message>
<message>
<source>layerCreate</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="425"/>
<source>preset:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="435"/>
<source>open file</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="445"/>
<source>record</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="455"/>
<source>reload</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="490"/>
<location filename="mocaphelperui.ui" line="1081"/>
<location filename="mocaphelperui.ui" line="1112"/>
<location filename="mocaphelperui.ui" line="1223"/>
<location filename="mocaphelperui.ui" line="1254"/>
<location filename="mocaphelperui.ui" line="1309"/>
<location filename="mocaphelperui.ui" line="1334"/>
<source>assign</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="504"/>
<source>case check</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="546"/>
<source>prefix:</source>
<translation>:</translation>
</message>
<message>
<source>layer name:</source>
<translation type="vanished">:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="592"/>
<source>default</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="624"/>
<source>expression:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="631"/>
<source>.</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="693"/>
<source>utility</source>
<translation></translation>
</message>
<message>
<source>select child ctrls</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="831"/>
<source>selected create layer</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="755"/>
<source>expression</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="779"/>
<source>exp select</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="821"/>
<source>exp create layer</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="789"/>
<source>extract layer info</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="847"/>
<source>ARB</source>
<translation></translation>
</message>
<message>
<source>animRebuild</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="944"/>
<source>basic</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="965"/>
<source>orient constraint</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1003"/>
<source>delete constraint</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="989"/>
<source>parent constraint</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1010"/>
<source>bake key</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="996"/>
<source>create locator</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="912"/>
<source>maintain offset</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="922"/>
<source>smart bake</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1017"/>
<source>point constraint</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="972"/>
<source>reposition</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1024"/>
<source>only bake constraint</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1038"/>
<source>simpleBake</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1067"/>
<source>target A:</source>
<translation>A:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1098"/>
<source>target B:</source>
<translation>B:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="671"/>
<location filename="mocaphelperui.ui" line="1133"/>
<source>all</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1123"/>
<location filename="mocaphelperui.ui" line="1138"/>
<source>parent</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="22"/>
<source>uiwindow</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="378"/>
<source>regularExp</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="511"/>
<source>children check</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="585"/>
<source>name:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="648"/>
<source>act on :</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="676"/>
<source>ctrl(nurbs)</source>
<translation>nurbs曲线</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="717"/>
<source>select child</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="727"/>
<source>select main ctrls</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="737"/>
<source>select child ctrl</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="747"/>
<source>select visible child ctrl</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="797"/>
<source>layercreate</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1143"/>
<source>point</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1148"/>
<source>orient</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1156"/>
<source>bake A into B</source>
<translation>A到B</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1163"/>
<source>bake B into A</source>
<translation>B到A</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1172"/>
<source>bake A into new locator</source>
<translation>A烘焙到空定位器</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1180"/>
<source>fk2ik</source>
<translation>fk转ik</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1209"/>
<source>endctrl:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1240"/>
<source>ctrlref:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1283"/>
<source>twist:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1320"/>
<source>twistref:</source>
<translation>:</translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1343"/>
<source>convert it !</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1351"/>
<source>pinPos</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1357"/>
<source>pin to current position</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1364"/>
<source>parent to first obj position</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1403"/>
<source>set from</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1410"/>
<source>sync range</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1417"/>
<source>set to</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1431"/>
<source>from:</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1441"/>
<source>to:</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1458"/>
<source>delete inrange</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1465"/>
<source>delete outrange</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1479"/>
<source>offset frame</source>
<translation></translation>
</message>
<message>
<location filename="mocaphelperui.ui" line="1492"/>
<source>sticky delete</source>
<translation></translation>
</message>
<message>
<source>language</source>
<translation type="vanished"></translation>
</message>
</context>
</TS>

Binary file not shown.

View File

@ -0,0 +1,23 @@
安装:
将这个文件夹的目录添加到到对应版本的maya.env文件中的MAYA_PLUG_IN_PATH这一行。
例子:
MAYA_PLUG_IN_PATH =C:\Users\(你的用户名)\Documents\maya\2018\plug-ins\MotionCapHelper
启动maya在maya里打开插件管理器如果出现了这个插件的名字mocaphelper.py就说明安装
顺利只要勾选这一个文件的加载就好不需要勾选其他的比如mocaphelperrecore.py等等文件
勾选后maya会载入插件之后使用mel或者python的moCapHelper_showUi -lan "CN"指令打开插件的中文界面
或者moCapHelper_showUi打开英文界面更推荐一点因为懒得更新汉化
可以把这个指令新建一个工具架的工具,方面后面调用
Installation:
Add the directory of this folder to the <MAYA_PLUG_IN_PATH> in the corresponding version of the maya.env file.
Example:
MAYA_PLUG_IN_PATH =C:\Users\<username>\Documents\maya\2018\plug-ins\MotionCapHelper
Start Maya, open the plugin manager in Maya, you should see a list of mocaphelper.py/mocaphelperui.py.....
just check the load state of "mocaphelper.py" file only, no need to check any other files such as mocaphelperrecore.py....
After checking this box, maya will load the plug-in, and then you can use "moCapHelper_showUi" command in mel or python to open the interface of this plug-in.
You can create a new shelf tool with this command.

View File

@ -0,0 +1,12 @@
'''
this is an example of how you set hotkey or use scripts to drive this plugin's cmds.
if you know python and pyside2,go see codes and .ui file to find what you need.
the most simple usage is to drive a qt pushbutton.(which is exactly what you did when you hit a button in plugin ui.)
and you might need QLineEdit.setText() to set str in those text field.
anyway,go check qt wiki :https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QWidget.html#qwidget
have fun scripting.
'''
import maya.cmds as cmds
cmds.moCapHelper_eval(s ="ui.arb_stickyDelButton.click()" )

View File

@ -0,0 +1,15 @@
import maya.cmds as cmds
import maya.mel as mel
curlayer = cmds.editDisplayLayerGlobals( query=True, cdl=True )
if curlayer =="defaultLayer" :
raise Exception("using default layer!")
else:
slist = cmds.editDisplayLayerMembers(curlayer,query=True )
print(slist)
cmds.select( clear=True )
cmds.select(slist, visible=True )
mel.eval("syncChannelBoxFcurveEd;")
mel.eval("syncChannelBoxFcurveEd;")
mel.eval("syncChannelBoxFcurveEd;")

View File

@ -0,0 +1,140 @@
# Copyright Epic Games, Inc. All Rights Reserved.
import logging
from PySide2 import QtWidgets, QtCore, QtGui
class LogWidget(logging.Handler):
"""
Custom Log Handler with embedded QtWidgets.QDockWidget
"""
def __init__(self):
super(LogWidget, self).__init__()
# Set default formatting
self.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s', '%Y-%m-%d %H:%M:%S'))
# Create dock
self._log_dock = QtWidgets.QDockWidget()
# Only allow it to be parented to the bottom
self._log_dock.setAllowedAreas(QtCore.Qt.BottomDockWidgetArea)
central_widget = QtWidgets.QWidget()
central_widget.setContentsMargins(0, 0, 0, 0)
self._log_dock.setWidget(central_widget)
main_layout = QtWidgets.QVBoxLayout()
main_layout.setContentsMargins(0, 0, 0, 0)
central_widget.setLayout(main_layout)
toolbar_layout = QtWidgets.QHBoxLayout()
toolbar_layout.setContentsMargins(0, 0, 0, 0)
main_layout.addLayout(toolbar_layout)
self._output_log = QtWidgets.QListWidget()
self._output_log.setProperty("Log", True)
self._output_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self._output_log.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self._output_log.customContextMenuRequested.connect(self._show_context_menu)
main_layout.addWidget(self._output_log)
icon_size_px = 25
icon_size = QtCore.QSize(icon_size_px, icon_size_px)
btn_size_px = 30
btn_size = QtCore.QSize(btn_size_px, btn_size_px)
self._debug_btn = QtWidgets.QPushButton()
self._debug_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:debug.png")))
self._debug_btn.setIconSize(icon_size)
self._debug_btn.setProperty("LogButton", True)
self._debug_btn.setCheckable(True)
self._debug_btn.setChecked(False)
self._debug_btn.setFixedSize(btn_size)
self._debug_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._debug_btn)
self._info_btn = QtWidgets.QPushButton()
self._info_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:info.png")))
self._info_btn.setIconSize(icon_size)
self._info_btn.setProperty("LogButton", True)
self._info_btn.setCheckable(True)
self._info_btn.setChecked(True)
self._info_btn.setFixedSize(btn_size)
self._info_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._info_btn)
self._warning_btn = QtWidgets.QPushButton()
self._warning_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:warning.png")))
self._warning_btn.setIconSize(icon_size)
self._warning_btn.setProperty("LogButton", True)
self._warning_btn.setCheckable(True)
self._warning_btn.setChecked(True)
self._warning_btn.setFixedSize(btn_size)
self._warning_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._warning_btn)
self._error_btn = QtWidgets.QPushButton()
self._error_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:error.png")))
self._error_btn.setIconSize(icon_size)
self._error_btn.setProperty("LogButton", True)
self._error_btn.setCheckable(True)
self._error_btn.setChecked(True)
self._error_btn.setFixedSize(btn_size)
self._error_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._error_btn)
toolbar_layout.addStretch(0)
self._clear_log_btn = QtWidgets.QPushButton()
self._clear_log_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:clear.png")))
self._clear_log_btn.setIconSize(icon_size)
self._clear_log_btn.setProperty("LogButton", True)
self._clear_log_btn.setFixedSize(btn_size)
self._clear_log_btn.clicked.connect(self._output_log.clear)
toolbar_layout.addWidget(self._clear_log_btn)
@property
def log_dock(self):
return self._log_dock
def emit(self, record):
level_colour_map = {
logging.DEBUG: QtGui.QColor(91, 192, 222),
logging.INFO: QtGui.QColor(247, 247, 247),
logging.WARNING: QtGui.QColor(240, 173, 78),
logging.ERROR: QtGui.QColor(217, 83, 79)
}
msg = self.format(record)
item = QtWidgets.QListWidgetItem(msg)
item.setData(QtCore.Qt.UserRole, record.levelno)
item.setForeground(QtGui.QBrush(level_colour_map[record.levelno]))
self._output_log.addItem(item)
self._refresh_log()
def _refresh_log(self):
level_btn_map = {
logging.DEBUG: self._debug_btn,
logging.INFO: self._info_btn,
logging.WARNING: self._warning_btn,
logging.ERROR: self._error_btn
}
for i in range(0, self._output_log.count()):
item = self._output_log.item(i)
data = item.data(QtCore.Qt.UserRole)
item.setHidden(not level_btn_map[data].isChecked())
def _copy_to_clipboard(self):
clipboard_text = ""
for item in self._output_log.selectedItems():
text = item.text()
clipboard_text += text
if text:
clipboard_text += "\n"
clipboard = QtWidgets.QApplication.clipboard()
clipboard.setText(clipboard_text)
def _show_context_menu(self, pos):
if not self._output_log.selectedItems():
return
menu = QtWidgets.QMenu(parent=self._output_log)
copy_action = menu.addAction("Copy")
copy_action.triggered.connect(self._copy_to_clipboard)
menu.exec_(QtGui.QCursor.pos())

View File

@ -0,0 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import keyframe_pro
from . import keyframe_pro_maya

View File

@ -0,0 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import *

View File

@ -0,0 +1,686 @@
import json
import socket
import time
import traceback
class KeyframeProClient(object):
"""
Client API for Keyframe Pro
"""
API_VERSION = "1.0.1"
PORT = 18181
HEADER_SIZE = 10
kpro_socket = None
kpro_initialized = False
def __init__(self, timeout=2):
"""
"""
self.timeout = timeout
self.show_timeout_errors = True
def connect(self, port=-1, display_errors=True):
"""
Create a connection with the application.
:param port: The port Keyframe Pro is listening on.
:return: True if connection was successful (or already exists). False otherwise.
"""
if self.is_connected():
return True
if port < 0:
port = self.__class__.PORT
try:
self.__class__.kpro_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__class__.kpro_socket.connect(("localhost", port))
self.__class__.kpro_socket.setblocking(0)
self.__class__.kpro_initialized = False
except:
self.__class__.kpro_socket = None
if display_errors:
traceback.print_exc()
return False
return True
def disconnect(self):
"""
Disconnect from the application.
:return: True if the existing connection was disconnect successfully. False otherwise.
"""
result = False
if self.__class__.kpro_socket:
try:
self.__class__.kpro_socket.close()
result = True
except:
traceback.print_exc()
self.__class__.kpro_socket = None
self.__class__.kpro_initialized = False
return result
def is_connected(self):
"""
Test if a connection exists.
:return: True if a connection exists. False otherwise.
"""
self.show_timeout_errors = False
connected = self.__class__.kpro_socket and self.echo("conn")
self.show_timeout_errors = True
if connected:
return True
else:
self.disconnect()
return False
def send(self, cmd):
"""
Send a command to the application and wait for a processed reply.
:param cmd: Dictionary containing the cmd and args
:return: Variable depending on cmd.
"""
json_cmd = json.dumps(cmd)
message = []
message.append("{:10d}".format(len(json_cmd))) # header
message.append(json_cmd)
try:
self.__class__.kpro_socket.sendall("".join(message))
except:
traceback.print_exc()
return None
return self.recv(cmd)
def recv(self, cmd):
"""
Wait for the application to reply to a previously sent cmd.
:param cmd: Dictionary containing the cmd and args
:return: Variable depending on cmd.
"""
total_data = []
data = ""
reply_length = 0
bytes_remaining = self.__class__.HEADER_SIZE
begin = time.time()
while time.time() - begin < self.timeout:
try:
data = self.__class__.kpro_socket.recv(bytes_remaining)
except:
time.sleep(0.01)
continue
if data:
total_data.append(data)
bytes_remaining -= len(data)
if(bytes_remaining <= 0):
if reply_length == 0:
header = "".join(total_data)
reply_length = int(header)
bytes_remaining = reply_length
total_data = []
else:
reply_json = "".join(total_data)
return json.loads(reply_json)
if self.show_timeout_errors:
if "cmd" in cmd.keys():
cmd_name = cmd["cmd"]
print('[KPRO][ERROR] "{0}" timed out.'.format(cmd_name))
else:
print('[KPRO][ERROR] Unknown cmd timed out.')
return None
def is_valid_reply(self, reply):
"""
Test if a reply from the application is valid. Output any messages.
:param reply: Dictionary containing the response to a cmd
:return: True if valid. False otherwise.
"""
if not reply:
return False
if not reply["success"]:
print('[KPRO][ERROR] "{0}" failed: {1}'.format(reply["cmd"], reply["msg"]))
return False
return True
def initialize(self):
"""
One time initialization required by the application.
:return: True if successfully initalized. False otherwise.
"""
if self.__class__.kpro_initialized:
return True
cmd = {
"cmd": "initialize",
"api_version": self.__class__.API_VERSION
}
reply = self.send(cmd)
if reply and reply["success"] and reply["result"] == 0:
self.__class__.kpro_initialized = True
return True
else:
print('[KPRO][ERROR] Initialization failed: {0}'.format(reply["msg"]))
self.disconnect()
return False
# ------------------------------------------------------------------
# COMMANDS
# ------------------------------------------------------------------
def echo(self, text):
"""
Get an echo response from the application.
:param text: The string to be sent to the application.
:return: A string containing the text on success. None otherwise.
"""
cmd = {
"cmd": "echo",
"text": text
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["result"]
else:
return None
def get_config(self):
"""
Get the configuration settings for the application.
:return: Dictionary containing the config values.
"""
cmd = {
"cmd": "get_config"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply
else:
return None
def new_project(self, empty=False):
"""
Create a new project.
:param empty: Create an empty project.
:return: True if new project created. False otherwise.
"""
cmd = {
"cmd": "new_project",
"empty": empty
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def open_project(self, file_path):
"""
Open an existing project.
:param file_path: Path to the project.
:return: True if the project is opened. False otherwise.
"""
cmd = {
"cmd": "open_project",
"file_path": file_path
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def save_project(self, file_path):
"""
Save the current project.
:param file_path: Path to the project.
:return: True if the project is saved. False otherwise.
"""
cmd = {
"cmd": "save_project",
"file_path": file_path
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def get_project_path(self):
"""
Get the path to the current project.
:return: The path to the project. None if there is an error.
"""
cmd = {
"cmd": "get_project_path"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["project_path"]
else:
return None
def import_file(self, file_path, name="", range_start=-1, range_end=-1, parent_id=""):
"""
Import a source file into the project.
:param file_path: Path to the source
:param name: Name of the source
:param range_start: Range start frame
:param range_end: Range end frame
:param parent_id: Parent folder of the source
:return: Dictionary representing the source object. None on error.
"""
cmd = {
"cmd": "import_file",
"file_path": file_path,
"name": name,
"range_start": range_start,
"range_end": range_end,
"parent_id": parent_id
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["source"]
else:
return None
def add_folder(self, name="", parent_id=""):
"""
Add a folder to the project.
:param name: Name of the folder
:param parent_id: Parent folder of the folder
:return: Dictionary representing the folder object. None on error.
"""
cmd = {
"cmd": "add_folder",
"name": name,
"parent_id": parent_id
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["folder"]
else:
return None
def add_timeline(self, name="", parent_id=""):
"""
Add a timeline to the project.
:param name: Name of the timeline
:param parent_id: Parent folder of the timeline
:return: Dictionary representing the timeline object. None on error.
"""
cmd = {
"cmd": "add_timeline",
"name": name,
"parent_id": parent_id
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["timeline"]
else:
return None
def remove(self, id, force=False):
"""
Remove a folder, timeline or source from the project.
:param id: ID for the object to be removed.
:param force: (Source only) Force removal if the source is in use in one or more timelines.
:return: True on successful removal. False otherwise.
"""
cmd = {
"cmd": "remove",
"id": id,
"force": force
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def update(self, obj):
"""
Update the folder, timeline or source object with the values contained in the obj dict.
Editable obj values that are different will be modified.
:param obj: Dictionary representing the object to be updated.
:return: Dictionary representing the updated object. None on error.
"""
cmd = {
"cmd": "update",
"object": obj
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["updated"]
else:
return None
def insert_element_in_timeline(self, source_id, timeline_id, index=-1):
"""
Insert a source element into a timeline.
:param source_id: ID of the source to be added to the timeline.
:param timeline_id: ID of the timeline.
:param index: Index to insert source at. Inserted at the end if index is out of range.
:return: True on successful insertion. False otherwise.
"""
cmd = {
"cmd": "insert_element_in_timeline",
"source_id": source_id,
"timeline_id": timeline_id,
"index": index
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def remove_element_from_timeline(self, timeline_id, index):
"""
Remove a source element from a timeline.
:param timeline_id: ID of the timeline.
:param index: Index of the element to be removed.
:return: True on successful removal. False otherwise.
"""
cmd = {
"cmd": "remove_element_from_timeline",
"timeline_id": timeline_id,
"index": index
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def get_timeline_elements(self, timeline_id):
"""
Get an ordered list of the sources in a timeline.
:param timeline_id: ID of the timeline.
:return: An ordered list of dictionaries representing the sources in a timeline. None on error.
"""
cmd = {
"cmd": "get_timeline_elements",
"timeline_id": timeline_id
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["sources"]
else:
return None
def get_folders(self):
"""
Get an unordered list of the folders in the project.
:return: An unordered list of dictionaries representing the folders in the project. None on error.
"""
cmd = {
"cmd": "get_folders"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["folders"]
else:
return None
def get_timelines(self):
"""
Get an unordered list of timelines in the project.
:return: An unordered list of dictionaries representing the timelines in the project. None on error.
"""
cmd = {
"cmd": "get_timelines"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["timelines"]
else:
return None
def get_sources(self):
"""
Get an unordered list of sources in the project.
:return: An unordered list of dictionaries representing the sources in the project. None on error.
"""
cmd = {
"cmd": "get_sources"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["sources"]
else:
return None
def get_frame(self):
"""
Get the current frame of the (primary) active timeline.
:return: The frame of the (primary) active timeline. Zero on error.
"""
cmd = {
"cmd": "get_frame"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["frame"]
else:
return 0
def set_frame(self, frame, audio=False):
"""
Set the current frame of the (primary) active timeline.
:param frame: Requested frame number
:param audio: Play audio for the frame after setting it.
:return: The frame of the (primary) active timeline. Zero on error.
"""
cmd = {
"cmd": "set_frame",
"frame": frame,
"audio": audio
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["frame"]
else:
return 0
def get_range(self):
"""
Get the current range of the (primary) active timeline.
:return: Tuple containing the range of the (primary) active timeline. None on error.
"""
cmd = {
"cmd": "get_range"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return (reply["start_frame"], reply["end_frame"])
else:
return None
def set_range(self, start_frame, end_frame):
"""
Set the current range of the (primary) active timeline.
:param start_frame: Requested range start frame number.
:param end_frame: Requested range end frame number.
:return: Tuple containing the range of the (primary) active timeline. None on error.
"""
cmd = {
"cmd": "set_range",
"start_frame": start_frame,
"end_frame": end_frame
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return (reply["start_frame"], reply["end_frame"])
else:
return None
def get_default_timeline(self):
"""
Get the project default timeline.
Imported files (sources) are automatically added to this timeline.
:return: Dictionary representing the timeline object (may be empty if unassigned). None on error.
"""
cmd = {
"cmd": "get_default_timeline"
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["timeline"]
else:
return None
def set_default_timeline(self, id):
"""
Set the project default timeline. An empty 'id' string will result unassign the default timeline.
Imported files (sources) are automatically added to this timeline.
:return: Dictionary representing the timeline object (may be empty if unassigned). None on error.
"""
cmd = {
"cmd": "set_default_timeline",
"id": id
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def get_active_in_viewer(self, index):
"""
Get the source/timeline assigned to a viewer.
:param index: Viewer index. (0 - Viewer A, 1 - Viewer B)
:return: Dictionary representing the timeline object (may be empty if unassigned). None on error.
"""
cmd = {
"cmd": "get_active_in_viewer",
"index": index
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return reply["timeline"]
else:
return None
def set_active_in_viewer(self, id, index):
"""
Set the source/timeline assigned to a viewer.
An empty 'id' string will unassign a timeline from the viewer.
:param index: Viewer index. (0 - Viewer A, 1 - Viewer B)
:return: Dictionary representing the timeline object (may be empty if unassigned). None on error.
"""
cmd = {
"cmd": "set_active_in_viewer",
"id": id,
"index": index
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
def set_viewer_layout(self, layout="single"):
"""
Set the viewer layout to single, split horizontal or split vertical.
:param layout: Desired layout ("single", "horizontal" or "vertical")
:return: True on success. False otherwise.
"""
cmd = {
"cmd": "set_viewer_layout",
"layout": layout,
}
reply = self.send(cmd)
if self.is_valid_reply(reply):
return True
else:
return False
if __name__ == "__main__":
kpro = KeyframeProClient()
if kpro.connect():
print("Connected successfully.")

View File

@ -0,0 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import *

View File

@ -0,0 +1,556 @@
import datetime
import os
import shutil
import subprocess
import sys
import time
import traceback
import maya.cmds as cmds
import maya.mel as mel
import maya.OpenMaya as om
from keyframe_pro.keyframe_pro_client import KeyframeProClient
class MayaToKeyframePro:
WINDOW_NAME = "MayaToKeyframeProWindow"
WINDOW_TITLE = "Keyframe Pro"
VERSION = "1.0.1"
KEYFRAME_PRO_PATH = "C:/Program Files/Keyframe Pro/bin/KeyframePro.exe"
PORT = 18181
SYNC_SCRIPT_NODE_NAME = "MayaToKeyframeProScriptNode"
CACHED_TEMP_DIR_OPTION_VAR = "MayaToKeyframeProCachedTempDir"
COLLAPSE_STATE_OPTION_VAR = "MayaToKeyframeProCollapseState"
SYNC_OFFSET_OPTION_VAR = "MayaToKeyframeProSyncOffset"
FROM_RANGE_START_OPTION_VAR = "MayaToKeyframeProFromRangeStart"
WAIT_FOR_OPEN_DURATION = 1 # Seconds to sleep after trying to open the application
BUTTON_COLOR_01 = (0.5, 0.5, 0.5)
BUTTON_COLOR_02 = (0.361, 0.361, 0.361)
SYNC_ACTIVE_COLOR = (0.0, 0.5, 0.0)
kpro_client = None
main_window = None
sync_layout = None
viewer_layout = None
playblast_layout = None
sync_from_range_start_cb = None
sync_offset_ifg = None
playblast_viewer_rbg = None
@classmethod
def open_keyframe_pro(cls, application_path=""):
if not application_path:
application_path = cls.KEYFRAME_PRO_PATH
if not application_path:
om.MGlobal.displayError("Keyframe Pro application path not set.")
elif not os.path.exists(application_path):
om.MGlobal.displayError("Keyframe Pro application path does not exist: {0}".format(application_path))
else:
try:
subprocess.Popen(cls.KEYFRAME_PRO_PATH, shell=False, stdin=None, stdout=None, stderr=None)
except:
traceback.print_exc()
om.MGlobal.displayError("Failed to open Keyframe Pro. See script editor for details.")
@classmethod
def is_initialized(cls, display_errors=True):
if not cls.kpro_client:
cls.kpro_client = KeyframeProClient()
if cls.kpro_client.connect(port=cls.PORT, display_errors=display_errors):
if cls.kpro_client.initialize():
return True
else:
if display_errors:
om.MGlobal.displayError("Connection failed. Application may be closed or the port may be in use ({0}).".format(cls.PORT))
if display_errors:
om.MGlobal.displayError("Failed to connect to Keyframe Pro. See script editor for details.")
return False
@classmethod
def toggle_sync(cls):
if not cls.sync_script_node_exists() and cls.is_initialized():
cls.create_sync_script_node()
if cls.sync_script_node_exists():
cls.update_sync_time()
else:
cls.delete_sync_script_node()
cls.update_sync_state()
@classmethod
def update_sync_time(cls):
if cls.is_initialized():
frame = cmds.currentTime(q=True) + cls.get_sync_offset()
if cls.get_from_range_start():
range = cls.kpro_client.get_range()
if range:
frame += range[0] - 1
cls.kpro_client.set_frame(frame)
@classmethod
def set_viewer_layout(cls, layout):
if cls.is_initialized():
cls.kpro_client.set_viewer_layout(layout)
@classmethod
def swap_timelines(cls):
if cls.is_initialized():
a = cls.kpro_client.get_active_in_viewer(0)
b = cls.kpro_client.get_active_in_viewer(1)
if b:
cls.kpro_client.set_active_in_viewer(b["id"], 0)
if a:
cls.kpro_client.set_active_in_viewer(a["id"], 1)
@classmethod
def playblast(cls):
format = cls.get_option_var("playblastFormat", "avi")
ext = ""
if format == "avi":
ext = "avi"
elif format == "qt":
ext = "mov"
else:
om.MGlobal.displayError("Current playblast format is image. Images are not supported in the current version of Keyframe Pro")
return
temp_dir = cls.get_temp_dir()
if not temp_dir:
return
if not os.path.exists(temp_dir):
os.makedirs(temp_dir)
name = "blast"
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
file_path = "{0}/{1}_{2}.{3}".format(temp_dir, name, timestamp, ext)
clear_cache = cls.get_option_var("playblastClearCache", True)
show_ornaments = cls.get_option_var("playblastShowOrnaments", False)
compression = cls.get_option_var("playblastCompression", "none")
quality = cls.get_option_var("playblastQuality", 70)
percent = cls.get_option_var("playblastScale", 0.5) * 100
padding = cls.get_option_var("playblastPadding", 4)
display_source_size = cls.get_option_var("playblastDisplaySizeSource", 1)
playblast_width = cls.get_option_var("playblastWidth", 720)
playblast_height = cls.get_option_var("playblastHeight", 480)
args = {"format": format,
"clearCache": clear_cache,
"viewer": False,
"showOrnaments": show_ornaments,
"fp": padding,
"percent": percent,
"compression": compression,
"quality": quality,
"filename": file_path
}
if display_source_size == 2:
args["widthHeight"] = [cmds.getAttr("defaultResolution.w"), cmds.getAttr("defaultResolution.h")]
elif display_source_size == 3:
args["widthHeight"] = [playblast_width, playblast_height]
playback_slider = mel.eval("$tempVar = $gPlayBackSlider")
if(cmds.timeControl(playback_slider, q=True, rv=True)):
range = cmds.timeControl(playback_slider, q=True, ra=True)
args["startTime"] = range[0]
args["endTime"] = range[1]
sound = cmds.timeControl(playback_slider, q=True, sound=True)
if sound:
args["sound"] = sound
file_path = cmds.playblast(**args)
om.MGlobal.displayInfo(file_path)
# Open in viewer
viewer_index = cmds.radioButtonGrp(cls.playblast_viewer_rbg, q=True, select=True) - 1
if viewer_index <= 1:
if not cls.is_initialized(False):
cls.open_keyframe_pro()
time.sleep(cls.WAIT_FOR_OPEN_DURATION)
if not cls.is_initialized():
om.MGlobal.displayError("Failed to open in viewer. See script editor for details.")
return
if viewer_index >= 0 and viewer_index <= 1:
# On import, source may be loaded into A. Restore current A if source is to be in B
source_in_a = None
if viewer_index > 0:
source_in_a = cls.kpro_client.get_active_in_viewer(0)
# Swap
source = cls.kpro_client.import_file(file_path)
if source:
cls.kpro_client.set_active_in_viewer(source["id"], viewer_index)
if source_in_a:
cls.kpro_client.set_active_in_viewer(source_in_a["id"], 0)
@classmethod
def get_option_var(cls, name, default):
if cmds.optionVar(exists=name):
return cmds.optionVar(q=name)
else:
return default
@classmethod
def open_temp_dir(cls):
temp_dir = cls.get_temp_dir()
if temp_dir:
if sys.platform == "win32":
os.startfile(temp_dir, 'explore')
else:
om.MGlobal.displayError("Open temp dir is not supported on the current platform ({0})".format(sys.platform))
@classmethod
def clear_temp_dir(cls):
result = cmds.confirmDialog(title='Confirm',
message='Clear temporary directory?',
button=['Yes', 'No'],
defaultButton='Yes',
cancelButton='No',
dismissString='No')
if result == "Yes":
temp_dir = cls.get_temp_dir()
if temp_dir:
errors_occurred = False
for the_file in os.listdir(temp_dir):
file_path = os.path.join(temp_dir, the_file)
try:
if os.path.isfile(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except:
om.MGlobal.displayWarning("Failed to remove file: {0}".format(file_path))
om.MGlobal.displayWarning("File may be open in an application")
errors_occurred = True
if errors_occurred:
om.MGlobal.displayWarning("Unable to remove all files. See script editor for details.")
else:
om.MGlobal.displayInfo("Temporary directory cleared: {0}".format(temp_dir))
@classmethod
def get_temp_dir(cls):
if cls.is_initialized(display_errors=False):
config = cls.kpro_client.get_config()
if config:
cmds.optionVar(sv=[cls.CACHED_TEMP_DIR_OPTION_VAR, config["temp_dir"]])
return config["temp_dir"]
temp_dir = cls.get_option_var(cls.CACHED_TEMP_DIR_OPTION_VAR, "")
if not temp_dir:
om.MGlobal.displayWarning("Unable to get temporary directory.")
return temp_dir
@classmethod
def sync_script_node_exists(cls):
return cmds.objExists(cls.SYNC_SCRIPT_NODE_NAME)
@classmethod
def create_sync_script_node(cls):
if not cls.sync_script_node_exists():
cmds.scriptNode(scriptType=7,
beforeScript="try: MayaToKeyframePro.update_sync_time()\nexcept: pass",
name=cls.SYNC_SCRIPT_NODE_NAME,
sourceType="python")
@classmethod
def delete_sync_script_node(cls):
if cls.sync_script_node_exists():
cmds.delete(cls.SYNC_SCRIPT_NODE_NAME)
@classmethod
def get_sync_offset(cls):
if cmds.optionVar(exists=cls.SYNC_OFFSET_OPTION_VAR):
return cmds.optionVar(q=cls.SYNC_OFFSET_OPTION_VAR)
else:
return 0
@classmethod
def set_sync_offset(cls, value):
cmds.intFieldGrp(cls.sync_offset_ifg, e=True, value1=value)
cmds.optionVar(iv=[cls.SYNC_OFFSET_OPTION_VAR, value])
if (cls.sync_script_node_exists()):
cls.update_sync_time()
@classmethod
def sync_offset_to_current(cls):
cls.set_sync_offset(-cmds.currentTime(q=True) + 1)
@classmethod
def sync_offset_changed(cls):
cls.set_sync_offset(cmds.intFieldGrp(cls.sync_offset_ifg, q=True, value1=True))
@classmethod
def get_from_range_start(cls):
if cmds.optionVar(exists=cls.FROM_RANGE_START_OPTION_VAR):
return cmds.optionVar(q=cls.FROM_RANGE_START_OPTION_VAR)
else:
return 1
@classmethod
def update_from_range_start(cls):
value = cmds.checkBox(cls.sync_from_range_start_cb, q=True, value=True)
cmds.optionVar(iv=[cls.FROM_RANGE_START_OPTION_VAR, value])
if cls.sync_script_node_exists():
cls.update_sync_time()
@classmethod
def get_collapse_state(cls):
if cmds.optionVar(exists=cls.COLLAPSE_STATE_OPTION_VAR):
collapse_state = cmds.optionVar(q=cls.COLLAPSE_STATE_OPTION_VAR)
if len(collapse_state) == 3:
for value in collapse_state:
if value < 0 or value > 1:
return [0, 1, 1]
return collapse_state
return [0, 1, 1]
@classmethod
def update_collapse_state(cls):
cmds.optionVar(clearArray=cls.COLLAPSE_STATE_OPTION_VAR)
layouts = [cls.sync_layout, cls.viewer_layout, cls.playblast_layout]
for layout in layouts:
collapse = cmds.frameLayout(layout, q=True, cl=True)
cmds.optionVar(iva=[cls.COLLAPSE_STATE_OPTION_VAR, collapse])
@classmethod
def display(cls):
if cmds.window(cls.WINDOW_NAME, exists=True):
cmds.deleteUI(cls.WINDOW_NAME, window=True)
collapse_state = cls.get_collapse_state()
# ---------------------------------------------------------------------
# Main layout
# ---------------------------------------------------------------------
cls.main_window = cmds.window(cls.WINDOW_NAME, title=cls.WINDOW_TITLE, s=True, tlb=False, rtf=True, mnb=False, mxb=False)
main_layout = cmds.formLayout(parent=cls.main_window)
cls.sync_layout = cmds.frameLayout(parent=main_layout,
label="Sync", collapsable=True,
cl=collapse_state[0],
cc=lambda *args: cmds.evalDeferred("MayaToKeyframePro.on_collapse_changed()"),
ec=lambda *args: cmds.evalDeferred("MayaToKeyframePro.on_collapse_changed()"))
sync_form_layout = cmds.formLayout(parent=cls.sync_layout)
cls.viewer_layout = cmds.frameLayout(parent=main_layout,
label="Viewer",
collapsable=True,
cl=collapse_state[1],
cc=lambda *args: cmds.evalDeferred("MayaToKeyframePro.on_collapse_changed()"),
ec=lambda *args: cmds.evalDeferred("MayaToKeyframePro.on_collapse_changed()"))
viewer_form_layout = cmds.formLayout(parent=cls.viewer_layout)
cls.playblast_layout = cmds.frameLayout(parent=main_layout,
label="Playblast",
collapsable=True,
cl=collapse_state[2],
cc=lambda *args: cmds.evalDeferred("MayaToKeyframePro.on_collapse_changed()"),
ec=lambda *args: cmds.evalDeferred("MayaToKeyframePro.on_collapse_changed()"))
playblast_form_layout = cmds.formLayout(parent=cls.playblast_layout)
cmds.formLayout(main_layout, e=True, af=(cls.sync_layout, "top", 0))
cmds.formLayout(main_layout, e=True, af=(cls.sync_layout, "left", 0))
cmds.formLayout(main_layout, e=True, af=(cls.sync_layout, "right", 0))
cmds.formLayout(main_layout, e=True, ac=(cls.viewer_layout, "top", 0, cls.sync_layout))
cmds.formLayout(main_layout, e=True, af=(cls.viewer_layout, "left", 0))
cmds.formLayout(main_layout, e=True, af=(cls.viewer_layout, "right", 0))
cmds.formLayout(main_layout, e=True, ac=(cls.playblast_layout, "top", 0, cls.viewer_layout))
cmds.formLayout(main_layout, e=True, af=(cls.playblast_layout, "left", 0))
cmds.formLayout(main_layout, e=True, af=(cls.playblast_layout, "right", 0))
# ---------------------------------------------------------------------
# Sync layout
# ---------------------------------------------------------------------
cls.sync_offset_ifg = cmds.intFieldGrp(label="Offset: ",
value1=MayaToKeyframePro.get_sync_offset(),
columnWidth2=(40, 48),
cl2=("left", "right"),
cc=lambda *args: MayaToKeyframePro.sync_offset_changed(),
parent=sync_form_layout)
cls.sync_from_range_start_cb = cmds.checkBox(label="From Range Start",
value=MayaToKeyframePro.get_from_range_start(),
cc=lambda *args: MayaToKeyframePro.update_from_range_start(),
parent=sync_form_layout)
sync_offset_to_current_btn = cmds.button(label="Current",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.sync_offset_to_current(),
parent=sync_form_layout)
reset_sync_offset_btn = cmds.button(label=" Reset ",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.set_sync_offset(0),
parent=sync_form_layout)
cls.sync_btn = cmds.button(label="SYNC", c=lambda *args: MayaToKeyframePro.toggle_sync(), parent=sync_form_layout)
top_offset = 1
bottom_offset = 4
left_position = 1
right_position = 99
spacing = 2
cmds.formLayout(sync_form_layout, e=True, af=(cls.sync_offset_ifg, "top", top_offset))
cmds.formLayout(sync_form_layout, e=True, ap=(cls.sync_offset_ifg, "left", 0, left_position))
cmds.formLayout(sync_form_layout, e=True, af=(sync_offset_to_current_btn, "top", top_offset))
cmds.formLayout(sync_form_layout, e=True, ac=(sync_offset_to_current_btn, "left", 0, cls.sync_offset_ifg))
cmds.formLayout(sync_form_layout, e=True, af=(reset_sync_offset_btn, "top", top_offset))
cmds.formLayout(sync_form_layout, e=True, ac=(reset_sync_offset_btn, "left", spacing, sync_offset_to_current_btn))
cmds.formLayout(sync_form_layout, e=True, ac=(cls.sync_from_range_start_cb, "top", top_offset, sync_offset_to_current_btn))
cmds.formLayout(sync_form_layout, e=True, ap=(cls.sync_from_range_start_cb, "left", 0, left_position))
cmds.formLayout(sync_form_layout, e=True, ac=(cls.sync_btn, "top", 2 * spacing, cls.sync_from_range_start_cb))
cmds.formLayout(sync_form_layout, e=True, af=(cls.sync_btn, "bottom", bottom_offset))
cmds.formLayout(sync_form_layout, e=True, ap=(cls.sync_btn, "left", 0, left_position))
cmds.formLayout(sync_form_layout, e=True, ap=(cls.sync_btn, "right", 0, right_position))
# ---------------------------------------------------------------------
# Viewer layout
# ---------------------------------------------------------------------
single_viewer_btn = cmds.button(label="Single",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.set_viewer_layout('single'),
parent=viewer_form_layout)
hori_viewer_btn = cmds.button(label="Horizontal",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.set_viewer_layout('horizontal'),
parent=viewer_form_layout)
vert_viewer_btn = cmds.button(label=" Vertical ",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.set_viewer_layout('vertical'),
parent=viewer_form_layout)
swap_timelines_btn = cmds.button(label="Swap Timelines",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.swap_timelines(),
parent=viewer_form_layout)
cmds.formLayout(viewer_form_layout, e=True, af=(single_viewer_btn, "top", top_offset))
cmds.formLayout(viewer_form_layout, e=True, ap=(single_viewer_btn, "left", 0, left_position))
cmds.formLayout(viewer_form_layout, e=True, ap=(single_viewer_btn, "right", 0, 38))
cmds.formLayout(viewer_form_layout, e=True, af=(hori_viewer_btn, "top", top_offset))
cmds.formLayout(viewer_form_layout, e=True, ac=(hori_viewer_btn, "left", spacing, single_viewer_btn))
cmds.formLayout(viewer_form_layout, e=True, ap=(hori_viewer_btn, "right", 0, 68))
cmds.formLayout(viewer_form_layout, e=True, af=(vert_viewer_btn, "top", top_offset))
cmds.formLayout(viewer_form_layout, e=True, ac=(vert_viewer_btn, "left", spacing, hori_viewer_btn))
cmds.formLayout(viewer_form_layout, e=True, ap=(vert_viewer_btn, "right", 0, right_position))
cmds.formLayout(viewer_form_layout, e=True, ac=(swap_timelines_btn, "top", spacing, single_viewer_btn))
cmds.formLayout(viewer_form_layout, e=True, af=(swap_timelines_btn, "bottom", bottom_offset))
cmds.formLayout(viewer_form_layout, e=True, ap=(swap_timelines_btn, "left", 0, left_position))
cmds.formLayout(viewer_form_layout, e=True, ap=(swap_timelines_btn, "right", 0, right_position))
# ---------------------------------------------------------------------
# Playblast layout
# ---------------------------------------------------------------------
cls.playblast_viewer_rbg = cmds.radioButtonGrp(label='Open in Viewer: ',
labelArray3=['A', 'B', 'None'],
numberOfRadioButtons=3,
select=1,
cw4=(100, 40, 40, 40),
cl4=("left", "left", "left", "left"),
parent=playblast_form_layout)
playblast_btn = cmds.button(label="PLAYBLAST",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.playblast(),
parent=playblast_form_layout)
open_temp_dir_btn = cmds.button(label="Open Temp Folder",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.open_temp_dir(),
parent=playblast_form_layout)
clear_temp_dir_btn = cmds.button(label="Clear Temp Folder",
bgc=cls.BUTTON_COLOR_01,
c=lambda *args: MayaToKeyframePro.clear_temp_dir(),
parent=playblast_form_layout)
version_label = cmds.text(label="v{0}".format(cls.VERSION), align="right")
cmds.formLayout(playblast_form_layout, e=True, af=(cls.playblast_viewer_rbg, "top", top_offset))
cmds.formLayout(playblast_form_layout, e=True, ap=(cls.playblast_viewer_rbg, "left", 0, left_position))
cmds.formLayout(playblast_form_layout, e=True, ac=(playblast_btn, "top", spacing, cls.playblast_viewer_rbg))
cmds.formLayout(playblast_form_layout, e=True, ap=(playblast_btn, "left", 0, left_position))
cmds.formLayout(playblast_form_layout, e=True, ap=(playblast_btn, "right", 0, right_position))
cmds.formLayout(playblast_form_layout, e=True, ac=(open_temp_dir_btn, "top", spacing, playblast_btn))
cmds.formLayout(playblast_form_layout, e=True, ap=(open_temp_dir_btn, "left", 0, left_position))
cmds.formLayout(playblast_form_layout, e=True, ap=(open_temp_dir_btn, "right", 1, 50))
cmds.formLayout(playblast_form_layout, e=True, ac=(clear_temp_dir_btn, "top", spacing, playblast_btn))
cmds.formLayout(playblast_form_layout, e=True, ap=(clear_temp_dir_btn, "left", 1, 50))
cmds.formLayout(playblast_form_layout, e=True, ap=(clear_temp_dir_btn, "right", 0, right_position))
cmds.formLayout(playblast_form_layout, e=True, ac=(version_label, "top", spacing, open_temp_dir_btn))
cmds.formLayout(playblast_form_layout, e=True, ap=(version_label, "right", 0, right_position))
# ---------------------------------------------------------------------
# Update and show
# ---------------------------------------------------------------------
cls.update_sync_state()
cls.on_collapse_changed()
cmds.setFocus(cls.sync_btn)
cmds.showWindow(cls.main_window)
@classmethod
def on_collapse_changed(cls):
total_height = 0
layouts = [cls.sync_layout, cls.viewer_layout, cls.playblast_layout]
for layout in layouts:
total_height += cmds.frameLayout(layout, q=True, h=True)
cmds.window(MayaToKeyframePro.main_window, e=True, h=total_height)
cls.update_collapse_state()
@classmethod
def update_sync_state(cls):
if cls.sync_script_node_exists():
cmds.button(cls.sync_btn, e=True, bgc=cls.SYNC_ACTIVE_COLOR, label="SYNCED")
else:
cmds.button(cls.sync_btn, e=True, bgc=cls.BUTTON_COLOR_01, label="SYNC")
if __name__ == "__main__":
MayaToKeyframePro.display()

File diff suppressed because it is too large Load Diff