超雑訳 Lumen: Real-time Global Illumination in Unreal Engine 5

こんにちわ。Pocolです。
今日は…
[Wright 2022] Daniel Wright, Krzystof Narkowicz, Patrick Kelly, “Lumen: Real-time Global Illumination in Unreal Engine 5”, SIGGRAPH 2022 Advances in Real-time Rendering course.
を読んでみようと思います。
いつもながら誤字・誤訳があるかと思いますので,ご指摘頂ける場合は正しい翻訳と共に指摘していただけると有難いです。



こんにちは、Daniel Wright です。今日は、同僚の Krzysztof Narkowicz と Patrick Kelly と一緒に、アンリアル エンジン 5 のリアルタイム グローバル イルミネーション システムである Lumen について紹介します。



完全にダイナミックな間接照明を使うのが夢でした。そうすることで、プレイヤーがゲームの世界とインタラクションするための新たな方法が解き放たれるのです。ベイクドライティングは、ドアを開けたり壁を破壊したりといった単純なインタラクションさえも制約します。そのような単純なインタラクションがダイナミックな間接照明で解決されるとしたら、どのような新しい複雑なインタラクションが見られるでしょうか?

また、ライティングアーティストのワークフローも改善したいと考えていました。ライティングのビルドが完了し、作業の結果が表示されるまで数分または数時間待つのではなく、すぐに結果を確認してほしいと思います。リアルタイムで結果を確認できれば、ライティングの品質はどれだけ向上するでしょうか?

また、ベイクすらできないような巨大なオープンワールドを作りたかったですし、何百人もの人が毎日レベルを変更し、ベイクされたライティングが決して最新にならないような大作でベイクされたライティングを使うことで生じる問題をすべて解決したかったです。

ダイナミックな間接照明を屋外で使える品質で解決するだけでは不十分で、ベイクド照明に匹敵する品質で解決し、ベイクドライティングでできるようなライティングのディテールや間接的な影をすべて得たいのです。



課題という点では、私たちがクオリティを合わせようとしているライティングビルドは、間接照明をリアルタイムで解決するよりも処理時間が10万倍もかかります。

グローバルイルミネーションは基本的にインコヒーレントであり、GPUがメモリと実行のコヒーレンシーのために設計されている場合、その光の移動を効率的に解決するのは困難です。

また、これは巨大な問題空間であり、非常に多くの異なる選択が可能で、どのパスが機能し、どのパスが機能しないかを知るだけでも一苦労です。

リアルタイムグローバルイルミネーションの成功マージンは非常に小さく、パフォーマンスとクオリティの両方を同時に満足させるのは難しいです。
まるで尾根の上に立っているようなもので、どちらかの方向に少し動くだけで、パフォーマンスやクオリティが落ちてしまうのです。

それでは、Lumenのアルゴリズムを最高レベルで概観し、後で詳しく説明することにしましょう。



リアルタイムの間接照明のために解決しなければならない最初の問題は、どうやって実際にレイをトレースするかということです。

ハードウェア・レイトレーシングは素晴らしいものであり、将来的なものですが、スケールダウンするためのオプションが必要です。PC市場では、ハードウェア・レイトレーシングをサポートしていないビデオカードがまだたくさんありますし、コンソールのハードウェア・レイトレーシングはそれほど高速ではありません。

また、重なり合うメッシュが多いシーンを処理したいのですが、ハードウェア・レイトレーシングの2レベルのアクセラレーション構造では時間がかかります。

そこで、これらの制限に対処するソフトウェア・レイトレーシングパスを開発することにします。



我々がソフトウェア・レイトレーシングに取り組み始めたとき、最初に試みたことのひとつは、たくさんの正射影カメラを使ってシーンをキャプチャすることでした。そして、カードの高さフィールドをレイトレースし、レイが当たったときにカードライティングをサンプリングします。

これは2Dサーフェス表現なので、ボクセルのような3D表現に比べて高い空間解像度が得られ、パララックスオクルージョンマッピングのようにハイトフィールドの特性を活用することで、高速なソフトウェア・トレーシングが可能になります。

しかし、結局のところ、ハイトフィールドでシーン全体をカバーすることは不可能であり、カバーが欠けている部分がリークの原因となります。



そのため、ソフトウェア・レイトレーシングのジオメトリ表現には、メッシュ符号付き距離フィールドを使うことにしました。これにより、信頼性の高いオクルージョンが得られ、すべての領域がカバーされ、何もない空間をスキップする球体トレーシングによって、高速なソフトウェア・レイトレーシングが可能になりました。ディスタンスフィールドサーフェスとの交点は、ヒット位置と法線のみを与え、マテリアル属性やライティングを見つけることはできません。



レイトレースがカードからヒットした場所のライティングを補間し、これをサーフェスキャッシュと呼びます。カバレッジが欠落している部分は、エネルギーが漏れる代りに、エネルギーが失われるだけです。カードのハイトフィールドをレイトレースしてもうまくいきませんでしたが、ライティングに使えばうまくいきます。



サーフェスキャッシュには他にも多くの利点があります。レイ間でマテリアル評価を共有し、サーフェスキャッシュの更新を直接制御できるようになります。また、ハードウェアレイトレーシングの高速パスを解放します。これについては、Patrickが後で詳しく説明します。



Lumenのレイトレーシングパイプラインを次に示します。最初に実行するScreen Tracingから始めます。これは、レイの開始付近で最も正確であるためです。次に、構成内容に応じてSoftware Ray TracingまたはHardwareを実行し、最後に、レイにジオメトリがない場合はスカイライトを実行します。



リアルタイムグローバルイルミネーションにおける次の基本的な問題は、間接照明経路全体を解決することです。

間接照明のシングルバウンスを提供するだけでは不十分で、屋内シーンではマルチバウンスディフューズが必要ですし、反射で見えるグローバルイルミネーションも必要です。



最初のバウンドが最も重要なので、それを分離し、専用のテクニックで解決します。ディフューズの場合はファイナルギャザーと呼ばれるもので、スペキュラーの場合はリフレクションデノイジングと呼ばれるものです。

最初のバウンス以降のバウンスは、フィードバックを使ったサーフェイスキャッシングで解決します。サーフェイスキャッシュからギャザーを行い、それ自身から読み込み、更新のたびに間接照明の別のバウンスを伝搬します。



リアルタイムのグローバル・イルミネーションで解決しなければならない3つ目の基本的な問題は、光伝達におけるノイズです。拡散GIでは1ピクセルにつき1本のレイを照射する余裕すらありませんが、高品質の屋内では実際には数百の有効なサンプルが必要です。



そこでファイナルギャザーのすべてのテクニックが必要となります。できるだけ少ない数のレイをトレースするためにアダプティブダウンサンプリングを使用し、それらのレイを最大限に活用するために空間的・時間的再利用を行い、可能な限り最良の方向にレイを送るためにプロダクトインポータンスサンプリングを使用します。これらがどのように機能するかについては、後で詳しく説明します。



ファイナルギャザーを不透明なものだけで解決することはできません。不透明については2Dドメインで操作し、フォグについてはビジブルフラスタム内のすべてのポイントについて解く必要があり、サーフェスキャッシュについてはテクスチャ空間ドメインで集めることになります。



反射におけるノイズを解決するために、空間的再利用と時間的再利用を使ってレイを最大限に活用し、可能な限り拡散レイを再利用します。



Lumenは、これらすべてを組み合わせることで、マルチバウンス間接照明を解決します。



スカイシャドウイング



また、アーティストが個々の光源を配置する必要のないエミッシブ・ライティングも、ノイズアーティファクトを発生させずにエミッシブ領域をどれだけ小さく明るくできるかには限界があるります。



Lumenはボリュームフォグと半透明に関するGIを解決します。



そしてLumenはリフレクションを解決します。Lumenは、サーフェスキャッシングによってこれらの機能を非常に効率的に提供し、プロジェクトのニーズに応じて、ソフトウェアまたはハードウェアのレイトレーシングを使用できます。



レイトレーシングのパイプラインから始まり、ファイナルギャザー、リフレクション、パフォーマンスとスケーラビリティへと進んでいきます。

ソフトウェア・レイトレーシングについては、同僚のKrzysztofにバトンタッチします。



Lumenはハイブリッドレイトレーシングパイプラインを使用しており、さまざまなテクニックを組み合わせて使用することができます。スクリーントレーシングが最初に行われ、次に各トレーシング手法が、レイがどこまで通過したか、ヒットを見つけたかどうかを書き出すことによって、次の手法にバトンタッチします。次のトレースメソッドは、前のメソッドが中断したところからレイを再開することができます。



ソフトウェアレイトレーシングもハードウェアレイトレーシングも、後で説明する理由により、ラスタライズされたGBufferとのミスマッチがあります。スクリーントレースはこれらのミスマッチを処理するのが得意ですが、表現内部で開始する場合、自己交差を引き起こしたり、ミスマッチがリークを引き起こしたりすることがあります。



例えば、我々のソフトウェアレイトレーシングはスキンメッシュを扱いませんが、スクリーントレースを使って三人称キャラクターから間接的な影を得ることができます。

スクリーントレースはどのようなスケールでも機能するため、どれだけスケールしても、詳細なGIに対応します。



スクリーントレースはリニアステップではうまく機能せず、ここに示した歩道のような薄いオブジェクトを飛ばしてしまうため、リークが生じてしまいます。



その代わりに、HZBトラバーサルを使用します。HZBトラバーサルは、最も近いHZB mipsのスタックレスウォークです。壁と平行に進むレイのような、グレージング角のレイの反復回数を制限し、拡散レイはトレースを高速化するために半分の解像度を使用します。

このアニメーションでは、5ステップごとにHZBトラバーサルの進行状況を表示しています。



次のトレース方法への引継ぎを正確に行わなければ、リークの原因になります。そのためには、レイがサーフェスの裏やスクリーンの外に出るたびに、最後に取り込まれなかった位置までステップバックします。



結局のところ、スクリーントレースはクオリティの点で勝っていますが、やればやるほど、失敗したときに気づくことが多くなります。ハードウェアレイトレーシングでは、複雑なサーフェスジオメトリからほとんどのレイを逃がすことができるため、わずかながらパフォーマンスも向上します。



スクリーントレースの実行後、いくつかのレイはスクリーントレースのヒットによって解決され、残りはまださらにトレースする必要があります。これらの空のトレースレーンすべてに対して次のトレースパスを実行する代わりに、まずコンパクションを実行します。



コンパクションを行う最も簡単な方法は、ローカルアトミックを使ってコンパクションされたインデックスを割り当てることです。これはレイをスクランブルする効果があります。赤い線は1つのウェイブの中の異なるレイで、シーン内の異なる位置からスタートしています。

この問題を解決するために、順序を保持するコンパクションを行いました。このコンパクションでは、コンパクト化されたインデックスを割り当てるために、より大きなスレッドグループ内で高速なプレフィックスサムを行います。

それでは、同僚のKrzysztofにバトンタッチします。



こんにちは、Krzysztofです。今回はLumenのソフトウェアレイトレーシングとサーフェスキャッシュについてお話します。



最初の疑問は、ハードウェアで解決できるのに、なぜソフトウェアでレイトレーシングをするのかということです。

アンリアル エンジンは、さまざまなプラットフォームやさまざまな種類のコンテンツをサポートしており、そのような多種多様なユースケースに対応するためには、さまざまなツールが必要です。ソフトウェアトレーシングの主な動機はここにあります。DXRをサポートしていないハードウェアでLumenを実行したいのですが、スケールダウンできるようにしたいのです。

