mGearを使ってみた。021 GuidからRigContrallerのビルド とスキニング(Maya2020 +mGear3.7.0版)

どうにかこうにか手動でGuidを昔のジョイントに合わせたものがこれ

https://www.mediafire.com/file/c7jlzs28s5bpvn5/MiChoPa094_imported_mGearBipeGuide_And_Genesis8FemaleJoint.zip/file

指が間違ってた。

でこの動画の続きによると

型の始まりのGuidのCUBEをクリックして Dupl.Sym.を押すと左右が対象になるみたいだったけど
つかってない手でやった。

つぎにGuidのトップノードを選択して新シーンとして保存してる

Guidトップ選択して Build From Selection

走りだす。

リグが出力されたようだ このあと動画のようにコントロールリグのサイズを変更しなくてスキンバインドのテストしたほうがいいと思う。

リグデフォーマグループを選択する

上やじるしを押すとすべての読み取るのに必要なジョイントが選択されます。

つまりはこれがしたいみたい。

設定は
ジョイント階層
測地線ボクセル
クラシックリニア
インタラクティブ
距離
チェックあり

チェック
チェック
チェック
チェックなし

ではリグを動かしてみましょう!

動かしにくいので最後にリグコントローラーのサイズを変更しよう。

ここでジョイントの表示サイズがでかすぎたのか変更してる。

表示サイズを大きくすると、ジョイントやボーンが選択しやすくなります。 表示サイズを小さくすると、フレクサなど他のオブジェクトが選択しやすくなります。 ディスプレイ > アニメーション > ジョイント サイズ(Display > Animation > Joint Size)を選択します。

一番下の8角形が大きすぎたので

Control+右クリックで「CV」を選択して小さくスケールしてる。

スケールできないからスケールツールをダブルクリックで起動しなおすことで初期化してスケールしてる。

ここでは逆に大きくした。

手の幅ぐらいのサイズにした

コントローラーハンドルここではBOXが頭にめり込んでるので直している。

した

体も同じくボディに埋まっているコントロールハンドルをCVモードで拡大していく

こんな感じ

