回答:
深さに基づいて水を照明するには、基本的に2つの異なるアプローチがあります。
Minecraftはボクセルベースの照明を使用します。これは、隣接するキューブに光を伝播することで機能し、ブロックのタイプに応じて輝度を下げます。暗い海はこのシステムの副作用です。
水は日光を遮断し、ブロックごとに3レベル(デフォルトの1レベルではなく)減ります。
0 (surface): 15 (direct sunlight)
1: 12
2: 9
3: 6
4: 3
5 and below: 0 (darkness)
従来の照明モデルを使用したゲームでは、光源と海底の間にある水の量を測定することでこの効果を作成できます。次に、この距離に基づいてライトがフェードされます。これを行うには、いくつかの方法があります。
平らな表面がある場合、水面から法線を通過させ、この法線と表面位置のドット積をジオメトリシェーダーに渡すと、光が水中を移動する距離を簡単に計算できます。
有効な水距離は
ここで、頂点の位置は、水面下の光の方向と水域に垂直な水面との間の角度です。
日没時には、水に入ると光が屈折するため、わずか50°未満になります。
良い説明のあるブログ投稿:デジタルカメラ:全反射
について詳細を含む別の投稿:デジタルカメラ:スネルの屈折の法則
水に平行な表面でハイトマップを使用している場合、になります。太陽が水面の真上にある場合、正しい係数は1です。
ポイントライトでは、光源に対する相対位置に基づいて各頂点について計算する必要があります。
固定水位または固定光方向では、方程式の一部は一定であり、パフォーマンス上の理由からシェーダーで計算されるべきではありません。
(光源から見た)別の深度マップに水面をレンダリングする場合、その深度テクスチャを使用して、水面内に到達するまでの光の距離を計算できます。
これを行うには、各頂点を頂点シェーダーで光源のビュー投影に投影し、ピクセルシェーダーでテクスチャルックアップを実行します。
表面が比較的平坦な場合は、より良い結果を得るために屈折した光源を使用する必要があります。
*次のように、ライトのPOVから深度をカウントすることにより、最も近い固体表面の前の水の量を決定できます。
結果のテクスチャには、light-view-spaceのライトの前にある水の量が含まれているため、使用する前に値を元に戻す必要があります。この方法は、指向性ライト(マイナス屈折)を計算するために機能しますが、表面が非常に不規則で、同じフラグメントに影響を与える水域の間に大量の空気がある場合、不正確な環境光につながります。
長所と短所は通常のシャドウマッピングの場合と同じですが、深度を計算する際にもう1つのバッファーが必要であり、より多くのジオメトリを描画する必要があるためパフォーマンスが低下します。
レイトレーシングは、最も正確ですが、透明なボリュームをレンダリングするための最も高価なソリューションです。これを行うには、2つの方法があります。1。海底から水面に向かって追跡する。2。光源から水に向かって追跡する。明るさを計算するには、床の各ポイントに複数の光線が必要です。
水をレンダリングするときに考慮すべきことがいくつかあります。
水中の光は、観測者に向かっている間に再び散乱するため、単色にブレンドする必要があります。
オブザーバが水没している場合、深度バッファの最終結果に基づいてフォグをレンダリングすることができます。霧の色は、その密度ではなく、観測者の表面からの距離によって変化するはずです!(Minecraftはエフェクトのこの部分のみを使用します。)
観測者が上から水を見る場合、表面と水面下のジオメトリの深さの差に基づいて霧を計算する必要があります。霧の色は、深さの差が大きくなるとわずかに暗くなりますが、霧が完全に不透明になるポイントにのみ変化するはずです。
霧の色は、各ピクセルの視線方向にも依存する必要があるため、どちらの場合も見下ろすと少し暗くなります。
偽のコースティクスにデカールの代わりにシームレスなタイル3D-Textureを使用する場合、垂直面でのストレッチを回避できます。表面近くの散乱光の強度は3次元で変化するため、通常2Dテクスチャを使用すると、シーンのどこかでストレッチが発生します。床の頂点位置を別の座標系に投影することにより、変化する光の角度をモデル化できます。
もう1つの可能性は、ライトの座標系の表面位置に基づいてライト密度を計算することですが、パフォーマンスが低下する可能性が最も高くなります。
コースティクスは、深さが増すにつれて拡散光よりも速くフェードするはずです。
色の分散が異なるため、深さを増すと光の色が変化します。これにより、たとえば、ビーチが水面と交差するような突然のエッジも防止されます。
屈折のため、光は通常よりもはるかに急に海底に当たります。スネルの法則についてのWikipediaの記事は、角度やベクトルの式を持っています。
Minecraftの空の照明効果はまっすぐ下にあると信じています-太陽がどこにあっても、それらの上にあるものによって物事は陰になります。次に、トーチなどからのローカル照明にドロップオフ効果を適用します。光源から遠ざかるほど、キューブの光は少なくなります。
この方法で行うと、水の各レイヤーがその下のレイヤーを累積的にシャドウするため、それぞれが徐々に暗くなります。木の葉はこのような日陰を提供しますが、累積的ではありません。葉の立方体が1であろうと100であろうと、木の下で同じ色合いが得られます。
これが使用されている方法であるという手がかりの1つは、見る人から遠く離れても水が暗くなることはないということです。はい、霧の効果は遠くで作動しますが、水の暗い効果ではありません。
したがって、照明を計算するための基本的な式は、擬似コードでは次のようになります...
light_on_cube = 1.0
for each cube above target cube, from lowest to highest {
if cube being examined is tree foliage
light_on_cube = 0.5
else if cube being examined is water
light_on_cube = light_on_cube - 0.1
else if cube being examined is solid
light_on_cube = 0
}
これは、オーバーハングまたは洞窟内の照明の計算には最適ではありません。この方法を使用すると、オーバーハング下で真っ暗になります。ただし、ローカルの光源(トーチ、火など)の両方を追加したり、太陽に照らされたブロックを光源として扱うことができます。このような何かがそれをするかもしれません...
ここでの考え方は、キューブが太陽やトーチで照らされている場合、その隣のキューブも何らかの方法で照らされるということです。そして、あなたはその照らされた立方体から遠く離れるほど、そこにある光は少なくなります。それは拡散照明を推定するためのちょっとしたやり方ですが、うまくいくと思いますか?
質問を誤解しているのかもしれませんが、ブロックの深さに応じてブロックの色を変更できないのはなぜですか?
深さd(0から始まるブロック単位)がある場合、明るさの合理的な方程式は次のようになります。
L =(1- m)e - kd + m
コード: L = (1.0 - m) * exp(-k * d) + m;
kは、暗くなる速度を制御します(高く=速く)。妥当な値は0.5です。
mは必要な最小の明るさです。
Lは0から1まで変化します。
使用しているグラフィックスAPIでブロックの色を変更する方法がわからない場合は、別の質問として使用してください(使用しているAPIと、シェーダーを使用しているかどうかの統計)。
e^-kd
ビットは単なる指数関数的減衰であり、ある値(深さ)で徐々にゼロに向かう傾向があるものの標準関数です。による乗算(1-m)
と加算はm
、減衰をスケーリングおよびオフセットするためのものであり、最小で終了しますがm
、それでも開始し1
ます。 en.wikipedia.org/wiki/Exponential_decay