ハードウェアのレイトレーシングを置き換えることはできませんが、トレーシングループを完全にコントロールすることができ、さまざまなトレードオフを行うことができます。例えば、BVHでインスタンスが重なっている場合、レイは最も近いヒットを見つけるためにそれぞれのインスタンスを訪れる必要があり、このアクセラレーション構造を変更することはできません。



高いレベルでは、メッシュごとのディスタンスフィールドとランドスケープコンポーネントごとのハイトフィールドという2つの基本的なプリミティブがあります。

これらのプリミティブは2つのレベル構造に格納され、下のレベルにはプリミティブがあり、上のレベルにはフラットなインスタンスディスクリプター配列があります。このアプローチによって、インスタンスをストレージに活用することができ、メモリ使用量を減らすことができます。

ディスタンスフィールドはアンリアルエンジンでは新しいものではありませんが、この講演では Lumen で必要となった新しい開発に焦点を当てます。



メッシュのインポート時にメッシュディスタンスフィールドを生成し、他のメッシュデータと一緒に保存します。

生成にはEmbreeポイントクエリーを使用し、最も近い三角形までの距離を効率的に求めます。また、各ボクセルから64本のレイを投射し、バックフェイスヒットをカウントして、ジオメトリの内側か外側かを判断し、ディスタンスフィールドの符号を決定します。

ボリューメトリック構造は解像度によってうまくスケールせず、かなりメモリを消費するため、ミップマップされた仮想ボリュームテクスチャ内に狭帯域のディスタンスフィールドのみを保存します。

Mip0の解像度はメッシュサイズとメッシュのインポート設定に基づいており、Mip1は解像度を半分にし、最大オブジェクト空間距離を2倍にします。



そしてフレームごとにシェーダーをディスパッチして、すべてのインスタンスをループさせます。このシェーダは、カメラからの距離に基づいて、ディスタンスフィールドアセットごとに必要なミップレベルを計算します。

次に、これらの要求をCPUにダウンロードし、追加のディスタンスフィールドミップをストリームインするか、もう使用されていないミップマップをドロップします。

ディスタンスフィールドブリックは固定サイズのプールに格納され、シンプルなリニアアロケータで管理されます。これは便利なセットアップで、可変サイズの3Dアロケーションやその結果生じるフラグメンテーションに対処する必要がないからです。



メッシュディスタンスフィールドトレーシングでは、レイ・マーチングを高速化するためにミップマップを使用します。サーフェスに近づきすぎたら、より高精度のミップマップを使用し、遠ざかりすぎたら、より低いミップマップに切り替えます。これはSebastienがClayblookのためにやったことに似ている。

また、パフォーマンス上の理由から、メッシュのディスタンスフィールドのレイマーチングの反復を64回に制限しています。

最後に、ヒットを見つけた後、6サンプルの中心差分を使用してジオメトリ法線を計算します。この法線は後でサーフェスキャッシュからマテリアルとライティングをサンプリングするために使用されます。



ランドスケープはコンポーネントに分割され、各コンポーネントのサーフェスキャッシュに1つのハイトフィールドを持ちあmす。

トップレベルでは、ハイトフィールドインスタンスはメッシュディスタンスフィールドインスタンスと同じように扱われ、カリングとトラバーサルコードを再利用します。

下のレベルは異なり、インスタンスごとに、3Dのディスタンスフィールドの代わりに、2Dのハイトフィールドをレイマーキングし、ゼロクロスを見つけようとします。一方がハイトフィールドの上、もう一方がハイトフィールドの下にある2つのサンプルを見つけた後、それらの間を線形補間して最終的なヒットポイントを近似します。

このヒットポイントを持って、サーフェスキャッシュから不透明度を評価し、このヒットを受け入れるべきか、それともスキップしてハイトフィールドの下をトレースし続けるべきかを決めることができます。

ヒットを受け入れたら、そのポイントでサーフェスキャッシュを評価し、レイの放射輝度を計算します。



この時点で、メモリー内のすべてのデータが揃い、個々のインスタンスをトレースする方法がわかりました。今度は、シーン全体をトレースする方法を考えなければなりません。シーン内のすべてのインスタンスをループして、それぞれのインスタンスをレイマーチすることはできません。

BVHとグリッドを試しました。これらのアクセラレーション構造は、フレームごとに一度だけ構築し、複数のパスで再利用できるので、本当に素晴らしいアクセラレーション構造です。残念ながら、長いインコヒーレントレイのパフォーマンスは十分ではありませんでした。ソフトウェアBVHトラバーサルは非常に複雑なカーネルを持っています。グリッドは複数のセルにまたがるオブジェクトを複雑に扱います。その上、インスタンスがオーバーラップしているシーンでは、最も近いヒットを見つけるために、それぞれのインスタンスをレイマーチする必要があります。

最終的に、我々はこの問題を単純化し、短いレイだけをトレースすることにしました。レイのフットプリントが広くなったら、別のトレース方法に切り替えます。



これは、正確なシーン表現が必要なのはレイの最初のセグメントだけであり、それ以降は粗いシーン表現に切り替えることができるという重要な認識でした。また、シーン全体を簡略化されたグローバルな表現に統合することができるため、オブジェクトの重なりの問題を解決する機会にもなりました。

ここではさまざまなアプローチを試しました。

明らかなのは、シーン構築ステップの一部としてシーン全体をマージすることですが、これはかなり制限的なワークフローで、ダイナミック・オブジェクトをサポートしていません。

ランタイムボクセル化とボクセルコーントレーシングも試しましたが、ジオメトリプロパティをボリュームにマージすると、特に下層のミップマップでは、多くのリークが発生します。

また、ボクセルビットブリックも試しました。これは、ボクセルごとに1ビットを保存し、それがジオメトリを含むかどうかをマークするものです。ビットブリックの単純なレイマーチングは驚くほど遅く、加速のために近接マップを追加した後、ボクセルをやめてグローバルディスタンスフィールドにたどり着きました。



グローバルディスタンスフィールドは、すべてのメッシュディスタンスフィールドとハイトフィールドを、カメラを中心としたクリップマップのセットに統合します。メッシュディスタンスフィールドとハイトフィールドは、実行時にマージしてLODするのが簡単なので、このための完璧なメッシュ表現です。

デフォルトでは、仮想テクスチャの4つの疎なクリップマップを使用します。すべてのクリップマップはディスタンスフィールドのブリックを格納し、すべてのブリックは狭帯域ディスタンスフィールドを格納します。

これはメッシュのディスタンスフィールドと同じようなセットアップですが、ミップマップ階層の代わりにクリップマップ階層を使用しています。



シーン内のすべてのオブジェクトをマージすると負荷が高くなるため、最後のフレーム以降に変更されたものだけを積極的にキャッシュして更新する必要があります。

さらにクリップマップを更新する頻度を減らすことで、時間スプライス更新も行い、クリップマップごとに個別のLOD設定を行うことで、遠くにある小さなオブジェクトをドロップすることができます。最大のクリップマップでは、マージするインスタンスの数も最大になるため、更新のパフォーマンスが向上します。

通常、シーン内の少数のオブジェクトのみが移動し、残りは完全に静止します。これを活用するために、キャッシュを動的なブリックと静的なブリックに分割します。これにより、車が移動しても、その周りの静的な建物を再計算する必要がなくなります。

キャッシュされた更新については、すべてのシーンの変更を追跡し、GPU上で変更されたブリックのリストを作成します。次に、シーン内のすべてのオブジェクトを現在のクリップマップにカリングし、結果のリストを修正済みのブリックにカリングします。最後のカリング手順では、解析オブジェクトの境界をチェックするより正確なカリングのために、メッシュディスタンスフィールドをサンプリングします。

この時点で、更新が必要な修正されたブリックのリストと、修正されたブリックごとのカリングされたオブジェクトのリストがあります。これで、永続的なブリックの割り当てと割り当て解除を行い、更新に進むことができます。



単一のブリックを更新するには、それに影響するすべてのオブジェクトをループし、ボクセルごとの最小距離を計算します。

ここでの1つの問題は、インスタンスは不均等なスケールを持つことができますが、ディスタンスフィールドに格納された距離は均一なオブジェクトスケールに対してのみ有効であるということです。

分析勾配を介して最も近いポイントを見つけ、そこからの距離を再計算しようとしましたが、ディスタンスフィールドの解像度が限られているため、実際にはうまく機能しませんでした。最終的にうまくいったのは、分析オブジェクトの境界までの距離を使用してディスタンスフィールドをバインドすることでした。不均等にスケールされたオブジェクトのほとんどは、壁のような単純なシェイプでもあるため、実際には非常にうまく機能します。

また、ダイナミックブリックを更新する場合は、オーバーラップするスタティックブリックを合成して、両方のキャッシュをトレース用の最終ディスタンスフィールドに結合する必要があります。

最後に、1/4解像度の非スパースディスタンスフィールドボリュームであり、空の領域のスキップを加速するために使用される粗いミップを更新します。クリップマップにはさまざまなLODレベルがあり、オブジェクトが最大のものから欠落している可能性があるため、クリップマップレベルをステップスルーする代わりに粗いミップを使用します。

粗いミップは非常に低解像度なので、常にグローバルディスタンスフィールドをサンプリングしてボリューム全体を更新し、Eikonalプロパゲーションを数回繰り返して拡張します。



グローバルディスタンスフィールドのトレースでは、最小のものから始まるクリップマップをループし、ヒットを見つけるまでそれぞれのクリップマップをレイマーチします。

ステップごとに、まず連続した粗いミップマップをサンプリングし、もしサーフェスに近ければ、スパースブリックもサンプリングします。

最後にヒットを見つけたら、6つのタップを用いてサーフェスグラデーションを計算し、サーフェスキャッシュをサンプリングしてライティングを得ます。



これで、ファーフィールドトレースのフォールバックメソッドがあれば、メッシュディスタンスフィールドトレースに戻ることができます。

短いレイだけをトレースするという前提であれば、BVHやワールドグリッドはもう必要ありません。その代わりに、オブジェクトを影響力のあるフロクセルグリッドにカリングすることができます。各セルは、レイがそのセルからスタートする場合に交差する必要があるすべてのオブジェクトのリストを含んでいます。

このリストを作成するために、まず、すべてのシーンオブジェクトをフロクセルにカリングします。次に、トレースパス中に使用されることのないフロクセルのために時間を浪費しないように、ジオメトリを含むフロクセルをマークします。

次に、マークされたフロクセルセルにオブジェクトをカリングします。最初のオブジェクトカリングテストは単なる大まかなバウンドテストであり、2番目のテストは正確なディスタンスフィールドのサンプルです。

最後に、カリングされたリストをオブジェクトの連続配列にまとめます。

GIや反射のためにピクセルからトレースする場合、適切なセルをロードし、その中のすべてのオブジェクトをループし、最後にヒットしたものまでレイマーチします。この結果、非常にシンプルで首尾一貫したトラッキングカーネルになります。



ディレクショナルレイは平行であり、ここで円錐のフットプリントが広くなることに頼ることはできません。つまり、全長のレイをトレースする必要があります。

そのために、オブジェクトをライトスペース2次元グリッドにカリングします。各セルは、そのセルからレイを開始するときに交差するオブジェクトの配列を含んでいます。

次に、このグリッドを埋めるために、オブジェクト指向の境界をラスタライズしてオブジェクトを散らばせます。ピクセルシェーダの内部では、メッシュディスタンスフィールドをサンプリングすることによって、さらに細かいカリングを行います。

最後にカリングされたリストをコンパクトにします。

