Houdini Engine For Maya を調べてみる

この記事は[Houdini Advent Calendar 2017](https://qiita.com/advent-calendar/2017/houdini) の14日目の記事です。

さて、今年は**HoudiniEngine**について書くと予定していましたが
正確には**Houdini Engine**本体ではなく
http://www.sidefx.com/docs/hengine/
そのプラグインとして提供されている**Houdini Engine for Maya**について書こうと思います。
http://www.sidefx.com/docs/maya/index.html

Houdini Engine for Maya自体は数年前からありますが
自分が触り始めたのはかなり最近なので、備忘録も兼ねて
同じようにこれからHoudini Engine For Mayaを触ろうと思っている人の助けになればと思います。

(この記事では使用するデータは[こちら](https://drive.google.com/open?id=1jNmR_Jk-w35kxQUFpDLyP4aBAPADOOnd)にあります。バージョン: Houdini16.5.268 / Maya2017)

## インストール場所
Houdini Engine For MayaはHoudiniのインストール時にチェックを入れていると
`$HFS/engine/maya/maya<version>/houdiniEngine-maya<version>`
に配置されます。
<img width="300" alt="PluginPath.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/1c6be124-59f1-6240-fb89-01b079be462e.jpeg">

こんな感じで**plugin**と**Script**がおいてあります

Scriptの中身は**mel**がほとんどで
HoudiniEngineForMayaでは色々な処理でこのmelを使っています。
なので挙動を知りたいときはこの中を読むのが良さそうです。
**AETemplate**もここに置いてあります。
http://www.sidefx.com/docs/maya/_maya__install.html

## 使えるコマンド
また、Plug-in ManagerでPlugin Infoを見てみると
Plug-in Featuresに **houdiniEngine**と**houdiniAsset**というコマンドが含まれているのが分かります。
（コマンドの他にも、**houdiniAsset**や、**houdiniInputGeometry**といった独自のノードタイプが定義されているのがわかります）

<img width="450" alt="Plugin_Info.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/83fa742a-0ed3-0e7d-bd08-7d315dc67c63.jpeg">

helpコマンドで引数が確認できます。

<img width="450" alt="maya_houdiniEngine_cmd.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/7aaf7d00-a106-f16b-9752-67a7dae2ed62.jpeg">

<img width="450" alt="maya_houdiniAsset_cmd.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/e8f57ad8-495f-13cb-0145-5781e4e777ba.jpeg">

## pythonで操作する
先ほどのコマンドはMayaのPython(maya.cmds)でも使えるので
試しにPythonで読み込みをしてみます。
こんな感じに書きます 

```python
import maya.cmds as cmds
cmds.houdiniAsset(loadAsset=["hdaファイルのパス","ノードの定義名"])
```

ノードの定義名と日本語で書いてみましたが要するにこの名前です
<img width="482" alt="load_asset_with_python_def.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/2f6d2d95-fffd-0c8d-f361-b4879353a0ba.jpeg">

なので例えば以下のような感じで書けば

```python
cmds.houdiniAsset(loadAsset=[r"C:\Program Files\Side Effects Software\Houdini 16.5.268\houdini\otls\OPlibPlaceholder.hda","Sop/testgeometry_pighead"])
```

お馴染みのブタ君もMayaに読み込めます。
<img width="600" alt="MayaHoudiniPig.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/e8db5949-37d2-25d8-00a7-ca9e199d55b3.jpeg">


もし、よく使いたいHDAがあればこんな感じのスクリプトを**Shelf**にしておけば良さそうです。
HDAの読み込み＆編集にはライセンスが必要ですが、作られる**Mesh**ノードはMaya標準のものなので
ブタ君のジオメトリだけ欲しい場合、こんな感じで分離してあげればそのまま保存しても問題ないです。

```python
import maya.cmds as cmds
hdaNode = cmds.houdiniAsset(loadAsset=[r"C:\Program Files\Side Effects Software\Houdini 16.5.268\houdini\otls\OPlibPlaceholder.hda","Sop/testgeometry_pighead"])
pigNode = hdaNode+"|testgeometry_pighead"
cmds.parent(pigNode,world=True)
cmds.delete(hdaNode)
```

## Houdini Engine For Mayaのデータ構造について
ブタ君は読めましたが様子がおかしいので
Maya内部でHoudiniのノードはどう定義されているか理解を深めたいと思います。

実は、先ほど読み込んだHDAはHoudiniで使う事を前提に作られているので
HoudiniEngineForMayaで使いたいHDAは**Maya用に最適化**しておく必要があります。
これがまた~~面倒で~~知識が必要なので、少しだけ解説していこうと思います。


##HoudiniのデータがMayaでどう扱われるか [Houdini >> Maya]
解説と言いつつ、基本は公式ドキュメントに書いてあるので
読んで頂くのが一番早いと思いますが
http://www.sidefx.com/docs/maya/_maya__outputs.html

よく使いそうな**Mesh**と**Particle**、**Volume**がどうなるか
簡単なデータを作って見てみたいと思います。

また、**Expression**や**Variables**もどうなるか気になるので検証してみます。
## ObjectとSOPについて
まず、基本的な所ですがHoudiniEngineForMayaでは
HDA内部で**Displayになっているノードだけ**作られます（オプションで切り替えることも出来ます）
<img width="600" alt="SingleNodeHoudini.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/9e914b6d-c0cc-5b63-c7b1-202a54eb9de8.jpeg">

複数表示させたい場合は、SOPではMergeをつかうと入力分ノードを作成してくれます
ObjectであればDisplayされているSOP（とその中身）の数だけ作成されます
<img width="600" alt="MultiNodeHoudini.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/e5d8802f-1a9c-d09f-d75f-839927c4336c.jpeg">

<img width="600" alt="MultiObjecHoudini.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/80ba5fcf-58f2-64c6-efbe-89e45a216140.jpeg">

また、HDAの中で**Group**を作っておくと、Mayaの**Set**に変換されるので
破壊FXでシェーダーをFaceにアサインしたい場合などに使えそうです。


## Volume
volumeは
**・名前がdensity, temperature, fuel, vel[xyz], Cd[xyz]**
**・各Volumeのresolutionが同じ**
という条件を満たしていれば、MayaFluidShapeとして作られます。
実際にこんなVolumeをHoudiniで作って
<img width="300" alt="HDA_Volumes.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/045e3cc8-5150-d9ea-0005-c2273e60fc11.jpeg">

HoudiniEngineForMayaで読み込んでみるとこんな感じに見えます。レンダリングも出来ました。

<img width="600" alt="HDA_MayaVolumes.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/c369cf6a-8035-c4f8-0c7b-f3cabc6e9840.jpeg">

試してませんが、**Pyro**とかもデータを整理して渡せばMayaの中でも使えるかもしれません。
個人的にHoudiniはVolumeの扱いが強みだと思っているので、Mayaでその機能が使えるととても嬉しいのですが
**VDBは対応していない**のと、**MayaFluid自体が重い**ので実用性があるかはわかりません・・。


## Particle
PartilceはnParticleとして読み込まれるようです。
Attributeに関しては公式ドキュメントに対応が書かれています
<img width="300" alt="HDA_Particle_Attributes.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/cfff4065-c5b1-3bb4-6549-c21873b3c733.jpeg">

ためしにPOPでこんなParticleを発生させてみたところ
Mayaでもそのまま再生されました。（上がHoudini 下がMaya)
<img width="600" alt="HDA_Particle.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/1681d5c7-3fbd-5f26-9bab-b848a56a1ec2.jpeg">



## Expression
実は↑のParticleで球体の回転に
``fit($FF,$FSTART,$FEND,0,360)``
というExpressionnを入れておいたのですが問題なく動きました。
FSTARTやFENDも、ちゃんとMayaの開始フレームと終了フレームを取ってきてくれます。

また、今回UI周りの説明を省略したまま書いてますが
**StringTypeのParameter**であれば**Expressionが使えます**
FloatやIntegerのParameterにはExpressionは使えません（というか入力できません）

例えばこんな風に**FontSOP**とそれを複製するHDAを作ってExpressionがどうなるか見てみます。
<img width="600" alt="HDA_Expression.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/ea473f44-d8c5-d6e4-7777-784434c7f2c0.jpeg">

Maya内部ではこんな感じにUIが変換されて複数行の文字列でExpressionを書くことも出来ます。
ただ、回数を指定するほうには文字が打てないので、実質Expressionを使う事が出来ません。
＊MayaのExpressionは使えます。

<img width="600" alt="HDA_ExpressionWindow.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/1509dd18-796a-0b69-4045-bef66e2dbcda.jpeg">

ちなみに、$HIPでMayaシーンのパスが取れるかと思いましたがダメでした。
全部は検証してませんが、使えないものもありそうです。

#MayaのノードをHDAに渡すとどうなるか [ Maya >> Houdini ]
HoudiniのノードがMayaでどう扱われるかは何となくわかったので逆も調べてみます。
MayaのノードをHDAに渡す場合は、HDAに**Input**があればMayaで次のようなUIが表示されます
または**ObjectMerge**などで指定する場合も同様のUIになります。
<img width="392" alt="SetToSelection.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/5d25efe9-eaba-f740-6980-3d1cc9b36194.jpeg">

試しに、MountaionSOPを使ってこんなHDAを作って
<img width="600" alt="MountainDeformer_Houdini.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/08484385-52de-1a27-3d83-ea050423bafa.jpeg">

Mayaにもってきてsphereをインプットしてみます。
<img width="600" alt="MountainDeformer_Maya.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/d243944c-293a-4b91-b6b4-e580e41520f8.jpeg">
お馴染みのMountainSopがMayaでも使えました。
このHDA、MountainDeformerと紛らわしい名前を付けましたが
**Inputされたオブジェクトに変更を加えるのではなく**、**別のオブジェクトが作成されます**
これはHoudiniEngineForMayaの仕様上、というかhoudiniAssetノードの仕様上仕方なさそうです。
<img width="600" alt="MountainDeformer_Maya_2.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/b0cc3e59-0c0e-fb93-63de-bb689da97fca.jpeg">

例えばNodeGraphを見てみると
InputされたGeometryは一旦**houdiniInnputGeometry**につながって
その後**houdiniAsset**(mountainDeformer)に渡ってるのがわかります。

<img width="600" alt="MountainDeformer_Maya_NodeNetwork.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/289be589-0ad4-020a-1616-3fcde65aab0c.jpeg">


Deformerっぽく扱いたければInMeshとoutMeshを使えば良さそうですが

<img width="600" alt="MountainDeformer_Maya_NodeNetwork_InMesh.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/cceaf173-4abe-9f3e-c2da-d10594d3a9fc.jpeg">

元ジオメトリ → houInputGeometry → houdiniAsset → 元ジオメトリ と繋ぐのはループになってしまう為

<img width="600" alt="MountainDeformer_Maya_NodeNetwork_copy.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/5c9824e9-6f66-626f-6d43-bad4bdf88e9f.jpeg">

どうしてもやりたければ
元ジオメトリ(複製） → houInputGeometry → houdiniAsset →　元ジオメトリ　と繋ぐしかなさそうです
微妙ですね。もし良い方法をご存知の方が居たら教えてください・・

しかし、実はなんとか繋いだとしても回避できない**大きな問題**があります。
それは、HoudiniEngineForMayaでは
**複数のオブジェクトをインプットしてもHDA内部では1つのオブジェクトとして扱われる**
という仕様になっている為。入力と出力で数が一致しません。
こんな感じです。
<img width="600" alt="HDA_multiShape.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/c84681f8-731c-1519-426f-4d3573168852.jpeg">

公式ドキュメントだと、**Mayaの機能でSeparateして使って**みたいなことが書いてありますが、それも微妙かなと・・
Groupで分けてSetにしても扱いづらいですし
一応、Split Geos by Groupというオプションもありますが。今後どうなるのかよくわかりません。
<img width="300" alt="split_by_group.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/bd887de8-cad3-04a0-56cd-182857a73187.jpeg">

このあたりのデータの流れをどうしたらいいか、開発者に相談してみたいですが
houdiniAssetノードではなく、自分で新しいノードタイプを作ったほうがいいのかもしれません
そのうち試してみたいなとは思います・・
http://www.sidefx.com/docs/hengine/index.html


## 内部アトリビュートについて知る
MayaからHDAへのデータの受け渡しについてもっと掘り下げてみます。
具体的には**Attributeどうなってるか**ですが
これは公式ドキュメントに見当たらないので・・**デバッグモード**を使ってみます。
デバッグモードではMayaのジオメトリがどういうアトリビュートをもっているか調べることができます。
使い方は多喜さんのブログに詳しく書かれているので、リンクを貼らせて頂きます。
http://ikatnek.blogspot.jp/p/houdini-engine-maya-debugging-menu.html
ただ、リンク先の画像に出ているAttributeと、自分の環境で出てくるAttribute名が少し違っていたので
まだ仕様が変わるかもしれません。**実際に自分が使ってるバージョンで**調べたほうが良さそうです。

<img width="600" alt="Maya_DebugAttributes.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/1df110e9-f282-cefe-0eea-4afd3361c6a2.jpeg">

**オブジェクトの名前がnameに格納されている**とか、使えそうな情報が入ってます。

このnameを使って**Group**を作るとか・・
Mayaのノード名はDAGパスで表記されているのを利用して**path**に変換して使えそうですね。

pathに変換する場合は、"|"を"/"にしたいのでwrangleでこんな感じにしとくのが良さそうです。

<img width="894" alt="Maya_DebugAttributes_rename.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/153791/38d50c48-31f7-70fc-6968-d32d13f24d60.jpeg">

他にもuvや頂点番号、シェーダー名などもAttributeに格納されるので
ツール開発をする際はこんな感じで調べたり確認したりするのが良さそうです。

以上。

##最後に
今回あまり面白い作例は用意できなかったんですが、仕事で使う機会も少しずつ出てきたので
ノウハウをためて、面白いツールができたら[orbolt](https://www.orbolt.com/search/?q=softpackage:Maya)あたりにでも出そうかと思います。

そして、***Houdini Engine for Maya***には、まだ色々機能があるんですが、解説しきれなかったので
残りの部分は、追記するか別記事にまとめるかしたいと思います。
***Houdini Engine for Unity***についても、そのうち書きたいと思っています。


##参考資料
Maya ドキュメント　http://www.sidefx.com/docs/maya16.0/index.html
SideFXフォーラム　https://www.sidefx.com/forum/46/

＊SideFXのAndrew Wongさんがフォーラムでいつも答えてくれています。
日本に居た時にもっと話しておけばよかった・・。応援しています！