HN 日本語サマリー

← 一覧へ戻る
プログラミング

「Around The World」ゲームで美しい空をレンダリングする

Rendering pretty sky in Around The World game (frozenfractal.com)

138 pointsby ibobev10 コメント

要約

この記事は、ゲーム「Around The World」における空のレンダリング改善について詳述しています。著者は、マルチプル・スキャッタリング(多重散乱)の正確なシミュレーション、法線ベクトルの操作による間接光の調整、大気散乱の修正、地平線の歪み補正、そしてトーンマッピングの適用を通じて、よりリアルで美しい空の表現を実現しました。

全文翻訳

Around The World 第34回: 美しい空

2026年10月12日 月曜日 by Thomas ten Cate · コメント
 ゲーム開発, Around the World

この記事は、海上の探検と発見のゲームである「Around The World」に関するシリーズの一部です。このゲームは現在開発の初期段階にあります。このプロジェクトが初めての方は、こちらで概要を読むことができます。

前回の投稿では、ゲームの雲をなんとか見られるようにしました。しかし、プレイテスト中に全体的な海、空、雲のまとまり具合に満足できなかったため、いくつかの小さな調整を行ったところ、見栄えが大幅に改善されました。

雲の中での光の散乱

前回の投稿の最後では、光の角度(横軸)と雲の密度(縦軸)に応じて雲から散乱される光の量を含む、povrayでレンダリングされたルックアップテーブルを使用していました。

[画像: たくさんの球]

そして、このテーブルに対する不満について書きました。

povrayは実際には多重散乱を全くシミュレートしていないのではないかと疑い始めています。ドキュメントにはその旨は書かれていません。サンプリング数や間隔をいくら設定しても、球体の底面が明るくなることはありません。

また、疑念を確認するために独自の再帰的レイトレーサーを書きたくなりましたが、衝動に抵抗しました […]

結局、好奇心に負けて、Rustで数百行のコードで、多重散乱をシミュレートするマルチスレッド再帰モンテカルロレイトレーサーを書いてしまいました。これは非常に単純で、この特定の状況にハードコードされているため、均一な密度の球形の雲を1つだけレンダリングできます。しかし、povrayが多重散乱をシミュレートしていないことを確認するには十分でした。多重散乱により、ルックアップテーブルは非常に異なる外観になります。

[画像: 再びたくさんの球]

比較は完全に同じ条件ではありません。パラメータの一部と軸のスケールも調整したためです。しかし、全体的な効果は明らかです。雲から出てくる光はより均一に分布し、雲全体が明るく見えます。

低密度(薄い雲)の場合、差はあまり顕著ではありません。トップの行のルックアップテーブルは非常に似ています。結局、密度が低いと、光線が複数回散乱される機会はあまりありません。そこで、より厚い雲層を表す、より高い密度での見た目を比較してみましょう。古いLUTでレンダリングされた雲は以下の通りです。

[画像: 古いLUTによる雲]

そして、新しいLUTによるものです。

[画像: エンジンでレンダリングされた雲]

前回の投稿で言及した「金属的な」外観はなくなりました。雲の底面は明るくなり、全体的にライティングが滑らかになりました。

奇妙なトリック

現実世界では、雲は太陽光だけを浴びているわけではありません。空からの間接的な太陽光も受け取り、散乱します。この光は通常青みがかっているため、雲もより青みがかった色合いを帯びるはずです。

日中だけ正しい「青」の項を追加したくはありません。日の出、日の入り、夜間でも、雲が空の現在の色に追従するようにしたいからです。Godotでこれをどのように実現できるでしょうか?

答えは単純ですが、Godotのライトレンダリングがどのように機能するかをある程度理解する必要があります。直接光はすでに処理していますが、Godotは環境からの間接光も考慮に入れています。これらはすべてユーザーの制御外のバックグラウンドで行われるため、私の理解は曖昧ですが、有用であるには十分です。

私の理解では、間接光は、あらゆる方向からの放射輝度と放射照度を含む1つまたは2つのキューブマップからサンプリングされます。(放射輝度と放射照度の違いは知っていますが、その区別を完全に理解しているわけではありません。)雲のような拡散材の場合、このキューブマップ(これらのキューブマップ?)は、間接光が最も多く来る方向であるサーフェス法線方向にサンプリングされると予想されます。

雲の底面では、この法線は地面に向かって下を向いているため、ここでは雲はほとんど間接光でレンダリングされます。実際には間接光を受け取りますが、それは上からであり、雲を通して散乱されています。では、法線を空に向かって上向きに調整したらどうなるでしょうか?効果は微妙ですが重要です。以下は調整前です。

[画像: 暗めの灰色の雲の底]

そして、調整後です。

[画像: 明るい青みがかった雲の底]

雲は実際に青みがかった色合いになり、空によく馴染むようになりました。全体的により柔らかく、遠くにあるように見え、雲はそうあるべきです。これは非常に気に入っています!

空がほとんど均一に青くない夕日の場合はどうでしょうか?以下は調整前です。

[画像: 法線曲げなしの夕日]

雲の底はオレンジ色に染まっています。これは、レイリー散乱による空の光の減衰により、直接太陽光がオレンジ色になっているためです。法線を調整した夕日は以下の通りです。

[画像: 法線曲げありの夕日]