シャドウレイをトレースするときは、適切なセルをロードし、中にあるすべてのオブジェクトをループし、ヒットするオブジェクトを見つけるまでレイマーチします。



これですべてのピースが揃い、それらを組み合わせて完全なソフトウェアレイトレーシングパイプラインを作ることができます。

我々はスクリーンスペーストレースから始めます。
次に、短いメッシュディスタンスフィールドトレースを使って未解決レイを続けます。
次に、グローバルディスタンスフィールドトレースを使用します。
そして最後に、任意のレイミスがスカイライトをサンプリングします。



結論から先に言うと、実用化するために解決しなければならないディスタンスフィールドの問題がいくつかあります。

まずひとつは、多くのメッシュが閉じていないことです。これはスキャンされたメッシュや、単に反対側から見ることを想定していないメッシュでよく起こります。ラスタライザーでは問題にはなりませんが、ディスタンスフィールドの場合、負の領域が生成され、ジオメトリからはみ出し、トレースを壊してしまいます。

この問題を解決するために、ディスタンスフィールドの生成時に、4ボクセルの後に仮想サーフェスを挿入します。言い換えれば、4ボクセルの後に負の距離を挿入します。

これは完全な解決策ではなく、ラスターとレイマーチングの間にミスマッチを起こすことに変わりはありませんが、巨大な負の領域を持つよりはましです。



もうひとつの問題は、メッシュが薄いことです。

離散的なディスタンスフィールドの表現は解像度によって制限され、2つのボクセル間の距離よりも小さなディテールを表現することはできません。

この図では、サンプリング点の間に配置された薄い壁の例を見ることができます。このようなディスタンスフィールドを評価しても、距離がゼロまたは負になることはなく、レイマーチャーがヒットを記録することはありません。勾配の計算も、この壁の周りの勾配がゼロになるため、不正確になります。

これは、暗い屋内と明るい屋外があり、壁を通過する1本のレイでさえも大規模なライトリークを引き起こすような、一般的なシナリオでは大惨事となる可能性があります。



この問題を克服するためには、ボクセルの対角線の半分だけ距離フィールドを広げる必要があります。

この拡張によってリークが修正され、どんな薄い面でも確実にヒットできるようになりました。グラディエントも修正されます。信頼できるディスタンスフィールドの値があるサーフェスからさらに離れて計算することになるからです。

エクスパンドは実行時に行われるので、元のディスタンスフィールドデータを保持することができます。

エクスパンドの欠点は、オーバーオクルージョンを引き起こすことです。また、サーフェスをエスケープするために大きなサーフェスバイアスが必要で、これによりコンタクトシャドウが壊れてしまいます。



サーフェイスバイアスの問題をどのように改善できるか見てみましょう。

元のディスタンスフィールドデータを保持し、実行時にサーフェスを拡張します。これにより、サーフェスから開始し、サーフェスから離れるにつれて線形に拡張することができます。こうすることで、サーフェスからスタートし、サーフェスから遠ざかるにつれてリニアに拡大することができます。こうすることで、サーフェスをスキップしてコンタクトシャドウを失う代わりに、最初のレイセグメンテーションをトレースすることができます。

同様の方法で、光源が置かれているサーフェスに当たらないように、シャドウレイの終わりでエクスパンドをフォールオフして0に戻す必要があります。



残念ながら、このヒューリスティックはグレージング角には使えません。拡大が速すぎて、ある時点でレイが自己交差してしまうからです。

これはグローバルイルミネーションや拡散レイでは問題ありませんが、反射レイではあまりよくありません。

輪レアwれは、反射のための2番目のヒューリスティックでこれを解決します。毎ステップ、サーフェイスまでの現在の距離に基づいて可能な限り拡大します。これにより、常に最初のサーフェスから脱出することができます。



これが、実際のディスタンスフィールドの拡大例です。

コンタクトシャドウを維持しつつ、薄いサーフェイスにも確実に当てることに成功しています。



ディスタンスフィールドエクスパンドは、壁のようなソリッドなジオメトリには効果的ですが,葉の間をライトが通過するのを完全に妨げてしまうフォリッジには向いていません。

これを解決するために、我々は別のヒューリスティックを導入する必要がありました。

我々は、両面マテリアルに基づいてディスタンスフィールドインスタンスをマークし、このデータを別のグローバルディスタンスフィールドチャンネルに再サンプルします。カバレッジによって、ライトをすべて遮るはずの薄いサーフェイスと、ライトをある程度通すはずの部分的な透明度を持つサーフェイスとを区別することができます。

レイマーチング中、ステップごとにカバレッジをサンプリングし、それに基づいてレイマーチングのステップサイズを大きくしたり小さくしたりします。さらに、ヒットするたびに確率的透明度のカバレッジを使用して、このヒットを受け入れるべきか、トレースを続行すべきかを決定します。

フォリッジのもう一つの問題は、通常アニメーションであり、事前計算されたディスタンスフィールドはアニメーションをサポートしないということです。これは通常、セルフシャドウの問題として現れるので、フォリッジに余分なサーフェスバイアスを追加することで修正します。



カバレッジチャンネルとエクストラバイアスによって、木々がすべてのライトを遮ることはなくなり、一部の光は葉を通り抜け、木々の間をバウンスします。



ディスタンスフィールドは鏡面反射には完璧ではありませんが、GIや粗い反射にはかなり適しています。このライトのシーンは、間接照明でほぼ完全に照らされていますが、ご覧のように、ディスタンスフィールドは、壁のランプやテレビからの間接的な影のような小さなディテールをすべて解像し、素晴らしい仕事をしています。

ディスタンスフィールドは特別なハードウェアを必要とせず、すべてのプラットフォームでサポートされています。

また、多目的なエンジンユーティリティでもあり、Lumen間でシーンのステップアップ作業を分担したり、パーティクルや物理コリジョンのような他のさまざまなユースケースにも対応します。

最後に、ディスタンスフィールドは、実行時にシーン全体を単一のグローバルディスタンスフィールドにマージすることで、インスタンスの重複が多い複雑なシーンのスケールダウンとサポートを可能にします。



今、我々は部屋の中の象に対処する必要があります。すなわち、ディスタンスフィールドトレースのためのマテリアルとライティングをどのように評価するか?



ディスタンスフィールドは頂点アトリビュートを持たないので、マテリアルシェーダーを実行することはできません。我々がアクセスできるのは、位置、法線、メッシュインスタンスのデータだけです。つまり、UVレスのサーフェス表現が必要なのです。

また、再帰的なマルチバウンスレイトレーシングを行う余裕がないため、この表現をさまざまな計算やレイパスのキャッシュに再利用したいと考えています。

カスタムのマテリアルグラフは非常に複雑で、レイがヒットするたびに評価するのはコストがかかります。

複数の影を投射するライトを使ったダイレクトライティングは、コストが高くつきます。

レイがヒットするたびに、再帰的に複数のレイをトレースし、それぞれについてマテリアルとライティングを評価する必要があるためです。



ディスタンスフィールドのヒットを評価できること以外にも、サーフェスのパラメタリゼーションに必要な要件があります。ボリュメトリックなものは薄い壁を表現するのに問題があり、ライトリークを引き起こす可能性があるため、サーフェス空間ベースであることを望んでいます。複雑なシーンで膨大な数のインスタンスをパラメータ化できるスケーラブルなソリューションが必要です。最後に、反射にも使用できるように、解像度を拡大できるようにしたいです。

複数のサーフェスパラメータライゼーションがありますが、そのほとんどは我々には機能しませんでした。

UVは複雑なメッシュには適していません。UVチャートがたくさん生成され、それをマージするのは簡単ではないからです。また、頂点アトリビュートを必要としますが、我々はそのアトリビュートにアクセスできません。

ボリューメトリックUVは薄い壁を表現できないし、遠くのものをLODする方法も不明です。

ボクセルカラーとサーフェルは解像度に制限があり、反射には使えません。



Lumenでは、一様な長方形のサーフェルの集まりとも言える投影カードを使うことにしました。

カードは投影ベースなので、それを評価するための頂点属性は必要ありません。

カードは規則的な構造をしているため、ルックアップが速いです。

カードは実行時にキャプチャでき、ベイクすることなく任意の解像度にスケールできます。

また、2面の薄い壁を表現することもできます。



メッシュ上にカードを配置するために、メッシュのインポート時に事前計算ステップを実行します。

すべてのカードは軸平行で、生成とルックアップが簡単になります。自由な向きのカードも試しましたが、配置が難しく、柔軟性を高める価値は結局ありませんでした。

生成は、入力された三角形データをボクセル化し、軸合わせされたサーフェルのセットにすることで単純化することから始まります。

次に、K-meansにインスパイアされたクラスタリングアルゴリズムを使って得られたサーフェルをクラスタリングし、得られたクラスタをカードに変換します。

生成中に何か問題が発生した場合 例えば、メッシュのアンラップが難しすぎたり、小さすぎたりした場合は、6面のキューブマップにフォールバックします。



最初の生成ステップでは、三角形メッシュを軸平行サーフェルに変換し、細かいディテールを除去してメッシュを単純化します。

物体を通して2dセル当たり64レイを投射することによりメッシュをボクセル化しました。3dセルごとにレイヒットを合計し、あるしきい値以上のサーフェルをスポーンします。

この数はサーフェルのカバレッジとしても保存され、後で特定のクラスターの有用性を評価するのに役立ちます。さらに、前のレイヒット位置を格納します。これは、クラスタの近接平面からサーフェルがビジブルかどうかを判断するために使用されます。

次に、すべてのサーフェイスについて、64のレイをトレースし、三角形の背面のヒット数をカウントします。これらのヒットのほとんどが背面である場合、与えられたサーフェルはジオメトリの内側にあり、それを破棄できます。また、ヒットまでの平均距離に基づくサーフェルのオクルージョンベースを計算しました。オクルージョンは、特定のサーファーをクラスタ化する重要性を判断するために使用されます。



次に初期クラスターを生成します。

これは、未使用のサーフェルを選び、そこからクラスタを暫定的に成長させることで行います。

まず、すべての未割り当てサーフェルをクラスタ境界までの距離で重み付けし、最も近いものを優先します。
また、最も重要なものを優先するために、サーフェルのオクルージョンによって重み付けを行います。
正方形のクラスタを優先するためにクラスタ比で重み付けし、最後に与えられたサーフェルがクラスタの近傍から見えるかどうかをチェックする。

次に、有効なサーフェルの候補がなくなるまで、有効なサーフェルを追加していきます。この時点でクラスタの重心を計算し直し、そこから成長を再開します。

再成長の限界に達した後、あるいはクラスターが変化しなくなった後、クラスターをリストに追加し、次の未使用サーフェルを見つけるのを試みます。

このステップの後、メッシュはクラスターで完全に覆われますが、これらのクラスターにグローバルに最適とは限りません。



最初のステップはグローバル最適化で、すべてのクラスターを現在のセントロイドから並列に再成長させます。ここでも、限界に達するかクラスタが変化しなくなるまで、並列成長を数回繰り返します。

並列成長の結果、クラスターが小さくなりすぎたり、空きができたりすることがあるので、繰り返しの後に、小さくなりすぎたクラスターを削除し、空いたスペースに新しいクラスターを挿入するようにします。

最後にクラスターをカバレッジでソートし、ユーザーが選んだ最も重要なクラスターを選んでカードに変換します。



メッシュごとにカードがあり、それをシーン内で管理する必要があります。

ここには相反する2つのニーズがあります。

一方では、複数のGIバウンスを処理するために小さなカードをたくさん持ちたい。GIはむしろ低頻度なので、ここでは多くの解像度を必要としませんが、すべてを一貫してカバーすることが重要です。

