Pivot Painter の解説



この記事は [Houdini Apprentice Advent Calendar 2022](https://qiita.com/advent-calendar/2022/happrentice) の20日目の記事になります。

# はじめに

Houdini における Pivot Painter について、また、Pivot Painter で作成したデータの Unreal Engine での利用例の解説をします。
Pivot Pinater とはどういうものなのかについての入門的な解説記事となってます。
Houdini 寄りの記事になり Unreal Engine の細かな説明は省いております。
また、ピボットペインターにはバージョン「1.0」と「2.0」の2つがあるのですが、記事中は「2.0」の仕様に沿った解説になってます。


# Pivot Painter とは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/87b2f14e-ec29-aa33-00f2-355ef0e91404.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/c3b773f6-66e2-b4c3-a0eb-96341c9749b3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/5e8488e6-50ea-5b0f-ca8b-e6286ece1ca9.png) 
![2022-12-16_20-47-52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/128ff1f3-e188-377c-8041-0b248796cda7.gif)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/d6cacd69-7489-afa2-d3e5-0b2ffc0069ae.png)



大雑把に説明すると、
**「オブジェクトを細かなサブオブジェクト単位でバラバラに動かす」**
ための
**データづくりの仕組み** です。

これで何ができるようになるかというと
- インタラクティブでプロシージャルなアニメーションの表現の幅が広がります
- 多量のジオメトリをCPUコストを割かずに動かすことが出来るようになります

この一端を具体的なサンプルとしてこの記事で紹介できればと思います。


#### 押さえておきたいポイント
・VATとは違います。Pivot Painter でアニメーション自体は作りません。
・Houdini だけの機能ではなく、3dsMax や Blender でも利用できる仕組みです。
・昔からゲーム開発で使われてきた「ゲームで使う情報をモデルの頂点に仕込む」ことと同じアプローチのものです。
・Pivot Painter 自体、特殊技術ではないので、昔からあるものです。
・一般的なマテリアルと一緒に使えます。


より正確な内容はドキュメントを参照ください。
・Unreal ver5.1 ドキュメント
https://docs.unrealengine.com/5.1/ja/pivot-painter-tool-in-unreal-engine/
・Houdini ver19 ドキュメント
https://www.sidefx.com/ja/docs/houdini/nodes/sop/labs--unreal_pivotpainter-1.1.html


# Labs Unreal Pivot Painter SOP

Houdini における Pivot Painter のツールが『Labs Unreal Pivot Painter SOP』です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/9f27506c-3d4b-c7c6-9f33-2dad9e63f179.png)
このSOPを使うことで「基準点（= ピボット）」の情報をメッシュとテクスチャに仕込んだデータを出力できます。

#### ここで記事中の用語について補足です

「Pivot Painter」について、以下のリンクには
https://www.sidefx.com/ja/tutorials/game-tools-pivot-painter/
>Pivot Painter は Houdini Digital Asset (HDA) であり、モデルの頂点と追加 UV チャネルにピボットと回転情報を保存します。 

とあります。

この記事では「Labs Unreal Pivot Painter SOP」のことを「Pivot Painter」や「Pivot Painter SOP」 と呼ぶことにします。


また、
・ピボットが設定されひと固まりで動くオブジェクト単位を「サブオブジェクト」
と呼ぶことで、単体のメッシュ、アセットと区別するようにします。

### Pivot Painter SOP に入力するデータについて

Pivot Painter へは下図のように2種類のデータを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/b4cff944-3b7d-9edb-c1cf-dac526ad4a33.png)
・左の入力：描画モデル（ポリゴンメッシュ）
・右の入力：ピボット（単なるポイントデータ）
となります。


### <span>@</span>hierarchy アトリビュート
ピボットを複数設置した時に、どのポリゴンメッシュがどのピボットと紐づくのか？
それを決めるために用意するのが <span>@</span>hierarchy というアトリビュートです。
メッシュ、ピボット双方に設定する必要があります。

<span>@</span>name や <span>@</span>path と同じような任意の名前情報です。
メッシュとピボットを紐づけるための識別情報となるため必須のアトリビュートになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/1c699992-ca7e-1fb6-1240-99f01fbbfdd6.png)


