水面下の屈折疑似表現


<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/011.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/011.jpg" alt="" /></a></p>

<p>水路などを表現する際、水面下の屈折表現としてGrabPassをよく使用すると思いますが、
MetaQuestなどAndroidプラットフォームの場合はGrabPassが機能しないので、別の方法で表現する必要があります。</p>
<p>今回はAndoroidプラットフォームにて、GrabPassを使わずに水路の水面下の屈折疑似をやってみたいと思います。
積木ではbuiltinのシーン制作として、AmplifyShaderEditorを使用しているのでそれを使用した一例です。</p>
<!-- wp:heading -->
<h2>水路っぽい背景と水面を準備</h2>
<!-- /wp:heading -->
水面のシェーダーとしてはとりあえずTransparentでOpacityとNormalmapを設定し、
NormalMapをスクロールで動かしています。1枚のスクロールだけではただスクロールしているだけに見えるので、
タイリング、スクロールするスピードを変えた2種類のNormalをblendしてスクロールさせています。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/001.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/001.jpg" alt="" /></a></p>
<p>現実であれば、屈折の関係で水面下のコンクリートが水面の揺らぎに合わせてゆらゆら動いて見えるもので、これをGrabPassで表現することが多いですが、それが使用できないとなると水面がNormalMapで揺らいでいますが、水面下に見える水路のコンクリートがまったく動いて見えないのでとてもチープな感じになってしまいます。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/first_amin.gif"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/first_amin.gif" alt="" /></a></p>
<!-- wp:heading -->
<h2>水面下の揺らぎの疑似表現を加えてブラッシュアップ</h2>
<!-- /wp:heading -->
<p>水面下の揺らぎは、AmplifiyShaderEditorのLocal Vertex Offsetで代用します。
なので、水面下のコンクリート部分だけモデルを分離して水面下用のモデルとします。
水面下のモデルはLocal Vertex Offsetで頂点を揺らすのである程度メッシュ分割しておきます。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/002.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/002.jpg" alt="" /></a>
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/003.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/003.jpg" alt="" /></a></p>
<p>コンクリートのシェーダーがこちら
とてもシンプルにAlbedoとNormalとSmoothnessが入っているのみです。
ここに水面の動きに合わせて頂点が動くようにしていきます。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/004.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/004.jpg" alt="" /></a></p>
<p>水面のNromalMapのスクロールで使ってるノードをそのまま持ってきて
Local Vertex Offsetにつなげます。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/005.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/005.jpg" alt="" /></a></p>
<p>頂点が動く強さを制御するために
Displace Scaleという名前でFloatを加え、XYZそれぞれ動いてもらいますが
今回に関してはY方向により動いてほしかったので、Yだけ2を乗算して他よりも
大きく動くようにしています。
最後に、頂点カラーのRをマスクとして、頂点カラーがＲのところは
全く動かないようにします。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/006.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/006.jpg" alt="" /></a></p>
<p>これの意図としては
水面下の頂点すべてが動いてしまうと、水面上のモデルとの境界で隙間が生じてしまうので
水面下モデルのエッジ部分のみ頂点カラーを赤に設定して、それをマスクとしてその部分だけは
頂点が動かないようにしています。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/007.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/007.jpg" alt="" /></a></p>
<p>どうでしょうか。
GrabPassを使用していなくとも、水面下モデルの頂点が水面の揺らぎNormalMapと同じノードによって直接上下左右に動いているので水面上から見ると屈折で揺らいでいるように見えます。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/2nd_anim.gif"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/2nd_anim.gif" alt="" /></a></p>
<p>これで疑似屈折表現としてはできましたが、水面に関してもう少し手を加えたいと思います。
<!-- wp:heading -->
<h2>水面のブラッシュアップ</h2>
<!-- /wp:heading -->
<p>汚れた水を想定していますが、水ですので水底が浅いほど水はより透明に見え、水底が深いところほど汚れによって不透明に見えるはずです。SSS的な感じ。
<p>水面のLocal Vertex Offsetも使用して水面自体の揺らぎも足してみましょう。
<p>水面のエッジ部分ギリギリまでSmoothnessのスペキュラーがでてると、そのスペキュラーが水面エッジで中途半端に途切れてゲームっぽいポリゴン感がでてしまうので、水面際にはスペキュラーが出ないように。</p>
<p>水面のLocal Vertex Offsetに関しては水面下と同じです。
水面の揺らぎで使用しているNormalMapノードをLocal Vertex Offsetにつないで頂点移動の強度を設定するのみです。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/008.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/008.jpg" alt="" /></a></p>
<p>水面のSSS的な表現と水面際までスペキュラーを出さない表現に関しては頂点カラーを利用します。<p>まず、水面モデルの頂点カラー赤にて、際から中心に向かってグラデーションになるように設定します。
赤ほど透明度が高く、黒くなるにしたがって透明度が下がる（濁ってみえる）ようにするためです。
また、水面エッジのみ頂点カラー緑を設定して、それをマスクとしてその部分だけはスペキュラーが出ないようにします。
際だけ赤と緑の混色となるので、DCCツール上では黄色の頂点カラーとなります。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/009.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/009.jpg" alt="" /></a></p>
<p>Amplify Shader Editorに適用します。
頂点カラー赤をマスクとしてOpacity２種をLerp　中心程透明度を下げ、エッジ程透明度を上げます。
頂点カラー緑をマスクとしてSmoothness２種をLerp エッジ部分だけSmooothnessを0にしてスペキュラーが出ないようにします。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/012.jpg"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/012.jpg" alt="" /></a></p>
<p>どうでしょうか。
Local Vertex Offset によってエッジの揺らぎが表現され、
SSS的な深さによる濁りの違いも表現できました。
<a href="https://tsumikiseisaku.com/blog/wp-content/uploads/finish_anim.gif"><img src="https://tsumikiseisaku.com/blog/wp-content/uploads/finish_anim.gif" alt="" /></a></p>
<p>今回シンプルな水路をサンプルとして挙げたのでやりやすかったですが、
自然の川底などでも応用できると思いますので、GrabPassを使えなくとも
できるだけ水っぽい表現を今後もやっていきたいと思います。</p>