リアルなゲーム画面を実現するための大気散乱シミュレーション

  • 大気散乱についてザックリ知りたい人向け
  • どんな処理かソースを公開
スポンサーリンク

大気散乱とは

エンジンを使ってどんな表現か見てみる

最近のゲームは画面が綺麗ですよね。

空の事に関して、大抵のことはゲームエンジンがやってくれます。

ゲームエンジンは使われれば使われるほど進化していきます。

特にアンリアルエンジンはオープンソースなので、技術習得にちょうどいいです。

まともに一から全部自分で作ろうとすると、やる事が多すぎて挫折すると思います。

せいぜいアニメーションを付けたモデルがキーボードで操作出来て終わるのではないでしょうか? 

ここからコリジョンやらイベントやアニメーションブレンド、ポストエフェクトなど沢山工程をふみます。

プログラムで空の時間変化を計算する

綺麗に見せる手法として、物理ベースレンダリングがあります。現実と同じように光源計算を行い、モデルの陰影をはっきりさせます。ただ、まともに計算してしまうと、光源計算で処理を取られてしまい、ゲームになりません。光の計算は事前にしておいて、モデルのレンダリング時にその結果を反映させます。そのため動的な光源計算には向いておりません。

最近は何でもかんでもテクスチャにデータを入れます。昔はモデルの表面の絵をシールのように張るだけでした。今は光や法線情報、計算結果などを入れています。画面に出ている絵は、こねくり回した最終形態の一枚のテクスチャみたいなものです。

話を本題に戻して、大気散乱シミュレーションの話です。

大気圏外から入ってくる光を減衰させながらスクリーン上の一ピクセルまで計算する感じです。レイリー散乱、ミー散乱等があります。

レイリー散乱は、光源からの光が長距離大気中を通過すると赤くなっていきます。夕日のように地平線が赤くなるのは、光が長い距離大気中で減衰されるためです。

ミー散乱はプログラム的には太陽を書いています。結果的に太陽になってくれるので助かります。大きさも決まります。主に大気中の粒子にあたって光が散乱するイメージです。

両方足して空の色を決めます。こうすることで、天球のグラデーションが完成します。

夕日になれば赤く染まるし、日中は真っ青です。

雲の表現はどうするのか?

雲の表現が入ると難しくなります。 雲の遮蔽を考慮した計算はやった事ないのですが、雲のテクスチャをグレースケールで持ってシェーダー上でミー散乱により光量を減衰させるとそれっぽくなりそうです。

雲に隠れた太陽は消えそうですよね。そのうちやってみたいです。

球面調和関数とは

モデルに投影する光を球面調和関数を使い計算していきます。

本来はマップ上に環境キューブマップを多数配置して、モデルの光源計算に反映させる方が綺麗なのですが、さすがにメモリが足りません。

そこで、オフラインで光量計算したキューブマップを簡単なパラメーターに落とし込みます。

極端にテクスチャを圧縮するようなものです。全方位で色情報を丸め込み重ね合わせで表現します。音のデーターをサンプリングレートを極端に下げて変換するイメージです。

とても時間のかかる処理なので、事前に計算してパラメーターを求めます。

話それました。空が決まってからモデルに光を落とすので、余談です。

大気散乱の具体的な方法

大気散乱に関して、詳しくはGPU GEMS2 16章を見るとよいです。

ソースも公開されています。本ではバーテクスシェーダーで実現していますが、ピクセルシェーダーで表現するほうがきれいです。当時よりグラボが進化したため実現できています。

肝心なのはカメラの位置とカメラの向き上の大気圏までの距離を計算することです。

カメラから外周(大気圏との境界)までの距離は

sqrt(OuterRadius*OuterRadius – rayPos*rayPos + pow( dot( rayPos, rayDir ), 2 ) ) – dot( rayPos, rayDir );

です。これにrayDirをかけて、rayPosを足せば、外周の交点が出ます。

この式とオリジナルソースを合体して、天球を描画するときれいな空ができます。

雲の減衰までできればいいんですけどね。

コメント