一方では、反射のために選択したサーフェスに高解像度のカードを数枚置きたい。鏡面反射の場合、カードはスクリーンのピクセル密度に合わせる必要があるので、ここでは多くの解像度が必要です。

最新のMatrix Awakensのデモでは、建物間でバウンスするライトを処理するために、カメラの周囲をカバーするインスタンスをたくさん用意しました。同時に、複数の反射面があり、高解像度のカードが必要でした。



この2つの要件から、仮想サーフェスキャッシュが導き出されます。

GIには、低解像度の常駐ページを使います。これらのページは距離に基づいてカメラの周りに割り当てられます。また、小さすぎるカードを削除する形のLODスキームもある。

反射には、スパースで最適なオンデマンドページを使用します。これらのページは反射レイのヒットに基づいて割り当てられ、使用されなくなると割り当てが解除されます。



レイがヒットするたびに、サーフェスキャッシュフィードバックを書き込み、各ページの解像度と更新レートを最適に選択できるようにしています。

レイヒットは複数のページをサンプリングしてブレンドするので、まず確率的に最も重要なページを選択する必要があります。次に、最後に使用された時間を更新し、要求されたミップレベルをフィードバックバッファに書き込みます。

すべての要求をGPUハッシュテーブルに挿入し、それをコンパクトにすることで、GPU上でこのフィードバックバッファをコンパクトにします。最後に、リクエストの配列はページごとのヒット数を持つユニークなページを含みます。

このリクエスト配列は後でCPUにダウンロードされ、そこでソートし、ページのマッピングとマッピング解除に使用することができます。



ページサイズより大きいカードは物理ページに分割され、別々に割り当てられます。

ページサイズより小さいカードはサブアロケートされます。つまり、1つの物理ページをマップし、そこから2dアロケータを使って複数の小さなカードを割り当てます。

これは重要なことで、ボーダーに多くのメモリを浪費しない大きなページを持つことができ、同時に物理ページサイズに切り上げdる必要のない小さなアロケーションをサポートすることができます。

ルックアップをフラットにすることで、高解像度のページが見つからない場合、ページテーブルが自動的に低解像度の常駐ページを指すようにしました。これにより、再帰的にフォールバックページを検索することなく、1回のルックアップでサーフェスキャッシュをサンプリングすることができます。



また、カードにメッシュとマテリアルのデータを入れる必要があり、それらは後でサーフェスに投影されます。

これは、正射影カメラでメッシュをカードにレンダリングし、アルベドや法線のようなサーフェスプロパティを書き込むことで実行時に行います。実行時にこれを行うことで、事前に計算されたデータを管理することなく、解像度のスケールアップやマテリアルの変更をサポートできるので便利です。

カードキャプチャはキャッシュされ、固定予算で更新される。毎フレーム、ページの更新要求を収集し、カメラからの距離と最後に使用された時間によって並べ替えます。そして、更新すべき重要なページを一定数選び、キャプチャします。さらに、アニメーション素材をサポートするために、フレームごとに少数の最も古いページも更新します。

従来、多数の小さなメッシュのレンダリングは、LODと多数の小さな描画呼び出しのために時間がかかっていました。Naniteでは、1回の描画呼び出しですべてのジオメトリをレンダリングでき、連続的なLODレベルを持っているので、小さなターゲットにレンダリングされたメッシュを簡素化できます。これにより、レンダリングが大幅にスピードアップし、より頻繁にカードをキャプチャできるようになりました。



カードキャプチャは、マテリアルとメッシュデータを固定されたビューに依存しないGBufferのような構造にリサンプルします。

失われたエネルギーを考慮してアルベドを修正することで、鏡面反射とサブサーフェス応答を近似します。

また、無効なテクセルにマークを付け、どのテクセルが有効なデータを含んでおらず、サンプリングできないかを後で分かるようにします。

キャプチャ中はアルファマスキングを無効にします。サーフェスキャッシュデータの欠如とアルファマスキングされたサーフェスポイントを区別する必要があるからです。これは後で、マテリアルシェーダーを扱うことなくヒットシェーダーを実行するのに便利です。

最後に、キャプチャされたサーフェスキャッシュデータは、結果として生じるメモリオーバーヘッドを最小化するために、実行時にBC圧縮されます。



これですべてのデータが揃ったので、サーフェスキャッシュをサンプリングできます。

まず、メッシュのインデックスに基づいてカードグリッドを検索することから始めます。次に、そのグリッドのセルを検索して6枚のカードを得る。サーフェイルの法線に基づいて、投影するカードを3枚選びます。

そして3枚のカードをサンプリングします。各カードについて、サーフェスキャッシュから4つの深度をギャザーし、手動でバイリニアフィルタリングを行います。

サーフェイスキャッシュに保存された深度とレイヒット深度との差分によって各テクセルを重み付けし、オクルージョンサンプルを破棄します。また、投影が伸びるのを防ぐために、カードの投影法線によってテクセルに重み付けをします。そして、無効とマークされたテクセルを破棄します。

最後に、すべてのサンプルをブレンドして、ヒットポイントにおける最終的なサーフェスキャッシュのプロパティを計算します。



いくつかのコンテンツでは、カードのスケールに限界がありました。この建物のように、小さなインスタンスがたくさん集まって大きなオブジェクトになる場合、小さなカードを大量に生成するか、オブジェクト全体を削除しなければならないという問題がありました。

この問題に対する我々の解決策は、実行時にカードをマージすることでした。

これは、重なり合う小さなインスタンスのグループを自動的に見つけるか、ユーザーから提供されたグループタグを使うことで行います。

各グループは、キューブマップのように6枚のスライドからキャプチャするために6枚のカードを取得します。これは、視聴者がそのグループの外側にいることを前提とした、かなり良い近似である。

最後に、カードはグループ全体を各カードにレンダリングすることでキャプチャされますが、これもNaniteのおかげでかなり高速です。



サーフェスキャッシュにマテリアルデータがありますが、まだ何らかの方法でライティングを計算する必要があります。

このスクリーンショットでは、複数のバウンスがいかに重要かがわかります。これがないと、シーンの半分が黒くなり、反射が消えます。

複数のシャドウレイを使用した直接ライティングや、再帰トレースを使用した間接ライティングは、非常にコストがかかります。ほとんどの場合、追加のレイを1つでも用意する余裕はありません。理想的には、すべてのライティングをサーフェスキャッシュから取得します。



サーフェスキャッシュにはすべてのメッシュとマテリアルのデータが含まれており、ライティングの評価とキャッシュに使用できます。

これはライトマッピングに似ていて、同じような問題にぶつかります。

テクセルからトレースする場合、サーフェスをエスケープするためにサーフェス法線とレイ方向に基づいた適切なバイアスが必要です。

テクセルがジオメトリの内側にある場合もあり、バイリニアフィルタリングによって壁から漏れることがあります。三角形の裏面に当たる光線を破棄することで、これを解決し、ジオメトリ内のテクセルを効果的に黒くします。



ライティングを毎フレーム評価するにはコストがかかりすぎるため、キャッシングを使い、毎フレームサーフェスキャッシュのサブセットのみを更新します。

ページが最後に使用され、最後に更新された時間に基づいて、更新するページを選択します。

最後に使用されたのは、レイがヒットするたびにGPUが現在のフレーム番号を書き込むフィードバックに基づいています。最終更新は、ページ更新ごとにインクリメントされます。

これらの2つのプロパティは、直接照明と間接照明で別々に追跡されます。具体的には、我々は間接照明よりも安価な直接照明をより速く更新します。

最も重要なページの固定数を選択するために、ヒストグラムを作成し、予算に達するまで連続したバケットから項目を選択します。

最後に、時にはカードのサイズを変更したり、新しいページをマッピングする必要があります。そのような場合、以前の照明が利用可能であれば再サンプリングを試み、高価な計算をすべて破棄しないようにします。



更新するページを選択した後、8×8のタイルに分割します。トレースの一貫性を最大化するために、これらのタイルをZオーダーで出力します。

そして、各タイルに対して最大8つのライトを選択します。現在のところ、最初の8つのライトを選ぶだけで、我々のユースケースではうまくいっていますが、将来的にはもっとスマートなライト選択戦略を使いたいと考えています。

すべてのライトに対して、シャドウマスクの1ビットを用意し、複数のシャドウメソッドを合成するために使用します。まず、利用可能なシャドウマップをサンプリングして、このシャドウマスクを作成します。このパスの間に、シャドウマップで解決できず、トレースする必要があるシャドウレイのコンパクト化されたリストも作成します。通常、それらはカメラの後ろに位置するテクセルです。次に、シャドウレイをトレースしてシャドウマスクを完成させます。

最後にライトパスを実行し、このシャドウマスクのライティング値を計算します。



間接照明はより難しいです。ここでは基本的に、二次バウンスを計算するためにサーフェス空間でファイナルギャザーを実行する必要があるからです。

間接レイがヒットするたびに複数のバウンスをサポートするために、現在のフレームの直接ライティングと最後のフレームの間接ライティングをサンプリングします。そのため、フレームごとに最初の2つのバウンスを計算し、次のバウンスはフィードバックに基づきます。

重要な注意点として、我々には非常に限られた予算しかないため、ここではパフォーマンスのために品質を犠牲にしています。つまり、更新するページ数が少ないだけでなく、レイの予算もかなり限られています。



理想を言えば、すべてのテクセルから少なくとも64本のレイをトレースしたいところだが、それではコストがかかりすぎます。その代わりに、4×4タイル上に半球状のプローブを置き、プローブのテクセルからのみトレースします。これにより、ダウンサンプルトレーシングが可能になり、サーフェス法線のディテールが保たれます。

プローブの位置とプローブのトレース方向は、サーフェスキャッシュページごとに保存されるフレームインデックスに基づいて、フレームごとにジッターさせます。

結果として得られるプローブは、トレース数が少ないためかなりノイズが多く、これをクリーンアップするために空間的および時間的な再利用も必要になります。



各テクセルについて、最も近いプローブを4つ選び、その間を補間して間接照明を計算します。

補間の際、プローブの一部が壁の後ろにある可能性があるため、リークを最小化するために2つのヒューリスティックを用いています。最初のヒューリスティックは、すべての半球プローブをその平面で重み付けし、その後ろのテクセルがスキップされるようにする。2つ目は、プローブの深度マップを使用して、プローブと評価テクセル間の可視性をチェックすることです。

最後に、補間した結果を間接照明アトラスに一時的にブレンドします。このアトラスと並行して、現在の累積フレーム数を保持します。間接照明の更新レートはかなり低いので、ゴースティングを最小限に抑えるために、累積フレーム数を合計4フレームに制限する必要があります。



これは、サーフェイルキャッシュ間接照明、つまり我々のセカンダリーバウンスに対するピクセルの最終的なギャザーの比較です。

セカンダリバウンスはパフォーマンス上の制約から品質が落ちますが、それでもピクセルギャザーとほぼ一致しています。

この品質レベルは、ディフューズマルチバウンスやラフリフレクションには問題なく、ミラーリフレクションには通常十分です。



最後の問題は、グローバルディスタンスフィールドのトレースから直接サーフェスキャッシュをサンプリングできないことです。グローバルディスタンスフィールドはマージされたシーン表現であり、どのメッシュインスタンスがヒットしたかはわかりません。

これを解決するために、すべてのカードをカメラを中心としたグローバルクリップマップのセットにマージします。

すべてのボクセルは軸に沿った方向ごとに放射輝度を保存し、サンプリング中に方向と近くのボクセルの間を補間します。

