Vector Displacement Map を Copernicus 内で表現

## 本記事で解説するもの
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">コペルニクス、Vector Displacement Map のテスト続き。<br>Opacityで抜けば宙に浮く事も可能？おもろいな～<a href="https://twitter.com/hashtag/Houdini?src=hash&amp;ref_src=twsrc%5Etfw">#Houdini</a> <a href="https://t.co/SdkX3BOvyA">pic.twitter.com/SdkX3BOvyA</a></p>&mdash; 岡田拓也 (@okada_takuya) <a href="https://twitter.com/okada_takuya/status/1854769715698450548?ref_src=twsrc%5Etfw">November 8, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※Copernicus内でテクスチャのみで表現しています。（ジオメトリはグリッドです。）
hipファイルはこちらから
↓
[VDM.hip](https://www.dropbox.com/scl/fi/4glx7tdw548lyjlqnbqwj/VDM.hip?rlkey=7vlgxtam5x6l1v0u2mmy1j0ap&dl=0 "VDM.hip")

## Vector Displacement Mapとは？
<!--
[tinybugbot](https://x.com/tinybugbot)氏のこんな摩訶不思議なツイートを見ました。
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="en" dir="ltr">make Vector Displacement Map with SOP and COP<br>- render with Karma and MaterialX 🐷<a href="https://twitter.com/hashtag/houdini?src=hash&amp;ref_src=twsrc%5Etfw">#houdini</a> <a href="https://t.co/0cYyR5azIV">pic.twitter.com/0cYyR5azIV</a></p>&mdash; tinybugbot (@tinybugbot) <a href="https://twitter.com/tinybugbot/status/1853831247845564486?ref_src=twsrc%5Etfw">November 5, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
恥ずかしながら、Vector Displacement Map （以下VDM）なるものを知りませんでした。
（ゲーム業界などではよく使われているのでしょうか…？）
-->



普通のDisplace は 白黒（1 float）の高さ情報だけの Height Map を用いて、面のNormal 方向に押し出します。
そのため、側面や側面の凹形状の表現がうまく行かないという弱点があります。
<img width="300" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/1198c7a5-7438-ac89-4c03-756f0a03f568.png"><img width="278" alt="03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/eadfdf86-583f-84d0-a0c0-ee5298c1f161.png">


方向の情報も加えた、Vector (3 float)で押し出すのが Vector Displacement Map です。

<img width="300" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/55970a45-e1b4-8fb5-94de-7db72b0c4d25.png"><img width="278" alt="03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/6a3148e2-92b7-fa74-e0ee-a5c126adb59f.png">


## Vulkan ビューポートでの Displace 解像度の変更

ちなみにですが、Displace の解像度の変更は Display Options から行えます。
![26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/5e654311-0b59-1735-84ea-de59aaa913d7.png)
![27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/764beca0-107d-47e7-99ff-2df529df38b7.png)



## Vector Displacement Map の作り方
差のVector情報を作ればいいだけなので、作るのはいたって簡単です。
立体の形状と、平らな状態の形状を２つ用意します。
（ここではUVPeltノードを使用して平面化しています。）

<img width="350" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/ae476d31-9f03-fc52-15e7-13d0d660490b.png"><img width="350" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/a6ea5537-023e-af74-f4d7-befbdb494814.png">

それらのP同士を引き算します。
ここでは変形前のPをrestとして保存しています。
v@vdm のアトリビュートの名前に決まりはありません。（予約語ではないです）

<img width="700" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/1ef45856-67a5-c97e-c511-b9baf43a691f.png">

Copernicus に持っていき、Null をつけて「VDM」と名前を付けました。
これで Vector Displacement Map の完成です！


<img width="700" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/63790129-a3ce-7257-414a-a13267c8b35c.png">


後はこのマップを読み込むシェーダー側の設定です。

## MaterialX での実装
なにか特別なことをする必要はなく、実は、MaterialX の Displace ノードはデフォルトで Vector が差せるのです！（つまり既に実装されてる…！）
![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/aa1a73f2-12e1-453c-b91d-c804c9ec3caa.png)

なので白黒の Height map の代わりに vector のカラーデータを差せばできてしまいます。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/190ecefb-9eca-23ce-08b0-7800952905e3.png)

※MaterialXの仕様なのか、MtlX Standard Surface の方にも何かしらのマップを貼らないと動作しなかったため、空の Image ノードを base_color に差しています。

## COP内の Preview Material で実装
ところが、 COP 内の Preview Material では Height Map に vector（RGB）を差すことができません。
Preview Material の実態は MaterialX なので動作しそうですが、
Vector Displacement Map を使用する想定で組まれていないようです。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/dc5ad39a-e355-301b-cb86-15365ee33dfd.png)