雲はピンク色になりました!これは実際の夕日の様子にかなり近いと思います。ピンクの色合いは、赤(直接太陽光)と青(間接空光)の混合の結果であり、緑のチャンネルがその間でいくらか失われているようです。

大気散乱

もう一つ気になっていたのは、地平線近くの空が不自然に黄色く見えることでした。太陽が低い位置にある場合はこれは正常で予想されることですが、太陽が真上にある場合でも発生していました。

[画像: 地平線近くで黄色にぼやける青空]

これは、レイマーチ中に散乱光(青みがかる)よりも外散乱(赤みを帯びる)を過剰に適用していることが原因だと疑い、偽の多重散乱項を追加するなどの様々なハックを試しました。最終的に、より良い修正は、レイマーチ中の操作の順序を変更することであることが判明しました。代わりに:

  1. レイセグメントに追加される(青みがかった)光
  2. レイセグメントでの外散乱による減衰(赤みを帯びる)

… の順序を逆にしました。

  1. レイセグメントでの外散乱による減衰(赤みを帯びる)
  2. レイセグメントに追加される(青みがかった)光

これにより、散乱光と比較して、経路での減衰が少なくなり、結果ははるかに良く見えます。

[画像: 地平線近くで白っぽくぼやける青空]

理論的にはこれは数値積分アプローチのアーティファクトであるはずなので、積分ステップ数を増やせば差はなくなるはずですが、そうはなりません。そのため、まだどこかに問題があるのではないかと疑っています。しかし、今はこれで十分であり、おそらく永遠にこれでいくでしょう。

地平線の歪み

リアルな空をレンダリングするには、大気の密度、高度、惑星のサイズなど、実際の地球のパラメータを使用する必要があります。しかし、私のゲームの惑星は地球の約75分の1の大きさであり、より強く湾曲しています。そのため、空に地球のパラメータを使用すると、空の地平線が実際の地平線の上にきてしまいます。2つの地平線の間では、空のシェーダーは惑星の中心に向かって大気の密度が指数関数的に増加し続けると仮定するため、特に日の出や日の入りで目立つ暗い帯が発生します。

[画像: 地平線歪みなしの夕日]

2つの地平線を一致させるために、空のシェーダーに簡単なハックを適用しました。グローバルなビューベクトルのy(垂直)成分に小さな値を加え、それを再正規化します。これにより、空全体が引き下げられ、特に地平線周辺で最も強く影響し、暗い帯が実際の地平線の後ろに隠れるようになります。

[画像: 地平線歪みありの夕日]

これはハックですが、安価で効果的です。

トーンマッピング

ああ、現代の3Dゲームアーティストの悩みの種です。ゲームは現在HDR(ハイダイナミックレンジ)でレンダリングされており、色の値が1.0の最大値よりも明るくなる可能性があります。これを通常のモニターに表示すると、結果はクランプされ、過飽和の色むらが発生します。

[画像: 低い太陽の位置にあるシーン、空は均一な淡い黄色]

これを修正するために、通常はトーンマッピングという数式を使用して、HDR値を表示用にLDR空間に戻します。Godotはいくつかのトーンマッパーを実装していますが、Reinhardは暗すぎ、ACESとAgXは彩度が低すぎると感じました。そこで最終的に、ホワイトポイントを2.0に設定したFilmicトーンマッパーを採用しました。

[画像: 太陽が低い位置にあるシーン、以前は均一だった黄色い部分にグラデーションが表示されている]

これにより、特に雲が柔らかく見え、遠くへフェードしていく様子がより良くなりました。

Godot自体が「写実的なレンダリング」のために少なくとも6.0を推奨しているため、ホワイトポイントの選択はまだかなり微妙ですが、それはすべてをより暗く見せるだけです。

トーンマッピングの調整は、トーンマッパーへの変更がそれ以前のすべてに影響するため、非常に難しい作業です。そのため、実際には、このプロセスはここで書いたほど直線的ではなく、トーンマッパーの調整とシーンライティングの調整の間で、行ったり来たりする必要がありました。例えば、空の明るさを文字通り2倍に減らしましたが、トーンマッピング後のコントラストが大幅に改善されました。

オーラリー

適切な昼夜サイクルが必要な場合、太陽が昇り沈む必要があります。そして、私たちの惑星を地球のように感じさせたい場合、日の出と日の入りの時刻は場所と季節に依存する必要があります。この依存性は、地球が太陽の周りを公転し、自身の軸を中心に回転することによるものです。同様のことが、月の空での動きや月の満ち欠けでも起こります。

これらの計算を正しく行うための数学をすべて理解するのは複雑に思えました。そこで、より簡単な方法を取りました。エンジン内で状況全体をモデル化し、惑星とその月をオーラリーのように回転させました。

[動画: 残念ながら、お使いのブラウザは埋め込み動画をサポートしていません。]

次に、エンジンに逆変換を計算させて、惑星表面のどこかの観測者の視点から、空のどこに何があるかを決定させました。これはうまくいき、レンダリングされたオーラリーは有用なデバッグ補助となりました。

すべてが終わった後、もう一度日の出のビデオをお見せする義務があるのではないでしょうか?そして、それのためにゲーム内の景色の良い場所を見つけましょう!

[動画: 残念ながら、お使いのブラウザは埋め込み動画をサポートしていません。]