アルファチャンネルに保存された重みで各サンプルを重み付けします。この重みにより、欠落したカードや、固定されたワールド空間軸へのカードの再投影を考慮することができます。



フレームごとにボリューム全体を更新するのはコストがかかりすぎるため、キャッシュを活用する必要があります。

グローバルディスタンスフィールドの更新と同様に、シーンの変更を追跡し、変更されたブリックのみを更新します。

変更されたブリックごとに、その中のオブジェクトのリストを作成します。

次に、スレッドごとに1つのトレースでレイトレーシングを実行します。すべてのトレースは1つのオブジェクトをレイマークし、アトミックminを使ってビジビリティバッファに出力します。

これにより、トレースをキャッシュし、シーン内でメッシュが動いたときだけ更新することができます。ライティングの変化を追跡するのは難しく、ライティングはフレームごとに変化する可能性があるため、ここではライティングの代わりにジオメトリをキャッシュします。



次に、フレームごとにビジビリティバッファ全体をシェーディングします。

まず、ビジビリティバッファをコンパクトにする必要があります。

コンパクションの後、最終的なライティングを計算するために、有効なビジビリティバッファのエントリごとにサーフェスキャッシュをサンプリングします。

このステップでは、ボクセルライティングボリュームのアルファチャンネルに格納されるプロジェクションウェイトも計算します。



サーフェスキャッシュの制限に関して、主なものは粗すぎるボクセルライティングの品質です。これは将来的に解決しなければならないことです。

カードはメッシュのインポート時に配置され、メッシュアニメーションには対応していません。我々フォリッジの深度ウェイトバイアスを増やすことで、これをいくらか緩和しています。これは、小さな変形に対してはそれなりにうまくいきますが、キャラクターに対してはうまくいきません。

レイヤー数が多すぎる樹木のような一部のメッシュは、妥当なレイヤー数を使用してアンラップできません。これは反射で顕著になることがありますが、拡散レイではエネルギーが少し不足するだけなので大きな問題ではありません。



サーフェスキャッシュの良いところは、ディスタンスフィールドトレーシングできることです。

また、様々な高価な計算をキャッシュするのにとても便利です。これはディスタンスフィールドトレーシングだけでなく、ハードウェアのレイトレーシングにも有効で、ヒット時に高価なマテリアルやライティングの評価をスキップすることができます。

最後に、信憑性のあるGIと反射のために重要な、高品質のマルチバウンスを可能にします。

ご清聴ありがとうございました。それではPatrickにバトンタッチします。



こんにちわ、私の名前はパトリックで、Lumenでのハードウェア・レイトレーシングの使い方について発表します。



その前に、この仕事を始めた最初の動機について述べておきたいです。

我々がハードウェアレイトレーシングに興味を持ったのには、いくつかの理由があります。ハードウェアレイトレーシングを使えば、生の三角形データを使ってレイとオブジェクトの交差を正確に計算できます。動的なマテリアルとライティングの評価が可能になり、シャープな画面外反射が可能になります。そして最後に、最新のゲーム機にハードウェアレイトレーシングが導入されたことで、この技術が以前よりもずっと広く利用できるようになりました。



まず、ハードウェアレイトレーシングとLumenを使った最初の実験の概要から説明しましょう。UE4モデルの組み込みとその欠点についても簡単に説明します。次に、サーフェスキャッシュを使用することでランタイムコストを最小化する代替モデルを紹介し、両方のモデルをミックスすることで質的な利点が得られることを実証します。

また、我々のシステムで不透明度を表現するための実用的なソリューションをいくつか紹介し、LumenのGPU駆動パイプラインがハードウェア・レイトレーシングの呼び出しをどのように変えたかについても説明します。

さらに、”The Matrix Awakens: An Unreal Engine Experience” の制作中に遭遇した、トラバーサル関連の複雑さについても紹介します: 例えば、Nainteのフォールバックメッシュの組み込みや、ファーフィールドへのトレース距離の延長などです。

最後に、UE5 でリリースされた完全なハードウェア レイトレーシング パイプラインを紹介します。



LumenにおけるHWRTの初期導入は、反省から始まりました。そしてこのタスクでは、UE4のレイトレース反射モデルを組み込むことから始めるのが最も適切だと思われました。Ray-Traced Reflectionsの統合は、ダイナミックなマテリアルとライティング評価のための直接的なソリューションとなりましたが、統合ソリューションを提供する前に、UE4モデルの欠点に対処する必要があることは当初から明らかでした。



UE4のリフレクションモデルをデプロイする際に遭遇した最も顕著な問題は、適切なスペキュラオクルージョンがないことでした。ミラーボールは、我々のLyraサンプルでそのアーチファクトをはっきりと示しており、影のないスカイライトが内部に不自然な青い色合いを加えています。



この画像でも、鏡面反射が正しく行われていないことがわかります。



同時に、ダイナミックな評価を偽造し、サーフェスキャッシュだけに頼るのも面白い試みだと気づきました。この呼び出しが最終的にLumenハードウェアレイトレーシングの「高速パス」になると判断した我々は、パイプラインにさらなる制約を課すことも決定し、BVH内のすべてのオブジェクトを強制的に不透明にすることで、エニーヒットシェーダーの使用を排除しました。

このモデルでは、マテリアルに依存するクローズヒットシェーダのセットを、単一のクローズヒットシェーダに置き換え、このシェーダは、ジオメトリ法線とサーフェスキャッシュパラメータライゼーションを抽出するのに必要なデータのみをフェッチします。そして、レイ生成シェーダは、法線重み付けされたサーフェスキャッシュ評価としてライティングを適用します。

このパイプラインをサーフェイスキャッシュパイプラインと呼びます。



サーフェイスキャッシュを利用することで、1回の評価で直接照明と間接照明を得ることができます。サーフェイスキャッシュを使用することで、以前に紹介した影のないスカイライトの問題を克服することができます。




そして、前述のスペキュラーオクルージョンを補正します。




サーフェイスキャッシュパイプラインの積極的な最適化により、帯域幅の圧力を最小化するために新しいペイロード構造を作りました。UE4 モデルで使用されている高品質のペイロードは、ダイナミックライティング用の GBuffer のようなパラメータを格納するために 64 バイトを必要とします。これには、BaseColor、Normal、Roughness、Opacity、Specularなどのパラメータが含まれます。これに対して、サーフェイスキャッシュペイロードは、サーフェイスキャッシュライティングルックアップに必要なパラメータを格納するために 20 バイトしか必要としません。

サーフェイスペイロードのパラメータセットを以下に示します。Materialに指定されているビットはサーフェイスパイプラインには必要ありませんが、その目的については後で説明します。



サーフェイスキャッシュパイプラインは、シェーダーバインディングテーブルの構築も簡素化します。新しいモデルでは、マテリアルに依存するリソースをフェッチする必要がなくなりました。多数のインスタンスの場合、これは CPU 時間に関して顕著な節約を生み出します。

残念ながら、DXR でサーフェス法線を再構築するには頂点およびインデックス バッファのバインディングが必要であり、UE5 では現在バインドレスリソースを使用し ていないため、バインディングループを完全に排除することはできません。



2つのモデルを構築した後、2つの戦略をミックスすることで、性能対品質のトレードオフを支配する自然なスケーリング制御が可能になると予想しました。これは、アルベド、直接照明、間接照明などのサーフェスキャッシュ項を、望ましい動的評価レベルに応じて条件付きで分離することで実現しました。これはまた、UE4モデルの動的評価にサーフェスキャッシュの間接照明を組み込むメカニズムを提示し、影のないスカイライトの根本的な問題を解消しました。

マテリアルを動的に評価するか、ライティングを動的に評価するかを個別に制御できたとしても、部分的な動的評価は完全な動的評価と同じくらいコストがかかることがわかりました。



この結果により、2つのライティング設定のみがアーティストに公開されます。サーフェスキャッシュモードは、前述のサーフェスキャッシュモデルを実装します。また、Hit-Lightingモードは、サーフェスキャッシュからの間接照明が組み込まれた、変更されたUE4モデルを表します。現時点では、反射用にHit-Lightingモデルのみを公開しています。

Hit-Lightingモデルは、以前に公開されたSorted-Deferredトレースパイプライン [Tatu Aalto 2018] [Kelly et al 2021] の修正バージョンを実装していることを指摘することが重要です。また、並べ替えられた遅延最適化ではマテリアルIDをエクスポートする必要があるため、Surface-Cacheペイロードに含まれています。


これにより、サーフェイストレース段階をHit-Lightingパイプラインの前提条件として再利用することができます。また、オプションで、レイごとに動的評価を呼び出す柔軟性も得られます。例えば、サーフェスキャッシュのパラメータ化を持たないメッシュに対してオプションでHit-Lightingを呼び出すために、このアイデアを実験しました。

Hit-Lightingパイプラインは、最初にサーフェイスキャッシュトレースパスを実行した後に、ソートと再トレースを追加します。



Lyraの例では、ヒットライティングがミラーボールに反射したスケルタルメッシュを直接照明しているのがわかります。スケルタルメッシュはサーフェイスキャッシュパラメタリゼーションを持たないので、この効果はHit-Lightingモデルでのみ可能です。



サーフェイスパイプラインは、部分的に不透明なジオメトリを扱う際に、さらなる課題をもたらします。前述したように、サーフェイスキャッシュモデルを採用する場合、BVH 内のすべてのジオメトリは完全に不透明であるとして明示的に扱います。これは、any-hit シェーディングを呼び出すと、ランタイムペナルティが顕著に発生するためで、我々はこれを避けたいと考えています。

不透明なトラバーサルで顕著な問題を克服する試みとして、我々は2つのマテリアル依存の戦略を採用しています。半透明のマテリアルに対しては、それらのメッシュを完全にスキップすることを選択します。アルファマスクされたマテリアルの場合、サーフェスキャッシュの不透明度を評価し、不透明度が50%以下のメッシュをスキップすることにします。

any-hitシェーダを省略することを選択したので、部分的に不透明なサーフェスに遭遇するたびに、レイ生成シェーダでシーンを繰り返しトラバースしなければなりません。この反復回数は MaxTranslucentSkipCount シェーダパラメータによって制御されます。



この例は、半透明のジオメトリセグメントに遭遇したときの MaxTranslucentSkipCount の適用を示しています。



この例では、トラバーサル中にジオメトリのアルファマスクを再構築するために、サーフェスキャッシュの不透明度を評価する応用を示しています。



LumenのGPU駆動パイプラインには、UE4にはなかった追加のディスパッチ制御が必要でした。Lumenパスは、画面ピクセルで直接操作するのではなく、プローブ、サーフェイスキャッシュテクセル、および画面タイルで操作します。多くの場合、ハードウェアレイトレーシングはセカンダリトレースタイプであり、フォールスルー技法として動作します。これらの理由から、間接ディスパッチを利用することが不可欠でした。このため、LumenはPCでDXR 1.1セマンティクスを優先します。

DXR 1.1の便利な機能として、インラインレイトレーシングがあります。RayQueryインタフェースを使用すると、シェーダバインドテーブルの複雑さが回避され、標準の計算シェーダとピクセルシェーダでハードウェアトラバーサルが可能になります。また、レイクエリを使用すると、コンパイラに最適化の大きな機会が提供されます。レイ生成の場合、TraceRay () 呼び出しにまたがる”ライブ状態”の量を最小限に抑えることを強くお勧めします。インラインレイトレースを使用すると、コンパイラは開発者の介入なしにこれを最小限に抑えることができます。

