Minecraftのように、水を深さとともに暗くする方法を教えてください。


24

Minecraftでは、水をより深く見ると、より暗い水が見えます。誰かがそのようなものをコーディングする方法を知っていますか?

効果のあるMinecraft 効果のあるMinecraft

効果のない同様のゲーム 効果のない同様のゲーム


18
水立方体の材料は半透明なので、これは自動的に行われませんか?
ペック

そうは思いません。比較のために、効果のない写真を追加しました。
ザビエル

2
多分それは水立方体にのみ適用される添加剤ブレンド効果でしょうか?繰り返しますが、素材は半透明なので、これは簡単です。
ペック

1
深さに応じてボックスの色を変更することもできます。
Ali1S232

回答:


51

深さに基づいて水を照明するには、基本的に2つの異なるアプローチがあります。

ボクセル照明

Minecraftはボクセルベースの照明を使用します。これは、隣接するキューブに光を伝播することで機能し、ブロックのタイプに応じて輝度を下げます。暗い海はこのシステムの副作用です。

水は日光を遮断し、ブロックごとに3レベル(デフォルトの1レベルではなく)減ります。

0 (surface): 15 (direct sunlight)
1:           12
2:            9
3:            6
4:            3
5 and below:  0 (darkness)

ソース:Minecraft Wiki-Light

距離ベースのシャドウイング

従来の照明モデルを使用したゲームでは、光源と海底の間にある水の量を測定することでこの効果を作成できます。次に、この距離に基づいてライトがフェードされます。これを行うには、いくつかの方法があります。

直接計算

平らな表面がある場合、水面から法線を通過させ\ vec {n}、この法線と表面位置のドット積をsジオメトリシェーダーに渡すと、光が水中を移動する距離を簡単に計算できます。

有効な水距離は

\ max(\ left(s-\ vec {n} \ cdot \ vec {p} \ right)、0)\ cdot \ left(1 + \ tan(\ alpha)\ right)

ここ\ vec {p}で、頂点の位置は、アルファ水面下の光の方向と水域に垂直な水面との間の角度です。

日没アルファ時には、水に入ると光が屈折するため、わずか50°未満になります。
良い説明のあるブログ投稿:デジタルカメラ:全反射
について詳細を含む別の投稿:デジタルカメラ:スネルの屈折の法則

水に平行な表面でハイトマップを使用している場合、に\ left(s-\ vec {n} \ cdot \ vec {p} \ right)なり\ left(s-h \ right)ます。太陽が水面の真上にある場合、正しい係数は1です。
ポイントライトではアルファ、光源に対する相対位置に基づいて各頂点について計算する必要があります。

固定水位または固定光方向では、方程式の一部は一定であり、パフォーマンス上の理由からシェーダーで計算されるべきではありません。

長所:

  • 速くて正確

短所:

  • 通常は1つのサーフェスのみが考慮されるため、平らな水面または真上からの光に対してのみ機能します。(粗い表面と傾斜した光の組み合わせは、視差マッピングである程度機能する可能性があります。)
  • コースティクスなし

シャドウマッピング

(光源から見た)別の深度マップに水面をレンダリングする場合、その深度テクスチャを使用して、水面内に到達するまでの光の距離を計算できます。
これを行うには、各頂点を頂点シェーダーで光源のビュー投影に投影し、ピクセルシェーダーでテクスチャルックアップを実行します。

表面が比較的平坦な場合は、より良い結果を得るために屈折した光源を使用する必要があります。

長所:

  • 閉塞しない限り、比較的複雑な水ジオメトリで動作します。*
  • ほとんどすべての種類の部分的に透明なボリュームに再利用できます。

短所:

  • 直接計算よりも遅い。
  • 深度マップ用に追加のVRAMが必要です。
  • 100%正確ではありません。

*次のように、ライトのPOVから深度をカウントすることにより、最も近い固体表面の前の水の量を決定できます。

  1. 通常どおり、シーン内のソリッドジオメトリをレンダリングします。フラグメントごとに、結果のテクスチャに深度値を追加します。
  2. 深度バッファを更新せずに水の前面をレンダリングし、結果からフラグメントの深度を減算します。
  3. 同じ方法で背面をレンダリングしますが、結果にフラグメントの深さを追加します。

結果のテクスチャには、light-view-spaceのライトの前にある水の量が含まれているため、使用する前に値を元に戻す必要があります。この方法は、指向性ライト(マイナス屈折)を計算するために機能しますが、表面が非常に不規則で、同じフラグメントに影響を与える水域の間に大量の空気がある場合、不正確な環境光につながります。
長所と短所は通常のシャドウマッピングの場合と同じですが、深度を計算する際にもう1つのバッファーが必要であり、より多くのジオメトリを描画する必要があるためパフォーマンスが低下します。

レイトレーシング

レイトレーシングは、最も正確ですが、透明なボリュームをレンダリングするための最も高価なソリューションです。これを行うには、2つの方法があります。1。海底から水面に向かって追跡する。2。光源から水に向かって追跡する。明るさを計算するには、床の各ポイントに複数の光線が必要です。

長所:

  • すべてのジオメトリで正しく動作します。
  • 正しいコースティクス!

