Unity シェーダー 滝

Unity シェーダーチュートリアル  滝を作ってみる

シェーダー

今まで数回にわたって基本的なシェーダーコードの解説を書いてきましたが、

1つ1つの要素をバラバラに解説されても掴みどころが分からない、なんて事もあると思います。

 

なので今回はもう少し実践的にやってみたいと思います。

実践編第1弾は「滝を作ってみる」です。

 

過去の案件で森&滝を作った事があるので、これを解説していきます。

 

今回は滝のシェーダーをどのように作っていったか、

順番に積み上げて見ていった方が分かりやすいと思うので、

完成版のシェーダーコードは最後に載せます。

 

 モデルの用意

シェーダーコードを見る前に、まずは滝のモデルを用意します。

3DCGで髪の毛を作る時の常套手段で、短冊状のモデルを重ねるバナナリーフと呼ばれる手法です。

 

【モデルダウンロード】

Unity シェーダー 滝

 

 シェーダー作成

 とりあえず

さて、ではどのように滝を表現すれば良いでしょうか?

とりあえずは透明シェーダーで、上から下に水流っぽいテクスチャがスクロールしていれば、

それっぽく見えるかもしれません。やってみましょう。

 

Unityのシェーダーでは _Time で時間が取得できるので、アニメーションに利用することができます。

xyzwで時間の流れる速さを選べます。[x:1/20、y:1、z:2、w:3]

テクスチャを縦にスクロールさせたい場合は UV の V を _Time で動かせば良いのです。


fixed flowTex = tex2D(_MainTex, IN.uv_MainTex + half2(0, _Time.x * _Flow)).r;

 

こんなテクスチャをスクロールさせてみました。

Unity シェーダー 滝

 

明るすぎて白飛びしてしまいました。明度を調節できるようにしましょう。

Unity シェーダー 滝Unity シェーダー 滝

 

_Brightness プロパティを追加しました。

 

Unity シェーダー 滝Unity シェーダー 滝

 

 横スクロールも入れてみよう

とりあえず上下に流れるようにはなりましたが、何か単調です。

微妙な横スクロールを追加して、より流れてる感が演出できないでしょうか。

 

縦スクロールとは違うテクスチャを使ってみましょう。こんなのにします。

何か水のしなやかな流れっぽくないですか?

Unity シェーダー 滝

 

ここでちょっと工夫します。縦スクロールも横スクロールも、

使用しているのは1チャンネルのみなので(0~1の透明情報が欲しいだけだから)、

1つのテクスチャにまとめてしまいましょう。

パラメーター的なテクスチャをRGBAチャンネルに振り分けて格納するのは、

メモリ削減のためにもよく使われる手法です。

 

今回は R チャンネルに横用、 B チャンネルに縦用を振り分けました。

Unity シェーダー 滝  Unity シェーダー 滝

 

 

横と縦でそれぞれテクスチャをサンプリングしています。

スクロールの方向が違うので _Time を使用してアニメーションさせるのは横が X縦が Y です。

また、横と縦でテクスチャのチャンネルを使い分けています。


fixed flowTexU = tex2D(_MainTex, IN.uv_MainTex + half2(_Time.x * _FlowU, 0)).r;  // 横スクロールテクスチャ

fixed flowTexV = tex2D(_MainTex, IN.uv_MainTex + half2(0, _Time.x * _FlowV)).g;  // 縦スクロールテクスチャ

 

Unity シェーダー 滝Unity シェーダー 滝

 

だんだんと良い感じになってきました。が、皆さん気になる点がありませんか?

 

 カオスが欲しい

3DCGというのは人の手作業で積み上げていくものなので、単調になりがちです。

特に自然や有機物を作る際には、形状の乱れや汚しなど、

カオスを入れれば入れるほど情報量が多くなり、リアルに近づいていきます

 

先ほどのテクスチャスクロールを見てください。

今のままだとすべてが同じスピードで流れていて表現力に乏しく、