### Pivot Painter SOP から出力されるファイルとその中身
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/943cf654-f613-9bdd-2bb7-c30d80693ebb.png)
右に入力されたポイントが持つデータが「ピボットの情報」としてテクスチャ出力され、
ポリゴンメッシュは <span>@</span>hierarchy を頼りに、テクスチャ内の適切なピクセルを参照できるようUV設定がされた上で出力されます。


Pivot Painter SOP で設定されるUVは、2番目のUVが使われます。
これは固定なので、マルチテクスチャ用のUVなどは2番目以外に設定しましょう。

### テクスチャ化されるピボットの情報の種類
ピボットのどんな情報が出力されるのか？
それは、Pivot Painter SOP のパラメータで自分で設定します。
「ピボットの位置」や「ピボットの向き」や「ID番号」などを、Unrealでの表現用途に従って選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/5a003cd4-194d-a078-2211-dc13a65e7064.png)
各項目の内容については下記リンクの「レンダーオプション」の欄に説明があります（よくわからないものもありますが・・・）

https://docs.unrealengine.com/5.1/ja/pivot-painter-tool-2.0-maxscript-reference-in-unreal-engine/

# 回転させる

では実際にデータを作りつつ Enreal Engine (以後UE)での利用例を見ていきます。

UE でのマテリアルによるメッシュの回転に必要な情報は
『回転の中心位置』(ピボットの位置)
『回転軸の向き』
『回転角度』
です。

それらを「Rotate About Axis」
と「Fix Rotate About Axi Normals」
に繋いで、**頂点位置の変更**と**頂点法線の回転**によってメッシュの回転を表現します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/ddedff77-32b8-1729-f6e5-164734ffe933.png)

『回転角度』については単なるfloat値なのでそれ自体は Pivot Painter で準備する必要はないのですが、サブオブジェクトごとに回転タイミングをずらすための数値を Pivot Painter から作成します。

以上を踏まえてデータを作成していきます

### Houdini でデータを作成する

先ほどの「回転する3つのボックス」を実際に作成してみます。
![2022-12-16_20-47-52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/128ff1f3-e188-377c-8041-0b248796cda7.gif)
ピボットとなるポイントを準備し、そのポイントに対して、Copy to Points でボックスを配置という流れで進めます。

まず、3つのポイントで構成される line を作成し、enumerate SOP で、ポイントごとに<span>@</span>hierarchyを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/8be686c6-891a-cf56-3cd0-7ae67f5898eb.png)


あとは、下図のようにメッシュとピボットを準備して Pivot Painter へ接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/c3c01e46-a515-3bdf-1c65-0998c9192f30.png)
(2)のノードでポイントが持つ <span>@</span>hierarchy がそれぞれ配置されるプリミティブへ引き継がれます。

### Pivot Painter SOP の設定
ここで出力したい情報の種類を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/900217f1-1793-25c2-45fe-f65dfdfd9189.png)
① 「Pivot Position」はUEでの『回転の中心位置』に使用（@Pの値が使われる）
② 「Selection Order」は回転タイミングをずらすための数値として利用（ポイントナンバーが使われる）
③ 「XVector」はUEでの『回転軸の向き』に使用（@Nの値が使われる）
となります。
繰り返しですが、これらのデータは右側に入力したポイントの情報が使われます。
<span>@</span>hierarchy そのものはデータとしては出力されず、ピクセル位置やUV値に変わります。

あとは出力先を指定して「Export」ボタンをクリック。
・fbxモデル
・テクスチャ（2枚）
が出力されます。
テクスチャ名は、出力するデータ内容に従って決まります。

### Unreal Engine へのインポートとテクスチャ設定

UEへインポートしたテクスチャは以下の設定を行います。

■共通の設定
・ミップマップなし
・sRGB : オフ
・Filter : Nearest

■16bit画像の設定
・圧縮設定 : HDR

■8bit画像の設定
・圧縮設定 : VectorDisplacementmap

