ホーム < ゲームつくろー! < Shader編

その12 波:波頭に近い所は発光しているように見えるかもしれない

 前章でゲルストナー波に環境マップとフレネル反射を施して、より水の波っぽさをアップさせました。見た目に少しずつ良い感じになってきています(^-^)。で、この章ではちょっとした工夫を一つ。



@ 深い海の表面にある薄い所

 この波シリーズ、基本的に「十分に深い海のような波」を想定して作ってきています。十分に水が深いと水底や波が崩れるなどの面倒事を考えなくて良くなり、実装がちょっと楽になるためその前提を敷いています。

 波立っている水面の色は、前章で説明したように、水本来の色味であるターコイズブルー系と周囲の映り込みである環境マップ色の合成でした。水面に衝突した入射光は屈折光と反射光に分離しますが、その内の屈折光は水深が深いため水の中で乱反射してしまい、拡散反射光として認識されると考えました。しかしもし水の厚みが薄ければ、乱反射した屈折光の多くは力を失う前に再度水面に抜け出るため、その水の色は入射光の色を反映するようになる…と考えられます。深い海の中でそのような厚みの薄い所というのがあるのか…というと、ありえます。それは「波頭近辺」です:


 光が波頭近辺に衝突したとします。幾分かは反射光として反射してしまいますが、残りは屈折光として波の中に突入していきます。この時内部では一定の割合で乱反射が起こります。あらゆる方向に屈折して広がっていく乱反射は、上図のように確率的には波頭の所程早く(≒多く)再び水平方向の海面へ飛び出していきます。という事は、波頭と波の底とでは色味が違って見えるはずです。波頭の所は乱反射した光がより多く波の厚み方向へ飛び出す、つまり横から見ると「発光」のような状態になります。その分入射光の色味を帯びた色になるはずです。そう「波頭は横から見ると発光する(透けた)ように見える」と考えられるんです。


A 視線ベクトルと海面法線が垂直程「横」から見てる事になる

 上の理屈を簡便に実現する一つの方法として「海面を横から見る程入射光の成分を加算する」という方法が考えられます。多くの場合、視線ベクトルと垂直に近い関係になるのは波頭近辺です。よって、視線ベクトルと法線の内積がゼロに近い程乱反射した光が飛び出して視線に入ってくると考えて良さそうです。物理的に云々ではなくて、それっぽく見えれば良いんです。

 これをシェーダに組み込むのは簡単です。前回までのシェーダのフラグメントシェーダ内に以下の要素を追加します:

// 視線に対して垂直に近い面は薄いのでちょっと発光
float3 lightColor = float3( 1.0, 1.0, 1.0 );
float waveTopAddPower = 1.0;
float waveTopAddColor = lightColor * pow( 1.0 - abs( dot( fromVtxToCameraW, normalW ) ), 10.0 ) * waveTopAddPower;

入射光の色(lightColor)は仮です。ディレクショナルライトなどの色を実際は使って下さい。肝は2行目。波頭加算色(waveTopAddColor)を求めています。まず、視線ベクトルと法線とで内積を計算しています。90度に近い程0に、水平に近い程±1になるので、絶対値を取って0〜1の範囲にします。0の方が強い力になって欲しいので、1.0から内積の結果を引き算して値を反転させています。次にその値をべき乗しています。これは90度に近い所だけを際立たせて加算したいからです。スペキュラ光と同じ発想ですね。最後に加算具合をwaveTopAddPowerで調節して終わりです。

 求めたwaveTopAddColorを波の色味に加算すると効果が表れます。実際にこの効果を付ける前と後の比較画像がこちら:


waveTopAddPower = 0.0

waveTopAddPower = 1.0

上がこの効果を入れていない波、下が強めに効果を入れた波です。効果を見やすくするためスペキュラは切ってあります。上の波は全体的にのっぺりとした感がありますが、下の波は波頭の所が際立って見えますよね。少し瑞々しさが増した感じ…でしょうか。また遠くの方の波がより光って見えます。視線との角度は遠く程90度になりやすいからです。もしこれが邪魔であるなら、距離が遠い程効果を小さくするように工夫するのもありです。

 という事で、ちょっとした工夫ですが割と効果的な「波頭を発光させる」でした(^-^)。比較動画はこちら: