プロダクションで使われているライトマップベイクの調査

レイトレ合宿8のアドベントカレンダー3週目の記事です。

はじめに

レイトレ合宿のアドベントカレンダーという事で、この記事ではレイトレを使ったライトマップベイクについての話をしようと思います。

昨今リアルタイムレイトレーシングをサポートするGPUも一般的になってきましたが、ゲーム開発においてすべてのライティングをランタイムでレイトレするのはまだまだ難しく、高品質なライティングを実現するためにはスタティックな部分を事前にベイクしておくことが不可欠です。そして、ゲームによってどの部分をランタイムに計算して、どの部分を事前計算にするかはライティング設計の肝になります。事前計算したライティング結果を保持するデータ構造はいくつかありますが、結果をテクスチャに保持するものをライトマップと呼びます。

この記事では、まずライトマップベイクの基本的な流れについて話をして、そのあと各プロダクションで行っているライトマップベイクの事例について紹介します。

導入

ライトマップベイクの流れについて簡単に紹介します。まずライティング結果をテクスチャにベイクするため、入力となるメッシュにはライトマップ用のUVを割り当てておきます。 この時、ワールドスペースでの位置が同じでない場合はライティング結果を共有できないため、UVは重ならないようにしておく必要があります。また、フィルタリング時にライティング結果が漏れないように、UVシェルの間には適切なパディングを入れておきます。

ベイクシステムに入力されたメッシュはまずUVスペースでラスタライズされ、トライアングルにヒットしたサンプルがワールドスペース上の3D Positionに変換されます。そのサンプルがレイを飛ばす原点となり、各サンプルからパストレを行ってライティングを計算します。各サンプルで計算されたライティング結果はそのサンプルが属するテクセルに保存され、ライティング情報を持ったテクスチャがライトマップとして出力されます。

一般的にはIrradianceがテクセルに保存されます。単純にテクセルに属しているサンプルのIrradianceの平均を保存する事もできますが、ランタイムでノーマルマップを参照してライティングするためにSHで保存することもできます。

Interactive Preview System

EAのFrostbiteで使われているライトマップのプレビューシステム [1] について紹介します。元の記事ではIrradiance Volumesの生成も含まれますが、この記事ではライトマップの話に絞ります。

このシステムの導入以前のワークフローでは、アーティストがエディタでシーンを編集し、長い時間をかけてライティングをベイクして結果をチェックしていました。もし結果が望みどおりになっていなかったら、またエディタに戻ってシーンを編集してもう一度ベイクするので、イテレーションコストが高く問題になっていました。そこで、アーティストの作業効率化を図るため、ベイクの途中経過をビジュアライズするシステムをDirectX Raytracing (DXR) APIを使って実装しました。GPUでモンテカルロパストレーシングを行うことでリアルタイムプレビューを実現しています。このシステムを使うと、アーティストはベイク結果を確認しながらインタラクティブにマテリアルを変えたり、ジオメトリを動かしたり、ライトを置くことができるようになります。また、メモリサイズに直接影響があるライトマップの解像度もプレビュー結果を見ながら調整することが可能です。

システムのパイプラインは以下のステップで実行されます:

  1. カメラの可視範囲を元にライティング計算するテクセルをスケジューリング (View Prioritization)
  2. Irradiance Cachingでパストレを高速化
  3. パストレの結果を前フレームのライトマップベイク結果とマージ
  4. プレビュー用にライトマップをポストプロセス

ここで3までの結果は次のフレームに引き継がれますが、4は現段階のベイク結果をプレビューしやすい状態にするポストプロセスなので、各フレームで独立して行われます。次にステップの詳細を見ていきます。

まずView Prioritizationについてです。カメラから見えていないテクセルをプレビューするのは無駄なので、見えているテクセルのみ計算するようにスケジュールします。これはカメラからシーンにレイを打ってヒットしたテクセルをスケジュールしますが、アトミックオペレーションを使って同じテクセルが複数回スケジュールされないようにもしています。この時に、Convergence Cullingという処理も行っています。これは各テクセルで計算しているライティングインテグレーションの収束度を確認して、十分に収束しているテクセルはこれ以上計算する必要が無いのでスケジュールしないようにします。

次にIrradiance Cashingについてです。ライトマップと同じUVスペースにキャッシュ用のテクスチャを用意して、直接光によるIrradianceをキャッシュしておくことでパストレを高速化します。パストレでNext Event Estimation (NEE) を行う時、パスの頂点からシャドウレイを飛ばして光源からのIrradianceを計算しますが、キャッシュを使うとNEEをテクセルフェッチするだけの処理に置き換えることができます。無駄なキャッシュ更新を防ぐため、ローカルライト、太陽、Sky Doomで別々のキャッシュを使います。アーティストがローカルライトを編集した時は、ローカルライトのキャッシュだけを無効化します。無効化されたキャッシュは、ライトマップベイクのパストレとは別に数フレームかけてアップデートされます。 直接光のキャッシュに加えて、間接光のキャッシュを使う事も可能です。これは、各ライトマップテクセルの収束度を確認していると上で書きましたが、もし十分収束しているテクセルにレイがヒットしたらトレースを止めてそのテクセルの値を間接光のIrradianceとして使う事ができます。