メッシュが変化する頂点とインデックスバッファーデータをヒットグループシェーダーに提供する必要がある場合を除き、サーフェイスキャッシュパイプラインではインラインレイトレースを使用できます。この補助バッファはPCにのみ必要です。ただし、コンソールレイトレーシング組み込みは、レイトレーシングヒット構造の一部としてジオメトリ法線へのアクセスを既に提供しています。このため、実際にコンソールでインラインレイトレースを活用し、特定のプラットフォームで顕著な高速化の恩恵を受けています。このコンソール特化の詳細については、AleksanderとTiagoの講演を参照してください。



The Matrix Awakens: An Unreal Engine Experienceでは、レイトレーシングモデルにとって難しい課題が提示されました。オープンワールドのため、大量のインスタンス数を使用する必要があり、トップレベルのアクセラレーション構造では、リビルドに時間がかかりすぎてしまいます。ワールド内のアクティブな車や歩行者の数が非常に多いため、ボトムレベルの加速構造をダイナミックに何度もリフィットする必要がありました。車の塗装やガラス素材は、鏡面反射がないとリアルになりません。

このデモのターゲットプラットフォームは、XboxシリーズX/SとPS5でした。これらのマシンは、ネイティブのレイトレーシングをサポートしていますが、ハイエンドのPCシステムで利用可能なものよりも全体的な計算能力が低く、トラバーサルが遅くなります。しかし、コンソールのAPIは、レイトレーシングのパイプラインにおいてより大きな柔軟性を提供し、我々はそれを活用することができました。たとえば、静的メッシュの加速構造を事前に構築してストリームすることができ、ボトムレベルの加速構造の構築と再適合に費やすフレームタイムを大幅に削減できます。コンソール固有の最適化の詳細については、Aleksander と Tiago の講演を参照してください。



残念ながら、デモではマテリアルが複雑だったため、Hit-Lightingモデルに頼ることは不可能でした。高い命令カウントとともに、我々のマスターマテリアルは、何十もの仮想テクスチャフェッチを呼び出していました。動的なマテリアルとライティングの評価は、単純に実行不可能でした。前述したように、ダイナミックオブジェクトでHit-Lightingを呼び出すことを当初は期待していましたが、予算が足りなくなりました。



このタイミングレポートでは、PS5で我々の複雑なマテリアルを使ってHit-Lightingを発動させた場合の驚異的な評価コストを示しています。興味深いことに、Hit-Lightingは質的にも大きなメリットをもたらしませんでした。これは、デモのスカイライト項に強く依存しているためで、現在ではどちらのパイプラインもサーフェイスキャッシュからフェッチしています。



Matrix Awakensに登場するアセットの大半はNaniteでレンダリングされています。これは、我々のアクセラレーション構造でネイティブのNaniteジオメトリ解像度をサポートする能力を持っていないため、ハードウェアレイトレーシングに直接的な複雑さをもたらします。これには複数の理由がありますが、そのうちのいくつかを紹介します。単純な答えは、レイトレーシングのための高品質のNaniteサポートは、まだ活発な研究分野であるということです。

その代わりに、我々は近似的な幾何学的表現でいくらか譲歩しなければなりません。我々は、ラスタライズされたジオメトリの簡略化された表現としてNaniteのフォールバックメッシュを使用し、それらをボトムレベルのアクセラレーション構造に格納します。これらのフォールバックメッシュは、ベースメッシュとのトポロジー保証を提供しないため、独自の課題をもたらします。

GBufferから直接トレースする場合、Naniteフォールバックメッシュを扱う際にいくつかの明らかな課題が生じます。近似形状は、従来のレイバイアスでは容易に克服できない自己交差の可能性を生み出します。



以下は、デモの車両をレンダリングする際に遭遇した、一般的な自己交差のアーティファクトの例です。アーティファクトの発生頻度を示すために、スクリーントレースを無効にしています。



同じショットをLumenScene表現に重ねると、克服しなければならない幾何学的ミスマッチのタイプがわかります。



しかし、複数の幾何学的詳細レベルに対するレイトレーシングは、新しい問題ではありません。TabellionとLamorletteは2004年にこの問題の解決策を発表しています[Tabellion et al 2004]。残念ながら、適切な実装は我々の予算には高すぎました。その代わりに、我々はトラバーサルアルゴリズムを修正し、まず、ある定義されたイプシロン-距離まで短いレイをキャストし、背面を無視するようにしました。この距離のトラバースに成功した後にのみ、サイドネス特性を無視した長いレイをキャストしました。この図はそのプロセスを示しています。



この技術を適用することで、以前は存在した自己交差のアーティファクトが取り除かれます。




スクリーントレースはまた、バウンディングビューフラスタムと一致する開始t-値を持つハードウェアトラバーサルを提供することによって、自己交差アーティファクトを克服します。



しかし、ビューフラスタムの固有の境界があるため、フレームの端の近くではこの技術は信頼できません。



だから結局、両方のテクニックを使うことになりました。



前述したように、デモではアクティブなインスタンスの数が非常に多く、ハードウェアのレイトレーシングモデルに大きな負荷がかかっていました。我々のシステムは、フレームごとにトップレベルのアクセラレーション構造を再構築しており、初期の実験では、我々のモデルは100Kインスタンスに制限されるだろうと示唆されていました。実験の時点では、コンテンツドレッシングは500Kのアクティブ・インスタンスに近づいており、1Mに達する予定でした。結果コストだけが問題ではなく、レイトラバーサルは三角形の数が多いため非常にコストがかかるようになりました。

予算内に収めるためには、最大許容トレース距離でリージョンする必要があることは明らかでした。最大トレース距離とレイトレーシングメッシュのカリング距離を一致させることで、当初の要件に合うようにシステムを絞り込むことができました。最終的に、トレース距離を200メートルに制限することが、目標を達成するために必要であることがわかりました。

しかし、トレース距離を制限することは、全体的なルックに大きな悪影響を及ぼしました。車の反射で遠くのスカイラインが見えなくなりました。さらに重要なのは、グローバルイルミネーションソルバーによる正確なスカイオクルージョンが完全になくなってしまったことです。

我々は、このリークに対処できるソリューションを必要としていました。



我々はこの目標を達成するために、ワールドパーティションシステムとそのHLOD表現を利用することにしました。HLODシステムの下では、メッシュは簡略化され、一緒にマージされ、距離のあるジオメトリの融合を作成します。

典型的なケースでは、HLOD表現はラスタライズされたジオメトリを直接置き換えるものです。しかし、実行可能なトレース距離の制限により、ラスタライザが通常この置き換えを必要とする前に、HLOD表現を組み込む必要がありました。このため、トップレベルのアクセラレーション構造では、2つの異なるメッシュ表現が同じスペースを占めることがよくありました。

この矛盾を克服するために、両方の表現をサブミットしますが、レイマスクでレイトラバーサル中に相互排除を強制します。HLODメッシュは、ジオメトリの “ファーフィールド” セットに属するものとしてタグ付けします。



レイトラバーサルは現在、”ニアフィールド “と “ファーフィールド “ジオメトリの両方に対するトラバーサル操作のユニオンで構成されます。順序付けされたトラバーサルでは、まずニアフィールドジオメトリに対して、メッシュのカリング距離と一致する距離までトレースします。ニアフィールドを逃したレイは、ファーフィールドに対するトラバーサルのために再キューされます。

順序付けされたトラバーサルを必要としないシャドーレイについては、操作の順序を逆にします。ファーフィールド表現には、ニアフィールドよりも少ないインスタンスと少ないジオメトリしか含まれていないため、このようにすることにしました。これにより、ファーフィールドのトラバースが速くなる。



ファーフィールドトレースを順序付きトラバーサルに組み込むことで、オリジナルのハードウェアトラバーサルパイプラインに新たなステージが追加されます。我々は、中間的なコンパクションステップを追加し、ニアフィールドのミスを新しいレイタイルに問い合わせし、その後、レイタイルをファーフィールド表現に対してトレースする間接的なディスパッチを行います。

今のところ、パイプラインからHit-Lightingモデルを一時的に削除しています。



このビジュアライゼーションは、ニアフィールドとファーフィールドのジオメトリの境界線を示しています。サーフェスキャッシュエントリを持たないジオメトリも強調表示されます。



ニアフィールドとファーフィールドの両方の表現を同じトップレベルの加速機構にサブミットするのは理想的とは言えません。そうすることで、不必要な幾何学的重複が生じます。レイマスクは不必要なトラバーサルを取り除きますが、トップレベルの加速構造構築へのダメージは相当なものです。ファーフィールド表現をオーバーレイする初期の実験では、すべてのニアフィールドトラバーサル・コストの44%という驚くべきペナルティが明らかになりました。

適切な解決策は、複数のトップレベル加速構造をサポートすることで、前述のレイマスクを使用する必要もなくなります。我々は、すでにアグレッシブな開発スケジュールの中で、このアーキテクチャーを生産半ばで採用することにためらいを感じていましたが、何とかする必要がありました。



以前の仮説に従って、ファーフィールドのジオメトリにグローバルな並進オフセットを適用することで、負担が軽減される可能性が示唆されました。そこで、このアイデアを試してみました。最終的には、同じ加速構造内にジオメトリを組み込むことによるペナルティを被ることになりましたが、並進オフセットによってオーバーヘッドコストは大幅に削減されました。



このアニメーションは、Lumenのパス全体にファーフィールドトレースを適用したものです。反射オクルージョンの影響が最も顕著ですが、遠景のグローバルイルミネーション寄与への影響も確認できます。




ここでは、ファーフィールドトレースステージが追加されたことによる品質向上をよりわかりやすく描写しています。



この時点で、最終的な階層型トラバーサルのパイプラインを明らかにするために必要なすべての構成要素について説明しました。簡単におさらいすると、われ和得rはアーティストに2つのシェーディングモデルを提示します:スピードのためのサーフェイスキャッシュモデルと、クオリティのためのHit-Lightingモデルです。また、高品質なニアフィールドのジオメトリ表現から、低品質ですがよりパフォーマンスの高い、ファーフィールドのジオメトリ表現へと、優雅にカスケードするメカニズムも提供します。



ステージの順序をいくつか変更することで、最初にすべてのサーフェイスステージを解決してから、オプションで結果をHit-Lightingのために再キューイングすることで、ディスパッチコストを最小化することができます。これは、両方の幾何学的表現を通してカスケードすることで行います。ヒットはコンパクト化され、オプションでHit-Lightingのために再キューイングされ、ミスはスカイライト評価を適用するためにカスケードされます。



我々のハードウェアトレースモデルは、オリジナルのUE4モデルからかなり変わりました。サーフェスキャッシュを活用することで、パフォーマンスを追求した最小限のトラバーサルスキームを構築できることを示しました。ファーフィールドのジオメトリ表現を追加することで、圧倒的なジオメトリインスタンスの複雑さに対処し、同時にレイのトラバーサル距離を大幅に拡張できることを示しました。そして、複雑なNaniteアセットを組み込む際に、固有のジオメトリLODのミスマッチに対処する方法を示しました。

ご視聴ありがとうございました。それではDainelに話を戻します。



それでは、レイトレーシングパイプラインのセクションの最後に、トレーシング手法のパフォーマンス比較をしてみたいと思います。



これらをコストと精度でグラフ化すると、グローバルディスタンスフィールドトレーシングが最も高速ですが、最も精度が低く、スクリーントレースやメッシュディスタンスフィールドトレーシングのような、より精度の高い手法で補完する必要があることがわかります。

ハードウェアレイトレーシングは非常に正確ですが、非常に高価で、スケールダウンする方法がありません。ライティングをヒットさせるハードウェアレイトレーシングは非常に高価で、コストのグラフから外れてしまいます。



