はじめまして。
今回、Houdini Advent Calendar に初参加します。
普段は CG 制作をしていますが、
Pythonについては最近勉強をし始めた初心者です。
今回は、
Python を使って、毎日の作業を少しだけ楽にした話
を書いてみようと思います。
テーマは、
Maya → Alembic → Houdini
この受け渡しを、できる範囲で自動化してみた
という内容です。
Python に詳しくなくても、「こういう考え方で自動化できるんだ」という雰囲気が伝われば嬉しいです。
この記事でやっていること
今回やっているのは、主にこの2つです。
- Maya
選択したオブジェクトを
オブジェクトごとに Alembic(.abc)として書き出す
- Houdini
Houdiniを起動
起動時に Alembic をまとめて読み込む
※注意点
最初にalembicにしたいオブジェクトを選択しておく必要があります。(複数選択可)親ノードを選択した場合、その配下は1つのabcにまとめて書き出されます。
Maya側:選択オブジェクトを自動で Alembic 書き出し
まずは Maya 側です。
このスクリプトのポイントは以下の通りです。
・選択しているオブジェクトを取得
・タイムライン範囲をそのまま使う
・選択オブジェクトごとに1ファイルずつ abc を出す
・ファイル名に 日時スタンプ を付ける
# -*- coding: utf-8 -*-
import maya.cmds as cmds
import os
import datetime
def export_selected_to_abc_auto():
# 選択チェック
sel = cmds.ls(sl=True, long=True)
if not sel:
cmds.warning(u"オブジェクトが選択されていません。")
return
# タイムラインのフレーム範囲
start = cmds.playbackOptions(q=True, min=True)
end = cmds.playbackOptions(q=True, max=True)
# 書き出し先フォルダのみ選択
folder = cmds.fileDialog2(
caption=u"Alembicを書き出すフォルダを選択",
fileMode=3
)
if not folder:
return
folder = folder[0]
# AbcExport プラグインチェック
if not cmds.pluginInfo("AbcExport", q=True, loaded=True):
cmds.loadPlugin("AbcExport")
# 日時スタンプ(全ファイルで共通)
now = datetime.datetime.now()
stamp = now.strftime("%Y%m%d_%H%M%S")
# 危険文字除去
def safe_name(name):
invalid = ['|', ':', '/', '\\', '*', '?', '"', '<', '>', ' ']
for c in invalid:
name = name.replace(c, '_')
return name
# ★ 選択したオブジェクトごとに 1 ファイルずつ書き出す
for node in sel:
# obj の名前だけ
short_name = safe_name(node.split("|")[-1])
# ファイル名: base_scene + obj名 + timestamp
file_name = "{}_{}.abc".format(short_name, stamp)
file_path = os.path.join(folder, file_name).replace("\\", "/")
# Alembic job(この obj のみ書き出し)
job = (
'-frameRange {start} {end} '
'-uvWrite -worldSpace -writeVisibility -dataFormat ogawa '
'-root "{root}" -file "{file}"'
).format(
start=start,
end=end,
root=node,
file=file_path
)
print(u"[AbcExport] " + job)
cmds.AbcExport(j=job)
cmds.confirmDialog(
title=u"完了",
message=u"選択オブジェクトを {} 個のABCとして書き出しました。".format(len(sel)),
button=["OK"],
defaultButton="OK"
)
# 実行
export_selected_to_abc_auto()
このスクリプトの使いどころ
キャラ・プロップを 個別に Houdini に持っていきたい
後工程(FXなど)で オブジェクト単位で扱いたい
名前衝突を避けたい
というケースで便利です。
Houdini側:起動して Alembic をまとめて読み込む
次は Houdini 側です。
ここでは、
Maya から Houdini を起動
起動時にだけ実行される 456.py を一時的に作成
Alembic を選択 → 読み込み → 繰り返し
読み込み後、456.py を削除
という流れにしています。
Mayaから Houdini を起動するコード
# -*- coding: utf-8 -*-
import os
import subprocess
import maya.cmds as cmds
def launch_houdini_with_geo_once():
# =========================================================
# ★ ここは環境によって変更が必要(Houdiniのインストール先)
# =========================================================
HFS = r"C:\Program Files\Side Effects Software\Houdini 20.0.547" # ★
houdini_exe = os.path.join(HFS, "bin", "houdini.exe") # ★(通常はHFSでOK)
if not os.path.exists(houdini_exe):
cmds.error(u"Houdini が見つかりません: {}".format(houdini_exe))
return
# =========================================================
# ① Maya のダイアログで .hip を選ぶ(環境依存なし)
# =========================================================
hip_file = cmds.fileDialog2(
caption=u"開きたい Houdini .hip ファイルを選んでください",
fileFilter=u"Houdini Scene (*.hip *.hiplc *.hipnc)",
fileMode=1
)
if not hip_file:
cmds.warning(u"キャンセルされました。")
return
hip_file = hip_file[0]
print(u"選択された HIP:", hip_file)
# =========================================================
# ★ ここは環境によって変える可能性あり(Houdiniのユーザ設定フォルダ)
# 例:ドキュメント位置が違う/バージョンが違う/カスタム設定
# =========================================================
user_root = os.environ.get("USERPROFILE") or os.path.expanduser("~")
HOUDINI_VER_DIR = "houdini20.0" # ★(例:houdini20.5 等)
scripts_dir = os.path.join(user_root, "Documents", HOUDINI_VER_DIR, "scripts") # ★
if not os.path.isdir(scripts_dir):
os.makedirs(scripts_dir)
startup_script = os.path.join(scripts_dir, "456.py") # ★(基本はそのまま)
# =========================================================
# ③ 起動時に一度だけ実行する処理(中身は基本そのままでOK)
# =========================================================
houdini_code = (
"import hou\n"
"import os\n"
"\n"
"def import_multiple_abc_loop():\n"
" obj = hou.node('/obj')\n"
" count = 0\n"
"\n"
" while True:\n"
" abc_path = hou.ui.selectFile(\n"
" title='Select Alembic (.abc)',\n"
" pattern='*.abc'\n"
" )\n"
"\n"
" if not abc_path:\n"
" break\n"
"\n"
" abc_path = hou.expandString(abc_path)\n"
" name = os.path.splitext(os.path.basename(abc_path))[0]\n"
"\n"
" arch = obj.createNode('alembicarchive', 'abc_' + name)\n"
" arch.parm('fileName').set(abc_path)\n"
" arch.parm('buildHierarchy').pressButton()\n"
" arch.moveToGoodPosition()\n"
"\n"
" count += 1\n"
"\n"
" res = hou.ui.displayMessage(\n"
" f\"Loaded: {abc_path}\\n\\nLoad another Alembic?\",\n"
" buttons=('Continue', 'Finish'),\n"
" default_choice=0,\n"
" close_choice=1\n"
" )\n"
"\n"
" if res != 0:\n"
" break\n"
"\n"
" hou.ui.displayMessage(f\"Loaded {count} Alembic files.\")\n"
"\n"
"# auto run\n"
"import_multiple_abc_loop()\n"
"\n"
"# =====================================================\n"
"# ★ ここは環境によって変える可能性あり(削除する456.pyのパス)\n"
"# HOUDINI_VER_DIR と合わせる\n"
"# =====================================================\n"
"script_path = hou.getenv('HOME') + '/houdini20.0/scripts/456.py' # ★\n"
"try:\n"
" os.remove(script_path)\n"
"except:\n"
" pass\n"
)
with open(startup_script, "w") as f:
f.write(houdini_code)
print(u"一時スクリプト作成:", startup_script)
# =========================================================
# ④ Houdini を指定した .hip で起動
# =========================================================
env = os.environ.copy()
env["HFS"] = HFS # ★(基本はそのままでOK)
subprocess.Popen([houdini_exe, hip_file], env=env)
# 実行
launch_houdini_with_geo_once()
※★マークの部分は、
使用している Houdini のバージョンやインストール先に合わせて変更してください。
以上二つのコードを上から順にそのまま Maya の Script Editor(Python)にコピペして実行すると使えます。
※maya2020で動作確認済み
おわりに
今回は、
Maya → Alembic → Houdini の流れを、
自分なりにpythonで整えた例を紹介しました。
まだ改善できる点は多いですが、
誰かの作業時間を減らすヒントになれば嬉しいです。
ここまで読んでいただき、ありがとうございました。