中に入って少し改造したいと思います。
右クリック→Allow Editing of Contents して、中に入ります。
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/6226658b-1c88-1d74-1dd8-48e0d0fc079e.png)

右上の SOP Import に入ります

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/9509fe9e-064d-a0a4-6341-76139ffce15c.png)

COP Preview Material を Allow Editing of Contents して、中に入ります。

![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/0bebc4bf-fce6-bc56-a5c4-2d6c27517f94.png)

Displaceするマテリアルとしないマテリアルを切り替える Switch ノードがあるのでバイパスします。
これによって、強制的にDisplaceのあるマテリアルを選択させるようにします。
続いて Material Network に入ります

![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/905045b8-9388-47a9-8ae8-8af521577cae.png)

左の COP Preview mat に入ります。
![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/02cfb25f-29ba-e391-6d73-c63138a35b55.png)

下の方にDisplace の項目があるので、寄っていきます
![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/a7c7e221-5e49-1f1c-6221-d7e1eac25b9d.png)

新たに MtlX Image を作成し、File Name に 「VDM」と名付けた Null を「op:」関数で指定します。

![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/4d7a5caa-a428-7338-f4ac-2cdca72a9e25.png)

MtlX Displacement に付けます
![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/46fa85a4-9eea-61c2-d1fa-daacb88c146e.png)

Copernicusに戻り、エラーの出てた Height Map のコネクトを切ります。

![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/f452b89f-c455-461f-d99d-d73e25ca3bdc.png)


動作しました！！

## 宙に浮かせるようにOpacity を設定
アルファを Opacity に差せば、グリッドと接続しているジャギジャギが取れ、浮いたような表現になりました。
ジャギジャギをより奇麗に取るには Vector Displacement Map に Smooth Fill ノードを挟んで、境界にも色が来るよう広げます。

![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/70d4e5c6-a322-ac46-6ad3-36deb8038bba.png)

後ろ見ると、完璧には上手くいってませんが…。

![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/622ddaae-f137-cbe2-3dcd-d2561d1f5a61.png)


また、バラバラにUV展開されたものでも Opacity を使えば浮かすことができます。

![24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/11b6d2ee-b5a0-4192-5691-a50194fbb075.png)

## 追記、Opacity 使用せずにジャギジャギを消す

<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">記事投稿してから思いついたけど、opacity で抜かなくても、平面を余すことなく使用すれば接続部分のジャギジャギ出ないな…！<a href="https://twitter.com/hashtag/Houdini?src=hash&amp;ref_src=twsrc%5Etfw">#Houdini</a> <a href="https://twitter.com/hashtag/Copernicus?src=hash&amp;ref_src=twsrc%5Etfw">#Copernicus</a> <a href="https://t.co/Cadsc140FA">pic.twitter.com/Cadsc140FA</a></p>&mdash; 岡田拓也 (@okada_takuya) <a href="https://twitter.com/okada_takuya/status/1864526614207582454?ref_src=twsrc%5Etfw">December 5, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※詳しいやり方は更新した hip を見てね

## ノイズを加えてみた
試しに出来た Vector Displacement Map にノイズを加えて遊んだりもしてみました。

![25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535300/ac42538b-cd7d-c9d9-1b58-2e29abc37815.png)

Vector Displacement Map の形状変更は癖が強く、とても難しいのですが、とりあえずノイズは単純に加えることができました！


## 終わりに
Vector Displacement Map を知るきっかけとなったのはこちらのポスト
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="en" dir="ltr">make Vector Displacement Map with SOP and COP<br>- render with Karma and MaterialX 🐷<a href="https://twitter.com/hashtag/houdini?src=hash&amp;ref_src=twsrc%5Etfw">#houdini</a> <a href="https://t.co/0cYyR5azIV">pic.twitter.com/0cYyR5azIV</a></p>&mdash; tinybugbot (@tinybugbot) <a href="https://twitter.com/tinybugbot/status/1853831247845564486?ref_src=twsrc%5Etfw">November 5, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[tinybugbot](https://x.com/tinybugbot)氏に感謝申し上げます！
Copernicusで様々な面白いポストをしていらっしゃるので、フォロー必須です！

最後まで読んでいただきありがとうございました！