Lumenを使用するプロジェクトは、どのトレース方法を使用するかを選択しなければなりません。ソフトウェアレイトレーシングは、次世代コンソールで毎秒60フレームのような、可能な限り絶対的な高速トレーシングを必要とするプロジェクトに最適な選択です。キットバッシングを使用して構築されたメッシュがたくさん重なり合うプロジェクトも、ソフトウェアレイトレーシングを使用する必要があります。これは、我々の技術デモの’Lumen in the land of Nanite’と’Valley of the Ancients’のケースです。

建築のビジュアライゼーションのように、可能な限り最高のクオリティが必要なプロジェクトでは、ハードウェアレイトレーシングを使うべきです。また、’The Matrix Awakens’のように鏡面反射が必要な場合や、間接照明に大きな影響を与えるスキンメッシュが必要な場合も、ハードウェアレイトレーシングを使用する必要があります。



それでは、2つのトレース手法のパフォーマンスをいくつかの異なるシーンで見てみましょう。まずは、膨大な数のメッシュが重なり合う’Lumen in the Nanite’から。このコンテンツは事実上Nainteのストレステストとして作られたもので、洞窟の表面に沿ったすべてのポイントに約100個のメッシュが重なっています。ハードウェアレイトレーシングでは、レイは重なり合ったメッシュをひとつひとつ横断しなければなりませんが、ソフトウェアレイトレーシングでは高速にマージされます。ハードウェアレイトレーシングは、このコンテンツでは非常に高価なので、出荷することはできませんでした。



Lyra UE5のサンプルゲームでは、状況が異なります。ここではジオメトリが重なっていないため、ハードウェアレイトレーシングが非常にうまく機能します。2つのテクニックのコスト差はそれほど大きくなく、クオリティの差もありません。ハードウェアが何をサポートするかによって、どちらとも言えます。



‘The Matrix Awakens’の技術デモでは、どちらのトレース方法もコストはほぼ同じです。ハードウェアレイトレーシングは、より高品質な反射を実現し、Far Fieldによる広大なビューレンジでのGIをサポートしているため、より良い選択です。



さて、Lumenのファイナルギャザーに移りましょう。



リアルタイムの間接照明で解決しなければならなかった3つ目の基本的な問題は、光伝達におけるでした。

1ピクセルに1本のレイも出す余裕はありません。左の図は、1ピクセルに1本のレイがどのように見えるかを示していますが、高品質の屋内GIには何百もの効果的なサンプルが必要です。



我々の初期の実験のひとつが、プレフィルターをかけたコーントレーシングでした。これは実装が非常に難しいのですが、もしうまくできれば、1つの円錐をトレースすることで、多くのレイの結果を得ることができます。コーンはノイズを解決するのに非常に効果的で、ファイナルギャザーを本質的に取るに足らないものにします。



我々はメッシュ符号付きディスタンスフィールドに対するコーントレーシングを実装しました。コーンがサーフェスと交差するたびに、コーンの交差のサイズを使用してサンプリングするサーフェスキャッシュのミップを計算し、交差するコーンに対してプリフィルタされたライティングを与えます。

コーンがサーフェスとニアミスするとき、それは部分的にしかオクルードされないので、これは透明性の問題になります。ディスタンスフィールドから得られるコーンの軸からサーフェスまでの距離を使って、コーンがどれくらいオクルードされたかを概算できます。

次に、順番の違うメッシュから複数の部分ヒットを計算する必要があります。我々はこれをWeighted Blended OITで解決しました。これはプライマリレイに対しては大きな距離で大きなリークがありますが、拡散間接レイに対しては小さな距離ではるかに少ないリークがありました。

ノイズの原因となるハードエッジがないため、コーントレースが機能していることが右図でわかります。



コーントレースはノイズの解決には非常に効果的でしたが、結局のところ、すべてのケースでリークを解決することはできませんでした。リークかオーバーオクルージョンのどちらかを選ばなければならなかったし、小さな距離の窓からのライティングを解決することはできませんでした。
また、ソフトウェアレイトレーシングでしか機能しませんでした。



だから、その代わりにモンテカルロ積分をします。モンテカルロ積分は、最高品質までスケールアップし、あらゆる種類のレイトレーシングをサポートしますが、ノイズの問題はファイナルギャザーに移ります。



拡散光移動を解決するための最も一般的なアプローチは、イラディアンスフィールドです。イラディアンスは、ボリューム内に配置されたプローブからトレースし、プローブ位置での放射照度を事前に積分し、それを画面上のピクセルに補間します。

この手法の最大の問題点は、放射照度がピクセルではなくプローブで計算されることであり、これがリークやオーバーオクルージョンの原因となり、プローブの配置を非常に難しくしている。

また、ボリューメトリックな表現であるため、低い空間解像度しか得られず、GIが平坦に見えてしまいます。



もう一方は、画面上の実際のピクセルからトレースし、事後的にスクリーンスペースデノイザーでノイズを解決しようとする方法です。

これには問題があります。ディノイザーは、半球を完全にカバーするために、非相関なレイのセットを必要とします。

デノイザー操作はスクリーン空間で行われるため非常に高価になり、ダウンサンプリングフィルタリングの機会がありません。デノイザーは、新たに明らかになった領域で収束するのに十分なサンプルがない、ディスオクルージョンという問題を抱えています。



その中間を見つけたい。我々は、インダイレクトシャドウのようにスクリーン上のピクセルからトレースする精度を求めますが、そのようなアプローチよりもはるかに低コストなものです。



我々のアプローチは、スクリーンスペースラディアンスキャッシングです。我々は、スクリーン上のピクセルに配置されたプローブ(我々はスクリーンプローブと呼んでいます)からトレースする。

これは効果的に適応的なダウンサンプリングです。左の図では、プローブが一様に配置されているのがわかりますが、より詳細なジオメトリがあるところでは、より多くのプローブを配置します。

プローブを配置し、そこからトレースした後、その輝度を同一平面内の他のピクセルに補間します。このため、補間によるリークは同一平面内のピクセルに限られ、目立ちにくいです。

フレームにわたってプローブの配置グリッドをジッターさせ、時間的に蓄積することで、良好なカバレッジを得ます。



昨年のアドバンスコースでLumenの不透明ファイナルギャザーを紹介しましたが、それ以来、’The Matrix Awakens’の技術デモでストレステストを行いました。それは我々の他のドメイン、Volumetric Final Gather、そしてTexture Space Gatherの原型となりました。



不透明ファイナルギャザーには3つの主要部分があり、まず各次元で1/16の解像度で動作するスクリーンスペースラディアンスキャッシュがあります。これはワールド空間ライディアンスキャッシュによってバックアップされ、より低い解像度で遠くのライティングを処理します。フル解像度では、補間、積分、テンポラルフィルター、コンタクトAOがあります。



ファイナルギャザーを使って、最も遠距離のライティングから最も近距離のライティングまでのシーンを見るとこんな感じです。最初はスカイライトだけです。



そして、ワールドスペースラディアンスキャッシュを追加します。これは、2メートル以上先のライティングを解決するもので、このシーンでは左側の壁だけです。



ワールドスペースラディアンスキャッシュのプローブを見ると、壁側のプローブはウィンドウを非常に正確に解像しているが、右側のプローブは壁を通して見ていることがわかります。



次に、スクリーンスペースライディアンスキャッシュを追加します。これは、近くのライティングをすべてキャプチャするもので、間接シャドウができますが、ダウンサンプリングされた空間になります。



ここにスクリーンプローブが置かれています。細かいジオメトリがあるところ以外は一様に配置され、グリッドを細分化してさらに配置します。



最後に、Contact AOを使用した場合の表示を示します。これは、スクリーンライディアンスキャッシュのダウンサンプリングによって失われたシャドウの詳細を補っています。



スクリーンスペースラディアンスキャッシュの詳細を見ましょう。



スクリーン空間ではなく、ラディアンスキャッシュ空間でフィルタリングを行うため、安価で大きな空間フィルタを提供できます。プローブ空間の非常に小さな3×3のフィルタリングカーネルは、48×48の大きなスクリーン空間のフィルタリングカーネルと同じノイズ低減を実現します。誤差の重み付けのために、すべてのピクセルの位置と法線を読み込むのではなく、プローブの位置を読み込むだけでよいのです。



入射ライティングを重点サンプリングします。重点サンプリングは、重要度推定と同じくらい良いものでしかなく、我々は、現在のフレームに再投影された最後のフレームのスクリーンスペースラディアンスから、入ってくるライティングの非常に正確な推定を持っています。ラディアンスキャッシュには、位置だけでなく方向でもインデックスが付けられているので、我々は非常に効率的に最後のフレームのすべてのレイを見つけることができます。画面の端のように再投影が失敗する場所では、ワールドスペースラディアンスキャッシュにフォールバックし、依然として効果的な重点サンプリングを行います。



我々はダウンサンプリングされた空間で活動しているので、より良いサンプリングを行うために、プローブごとにスレッドグループ全体を立ち上げる余裕があります。プロダクト重点サンプリングは通常オフラインレンダリングでしかできませんが、我々はリアルタイムでそれを行うことができます。

プロダクト重点サンプリングは、BRDFやライティングのみを重点サンプリングするよりも優れています。また、方向が他の分布で低いウェイトを持っていた場合にトレース処理を捨ててしまう多重点サンプリングよりも優れています。

左側は、壁面上のプローブのBRDFで、1つの半球の方向だけが重要です。中央は、前のフレームから入ってきたライティングで、ライティングのほとんどがこの2つの方向から来ていることがわかります。次に、無駄なレイを、プロダクトで最も重要な方向に割り当て直します。



ここで白いレイは、最も重要な方向をスーパーサンプリングするために生成したものです。実際にはこれ以上レイをトレースすることなく、4倍のレイをトレースするクオリティを得ています。



ワールドスペースラディアンスキャッシュの詳細を見てみましょう。



ワールドスペースラディアンスキャッシュは、方向分解能は高いが空間分解能は低い、遠方のライティングを扱っています。これは、部屋のライティングがすべて遠くの小さな窓からきていて、少数のレイで見逃していた問題を解決します。スクリーンのプローブレイを短くすることで、2つのラディアンスキャッシュを統合し、それが外れた場合はワールドスペースラディアンスキャッシュから補間します。

ワールドスペースラディアンスキャッシュは、プローブの位置が安定しているため誤差が安定しており、隠しやすいです。


ワールドスペースラディアンス・キャッシュは疎なカバレッジを持っており、プローブ間のスクリーン距離を一定に保つためにクリップマップ分布を使用し、オーバーサンプルやアンダーサンプルがないようにしています。

プローブは永続的な割り当てを使用しているため、フレームをまたいでも生き残ることができます。



新しいフレームでまだ必要な前フレームのプローブを引き継ぐことで、それらをキャッシュします。そして、カメラやシーンの動きによって明らかになった位置に対して、新しいプローブをトレースします。

これらのプローブのサブセットを再トレースして、ライティングの変化をワールドに伝搬させます。昨年から、GPUのプライオリティキューを使用して、更新するプローブの固定数を選択することで、可変入力で動作しているにもかかわらず、キャッシュ全体の更新コストを固定にすることで、これを改善しました。



“The Matrix Awakens”には実験的なナイトモードがあり、エミッシブメッシュで全体が照らされます。このシーンのライティングのほとんどは、小さくて明るい電球メッシュから来ているので、光源を明示的にサンプリングしていない我々のGIメソッドで直接ライティングを扱うのは、絶対的なストレステストです。ワールドスペースラディアンスキャッシュは、より高い指向性解像度でより正確に直接ライティングを解決し、このスクリーンショットの比較では伝わりませんが、時間的に安定しています。