テクスチャ解像度は、Pivotの数のピクセル数になるので、圧縮設定によるメモリ圧迫はまずありません。
この例のテクスチャ解像度は、3 x 1 という非常に小さなものになります。

### シェーダーグラフの作成
シェーダーグラフの全体です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/22e28c04-93aa-9da3-61fd-50f18cb2ddae.png)
ポイントとなるのはオレンジで囲った部分。
テクスチャからピボットの情報を、それぞれ専用のマテリアル関数で変換（デコード）します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/f8759461-e848-bc33-5ab2-a2d3a3920de3.png)

ネットワークの下段のエリアで「回転角度」を Time から sine を使って作成。
タイミングをずらすために②の情報をTimeに足し算しています。

以上の情報を、前述の「Rotate About Axis」と「Fix Rotate About Axi Normals」につなぎ、マテリアルへ接続します。
Rotation Angle へは「回転角度」を接続しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/765ca6a2-9351-1ed2-9cb5-757f78849780.png)
あとは図の通り「マテリアルの結果ノード」へ接続するとサブオブジェクトがそれぞれのピボットを中心に回転するようになるはずです。

### バリエーション その1
同じ手法の別バリエーションです。
![2022-12-17_14-57-41.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/f5a707c1-1b13-4f79-62f0-f50fcd8b03d2.gif)
Houdini でピボット用のポイントを、line ではなく Circle で作成しただけです。
Pivot Painter の出力設定、シェーダー、どちらも変更なしです。
※マテリアルのパラメータ値は適宜調整

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/096f25ad-0403-4946-c4ee-a1470e4cb798.png)

### バリエーション その2
同じ手法の、また別のバリエーションです。
![2022-12-17_15-15-57.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/9c6af7f5-6b1f-cafe-8911-504690f1f615.gif)
今回は、Torusをスタートとして、ネットワークは一新してますが複雑なことはしていません。
Pivot Painter の出力設定、シェーダー、どちらも変更なしです。
※マテリアルのパラメータ値は適宜調整
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/c4ba661e-bfa4-0652-c711-65ed35eb5d7f.png)
<span>@</span>hierarchay の設定は
Assemble SOP (オレンジ) で作成した Primitive の <span>@</span>name を
Attribute Promote (紫) で Point の <span>@</span>hierarchay に変換して設定。

### テクスチャの使用
Pivot Painter からのデータは、一般的なPBRテクスチャと共に通常のマテリアルの中で使用できます。
こちらは、ノーマルマップやエミッシブと共に使用した例です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/52625146-f657-dc65-263c-c7eb69e7b1bf.png)
注意点として
- ノーマルマップを使うときは、回転した頂点法線とのコンバインを忘れずに
- マルチテクスチャ用のUVは、2番目以外のUVに準備します



# 移動させる
![2022-12-17_17-43-19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/caf48e3f-fec1-3e6f-dc39-42c2d12f92c8.gif)
UE でのマテリアルによるメッシュの移動に必要な情報は
『移動の方向』
『移動量』
です。
『移動の方向』x 『移動量』をマテリアルの World Position Offset (ワールド位置オフセット)につなぐだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/72df9dfe-2339-b013-6e55-f07df1b334f5.png)

### Pivot Painter からの出力データ
XVector と Selection Order を出力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/507c1ab5-3b7d-9a81-8c54-fff65d4412e4.png)
複雑ではないのでネットワークは省略。
移動方向が縦方向のみと分かっているなら、X Vector の出力は必要ありません。
<span>@</span>hierarchy の設定だけは忘れずに。
Selection Order は、回転の時と同じく、移動タイミングをずらす目的で使用します。


# スケールさせる + インタラクションさせる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/f5abb064-21ea-4772-536a-a30c3b55b4ea.png)
UE でのマテリアルによるメッシュのスケールに必要な情報は
『ピボットの位置』
です。

頂点が『ピボットの位置』にどれだけ近づくかでスケールを表現します。
サブオブジェクトの全頂点が『ピボットの位置』になった時、スケールとしては0になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/2823b852-63a5-d265-2880-d4ce29ef269f.png)
使っているMeshデータとテクスチャは回転で使ったサンプルと同じです。