mGearを使ってみた。020 (Maya2020 +mGear3.7.0版

ちょっとさらに仕切り直し

Maya2016 +mGear2.6.1系 から

Maya2020 +mGear3.7.0_beta_01に乗り換えてみた。

1、モデルを用意した

2,mGear/Shifter/Guide Managerを起動

3,mGear/Shifter/Guid Template Samples/Biped Template を実行
黄色いguidが作成された。

4、guideのサイズをモデルに合わせる
  合わせやすいようにシェーディング/ワイヤーフレームシェードにした

ここではもとにあったジョイントに全くびったり合わせるために

ジョイントを読み込みました。

位置合わせツールがあったら楽なのにと思いました。

いろいろやったが下のスクリプトなど作ったがJointの数とターゲットの数も違うし使えなかった仕事としてならたぶん無理やりできるんだろうなと思う。

import maya.cmds as cmds
selectedList=cmds.ls( selection=True )
print("selectedList="+str(selectedList))
jointOriginal=selectedList[0]
guidTarget=selectedList[1]

#world座標を取る いろいろ考えたけど親基準にローカル座標そろえるのやめた。なぜなら親もローカル座標そろえないと話は始まらないから。
#cmds.pointPosition( 'particle1.pt[1]', world=True )
#def getParentWorldPos()
j_parentlist=cmds.listRelatives(jointOriginal, parent=True )
g_parentlist=cmds.listRelatives(jointOriginal, parent=True )
#print("parentlist="+str(parentlist))
jointOriginalParent=j_parentlist[0]
guidTargetParent=g_parentlist[0]
print("jointOriginalParent="+str(jointOriginalParent))
print("guidTargetParent="+str(guidTargetParent))
jointOriginalParentWorldXYZ=cmds.xform(jointOriginalParent,worldSpace=True, q=True, translation=True )
guidTargetParentWorldXYZ=cmds.xform(guidTargetParent,worldSpace=True, q=True, translation=True )
jointOriginalParentWorldXYZrot=cmds.xform(jointOriginalParent,worldSpace=True, q=True, rotation=True )
guidTargetParentWorldXYZrot=cmds.xform(guidTargetParent,worldSpace=True, q=True, rotation=True )
print("jointOriginalParentWorldXYZ="+str(jointOriginalParentWorldXYZ))
print("guidTargetParentWorldXYZ="+str(guidTargetParentWorldXYZ))
w_xDiff=jointOriginalParentWorldXYZ[0]-guidTargetParentWorldXYZ[0]
w_yDiff=jointOriginalParentWorldXYZ[1]-guidTargetParentWorldXYZ[1]
w_zDiff=jointOriginalParentWorldXYZ[2]-guidTargetParentWorldXYZ[2]

w_xDiffR=jointOriginalParentWorldXYZrot[0]-guidTargetParentWorldXYZrot[0]
w_yDiffR=jointOriginalParentWorldXYZrot[1]-guidTargetParentWorldXYZrot[1]
w_zDiffR=jointOriginalParentWorldXYZrot[2]-guidTargetParentWorldXYZrot[2]
worldDiff=[w_xDiff,w_yDiff,w_zDiff]
worldDiffR=[w_xDiffR,w_yDiffR,w_zDiffR]

print("worldDiff="+str(worldDiff))
print("worldDiffR="+str(worldDiffR))
""""""
tx=cmds.getAttr(jointOriginal+".tx")
ty=cmds.getAttr(jointOriginal+".ty")
tz=cmds.getAttr(jointOriginal+".tz")
print(" tx= "+str(tx)+" ty= "+str(ty)+" tz= "+str(tz))
"""
cmds.setAttr(guidTarget+".tx",tx)
cmds.setAttr(guidTarget+".ty",ty)
cmds.setAttr(guidTarget+".tz",tz)
"""
guid_Scale=9.869
goTX=guid_Scale/tx+w_xDiff
goTY=guid_Scale/ty+w_yDiff
goTZ=guid_Scale/tz+w_zDiff
print(" goTX= "+str(goTX)+" goTY= "+str(goTY)+" goTZ= "+str(goTZ))

""""""
#ZをXに
""""""
cmds.setAttr(guidTarget+".tx",goTZ)
cmds.setAttr(guidTarget+".ty",goTY)
cmds.setAttr(guidTarget+".tz",goTX)

"""
cmds.setAttr(guidTarget+".rx",goTZ)
cmds.setAttr(guidTarget+".ry",goTX)
cmds.setAttr(guidTarget+".rz",goTY)
"""

地道にジョイントにguideを合わせるしかない。(今のところ)

単位が違くなってるのはさっきguide側にスケールかけたからだった。

これはjoint rHand

これはguide のarm_R0_wrist

もう少しで、いけそうなのになあ

mGearを使ってみた。004

用意したモデルに

Shifter/Guide Template Samples /Biped Templateをやってみたらエラー

エラー: AttributeError: file C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release\scripts\mgear\core\utils.py line 223: nt.NurbsCurve(u’global_C0_axisShape’) has no attribute or method named ‘lineWidth’ #

バージョン的にだめな予感がしてきたので過去のmGearを探すことにした。

https://github.com/mgear-dev/mgear/releases/tag/v2.6.1

mGearを使ってみた。004

こんどは

mGear/Shifter/Guid Mannager起動してみたら起動したエラー

File “C:/Users/whaison/Documents/maya/2016/ja_JP/scripts/mGear/mgear_3.7.0_beta_01/release/scripts/mgear/shifter_classic_components\ui_slider_01\settingsUI.py”, line 11, in
from PySide2 import QtCore, QtGui, QtWidgets
ImportError: No module named PySide2

Maya2016にはPyside2はありませんよねそりゃ

以下の3つのファイルのソースを変更する

C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release\scripts\mgear\shifter_classic_components\ui_slider_01\settingsUI.py

C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release\scripts\mgear\shifter_classic_components\ui_container_01\settingsUI.py

C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release\scripts\mgear\shifter_classic_components\sdk_control_01\settingsUI.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'C:\Users\Justi\OneDrive\Documents\maya\mGear\scripts\mgear\shifter_classic_components\sdk_control_01\settingsUI.ui'
#
# Created: Sat Aug 24 10:20:58 2019
#      by: pyside2-uic  running on PySide2 2.0.0~alpha0
#
# WARNING! All changes made in this file will be lost!

#from PySide2 import QtCore, QtGui, QtWidgets
from PySide import QtCore, QtGui

エラーなく動いた。

今回の変更はただのUIのロード先の変更なのでたーぶーん全体的には動く予感

mGearを使ってみた。003

エラー: AttributeError: file C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release\scripts\mgear\core\pyqt.py line 160: ‘module’ object has no attribute ‘workspaceControl’

についてだが

この160行目をコメントしたら動いた。

C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release\scripts\mgear\core\pyqt.py

"""pyQt/pySide widgets and helper functions for mGear"""

#############################################
# GLOBAL
#############################################
import os
import traceback
import maya.OpenMayaUI as omui
import pymel.core as pm

from mgear.vendor.Qt import QtWidgets
from mgear.vendor.Qt import QtCompat
from mgear.vendor.Qt import QtGui
from mgear.vendor.Qt import QtSvg

UI_EXT = "ui"

_LOGICAL_DPI_KEY = "_LOGICAL_DPI"

#################
# Old qt importer
#################


def _qt_import(binding, shi=False, cui=False):
    QtGui = None
    QtCore = None
    QtWidgets = None
    wrapInstance = None

    if binding == "PySide2":
        from PySide2 import QtGui, QtCore, QtWidgets
        import shiboken2 as shiboken
        from shiboken2 import wrapInstance
        from pyside2uic import compileUi

    elif binding == "PySide":
        from PySide import QtGui, QtCore
        import PySide.QtGui as QtWidgets
        import shiboken
        from shiboken import wrapInstance
        from pysideuic import compileUi

    elif binding == "PyQt4":
        from PyQt4 import QtGui
        from PyQt4 import QtCore
        import PyQt4.QtGui as QtWidgets
        from sip import wrapinstance as wrapInstance
        from PyQt4.uic import compileUi
        print("Warning: 'shiboken' is not supported in 'PyQt4' Qt binding")
        shiboken = None

    else:
        raise Exception("Unsupported python Qt binding '%s'" % binding)

    rv = [QtGui, QtCore, QtWidgets, wrapInstance]
    if shi:
        rv.append(shiboken)
    if cui:
        rv.append(compileUi)
    return rv


def qt_import(shi=False, cui=False):
    """
    import pyside/pyQt

    Returns:
        multi: QtGui, QtCore, QtWidgets, wrapInstance

    """
    lookup = ["PySide2", "PySide", "PyQt4"]

    preferredBinding = os.environ.get("MGEAR_PYTHON_QT_BINDING", None)
    if preferredBinding is not None and preferredBinding in lookup:
        lookup.remove(preferredBinding)
        lookup.insert(0, preferredBinding)

    for binding in lookup:
        try:
            return _qt_import(binding, shi, cui)
        except Exception:
            pass

    raise _qt_import("ThisBindingSurelyDoesNotExist", False, False)


compileUi = qt_import(shi=True, cui=True)[-1]

#############################################
# helper Maya pyQt functions
#############################################


def ui2py(filePath=None, *args):
    """Convert qtDesigner .ui files to .py"""

    if not filePath:
        startDir = pm.workspace(q=True, rootDirectory=True)
        filePath = pm.fileDialog2(dialogStyle=2,
                                  fileMode=1,
                                  startingDirectory=startDir,
                                  fileFilter='PyQt Designer (*%s)' % UI_EXT,
                                  okc="Compile to .py")
        if not filePath:
            return False
        filePath = filePath[0]
    if not filePath:
        return False

    if not filePath.endswith(UI_EXT):
        filePath += UI_EXT
    compiledFilePath = filePath[:-2] + "py"
    pyfile = open(compiledFilePath, 'w')
    compileUi(filePath, pyfile, False, 4, False)
    pyfile.close()

    info = "PyQt Designer file compiled to .py in: "
    pm.displayInfo(info + compiledFilePath)


def maya_main_window():
    """Get Maya's main window

    Returns:
        QMainWindow: main window.

    """

    main_window_ptr = omui.MQtUtil.mainWindow()
    return QtCompat.wrapInstance(long(main_window_ptr), QtWidgets.QWidget)


def showDialog(dialog, dInst=True, dockable=False, *args):
    """
    Show the defined dialog window

    Attributes:
        dialog (QDialog): The window to show.

    """
    if dInst:
        try:
            for c in maya_main_window().children():
                if isinstance(c, dialog):
                    c.deleteLater()
        except Exception:
            pass

    # Create minimal dialog object

    # if versions.current() >= 20180000:
    #     windw = dialog(maya_main_window())
    # else:
    windw = dialog()

    # ensure clean workspace name
    if hasattr(windw, "toolName") and dockable:
        control = windw.toolName + "WorkspaceControl"
        #if pm.workspaceControl(control, q=True, exists=True):
        #    pm.workspaceControl(control, e=True, close=True)
        #    pm.deleteUI(control, control=True)
    desktop = QtWidgets.QApplication.desktop()
    screen = desktop.screen()
    screen_center = screen.rect().center()
    windw_center = windw.rect().center()
    windw.move(screen_center - windw_center)

    # Delete the UI if errors occur to avoid causing winEvent
    # and event errors (in Maya 2014)
    try:
        if dockable:
            windw.show(dockable=True)
        else:
            windw.show()
        return windw
    except Exception:
        windw.deleteLater()
        traceback.print_exc()


def deleteInstances(dialog, checkinstance):
    """Delete any instance of a given dialog

    Delete any instance of a given dialog and if the dialog is
    instance of checkinstance.

    Attributes:
        dialog (QDialog): The dialog to delete.
        checkinstance (QDialog): The instance to check the type of dialog.

    """
    mayaMainWindow = maya_main_window()
    for obj in mayaMainWindow.children():
        if isinstance(obj, checkinstance):
            if obj.widget().objectName() == dialog.toolName:
                print 'Deleting instance {0}'.format(obj)
                mayaMainWindow.removeDockWidget(obj)
                obj.setParent(None)
                obj.deleteLater()


def fakeTranslate(*args):
    """Fake Translation

    fake QApplication.translate. This function helps to bypass the
    incompativility for the Unicode utf8  deprecated in pyside2

    """
    return args[1]


def position_window(window):
    """ set the position for the windonw

    Function borrowed from Cesar Saez QuickLauncher
    Args:
        window (QtWidget): the window to position
    """
    pos = QtGui.QCursor.pos()
    window.move(pos.x(), pos.y())


def get_main_window(widget=None):
    """Get the active window

    Function borrowed from Cesar Saez QuickLauncher
    Args:
        widget (QtWidget, optional): window

    Returns:
        QtWidget: parent of the window
    """
    widget = widget or QtWidgets.QApplication.activeWindow()
    if widget is None:
        return
    parent = widget.parent()
    if parent is None:
        return widget
    return get_main_window(parent)


def get_instance(parent, gui_class):
    """Get instace of a window from a given parent

    Function borrowed from Cesar Saez QuickLauncher
    Args:
        parent (QtWidget): parent
        gui_class (QtWidget): instance class to check

    """
    for children in parent.children():
        if isinstance(children, gui_class):
            return children
    return None


def get_icon_path(icon_name=None):
    """ Gets the directory path to the icon
    """

    file_dir = os.path.dirname(__file__)

    if "\\" in file_dir:
        file_dir = file_dir.replace("\\", "/")
    if icon_name:
        return "{0}/icons/{1}".format(file_dir, icon_name)
    else:
        return "{}/icons".format(file_dir)


def get_icon(icon, size=24):
    """get svg icon from icon resources folder as a pixel map
    """
    img = get_icon_path("{}.svg".format(icon))
    svg_renderer = QtSvg.QSvgRenderer(img)
    image = QtGui.QImage(size, size, QtGui.QImage.Format_ARGB32)
    # Set the ARGB to 0 to prevent rendering artifacts
    image.fill(0x00000000)
    svg_renderer.render(QtGui.QPainter(image))
    pixmap = QtGui.QPixmap.fromImage(image)

    return pixmap


# dpi scale test -------------------------------------------------------------
def get_logicaldpi():
    """attempting to "cache" the query to the maya main window for speed

    Returns:
        int: dpi of the monitor
    """
    if _LOGICAL_DPI_KEY not in os.environ.keys():
        try:
            logical_dpi = maya_main_window().logicalDpiX()
        except Exception:
            logical_dpi = 96
        finally:
            os.environ[_LOGICAL_DPI_KEY] = str(logical_dpi)
    return int(os.environ.get(_LOGICAL_DPI_KEY)) or 96


def dpi_scale(value, default=96, min_=1, max_=2):
    """Scale the provided value by the scale that maya is using
    which is derived from the 'average' dpi of 96 from windows, linux, osx.

    Args:
        value (int, float): value to scale
        default (int, optional): assumed default from various platforms
        min_ (int, optional): if you do not want the value under 96 dpi
        max_ (int, optional): if you do not want a value higher than 200% scale

    Returns:
        # int, float: scaled value
    """
    return value * max(min_, min(get_logicaldpi() / float(default), max_))

mGear/Shifter/Guid Mannager起動してみたら起動した。

mGearを使ってみた。002

mGear/Shifter/Guid Mannager起動してみたら起動できなかった。

エラー: AttributeError: file C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release\scripts\mgear\core\pyqt.py line 160: ‘module’ object has no attribute ‘workspaceControl’

zipフォルダにはいってるdrag_n_drop_install.pyってなんやろね

たぶんインストールが的確じゃなかった。

drag_n_drop_install.pyの

__file__がみつかりません

エラー: line 1: NameError: file line 59: global name ‘file‘ is not defined

こうすりゃ動くはず

"""
Drag and drop this file into your viewport to run the mGear installer.

1. Default Install:
     Will install in the users documents folder where Maya is installed, a
     restart will not be required.

2. Custom Install:
    Will install in the user specified directory, this method will write the
    correct module path in the Maya.env file, but a restart will be required
    in this case.

"""
import os
import sys
import shutil

try:
    import pymel.core as pm
    from pymel import mayautils
    from maya.app.startup import basic
    is_maya = True

except ImportError():
    is_maya = False

# -- maya requires this in order to successfully execute


def onMayaDroppedPythonFile(*args, **kwargs):
    """
    This function is only supported since Maya 2017 Update 3
    """
    pass


def files_exist(file_list):
    """Get all file paths that exist.

    Args:
        file_list (list): List of paths to iterate through

    Returns:
        list: List of all paths found
    """

    file_found = []
    for item in file_list:
        if os.path.exists(item):
            found = item
            file_found.append(found)

    return file_found


def _dropped_install():

    # -- current folder where the installer resides
    #current_folder = os.path.dirname(__file__)
    current_folder = os.path.dirname("C:/Users/whaison/Documents/maya/2016/ja_JP/scripts/mGear/mgear_3.7.0_beta_01/drag_n_drop_install.py")
    # -- folder of all conents of mgear resides
    mgear_folder = os.path.normpath(os.path.join(current_folder, "release"))
    custom_path = False

    # -- default modules folder to install to
    install_path = os.path.normpath(os.path.join(
        os.environ['MAYA_APP_DIR'], "modules"))

    # -- mesage for the main installer dialog window
    message = (
        "mGear will be installed here:\n"
        "{}\n"
        "\n"
        "Make sure to SAVE your scene before continuing.\n"
        "\n"
        "NOTE: Installing to a custom directory will require a restart.\n"
        "\n"
        "Would you like to continue?".format(install_path)
    )

    # -- installer dialog window
    input = pm.confirmDialog(title="Installation Path",
                             message=message,
                             icon="question",
                             button=["OK", "Cancel", "No, Custom Path"],
                             cancelButton="Cancel",
                             dismissString="Cancel")

    if input == "Cancel":
        pm.displayError("mGear installation has been cancelled.")
        return
    elif input == "No, Custom Path":
        install_path = None

    # -- custom path will be set here
    if install_path is None:
        install_path = pm.fileDialog2(
            fileMode=3,
            okCaption="Install here",
            caption="Please choose a folder to install mGear...")[0]
        custom_path = True

    # -- if install path is still None, exit
    if not install_path:
        return

    # -- flush the undo que in case there is anything that might disrupt
    # the install
    pm.flushUndo()

    # -- create a fresh scene incase there are any solvers still
    # loaded in memory
    pm.newFile(force=True)

    # -- mgear install path
    mgear_install_path = os.path.join(install_path, "mgear")

    # -- make sure the the mgear folder does not exist
    if os.path.exists(mgear_install_path):
        shutil.rmtree(mgear_install_path)

    # -- copy to a folder because tge copytree gives issues with
    # existing folders
    shutil.copytree(mgear_folder, mgear_install_path)

    # -- look in install directory for files of same name
    search_names = ["platforms", "mGear.mod", "scripts"]

    # -- construct path names
    full_path = [os.path.join(install_path, x) for x in search_names]

    # -- files of the same name
    found = files_exist(full_path)
    if found:
        # -- message if same files are found
        message = ("mGear files already exist in the install location.\n"
                   "\n"
                   "Would you like to overrite them?")
        # -- same files dialog window
        input = pm.confirmDialog(title="Delete existing files",
                                 message=message,
                                 icon="warning",
                                 button=["OK", "Cancel"],
                                 cancelButton="Cancel",
                                 dismissString="Cancel")

        if input == "Cancel":
            # -- delete the temp folder
            shutil.rmtree(mgear_install_path)
            pm.displayError("mGear installation has been cancelled.")
            return

    # -- iterate over folders and remove them
    for item in os.listdir(mgear_install_path):
        if os.path.exists(os.path.join(install_path, item)):
            # -- unload plugins incase there is a faulty install
            try:
                pm.unloadPlugin("mgear_solvers.mll", force=True)
                pm.unloadPlugin("weightDriver.mll", force=True)
            except:
                pass
            # -- delete file and folders
            if os.path.isfile(os.path.join(install_path, item)):
                os.remove(os.path.join(install_path, item))
            elif os.path.isdir(os.path.join(install_path, item)):
                shutil.rmtree(os.path.join(install_path, item))
        # -- move the folder to the install path
        shutil.move(os.path.join(install_path, "mgear", item), install_path)

    # -- delete the temp folder
    shutil.rmtree(mgear_install_path)

    # -- now let's get mgear up and running
    # -- add to the system path
    if not os.path.join(install_path, "scripts") in sys.path:
        sys.path.append(os.path.join(install_path, "scripts"))

    if custom_path:
        # -- we look for the Maya.env file and write the path to it
        env_file = os.path.normpath(os.path.join(
            os.environ["MAYA_APP_DIR"], pm.about(version=True), "Maya.env"))
        if os.path.exists(env_file):
            f = open(env_file, "w")
            f.write("MAYA_MODULE_PATH={0}".format(install_path))
            f.close()

        # -- custom install dialog message
        message = ("A re-start of Maya will be required after this setup.")

        # -- custom install dialog window
        input = pm.confirmDialog(title="Custom Install Path Restart",
                                 message=message,
                                 icon="information",
                                 button=["OK"])

    # -- if not a custom install we can load in the module
    else:
        # -- allows for not having to restart maya
        pm.loadModule(scan=True)
        pm.loadModule(allModules=True)

        # -- reload user setup files
        basic.executeUserSetup()

        # -- force load the plugins just incase it does not happen
        try:
            pm.loadPlugin("mgear_solvers.mll")
            pm.loadPlugin("weightDriver.mll")
        except:
            pass
        # -- installation message
        message = ("Installation Complete!")
        # -- installation dialog window
        input = pm.confirmDialog(title="Installation",
                                 message=message,
                                 icon="information",
                                 button=["OK"])

    pm.displayInfo("Installation Complete")

if is_maya:
    _dropped_install()

で動いた OK押した

インストール完了と出た。

mGearを使ってみた。001

ここからリリース版をダウンロードする。

最新版は

https://github.com/mgear-dev/mgear_dist/releases

Maya2016は

https://github.com/mgear-dev/mgear/releases/tag/v2.6.1

zip をいい感じのフォルダに解凍する

普通はここに入れるものだからここに入れる。

C:\Users\whaison\Documents\maya\マヤのバージョン\ja_JP\scripts

いれたらmGear.modのフォルダまでのパスをコピーしておく

たとえば

C:\Users\whaison\Documents\maya\2020\ja_JP\scripts\mGear\mgear_3.7.0_beta_01\release

とか

C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\mGear\mgear_2.6.1

C:\Users\whaison\Documents\maya\マヤのバージョン\Maya.envを開いて

MAYA_MODULE_PATH=ここにペーストして保存する。

Mayaを起動すると、、

インストールできた

Python3.7.6とPyQt5を使ってuiファイルをロードする。

import sys
from PyQt5 import QtWidgets, uic
from PyQt5.QtGui import QPixmap
import pityna
import responder


#class MainWindow(QtWidgets.QMainWindow):
class MainWindow():
    def __init__(self):
        #super().__init__()
        self.pityna=pityna.Pityna('pityna')
        self.action=True
        #self.ui = uic.loadUi("../../qt_Pityna_Simple.ui")
        self.ui = uic.loadUi("qt_Pityna_Simple.ui")
        self.ui.label_2.setPixmap(QPixmap("img1.gif"))
        self.slotSetting()
        self.ui.show()        
    def slotSetting(self):
        self.ui.buttonTalk.clicked.connect(self.buttonTalkSlot)
        self.ui.radioButton.clicked.connect(self.showResponderName)
        self.ui.radioButton_2.clicked.connect(self.HideResponderName)
        self.ui.menuClose.triggered.connect(self.close)
    def putlog(self,str):
        self.ui.listWidgetLog.addItem(str)
    def prompt(self):
        p=self.pityna.get_name()
        if self.action==True:
            p+=':'+self.pityna.get_responder_name()
        return p+'> '
    def buttonTalkSlot(self):
        print("buttonTalkSlot")
        value= self.ui.lineEdit.text()
        if not value:
            self.ui.labelResponce.setText('なに?')
        else:
            responce=self.pityna.dialogue(value)
            self.ui.labelResponce.setText(responce)
            self.putlog('> '+value)
            self.putlog(self.prompt() + responce)
            self.ui.lineEdit.clear()
    def showResponderName(self):
        print("showResponderName")
        self.action=True
    def HideResponderName(self):
        print("HideResponderName")
        self.action=False
    def close(self):
        replay = QtWidgets.QMessageBox.question(
            self.ui, 
            '確認', 
            'プログラムを終了しますか?',
            buttons=QtWidgets.QMessageBox.Yes | 
                    QtWidgets.QMessageBox.No
            )
        if replay==QtWidgets.QMessageBox.Yes:
            #event.accept()
            self.ui.close()
        else:
            #event.ignore()
            pass
        
app = QtWidgets.QApplication(sys.argv)
MainWindow=MainWindow()
ret=app.exec()
sys.exit(ret)

https://www.mediafire.com/file/zaecgqbqjx878er/Ch5_01.zip/file

https://www.mediafire.com/file/si4atzrh6uatidf/Ch6_31templateDict.zip/file

参考リンク
https://www.learnpyqt.com/blog/pyqt5-vs-pyside2/

UE4 ひとつなぎのMayaファイルからスケルトンメッシュとアニメーションフレームを指定して読み込み python

アニメーションフレームを指定して読み込み python

python

元々読み込み可能なスケルタルメッシュを推奨します。

# coding: UTF-8
import unreal
import sys
import os
import re
import datetime
import subprocess
import uuid
unreal.log_warning("--------------chara_anim_split_importer.py--start000-----------------")
unreal.log_warning("    ")

class CharaAnimSplitImporter:

    def mainWay(self):
        unreal.log_warning("mainWay 010")
        self.AssetRegistryLoaded=False
        #----------------------------------------------------------
        unreal.log_warning("mainWay 011")
        self.tickhandle = None
        unreal.log_warning("mainWay 012")

        unreal.log_warning("mainWay 0121 10s")
        self.tickhandle = unreal.register_slate_pre_tick_callback(self.testRegistry)
        unreal.log_warning("mainWay 013 tickhandle="+str(self.tickhandle))
        #self.main_way_start2()
        #self.timeloop()
        
    def testRegistry(self,deltaTime):
        unreal.log_warning("testRegistry ticking...mainWay")
        asset_registry = unreal.AssetRegistryHelpers.get_asset_registry()
        if asset_registry.is_loading_assets():
            unreal.log_warning("still loading...mainWay")
        else:
            unreal.log_warning("ready!.....mainWay")
            if(self.AssetRegistryLoaded==False):
                self.AssetRegistryLoaded=True
                self.main_way_start2()
                
            unreal.unregister_slate_pre_tick_callback(self.tickhandle)
            unreal.unregister_slate_pre_tick_callback(self.tickhandle)


    def getUE4EXT(self,file_path):
        basename_without_ext = os.path.splitext(os.path.basename(file_path))[0]
        underBarArr=basename_without_ext.split("_")
        UE4EXT=underBarArr[0]
        return UE4EXT

    def Add_Env_Variable(self):
        #pythonDir=os.path.dirname(sys.argv[0])
        #MyDir=os.path.dirname(__file__)
        MyDir=os.path.dirname(self.get__file__())
        MyDir=os.path.abspath(MyDir)
        MyDir=re.sub(r'\\', '/', MyDir)
        #MyDir=MyDir+"/"
        MyDir=MyDir
        print("MyDir="+MyDir)
        self.MyDir=MyDir
        #K:/Test_Env_Enlighten/Tool/Environment/UnUpResourceData/
        #K:/Test_Env_Enlighten/Tool/Environment/UnUpResourceData/
        
        print("------------sys.path-------------")
        for path in sys.path:
            print("path="+path)
        print("------------sys.path-------------")
        for path in sys.path:
            path=os.path.abspath(path)
            path=re.sub(r'\\', '/', path)
            #print("path ="+path)
            #print("MyDir="+MyDir)
            if(path==MyDir or path+"/"==MyDir):
                print("Hit")
                sys.path.pop()
        print("-----------DELETED------------")
        for path in sys.path:
            print("path="+path)    
        print("-----------DELETED--------------")
        
        sys.path.append(MyDir)
        print("-----------ADDED------------")
        for path in sys.path:
            print("path="+path)    
        print("-----------ADDED--------------")


    def setting_txt_to_dict(self,myDir):
        print(" setting.txt file Open!!")
        test_data = open(myDir+'/setting.txt', "r")

        # 行ごとにすべて読み込んでリストデータにする
        lines = test_data.readlines()
        
        dict = {}
        # 一行ずつ表示する
        for line in lines:
            print(line)
            if(line.find("#")>-1):
                #print("comment line= "+line)
                pass
            elif(line=="\n"):
                pass
            else:
                lines=line.split("=")
                lines[1]=lines[1].replace('\n','')
                lines[1]=lines[1].replace('"','')
                lines[1]=lines[1].replace(' ','')
                lines[0]=lines[0].replace(' ','')
                dict[lines[0]] = lines[1]
           
        for k, v in dict.items(): # for/if文では文末のコロン「:」を忘れないように
            print("key= "+k+" ,value= "+v)
        # ファイルをクローズする
        test_data.close()
        return dict 

    def main_way_start2(self):
        self.Add_Env_Variable()
        
        myDir=self.getmyDir()
        
        myCharaPath=myDir+"Female_A_V3_GameJoint.fbx"
        
        # アニメーションフレーム範囲を読み込む
        self.loadAnimChara(myCharaPath,12,100,"Female_A_V3_GameJoint_Anim_01")
        self.loadAnimChara(myCharaPath,120,180,"Female_A_V3_GameJoint_Anim_02")
        
    def loadAnimChara(self,myCharaPath,startFrame,endFrame,AnimName):
        # FBXインポート時の設定
        mesh_data = unreal.EditorAssetLibrary.find_asset_data("/Game/Mannequin/Character/Mesh/SK_Mannequin")
        #mesh_data = unreal.EditorAssetLibrary.find_asset_data("/Game/UE4_Female_A/Female_A_V3_GameJoint.Female_A_V3_GameJoint")

        mesh = mesh_data.get_asset()
        mesh.skeleton
        
        op = unreal.FbxImportUI()
        #op.import_materials = True # マテリアルもインポート
        op.import_animations=True
        op.set_editor_property("automated_import_should_detect_type", False)
        op.set_editor_property("create_physics_asset", False)
        op.set_editor_property("import_as_skeletal", False)
        op.set_editor_property("import_materials", False)
        op.set_editor_property("import_mesh", False)
        op.set_editor_property("import_rigid_mesh", False)
        op.set_editor_property("import_textures", False)
        op.set_editor_property("is_obj_import", False)
        op.set_editor_property("mesh_type_to_import", unreal.FBXImportType.FBXIT_ANIMATION)

        #op.static_mesh_import_data.combine_meshes = True # メッシュを1つにまとめる
        op.skeleton= mesh.skeleton
        #op.set_editor_property("anim_start_frame", 12)#[Read-Only]
        #op.set_editor_property("anim_end_frame", 100)#[Read-Only]
        #anim_sequence_import_data=op.set_editor_property("anim_sequence_import_data", 100)
        anim_sequence_import_data=op.get_editor_property("anim_sequence_import_data")
        anim_sequence_import_data.set_editor_property("animation_length", unreal.FBXAnimationLengthImportType.FBXALIT_SET_RANGE)
        startEnd=unreal.Int32Interval()
        #startEnd.min=12
        #startEnd.max=100
        startEnd.set_editor_property("min", startFrame)
        startEnd.set_editor_property("max", endFrame)
        #anim_sequence_import_data.frame_import_range  = startEnd
        anim_sequence_import_data.set_editor_property("frame_import_range", startEnd)
        
        
        # FBXインポートのタスクを生成
        task = unreal.AssetImportTask()
        task.automated = True
        #task.destination_path = '/Game/UE4_Female_A_Auto/' # アセットを保存するフォルダ
        task.destination_path = '/Game/UE4_Female_A/Pose/' # アセットを保存するフォルダ
        task.destination_name = 'Female_A_V3_GameJoint' # UE4上のアセット名
        task.destination_name = AnimName # UE4上のアセット名
        task.filename = "E:/download/Sculpt_forger_Girl17_Model_Download_UE4_Checked_EyeLash/Sculpt_forger_Girl17_Model_Download_UE4_Checked_EyeLash/Female_A/Female_A_V3_GameJoint.fbx" # 読み込みたいFBXファイル名を指定する
        task.options = op

        tasks = [task]

        # タスクを実行
        # FBXとマテリアルがインポートされる
        atool = unreal.AssetToolsHelpers.get_asset_tools()
        atool.import_asset_tasks(tasks)
    
    def get__file__(self):
        # 他のファイルから呼べば__file__で取れる。
        return "E:\download\Sculpt_forger_Girl17_Model_Download_UE4_Checked_EyeLash\Sculpt_forger_Girl17_Model_Download_UE4_Checked_EyeLash\Female_A\chara_anim_split_importer.py"
    
    def getmyDir(self):
        #myDir=os.path.dirname(__file__)
        myDir=os.path.dirname(self.get__file__())
        myDir=os.path.abspath(myDir)
        myDir=re.sub(r'\\', '/', myDir)
        myDir=myDir+"/"
        print("myDir="+myDir)
        self.myDir=myDir
        return myDir
        

    def debug_Write(self,s):
        #s= self.debug_data+"\n"
        dt_now = datetime.datetime.now()
        dt_format=dt_now.strftime('%Y_%m_%d__%H_%M_%S')
        #path_w=self.getmyDir()+"/debug_un_up_resource_data_log.csv"
        path_w=self.getmyDir()+"/chara_anim_split_importer_"+dt_format+".csv"
        with open(path_w, mode='w') as f:
            f.write(s)
        
        with open(path_w) as f:
            print(f.read())
        
        
unreal.log("---------------chara_anim_split_importer.py--start class_ins Make-------------------------------")
classIns=CharaAnimSplitImporter()
unreal.log("---------------chara_anim_split_importer.py--start class_ins MainWay()-------------------------------")
classIns.mainWay()

unreal.log_warning("--------------chara_anim_split_importer.py--end000-----------------")
unreal.log_warning("  END PYTHON. ")
unreal.log_warning("  END PYTHON. ")