また、横スクロールに至っては同じ方向にしか動いていないので非常に不自然です。

もっとランダムさが欲しいですね。

バナナリーフの短冊ごとに流れるスピードを変えてみましょう。

 

Q. モデルの箇所によって流れるスピードを変えるにはどうすれば良いでしょうか?

① 短冊ごとにマテリアルを分けて Flow Speed を変える ・・・・・ やってられません

② 短冊ごとに違う値を設定できるようにテクスチャで描き分ける ・・・・・ ちょっとメンドクサイ

③ 短冊ごとに頂点カラーの明度を変えて Flow Speed に幅を付ける ・・・・・ 簡単そう

 

ということで、頂点カラーの明度によって Flow Speed を最小値~最大値に振り分けてみましょう。

頂点カラーの使い方については前回の記事に書いてあります。

 

先ほどのモデルにはすでに頂点カラーが仕込んであります。

Rチャンネルが横スクロール用、Gチャンネルが縦スクロール用です。

(色に惑わされないで下さい。単なる 0~1 のパラメーターです。)

Unity シェーダー 滝

 

注意点として、RとGで同じ濃度の頂点カラーを使ってはいけません

同じにしてしまうと、横スクロールが遅い所では縦スクロールも遅く、

横スクロールが速い所では縦スクロールも速いという様に、

ランダムに振り分けたにもかかわらず、ランダムに見えなくなってしまうからです。

できる限りすべてをランダムにしてカオスを作り上げることが重要です。

 

 

R、G それぞれの頂点カラーが 0~1 まで、短冊ごとにランダムに振り分けられているので、

lerp(min, max, interpolation) によって、最少値~最大値の幅で補完されます。

 

また、横スクロールについては左方向か右方向かもランダムに振り分けたいので

round(IN.color.r) * 2 - 1 を乗算しています。

round は、四捨五入なので 0~1 に振り分けられている値が 0 か 1 のどちらかに丸められます。

そして * 2 - 1-1 か 1 になります。つまり左方向か右方向か(正か負か)です。

 


float2 uvOffset;

uvOffset.x = _Time.x * lerp(_FlowU.x, _FlowU.y, IN.color.r) * (round(IN.color.r) * 2 - 1);

uvOffset.y = _Time.x * lerp(_FlowV.x, _FlowV.y, IN.color.g);

 

fixed flowTexU = tex2D(_MainTex, IN.uv_MainTex + half2(uvOffset.x, 0)).r;

fixed flowTexV = tex2D(_MainTex, IN.uv_MainTex + half2(0, uvOffset.y)).g;

 

Unity シェーダー 滝Unity シェーダー 滝

 

 形状を目立ちを防ぐ

下図の印を付けた部分が少し気になります。

短冊の両端でテクスチャがスパッと切れているのでバナナリーフモデリングが目立ちます。

Unity シェーダー 滝

 

短冊の端に行くにしたがってグラデーションで滑らかに消してしまいましょう。

使っていなかった頂点カラーのBチャンネルを設定しました。短冊の端が0で中央が1です。

(色に惑わされないで下さい。単なる 0~1 のパラメーターです。)

Unity シェーダー 滝

 

単純に頂点カラーのBチャンネルも取得して乗算しているだけです。

 

エッジの部分が目立たなくなりました。

Unity シェーダー 滝

 

 最終調整

最後に、色とコントラストを調整できるようにしてみましょう。

 

_Color プロパティを単純に乗算しています。

また、 _Gammaプロパティで Photoshop で言う、レベル補正的な事をしています。


o.Emission   = pow(flowTexU * flowTexV * IN.color.b, _Gamma) * _Brightness * _Color;

 

Unity シェーダー 滝Unity シェーダー 滝

 

 おわりに

UVアニメーションと頂点カラーを利用して、滝を作ってみましたがいかがでしょうか。

さらにここにディスプレイスを足してもっとボリューム感を出したりすることもできますね。

 

やっていることは単純なので、あとは組み合わせのアイデア次第です。

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)