ポストプロセスはノイズフリーなベイク結果予測をアーティストに提供するため、プレビュー前にライトマップへ適用されます。ただし、上述した通りこのポストプロセスはプレビューのための処理なので、実際のライトマップベイクへは影響を与えません。このシステムではDilationとDenoisingの2つのポストプロセスを行います。Dilationは無効値で黒くなっているテクセルを隣接している有効なテクセルの値で埋める処理で、Denoisingはまだ収束していないテクセルのノイズを除去します。

最後にこのシステムで推奨されているハードウェアセットアップについて紹介します。このプレビューシステムを快適に使うためにはDual GPUが推奨されています。1つ目のGPUでFrostbiteのエディタとゲームを描画して、2つ目のGPUで非同期にライトマップのアップデートを行います。各アップデートが終わったタイミングで結果が1つ目のGPUにコピーされてライティングがビジュアライズされます。ローカルマシーンではDual GPUが推奨ですが、将来的にはDXR対応GPUのファームを世界中に用意して、どのEAスタジオからでもグローバルイルミネーションのプレビューと高品質なベイクのシステムが使えるような環境構築を目指したいということでした。

Ray Guiding

Activisionで使われているライトマップベイクの手法 [2] について紹介します。ベイクを高速化するため、Path Guiding [3] の手法を取り入れました。Path GuidingはImportance Samplingのための理想的なPDFを学習してインテグレーションの収束を高速化します。具体的には、パストレ中に各パス頂点のIncident Radianceをキャッシュしておいて、その分布を元にPDFを学習します。今回紹介するRay GuidingはPath Guidingの手法を取り入れつつライトマップベイクの用途に最適化することで、Path Guidingが持っている問題点のいくつかを解決しています。

まずPath Guidingの問題点の1つにメモリサイズがあります。Radianceをキャッシュするため5Dのグローバルなデータ構造が必要で、またメモリサイズはシーンの複雑度にも依存してしまいます。本手法のRay Guidingではライトマップのテクセルから飛ばす最初のレイのみをガイドし (なのでPath GuidingではなくRay Guidingと呼んでいると思われます)、PositionとNormalが似ているテクセルでクラスタリングして学習するPDFも共有化します。そのため、3D Positionの情報が必要なくなり、キャッシュに使うのは2DのDirectional Quadtreeのみになります。また、1つのクラスタのベイクが終わったらPDFを破棄して次のクラスタをベイクするストリーミング処理ができるため、メモリもシーンの複雑度に依存しないサイズに固定できます。クラスタリングにはもう1つ利点があり、PDFを共有化することで学習するためのサンプル数を増やすことができます。

Path Guidingの2つ目の問題点は、学習用のサンプルが少ないとRadiance分布の情報が不足するため、PDFがOverfitしてしまうリスクがあるということです。この手法ではOverfittingを和らげるため、Quadtreeにキャッシュされている値をスムージングするフィルタを導入しました。ただし、フィルタリングが強すぎるとPDFが一様になってしまいRay Guidingの効果がなくなってしまいます。実際のプロダクションではフィルタリングパラメータを0.25に固定しています (1.0でPDFが一様になる)。

Path Guidingの学習は複数回イテレーションして行います。各イテレーションで前イテレーションまでに学習したPDFを使い1からパストレして、PDFの学習を進めます。ただ、各イテレーションの学習で使われたサンプルは破棄するのですが、本手法では学習で使われたすべてのサンプルを再利用してVarianceを減らす方法を提案しています。具体的には、各イテレーションで得られるテクセルのEstimatorにウェイトをかけて足し合わせたものを最終的なテクセル値としてVarianceを減らします。ウェイトは各EstimatorのVarianceの逆数に比例するようにします (Greybill-Deal Estimator)。Varianceが大きいEstimatorの影響が小さくなるので、Fireflyなどの外れ値を除去できるようになります。ここで、各Estimatorの計算で使うサンプルが同じだとBiasが入ってしまいますが、逆に独立したサンプルを使うとVarianceが大きくなってしまうというトレードオフがあります。本手法ではBiasは許容してVarianceを減らすようにしていますが、ライトマップ全体でグローバルなUnbiasedとBiasedの輝度を見積もって、その比でライトマップをスケールすることでBiasを最小限にする補正を行っています。

まとめ

プロダクションで実際に使われているライトマップベイクについて紹介しました。1つ目はアーティストがライトマップベイクの結果をプレビューできるシステム、2つ目は純粋にベイク時間を短くする手法でしたが、どちらも制作のイテレーションコストを下げる仕組みになります。プロダクションでは、アーティストがよりクリエイティブな作業に集中できるような環境を構築することが肝になりますね。

参考文献

[1] Diede Apers, Petter Edblom, Charles de Rousiers, and Sébastien Hillaire. 2019. Interactive light map and irradiance volume preview in frostbite. Ray Tracing Gems, 377-407.

[2] Ari Silvennoinen, and Peter-Pike Sloan. 2019. Ray guiding for production lightmap baking. SIGGRAPH Asia 2019 Technical Briefs, 91-94.

[3] Thomas Müller, Markus Gross, and Jan Novák. 2017. Practical path guiding for efficient light‐transport simulation. Computer Graphics Forum 36, 4.