Houdini to Unity備忘録

# 座標系
HoudiniとUnityはX軸の向きが逆です。Z軸が逆になっているとも捉えられます。どっちを逆にしても同じ事です。
Houdini標準のFBX Outputで出力されたFBXをUnityにインポートしてみると、X軸が反転された状態になっています。なので基本的には座標系の違いを気にせず作業ができます。
頂点カラーやUVに何らかのアトリビュートをパックしたFBXを書き出したり、CSVを出力するなどする際はこの座標系の違いを考慮して書き出す又は読み込む必要があります。この場合はX軸を反転させて値を扱うと標準のFBX Outputと挙動を合わせられます。Z軸反転で値を扱うと一貫性がなくなるのでX軸反転がお勧めです。

# FBXのスケール
FBX Outputで出力したFBXをUnityにインポートすると、スケールが1/100倍になる。
Transformなどで100倍にスケールして出力するか、Unity側でFBXのImportSettingsでConvert Unitsのトグルをオフにすることで解決する。
UnityのPreset ManagerやAssetPostProcessorを使用してImport Settingsの設定を自動化するのもお勧め。

# 法線
primitiveとvertex(or point)の法線は独立しているので、normalノードで法線を反転させてもUnityに持って行っても面の表裏は反転せずにシェーディングに法線反転した法線が反映されるだけ。
Reverseノードで面の表裏を反転させられる。(pointやvertexではなくてprimitiveの法線を反転させられる。)
Houdini上でもvertexやpointの法線を整えたはずなのにシーンでの見え方がおかしい感じがする時もprimitiveの向きがおかしいのが原因だったりするのでReverseしておけばOK。

# Material
1メッシュ内に複数のマテリアルを含んだ状態でモデルを出力したい場合はSOP内(geometryノード内)でmaterialノードをサブメッシュ毎に繋いでMaterialパラメータでそれぞれ適当にマテリアルを設定しておけば出力時にサブメッシュで分割される。
マテリアル自体は/mat/の位置にPrincipleShaderノードを置いておけばそれが前述のMaterialパラメータで選択出来る。
Houdini上でわざわざマテリアルを作るのが面倒な場合は、Primitiveにshop_materialpathアトリビュートを追加して、サブメッシュごとに異なる文字列を入れるだけでもFBXのサブメッシュは作れる。
また、shop_materialpathアトリビュートの文字列はFBX内でマテリアルの名前として扱われるので、UnityのImport SettingsのMaterialの設定をいじると同じ名前のマテリアルをプロジェクトから探して自動で設置するボタンもある。マテリアルの数が多いデータやパイプライン的にフローを構築したい場合はこの使用に乗っかるのもおすすめ。ただし、同名のマテリアルが存在する場合の挙動は未確認です。

# Tangent
Unityに持っていくと「このモデルはTangentとBinormalが無いよー」って警告が出る場合がある。~~polyFrameノードでTangetは生成できるけどpointにTangent持たせても、vertexにTangent持たせても警告が出てくる。UnityのImportSettingsでimportやめて計算させて解決が無難そう。ようわからん。~~
Houdini側でTangentだけでなくBinormalのアトリビュートも持たせた状態でFBXを出力すると、Unity側でもTangentをImportできるようです。FBXのImport SettingsでTangentの項目をImportに設定するとHoudini側で出力したTangentを使用できます。
Houdini上ではTangentを表すアトリビュートはtangentu、Binormalを表すアトリビュートをtangentvに相当します。PolyFrameノードで計算したり、既にNとtangnetuがアトリビュートにある場合は外積でtangentvを計算するなどでN,tangnetu,tangentvを全て揃えるのが安心です。

# 頂点数
HoudiniでのVertexがFBXのVertexになる。PointはあくまでもHoudini内での概念。なので、出力したFBXをUnityのプロジェクトビューで選択してInspectorを見ると頂点数はPointの数ではなくてVertexの数と一致する。

Houdiniから出力したFBXのメッシュをParticle Systemの発火点に使う場合（Shapeモジュールでメッシュを指定して頂点の位置にパーティクルが出てくる状態）、一か所に4つパーティクルが重なったりすることがある。これは同じ位置の頂点が1つにまとめられていないから。Import SettingsでOptimize Meshをオフにすると、頂点が一つにまとめられている挙動をする。（パーティクル重ならない。）
ただ、Optimize Meshも含めImport Settingsをどう弄ってもInspectorで表示される頂点数は変化しない。パーティクルの挙動が変わるだけなので注意。

結論、多分、HoudiniのPointをFBXの頂点として考えたい時は、Optimize Meshはオフにすれば良い。

多分この辺出力時にHoudiniがベストな状態にしてくれてそうな気が最近はしてるがちゃんと確かめてはいない。

# 出力するFBXの階層
`/Obj/`直下のGeometryノード一つをFBXとして出力する場合は1メッシュのまとめられて出力される。複数のGeometryノードをSubnetにまとめれば、階層化されて2メッシュが含まれてFBXを書き出せる。GeometryノードのTransformを弄ればPivotやRotationの値も任意に設定できる。（HoudiniとUnityの右手/左手座標系の違いから値の符号が反転していることはある。）
ただ、ワークフローとしては1つのGeometryノード内で階層を指定したい。Houdini 18.0.499からprimitiveにpathアトリビュートを持たせるとROPでFBXを出力する際に階層化される機能がある。この場合各階層のPivotやRotationの値はすべて0になるので細かい要求が満たせない。残念。
（なのでその辺も指定出来てワークフロー的にも無理過ぎないノードを作り途中。）

アドベントカレンダーを機に、一つのGeometryを階層で分けたFBXで出力する為のノード群を開発しました。[【Houdini】1ジオメトリーから階層付きFBXを出力するツールの開発](https://qiita.com/kajitaj63b3/items/2aec4406cd87affcef4b)
ただし、どんなアプローチをとっても満足なツールにはならなそうなので、多少スマートじゃないものになった...。
Unityに持っていくとスケールが1/100になる仕様のギャップも吸収するように作ってあります。

# FBX出力設定
ASCII Formatで出力するとデータサイズが大きくなるので、理由がない限りチェックを外すと良い。

# 頂点カラー
vertexのCdアトリビュートが頂点カラーとして出力される。Alphaアトリビュートが頂点カラーのアルファになる。
頂点カラーにprimitivの中心座標とか、色ではなく座標をいれてUnityでシェーダーでデコードする場合はHoudiniとUnityの座標系の違いを考慮して、x軸の値(`color.r`)を反転(`r = 1-r;`)する必要がある。

# Self-intersecting
モデルとか状況次第で変わる話だろうけど、出力したFBXをunityでインポートした時に、「self-intersectingしてるからdiscardしたよ」みたいな警告が出ることがある。poly doctor SOPやclean SOPで重複プリミティブやゴミ頂点の削除ができるのでまずそれを試す。
poly doctor SOPは5角形以上のポリゴンに対しての処理があったりして、poly doctorを使うだけだと、寧ろ意図していない形のプリミティブが生成されてしまったりする場合があるので、divide SOPで三角化しておいてからpoly doctorに通すと崩れずに解決できる。

Poly Reduceなどでポリゴン削減時も先にDivdideで三角化しておくと、Self-intersectingを防げる。