短所:

  • スロー!

追加の効果

水をレンダリングするときに考慮すべきことがいくつかあります。

水中の光は、観測者に向かっている間に再び散乱するため、単色にブレンドする必要があります。

オブザーバが水没している場合、深度バッファの最終結果に基づいてフォグをレンダリングすることができます。霧の色は、その密度ではなく、観測者の表面からの距離によって変化するはずです!(Minecraftはエフェクトのこの部分のみを使用します。)

観測者が上から水を見る場合、表面と水面下のジオメトリの深さの差に基づいて霧を計算する必要があります。霧の色は、深さの差が大きくなるとわずかに暗くなりますが、霧が完全に不透明になるポイントにのみ変化するはずです。

霧の色は、各ピクセルの視線方向にも依存する必要があるため、どちらの場合も見下ろすと少し暗くなります。

偽造コースティクス

偽のコースティクスにデカールの代わりにシームレスなタイル3D-Textureを使用する場合、垂直面でのストレッチを回避できます。表面近くの散乱光の強度は3次元で変化するため、通常2Dテクスチャを使用すると、シーンのどこかでストレッチが発生します。床の頂点位置を別の座標系に投影することにより、変化する光の角度をモデル化できます。

もう1つの可能性は、ライトの座標系の表面位置に基づいてライト密度を計算することですが、パフォーマンスが低下する可能性が最も高くなります。

コースティクスは、深さが増すにつれて拡散光よりも速くフェードするはずです。

色のグラデーション

色の分散が異なるため、深さを増すと光の色が変化します。これにより、たとえば、ビーチが水面と交差するような突然のエッジも防止されます。

入射角

屈折のため、光は通常よりもはるかに急に海底に当たります。スネルの法則についてのWikipediaの記事は、角度やベクトルの式を持っています。


6

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
}

これは、オーバーハングまたは洞窟内の照明の計算には最適ではありません。この方法を使用すると、オーバーハング下で真っ暗になります。ただし、ローカルの光源(トーチ、火など)の両方を追加したり、太陽に照らされたブロックを光源として扱うことができます。このような何かがそれをするかもしれません...

  1. 各キューブの真上から(擬似コードを介して)太陽からの光を計算します。
  2. 立方体の横に光源がある場合、完全に点灯していると見なします(1.0)
  3. 立方体が真上から太陽を受けていない場合、完全に照らされた立方体からの距離に基づいて、立方体に光を与えます。近いほど光量が多くなり、遠いほど光量が少なくなります(ゼロになるまで)。

ここでの考え方は、キューブが太陽やトーチで照らされている場合、その隣のキューブも何らかの方法で照らされるということです。そして、あなたはその照らされた立方体から遠く離れるほど、そこにある光は少なくなります。それは拡散照明を推定するためのちょっとしたやり方ですが、うまくいくと思いますか?


1
ええ、私はそれがチケットだと確信しています。私は自分のゲームで似たようなことをしました。
マイケルハウス

ちなみに、GoogleリーダーリストByte56にあなたのブログを追加しました-開発者ブログFTW!
ティム・ホルト

ああ、どうもありがとう。まだこの質問のトピックから外れていますが、私はベイリー教授のクラスに関するあなたのブログを読みました。私は去年そのクラスにいました!昨年もそのプレゼンテーションを行ったと思います。あなたの名前はおなじみだと思いました。小さな世界:)
マイケルハウス

3

質問を誤解しているのかもしれませんが、ブロックの深さに応じてブロックの色を変更できないのはなぜですか?

深さd(0から始まるブロック単位)がある場合、明るさの合理的な方程式は次のようになります。

L =(1- me - kd + m

コード: L = (1.0 - m) * exp(-k * d) + m;

kは、暗くなる速度を制御します(高く=速く)。妥当な値は0.5です。
mは必要な最小の明るさです。
Lは0から1まで変化します。

使用しているグラフィックスAPIでブロックの色を変更する方法がわからない場合は、別の質問として使用してください(使用しているAPIと、シェーダーを使用しているかどうかの統計)。


私は単にそうすることを考えていませんでした。好奇心から、その方程式はどこで得ましたか?
ザビエル

1
@Xavier:できたばかりです。このe^-kdビットは単なる指数関数的減衰であり、ある値(深さ)で徐々にゼロに向かう傾向があるものの標準関数です。による乗算(1-m)と加算はm、減衰をスケーリングおよびオフセットするためのものであり、最小で終了しますがm、それでも開始し1ます。 en.wikipedia.org/wiki/Exponential_decay
ピーターアレクサンダー

つまり、より深い色相のブロックは、ブロックにアルファ色がある場合にのみ表示されます。この場合、ブロックの色を変更する必要はありません。アルファは自動的にエフェクトを作成します。
ジョナサンコネル

@ジョナサン:あなたは水ブロックをレンダリングせず、色が暗くなって海底にブロックをレンダリングし、水面に単一のアルファ層を持ちます。
ピーターアレクサンダー

@Peter Alexander Ok、これらのブロック型ゲームでは、水でさえブロックでできていると思いました。
ジョナサンコネル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.