3D制作効率化のためのMayaツール開発
はじめに
Craft Egg Advent Calendar 2022 20日目の記事担当のへるつです。
Craft Eggではテクニカルアーティストとして3Dアセット制作フローの整備を担当しています。今回はDCCツールであるMayaのツール開発について紹介します。
Mayaツール開発
Maya Python APIを利用して、Mayaに内蔵されているモジュールに対してAPIを利用することで操作の簡略化や自動化を行うことができます。
Unity向けに制作する場合、Mayaで制作したモデルやモーションはFBXとして出力してUnityで再生できるようにする必要があります。Unityでは人型のアニメーションをHumanoidとしてバインドすることでMecanimのシステムを使い再生することができます。Humanoidは骨の構造さえルールに沿っていれば、体格差や身長差がある別々のモデルに対しても、共通のアニメーションを再生させることができます。そのため、Maya上で共通のリグに対してモーションをつけモーションデータのみ出力し、Unity上のモデルで再生させることで、すべてのキャラクターモデルでそのアニメーションが再生できるということになります。
しかし、モーションを出力する前に毎回Mayaで必要なデータを整理する作業が発生することがあります。これはアニメーターにとって無駄なコストであり、手動でデータを変更するのはヒューマンエラーが発生します。そこでMayaではツールを制作することでその作業を簡略化できます。
弊社でアニメーターがモーションを出力する際に行っていた作業はこの通りです。
- モーションをつけたシーンを開く
- リファレンスしているリグのシーンをオブジェクトとしてインポートする
- リグシーン内のリファレンスオブジェクトをインポート
- インポートしたオブジェクトを整理する
- ネームスペースの削除
- リグのキーのシミュレーションベイク
- ブレンドシェイプのシミュレーションベイク
- 髪などの不要なオブジェクトの削除
- Unityのモデルとの構造が合うように構造の変更
- シーンの最適化
- 設定を確認しFBXの出力
- カメラのベイク
- カメラを出力
- 設定を確認しFBXの出力
このような作業ルーティンはプロジェクトのモデルの要件やモデラーの癖によって様々だと思いますが、手作業でやってるのであればスクリプトで効率化・エラーの防止をする必要性があります。
上記の作業をスクリプトで書いた場合は以下の作業になります。
- モーションをつけたシーンを開く
- モーションエクスポートツールを起動する
- キャラクターのセットアップのボタンを押下(2~5の作業が終わる)
- モーションを出力ボタンを押下(6~14の作業が終わる)
MayaではGUIで操作する際に内部ではmelが実行されているため、MayaのGUI操作で実現できているということはPythonやmelで独自にコードを書くことでも実現できるということになります。Mayaにmelのスクリプトが格納されているため、コードを見ることで処理の流れは把握できますし、ドキュメントでAPIの利用方法も公開されています。Script Editorを開くと実行されているコマンドが出力されています。
今回はエクスポートの事例を紹介しましたが、3Dアセット制作は多くのことが手動で行われており、スクリプトを実装することでクリエイターのルーチンワークを減らすことになります。Mayaに限らずSubstance Painter、Houdini、Blenderなどの各DCCツールにおいても同じことが言えます。
ツールの導入方法
MayaではPythonやMelの実行環境がツール内に用意されているため、Script Editor上でコードを書いて保存することでスクリプト自体は実装することができるのですが、全員に同じツールを配布、Gitでバージョン管理、ある程度の規模のコードベースとなってくるとスクリプト単体ではなくリポジトリとして開発することになります。その際にMayaで独自のツールをパッケージとして導入する流れを紹介します。
userSetupの実装
Mayaでは登録されたパッケージ直下にあるuserSetup.pyを実行するためuserSetupを起点に処理が実行されます。なのでツールを立ち上げる、起動処理をここに実装する必要があります。
maya.utils.executeDeferredはMayaのGUIがロードされた後に実行されるイベントで、それに対してuserSetup関数を登録しています。
# -*- coding: utf-8 -*-
import maya.utils
import sys
from my_project.tool import tool_setup
def userSetup():
sys.dont_write_bytecode = True
tool_setup.MyProjectTool.start()
maya.utils.executeDeferred(userSetup)
その先はSetProject、ツールの機能が並んだシェルフやメニューの作成、fpsの設定など初期設定を行う実装などがあるといいです。
def onscene_loaded():
if cmds.fileInfo("scenesOpened", q=True) > 0:
print(u"シーンが読み込まれました")
set_fps()
def set_fps():
cmds.playbackOptions(playbackSpeed=1, edit=True, fps=60)
cmds.currentUnit(time="ntscf", updateAnimation=True)
def set_project():
root = "..プロジェクトのルートパス"
if "workspace.mel" in os.listdir(root):
cmds.workspace(root, o=True)
class MyProjectTool(object):
u"""ツールセットアップ処理"""
@classmethod
def start(cls, *args):
set_project()
cmds.scriptJob(event=["SceneOpened", onscene_loaded])
shelve_setup.create_shelves()
モジュールファイルの作成
Mayaではmodファイルでモジュール内のそれぞれのアセットの場所を指定します。
+ PLATFORM:win64 MyMayaTools 0.0.1 C:\my_project\my-maya-tools
PYTHONPATH +:= src
PYTHONPATH +:= vendor
XBMLANGPATH +:= src\assets\images\icon
Mayaがインストールされているmodulesフォルダにmodファイルを配置します。C:\Program Files\Autodesk\Maya2020\modules
そうすることでMaya起動時にmodファイルからスクリプトを読み込みuserSetup.pyが実行されツールが起動します。
MyProjectToolsで使用するPythonのライブラリをpipなどで追加する場合は、vendorにインストールします。
cd C:\Program Files\Autodesk\Maya2020\bin>
mayapy -m pip install enum34 -t C:\my_project\MyMayaTools\vendor
起動ファイルの作成
今のままでも起動できるのですが、最低でもバッチファイルなどは最低でも用意してあげたほうがいいでしょう。
以下は英語設定でコマンドプロンプトはバックグラウンドにしてMayaを起動します。社内の複数のプロジェクトで並行で作業する必要がある場合、起動オプションを設定しないといけないことがあります。3Dのクリエイターは基本的にWindows環境で作業するためバッチファイルは書けると役立つと思います。
::---------------------------------------------------
::Exe
::---------------------------------------------------
@if not "%~0"=="%~dp0.\%~nx0" start /min cmd /c,"%~dp0.\%~nx0" %* & goto :eof
SET MAYA_UI_LANGUAGE=en_US
"C:\Program Files\Autodesk\Maya2020\bin\maya.exe"
GUIの作成
MayaではQt、PySideを使ってUIを作成します。Qtを使用するにあたってはPyQt5などもありますがライセンスなどの違いがあります。
PySideはMayaに含まれているのでインポートするだけで呼び出すことができます。QtWidgetをQMainWindowを継承するなどしてウインドウを以下のように作成します。
from maya import cmds
import from PySide2 import QtCore, QtWidgets
class ExportWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None)
super(ExportWindow, self).__init__(parent)
self.setWindowTitle("Motion Exporter")
box_layout = QtWidgets.QVBoxLayout()
_button = QtWidgets.QPushButton(u"Click!")
box_layout.addWidget(_button)
# クリックイベントに
_button.clicked.connect(self._ButonClickEvent)
def ButtonClickEvent():
u"""なにかやる"""
QtWQidgetsには他にも多数のUIが用意されています。
cmds.confirmDialog(title=u"エラー", message=u"データが正しくありません")
cmdsとしてすでにUIが実装されているものもあります。QtはGUIの開発環境としてはとても充実していると思います。
maya.cmds
cmdsを利用してMayaやノードなどに対して操作することができます。
# pShere1が存在した場合削除
if cmds.ls("pSphere1")
cmds.delete("pSphere1")
# transtate Xに5代入
cmds.setAttr("pSphere1.tx", 5)
# 選択したメッシュのキーをベイク
selected_node = cmds.ls(sl=True)
cmds.bakeResults(selected_node,
hierarchy="both",
time=(0, 100),
smart=False,simulation=True,
shape=True
)
# 選択したメッシュを出力
# FBXの出力オプションの指定
cmds.FBXResetExport()
cmds.FBXProperty("Export|IncludeGrp|Geometry|Triangulate", "-v", 0)
cmds.FBXProperty("Export|IncludeGrp|Animation", "-v", 1)
cmds.FBXExportAnimationOnly("-v", False)
cmds.FBXExportBakeComplexAnimation("-v", True)
cmds.FBXExportBakeResampleAnimation('-v', False)
cmds.FBXExportBakeComplexStart('-v', int(start_time))
cmds.FBXExportBakeComplexEnd('-v', int(end_time))
cmds.FBXExportCameras("-v", False)
cmds.FBXExportIncludeChildren("-v", True)
cmds.FBXExportLights("-v", False)
cmds.FBXExportQuaternion("-v", "quaternion")
cmds.FBXExportApplyConstantKeyReducer("-v", True)
cmds.FBXExportUseSceneName("-v", False)
cmds.FBXExportConvertUnitString("cm")
cmds.FBXExport('-f', "出力先のパス", '-s')
あらゆるノードはDAGの構造となっているため、すべて同じようにアトリビュートにアクセスしたり操作することができます。
基本的にこのAPIを使って効率化のためのコードを実装していきます。
まとめ
Mayaのツールに導入の流れを説明しました。ゲーム開発は規模が大きくなるほど効率化が求められるため、各DCCツールでスクリプトによる効率化が求められると思います。TAがいなくてもこういったツールは常に必要とされているので、作業の効率化が必要な場合は参考にしていただけたらと思います。
Discussion