## Script Flow
1. Open New Scene
2. Get Default Hik List
3. Import Source Fbx
4. Rename Fbx with 'source:' namespace
5. Save source hik to list
6. Import Target Fbx
7. Get Target Hik from diff between cuurent hik list and default+source hik list
8. Retarget target Hik to source
9. bake
merge.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import maya.cmds as cmds
import pymel.core as pm
from maya import mel
def GetHikList():
mel.eval("HIKCharacterControlsTool;")
_HUMAN_IK_SOURCE_MENU = "hikSourceList"
_HUMAN_IK_SOURCE_MENU_OPTION = _HUMAN_IK_SOURCE_MENU + "|OptionMenu"
items = cmds.optionMenuGrp(_HUMAN_IK_SOURCE_MENU, q=True, ill=True)
hikList = []
for i in xrange(0, len(items)):
label = cmds.menuItem(items[i], q=True, l=True)
hikList.append(label)
return hikList
def GetCurrentHikCharacter():
"""
....Get the current active character definition.
...."""
mel.eval("HIKCharacterControlsTool;")
char = mel.eval("hikGetCurrentCharacter();")
return char
def hikUpdateTool():
melCode = """
if ( hikIsCharacterizationToolUICmdPluginLoaded() )
{
hikUpdateCharacterList();
hikUpdateCurrentCharacterFromUI();
hikUpdateContextualUI();
hikControlRigSelectionChangedCallback;
hikUpdateSourceList();
hikUpdateCurrentSourceFromUI();
hikUpdateContextualUI();
hikControlRigSelectionChangedCallback;
}
"""
try:
mel.eval(melCode)
except:
pass
def SetHikChar(targetChar):
mel.eval("HIKCharacterControlsTool;")
mel.eval('hikSetCurrentCharacter("{0}")'.format(targetChar))
hikUpdateTool()
def SetHikSourceChar(source):
_HUMAN_IK_SOURCE_MENU = "hikSourceList"
_HUMAN_IK_SOURCE_MENU_OPTION = _HUMAN_IK_SOURCE_MENU + "|OptionMenu"
items = cmds.optionMenuGrp(_HUMAN_IK_SOURCE_MENU, q=True, ill=True)
for i in xrange(0, len(items)):
label = cmds.menuItem(items[i], q=True, l=True)
# 空白が頭に入っているので除去
if label.lstrip() == source:
cmds.optionMenu(_HUMAN_IK_SOURCE_MENU_OPTION, e=True, sl=i + 1)
mel.eval("hikUpdateCurrentSourceFromUI()")
mel.eval("hikUpdateContextualUI()")
mel.eval("hikControlRigSelectionChangedCallback")
break
def isCharacterDefinition(char):
# Check Node Exists
if not cmds.objExists(char): return False
# Check Node Type
if cmds.objectType(char) != 'HIKCharacterNode': return False
return True
def getCharacterNodes(char):
# Check Node
if not isCharacterDefinition(char):
raise Exception(
'Invalid character definition node! Object "'
+ char
+ '" does not exist or is not a valid HIKCharacterNode!'
)
# Get Character Nodes
charNodes = mel.eval('hikGetSkeletonNodes "' + char + '"')
# Return Result
return charNodes
def bake(char, start, end):
cmds.playbackOptions(min=start, max=end)
bones = getCharacterNodes(char)
# Bake Animation
cmds.bakeResults(
bones,
simulation=True,
t=(start, end),
sampleBy=1,
disableImplicitControl=True,
preserveOutsideKeys=False,
sparseAnimCurveBake=False,
removeBakedAttributeFromLayer=False,
bakeOnOverrideLayer=False,
minimizeRotation=False,
at=["tx", "ty", "tz", "rx", "ry", "rz"],
)
def main(sourceFile, targetFile):
cmds.file(new=True, force=True)
defaultHikList = GetHikList()
cmds.file(sourceFile, i=True, force=True)
allTransform = cmds.ls()
cmds.select(allTransform)
for i in allTransform:
try:
oldName = i.split("|")[-1]
newName = ":source:{}".format(oldName)
if ":" in oldName:
newName = ":source:" + oldName.split(":")[-1]
new = cmds.rename(oldName, newName)
except:
continue
joints = cmds.ls("*:*", long=True, type="joint")
cmds.select(joints)
all_keys = sorted(cmds.keyframe(joints, q=True) or [])
if all_keys:
start = int(all_keys[0])
end = int(all_keys[-1])
print(start, end)
sourceChar = GetCurrentHikCharacter()
cmds.file(targetFile, i=True, force=True)
hikList = GetHikList()
targetChar = ""
for hik in hikList:
if hik not in defaultHikList:
if hik != sourceChar:
targetChar = hik.lstrip()
break
SetHikChar(targetChar)
SetHikSourceChar(sourceChar)
bake(targetChar, start, end)
merge_ui.py
#-*- coding:utf-8
VERSION = 'v1'
import ConfigParser
import csv
import glob
import os
import re
import sys
import maya
import pymel.core as pm
sys.path.append(r'J:/vd2/tool/runtime/qbLauncherX/versions/002.009.000/lib/all/Qt.py/python')
from Qt import __binding__, QtGui, QtCore, QtWidgets
if __binding__ == 'PySide2':
import pyside2uic as pysideuic
from shiboken2 import wrapInstance
elif __binding__ == 'PySide':
import pysideuic
from shiboken import wrapInstance
import maya.OpenMayaUI as apiUI
def getMainWindow():
pointer = apiUI.MQtUtil.mainWindow()
if pointer is not None:
_MainWindow = wrapInstance(long(pointer), QtWidgets.QWidget)
return _MainWindow
#####################UI########################
class Main_Window(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Main_Window, self).__init__(parent)
self.inint_widget()
def selectFile(self, ftype):
if self.sourcefname is not None and os.path.isfile(self.sourcefname):
directory = self.sourcefname
else:
directory = QtCore.QDir.currentPath()
dialog = QtWidgets.QFileDialog.getOpenFileName(
self, 'Select fbx file', directory, 'fbx files (*fbx)')
if dialog[0] != 0:
if ftype == 'source':
self.sourcefname = str(dialog[0])
self.sourceflineEdit.setText(str(dialog[0]))
else:
self.targetfname = str(dialog[0])
self.targetflineEdit.setText(str(dialog[0]))
def run(self, sourceFile, targetFile):
sys.path.append(r"I:/script/bin/td/maya/scripts/mocapConvert/merge")
import merge
reload(merge)
print(sourceFile, targetFile)
merge.main(sourceFile, targetFile)
def inint_widget(self):
QV_0_ayout = QtWidgets.QVBoxLayout()
QV_A_ayout = QtWidgets.QHBoxLayout()
QV_B_ayout = QtWidgets.QHBoxLayout()
QV_C_ayout = QtWidgets.QVBoxLayout()
QV_D_ayout = QtWidgets.QHBoxLayout()
QV_E_ayout = QtWidgets.QHBoxLayout()
self.sourcefname = ''
self.sourceflineEdit = QtWidgets.QLineEdit()
label = QtWidgets.QLabel('Source: ')
QV_A_ayout.addWidget(label)
QV_A_ayout.addWidget(self.sourceflineEdit)
sourceBrouseBtn = QtWidgets.QPushButton('...')
QV_A_ayout.addWidget(sourceBrouseBtn)
sourceBrouseBtn.clicked.connect(lambda: self.selectFile('source'))
self.targetfname = ''
self.targetflineEdit = QtWidgets.QLineEdit()
label = QtWidgets.QLabel('Target: ')
QV_B_ayout.addWidget(label)
QV_B_ayout.addWidget(self.targetflineEdit)
targetBrouseBtn = QtWidgets.QPushButton('...')
QV_B_ayout.addWidget(targetBrouseBtn)
targetBrouseBtn.clicked.connect(lambda: self.selectFile('target'))
QV_0_ayout.addLayout(QV_D_ayout)
QV_0_ayout.addLayout(QV_E_ayout)
QV_0_ayout.addLayout(QV_A_ayout)
QV_0_ayout.addLayout(QV_B_ayout)
# self.seqListTextField = QtWidgets.QLineEdit()
# self.seqListTextField.setFixedHeight(20)
# self.seqListTextField.setPlaceholderText('Enter Seq Seperate With Comma')
# self.seqListTextField.setToolTip('s026, s027')
# self.seqListTextField.setObjectName('testLineEdit')
button_layout = QtWidgets.QLabel(' ')
runBtn = QtWidgets.QPushButton('Transfer')
QV_C_ayout.addWidget(runBtn)
runBtn.clicked.connect(lambda: self.run(self.sourcefname, self.targetfname))
# shotgun_button = QtWidgets.QPushButton('OPEN_SHOTGUN')
# QV_C_ayout.addWidget(self.seqListTextField)
# QV_C_ayout.addWidget(shotgun_button)
# shotgun_button.setStyleSheet("background-color: orange")
QVlayout = QtWidgets.QVBoxLayout()
QVlayout.addLayout(QV_0_ayout)
QVlayout.addLayout(QV_C_ayout)
w = QtWidgets.QWidget()
w.setLayout(QVlayout)
self.setCentralWidget(w)
self.setWindowTitle('Animation Retarget Tool')
print("INIT")
########################################################
def run():
global main_window
try:
main_window.close()
except:
pass
maya_main_wid = getMainWindow()
main_window = Main_Window(parent = maya_main_wid)
main_window.show()
main_window.setMinimumSize(600,250)
main_window.setMaximumSize(600,250)
if __name__ == '__main__':
run()