### インタラクション
この記事中のアニメーションはどれも、マテリアルでのプロシージャルアニメーションなので「時間軸によるアニメーション」だけでなく、インタラクションによるアニメーション再生が可能です。
このスケールのアニメーションは、ブループリントを使ってプレイヤーからの距離をドライバにしてアニメーション再生しています。
![2022-12-18_17-01-11.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/d1420b31-f2f2-25dd-95cc-f7c88c83a3ab.gif)
インタラクションの方法としては
- スクリプトによるアニメーション再生
- オブジェクトの高さによるアニメーション再生
- 別オブジェクトのボーン角度によるアニメーション再生
- 開く扉に合わせたアニメーション再生

など、様々なトリガー、ドライバが考えられます。


# 階層構造の利用
階層構造については詳しく検証できていないため浅い説明で済ませます。
![2022-12-18_8-40-14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/e5be3392-1519-88f8-b83d-6eeaaac0807a.gif)
<span>@</span>hierarchy に "/"(スラッシュ)を加えることで、階層を表現可能です。
この例では、サブオブジェクトが何階層目にあるか（階層の数）をマスクとして利用することで「移動」or「回転」という別の動きをさせています。
多分、最もシンプルな階層構造の使い方ではないかと。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/dcdaf1ff-f829-8e9b-1385-1e1aa02538db.png)
上図の場合、オレンジ矢印が第一階層のサブオブジェクト、
グリーン矢印が第二階層のサブオブジェクトとなります。
Pivot Painter SOP で「Normalised 0-1 HIerarchy Position 」を指定することで、
「自身の階層数」÷「オブジェクトの持つ最大階層数」
つまりノーマライズされた 0-1 float値がテクスチャに格納されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/26831d79-59a0-79be-5150-3fb5ab912ccd.png)
データとしては単にノーマライズされた値なので Unreal Engine でのデコードは必要なく、オブジェクトの持つ最大階層の数を掛け算して利用します。

親子階層を考慮したアニメーションも可能なのですが、その辺についてはより踏み込んだ内容となり解析もできていないためここでは取り上げておりません。
UEの「機能別サンプル」に、Pivot Painter のサンプルシーンがあるので、そちらを確認してみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314518/1b596e8b-fc84-1efd-99c7-2914ace79bc8.png)



# ピボットペインターの使いどころ
よく見る事例は「風に揺れる木」の表現ですが、その他にも、人工的なモノのアニメーションを中心に面白い表現ができそうです。
スクリプト等からのインタラクションが可能である点から、特にUIやHUD等、ゲームでの利用範囲は広いと思われます。
また、Unreal Engine 5.1 からは、動的にポリゴン数を最適化する「Nanite」を、Pivot Painter による変形モデルで利用できるようなりました。
CPUだけでなくGPUコストも抑えつつ細かなアニメーション表現ができるようになります。

# トラブルシューティング
意図した動きをしてくれない時の確認ポイントです。
・Pivot Painter SOP の出力したいデータ内用を確認
・正しいテクスチャを使っているか確認（出力データ内容に従ってテクスチャ名が変わります)
・テクスチャのFilterや圧縮など、正しい設定になっているか確認
　sRGB のチェックをオフにしないと軸の向きがずれます

こちらのリンクの「トラブルシューティング」欄もご覧ください

https://docs.unrealengine.com/5.1/ja/pivot-painter-tool-2.0-in-unreal-engine/



# 最後に
以上、Pivot Painter の入門的な解説でした。
UE側については大分端折りましたが、それでも長い記事になってしまいました。
最後までお読みいただいた方、お疲れさまでした。

- 使用したバージョンはこちら
Houdini 19.5.435 (Indie)
　Labs Unreal Pivot Painter SOP 1.1
Unreal Engine 5.1

- 今回のサンプルファイルは[こちら](https://drive.google.com/file/d/17bOnETsVAJ2h9p-nApj86BCDCVaKj_9o/view?usp=share_link) (hipファイルのみです)

- この記事で紹介したサンプルを、インゲームで撮影した動画はこちら↓

https://www.youtube.com/watch?v=OKKKhrz9tuQ