LoginSignup
0
0

More than 1 year has passed since last update.

maya python humanIK retarget

Last updated at Posted at 2022-10-26

## 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()
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0