次に、フル解像度のテンポラルフィルターに移ります。



テンポラルフィルターは、プローブの位置と方向のジッターをカバーするために必要です。安定したテンポラルフィルターが必要なので、近傍クランプを使うことはできず、代わりに深度と法線の違いに基づいてヒストリーを棄却します。

これは非常に安定した結果をもたらし、我々が必要とするものですが、ライティングの変化に対する反応が遅くなり、動く物体の背後にゴーストとして現れます。



我々は、トレースが高速で移動する物体にぶつかるタイミングを検出し、高速で移動する物体からのライティングが大部分を占めるピクセルのテンポラルフィルタを高速化することで、これを改善します。

また、テンポラルフィルターの後に最短距離オクルージョンを適用することで、タイムラグが生じないようにしています。



ほとんどのダイナミックなシーンの変化では、遠景のライティングの伝搬にもっとレイテンシーをかける余裕があります。最短距離の間接照明はレイテンシーに余裕がありませんが、スカイライトは多くのレイテンシーを回避できます。ファイナルギャザーでは、放射を距離の範囲に分け、それぞれ異なるテクニックで解決しているので、このキャッシュの機会を利用するようにすでにセットアップされているのは興味深いことです。



スクリーン空間の輝度キャッシュは時間的に蓄積することで、許容される待ち時間を利用することができます。一方、ワールド空間の輝度キャッシュは前のフレームのプローブ全体を再利用することができ、スカイライトは何フレームにもわたってゆっくりと更新することができます。



次に、半透明性とフォグに関するGIに移ります。スカイライトに影をつけないと、半透明の塵がどのように見えるかわかるでしょう。

フォグについては、可視深度範囲のあらゆる場所でGIを解決する必要があり、法線を持つ半球ではなく、入射球全体にわたって解決する必要があります。

また、不透明ファイナルギャザーの約1/8の予算しかないので、非常に高速なテクニックが必要になります。



我々のボリュームメトリックファイナルギャザーは、フロクセルグリッドであるプローブボリュームでビューフラフラムをカバーします。八面体プローブをトレースし、HZBテストで決定された不可視プローブをスキップします。

ラディアンスを見つけるためにトレースした後、ラディアンスに空間フィルタをかけ、少ないトレース数でノイズを減らすために時間的に蓄積します。

その後、球面調和放射輝度に事前積分し、フォワード半透明パスまたはボリュームメトリックフォグパスで放射輝度を補間します。



トレース数を増やしても、この洞窟のように、小さな穴から差し込む空の光で全体が照らされているような、遠くの照明のノイズを解決することはできません。

我々は、遠景のライティングに別のワールドスペースライディアンスキャッシュを使用しています。これはまた、指向性の解像度が高く、安定した遠景のライティングが得られます。



このワールドラディアンスキャッシュにデータを入れるには、フロクセルのグリッドのあちこちにプローブを配置する必要があります。そしてプローブからトレースし、ラディアンスをミップマップにプレフィルターします。

フロクセルのトレースを短くし、ミスした場合はワールドプローブから補間します。ワールドプローブのレイはフロクセルのレイより16倍多いので、ミップはエイリアシングを低減します。

この新しい半透明ラディアンスキャッシュを不透明ワールドラディアンスキャッシュとオーバーラップさせ、多くのディスパッチが隙間に収まるようにし、ほぼフリーにしました。



Lumen リフレクションに移ります。



反射については、Tomasz Stachowiakの素晴らしい講演に基づき、スクリーン空間のノイズ除去を伴う確率積分を使用します。

我々のパイプラインを高いレベルで見ると、まず可視GGXローブを重点サンプリングによってレイを生成し、次にレイトレーシングパイプラインを使ってレイをトレースします。次に、空間再利用パスを実行します。これは、スクリーン空間に隣接するものを見て、そのBRDFに基づいて重み付けし直します。次に、テンポラルアキュムレーションを行い、最後にバイラテラルフィルターで残りのノイズをクリーンアップします。



“The Matrix Awakens”では、このようなステップを踏んでいます。生のトレースから始めると、ノイズが多いです。



空間的な再利用を行った後では減少するが、まだ目に見えます。



テンポラルアキュムレーションを適用したところ、ファイアフライは大幅に減少したが、非常に明るい部分にはまだノイズが残っています。



これをバイラテラルフィルターでクリーンアップします。



そして最後に、フルフレームのテンポラルアンチエイリアシングで、もう少しきれいになります。



バイラテラルフィルターは、物理的な再利用だけでは不十分な場合の最後の手段です。空間的再利用パスの後、高い分散を持つ領域に対して実行し、テンポラルヒストリーを持たないディスオクルージョンによって新たに明らかになった領域では、2倍の強さで強制的に実行します。ファイアフライを除去するためにバイラテラルフィルターのトーンマップウェイティングを使います。これは空間再利用パスで使うとハイライトがつぶれてしまいますが、ここでは完璧に機能します。



反射の問題のひとつは、インコヒーレントなレイトレースに時間がかかることだ。マテリアルのラフネスが1に近づくと、GGXローブは拡散に近づき、レイは非常にインコヒーレントになります。

0.4から1までの最も粗い反射は、しばしばスクリーンの半分をカバーし、それは重要な最適化の機会です。次に、0.3から0.4のグロッシー反射があり、これはより多くの指向性を必要としますが、トレースするのに非常に時間がかかります。



拡散GIで行った作業を再利用するだけで、最も粗い反射の不整合を解決できます。スクリーンスペースラディアンスキャッシュは、広いスペキュラローブに対して十分な方向分解能を持っており、GGXローブを重点サンプリングして方向を取得し、スクリーンプローブから放射輝度を補間することによって、単に再サンプリングすることができます。

これにより、反射のコストが削減されます。これは、画面のどの程度の部分が反射光線をスキップできるかによって異なりますが、ほとんどのシーンでは、50%から70%のコストが削減されます。



グロッシー反射の中間領域では、スクリーンスペースラディアンスキャッシュには十分な方向解像度がありませんが、ワールドスペースラディアンスキャッシュcheにはあります。我々は反射レイを短くし、失敗時にワールドスペースラディアンスキャッシュから補間します。

これにより、レイのビニングとソートの必要性がなくなります。なぜなら、レイを短くすることで指向性の発散を減らし、すでに起点によって順序付けされているからです。

“The Matrix Awakens”では、道路反射のコストがさらに16%削減されています。



また、再利用による効率的なクリアコートの反射も行っています。光沢のあるボトムペイントレイヤーは、スクリーンスペースラディアンスキャッシュを再利用でき、トップクリアコートレイヤーのために新しいレイをトレースするだけでよいのです。



反射パイプラインはタイルに基づいているため、拡散レイを非常に効率的に再利用した空や領域をスキップできます。パイプラインには多くのディスパッチがあり、右側に表示されていますが、トレースパイプラインにはさらに多くのディスパッチがあり、作業が必要な画面の部分だけを操作できるため、これは重要です。

実際には、シーンに応じて、リフレクションパイプライン全体を複数回実行します。不透明の場合は少なくとも1回実行しますが、半透明の反射や水の反射の場合はもう一度実行することがあります。そのため、画面の必要な部分のみを操作できることが重要です。



タイルベースのリフレクションパイプラインの実装には、処理されていない可能性がある近隣から読み取られたすべてのノイズ除去パスがあります。テンポラルフィルタの近傍クランプでは、テクスチャの未使用領域、またはテンポラルフィルタの分岐をクリアできます。テンポラルフィルターの前に実行されるパスでタイルの境界をクリアする方が若干高速です。空間再利用パスの他のスレッドとの競合状態を回避するために、未使用のタイルのテクセルのみをクリアできます。



半透明の反射については、任意の数のレイヤーをサポートする必要があり、ピクセルシェーダから直接はできないので、ピクセルシェーダの外側で解決し、それをピクセルシェーダに補間する必要があります。同時に、ガラスは鏡面反射が必要なので、そこでは補間はできません。



ガラスの反射を提供するために、デプスピーリングを使って半透明の最前層を最小限のGBufferに抽出します。その後、パイプラインのオーバーヘッドを減らすためにノイズ除去機能を無効にして、有効なピクセルに対してのみ反射パイプラインを再度実行します。



残りのレイヤーには、再びワールドスペースラディアンス・キャッシュを使います。ラディアンスキャッシュを不透明ファイナルギャザーとして使います。半透明のサーフェイスを低解像度でラスタライズして新しいプローブをマークし、各ピクセルの位置に必要なプローブをマークします。

それから、任意の数のレイヤーで半透明をラスタライズし、そのピクセルシェーダがグロッシー反射のためにラディアンスキャッシュから補間します。



Lumenのパフォーマンスとスケーラビリティに話を移しましょう。



ここに示した測定はすべて1080pの解像度で撮影され、テンポラルスーパーレゾリューションは4kで出力されました。これによって、Lumenをネイティブの4kで、実際の画質設定で実行した場合よりも、最終的な画質がはるかに向上することがわかりました。

‘High’ 設定では60フレーム/秒、’Epi’ 設定では30フレーム/秒を目標としています。’High’ 設定にはメッシュSDFトレーシングがなく、最速の方法であるグローバルSDFトレーシングのみを使用しており、’Epic’ 設定にはピクセルあたり4倍のレイがあります。



“Lumen in the Land of Nanite”では、スムースなマテリアルがないので、反射コストは非常に小さいです。Lumenの総コストはHighで2.8ミリ秒であり、60フレーム/秒の予算に簡単に収まります。Epic品質では、ピクセルあたり4倍のレイを照射しているため、合計コストは4.6ミリ秒となり、より正確な間接シャドウと、より優れた時間的安定性が得られます。



ソフトウェア レイトレーシングを使用したUE5のサンプルゲーム”Lyra”では、総LumenコストはHighで4.3ミリ秒です。このシーンはシンプルに見えますが、きれいなディフューズテクスチャと滑らかなマテリアルで、リアルタイムGIとリフレクションには多くの処理が必要です。

Epic設定では、右側にあるように、フル解像度の反射があります。



“The Matrix Awakens”では、ファーフィールドを使ったハードウェアレイトレーシングを使用していますが、より複雑なシーンなので、トレーシングコストが高くなっています。高設定では、総ルーメンコストは6.4ミリ秒ですが、Epicでは11.3ミリ秒と大幅に高品質です。



2080 TIで実行されているアーキテクチャルビジュアライゼーションシーンを見てみましょう。Epicの設定では、Lumenのコストは7.3ミリ秒で、画面の一部を拡大したときにノイズが少し見える程度です。ファイナルギャザーを1ピクセルあたり1レイまで上げると、非常にスムーズな間接照明が得られます。



将来的には、ダウンサンプルの放射輝度キャッシュで、放射メッシュを明示的にサンプリングしたいと思います。サーフェスキャッシュのカバレッジを改善し、スキンメッシュをサポートするためにまだ取り組んでいます。

サーフェスキャッシュをまったく使用しないモードが欲しいのですが、これはおそらく非常に高価で、ハイエンドでしか実行できないでしょう。

我々は常に、予算的に厳しい60フレーム/秒でのこれらのテクニックの品質に取り組んでいます。



Unreal Engineレンダリングチームの皆さん、特にハードウェアレイトレーシングに携わった皆さん、そして素晴らしい技術デモを作ってくれたEpicのSpecial Projectsチームに感謝します。そして、アドバンスコースのNatashaに感謝します。



以下はこの講演の参考文献です。ご参加いただきありがとうございました。