NVIDIA RTXブランチについて

Unreal Engine 4 アドベントカレンダーその1 2日目

はじめに

今年、Ray Tracing Night Week 2020にてUE4レイトレのアップデートについて講演を行いました。

UE4.25のレイトレーシングで出来ること/出来ないこと

この中で謎の半導体メーカーであるNVIDIA様のRTXブランチについて言及したところ、これについての質問が寄せられました。
質疑応答の際に答えはしたのですが、動画内で言葉だけで説明したのだとわかりにくいですし機能についてもよくわからないと思いますので、ブログにて簡単ですが紹介させていただこうと思った次第です。

この記事はRTXブランチに興味がある方向けのものですが、エンジンビルドについては言及しません。
エンジンビルドについて知りたい方は株式会社ヒストリア様の以下の記事を参考にしてください。

historia.co.jp

また、あくまでもRTXブランチ紹介記事ですので、以下のような方は対象としていません。

  • RTXブランチをすでに使っている方
  • NVIDIA社の中の人

ソースコードのダウンロード

RTXブランチのソースコードGitHubから行います。URLは以下です。

https://github.com/NvPhysX/UnrealEngine/tree/RTX-4.25

ブランチは他にもいくつかあり、RTX以外のブランチも多く存在していますが、今回はそちらの解説は行いません。
URLにアクセスしても見られないという方はGitHubのアカウントを作成し、Epic Games様のUE4ソースコードにアクセスできるようにしましょう。
ダウンロードからビルドの流れは前述の記事の通りです。

現在はUE4.25までしか対応していませんが、UE4.26が正式版になるとそちらへのマージ、対応が行われる可能性があります。

機能について

このブランチの目的はNVIDIA様がレイトレーシングの様々な機能のテスト、パフォーマンス調整を行うものと思われます。
ここで実装された機能がUE4本流にマージされている例もあります。 機能についての簡単な解説はREADME.mdファイルに記述されているので、とりあえずどんな機能があるかを知るだけならGitHubのWebページでも見ることが出来ます。

以下で各機能について解説を行いますが、一部の機能については少し詳しく解説を加えています。

Direct Optimizations

出力結果に変化がない、特にデメリットのない最適化です。
必ず高速化するわけではありませんが、使用することで映像に変化があるということは基本的にありません。

バウンス回数の固定

UE4のリフレクションではマルチバウンスに対応しており、バウンス回数は変更可能です。
リフレクションシェーダは内部にバウンス回数に対する動的なループを持っていますが、動的なループは基本的に負荷が高くなります。
シェーダコンパイル時にループ回数が固定できると動的ループが展開され、一般的には高速化します。
この修正はそのループ回数を固定してシェーダコンパイルが可能な修正ですが、現在はバウンス回数が1回のときのみ固定されます。

半透明マスキング

UE4のレイトレ半透明は画面全体にレイトレースを行いますが、半透明マテリアルにレイが衝突しないピクセルでもレイトレースします。
これは無駄なので、一旦半透明メッシュをステンシルバッファに描画し、ステンシルでマークされた部分以外はレイトレースをキャンセルします。
画面全体を半透明メッシュが覆うような状況では高速化しない可能性がありそうですが、r.RayTracing.Translucency.MaskのCVarでON/OFFを切り替えることができるので、これを使ってパフォーマンス計測しましょう。

インスタンススタティックメッシュ(ISM)のカリング最適化

FoliageのISMのカリングを最適化しています。
ISMカリングのCPU負荷が高い状況では有効な機能です。

動的メッシュのバッチ作成の並列化

レイトレ界に登録する動的メッシュは静的メッシュとは違った処理を行う必要があります。
そのためのコマンドを発行する部分は通常では並列化されていませんが、大量に動的メッシュがある場合に不利になります。
r.RayTracing.ParallelMeshBatchSetupのCVarをONにすることで動的メッシュの処理を並列化出来ます。

マテリアルバインドの高速化

r.RayTracing.BatchMaterialsでON/OFFできる機能で、マテリアルバインド処理を単純化することで高速化するもののようです。
バインドするマテリアル数が多い状況で高速化するのかな?

Quality Tradeoffs

これらの最適化は映像クオリティとのトレードオフを要求します。
コメントでは違いを見つけるのは困難な程度のしきい値で設定されていると書かれています。

シャドウレイのシザリング

ポイントライトなどの効果範囲が限定されるライトでは画面全体をレイトレースせずに効果範囲のみをレンダリングするほうが効果的です。
どうやらこの機能はレイトレースシャドウを効果範囲でシザリングする機能を提供しているようです。
単純なレイトレースシャドウであればトレードオフはありませんが、デノイザーが絡むとシザーボックス境界付近に問題が出ることがあります。

影を落とすライトの優先度付け

r.RayTracing.Shadow.MaxLightsr.RayTracing.Shadow.MaxDenoisedLightsがCVarに追加されます。
この指定によってシャドウを落とすライトの数を制限することが可能です。
制限されるとライトを距離や範囲で優先度付けして、優先度の高いものから順に制限数までシャドウを落とすようにします。
この設定はMovableライトには適用されず、Static, Stationaryライトに適用されます。

また、r.RayTracing.Shadow.FallbackToSharpを利用すると、エリアライトで本来ならデノイズが必要なレイトレースシャドウをシャープな影にしてデノイズを避けるようです。

ライトの優先度付け

リフレクションやGIではレイトレースしてヒットしたマテリアルに対してライティング計算を行います。
この際に影響するライトの数はエンジン側で256個で制限されていますが、シーン中にはそれを超えるライトの配置が可能です。
配置されているライト数が256を超える場合、デフォルトでは頭から順に256個を利用するようにしますが、この機能を使うことでライトに優先度を付けて上位から選択するようにします。
r.RayTracing.Lighting.MaxLightsは登録するライトの個数を指定します。優先度付けしたライトを指定個数まで登録するようになります。
r.RayTracing.Lighting.MaxShadowLightsはリフレクションなどのライト計算時にシャドウレイを飛ばすライトの個数を制限します。
これらの設定は単純なカリング処理となるので、大量にライトが配置されている場所ではポッピングするので注意してください。

f:id:monsho:20201122102039p:plain

ライトの優先度付けルールはr.RayTracing.Lighting.Priority.~である程度の調整ができますので、ゲームに合わせて対応すると良いでしょう。
例えば屋外の場合はフラスタムを重視するほうが良さそうですが、屋内の狭い部屋ならカメラ周辺やカメラ後方を重要視したほうがいいかもしれません。

ラフネスへの乗算値

ラフネスが高いと反射レイは様々な方向に飛んでノイズが大きくなります。するとデノイズでは間に合わなくなり、もやもやしたノイズが残ることになります。
ラフネス値をマテリアルごとに調整する事もできますが、大変ですしラスタライザでのライティング結果にも影響を及ぼします。
r.RayTracing.Reflections.RoughnessMultiplierを利用すると、レイトレリフレクションのときのみラフネス値に補正をかけることが出来ます。
r.RayTracing.Reflections.MaxRoughnessと違ってレイトレをキャンセルすることはありませんが、ノイズの調整には扱いやすいと思います。

Enhanced Features

UE4本流にはない機能を追加しています。
あなたのアプリケーションに必要な機能が見つかるかもしれません。
見つけてしまった場合、Epicさんにマージ要求するか、自前でマージしましょう。

Hybrid Translucency

Ray Tracing Night Week 2020でも言及した機能で、デフォルトのレイトレ半透明の代替として使用することが出来ます。

デフォルトのレイトレ半透明は半透明に対する反射と屈折を1つのレイトレシェーダ内で別のレイトレースで実現します。
この手法は高品位ではあるものの、処理負荷が高く、その上半透明が多重に重なっている場合に問題が発生することがあります。

Hybrid Translucencyは反射のみをレイトレで対応し、屈折についてはこれまでどおりのラスタライザで対応します。
反射は別バッファにレンダリングすることで対応しますが、複数の重なりに対してはレイヤー数を増やしてカバーします。
レイヤー数が少なければデフォルトのレイトレ半透明より負荷が軽くなる可能性が高く、また、半透明の重なりによるレンダリングエラーにも対応しやすいので映像作品よりゲーム作品向けと言えます。

詳しくはshikihuikuさんの記事をご覧ください。

UE4 RTX-4.23ブランチのHybrid Translucencyは何をしているのかshikihuiku.wordpress.com

ライトファンクション、ライトチャンネル

UE4本流では対応していないライトファンクションとライトチャンネルに対応する修正です。
これらの機能を多用しているアプリケーションではマージを検討したほうが良いでしょう。
特にライトチャンネルはパフォーマンスが上がることもあります。

余談ですが、UE4本流では使用されていないCallable Shaderがライトファンクションでは使われています。
自分も使ったことがなかった機能なのでちょっと感動したけど、PSやCSでもCallable Shader使いたい…

Cast Static Shadows/Cast Dynamic Shadows対応

デフォルトではリフレクションのシャドウキャスト設定はCast Shadowsフラグだけをチェックしていますが、RTXブランチではCast Static Shadows/Cast Dynamic Shadowsにも対応しています。
ただ、フラグに対応しているというだけで、静的/動的なメッシュにきちんと対応するわけではなく、この2つのフラグが落ちていたらシャドウを落とさない、という形になるだけです。

非対称ScreenPercentage

レイトレリフレクション/GIではScreenPercentage設定が存在しますが、この設定は細かく調整されているわけではなく100%(デフォルト)の後は50%、25%という順番で下がっていきます。
つまり、縦横が1/2、1/4という形でしか下がっていきません。

この修正では縦横比が変わる形での調整ができるようになっていて、70%では横だけが1/2になります。
50%だとどうしても汚くて困る、という場合に試してみると良いかもしれません。

Subsurfaceのバックフェースライトカリング

UE4本流では一部のシェーディングモデルにおいて、ライトの方向と法線方向が水平より下(つまり背面)になっている場合にシャドウレイの発射をキャンセルする機能があります。
DefaultLitでは特に問題ないようですが、Subsurfaceでは陰影のエッジが非常に汚くなってしまいます。
r.RayTracing.Shadow.CullTransmissivesを利用すると正しくシャドウレイを飛ばすようになり、陰影のエッジが綺麗になります。

f:id:monsho:20201122114505p:plain

Debugging & Visualization Features

デバッグ用の機能追加です。

BVHの視覚化

ShowFlag.VisualizeBVHComplexity/VisualizeBVHOverlapを利用してBVHの複雑さを視覚化出来ます。
レイトレーシングではオブジェクトやポリゴンが重なり合っている部分では処理負荷が高くなる傾向がありますので、できる限り分散して配置した方が有利です。
この機能を使って負荷が高い場所、つまり重なりが複雑な部分をチェックしてパフォーマンス改善に役立てることが出来ます。

f:id:monsho:20201122120758p:plain

レイトレーシング負荷の視覚化

ShowFlag.VisualizeRayTimingを利用してレイトレーシング自体の負荷を確認することが出来ます。
レイトレは様々な要素がパフォーマンスに複雑に関わってくるため、この視覚化はマテリアルの複雑性のみを視覚化しているわけではないことに注意してください。
また、レイの反射方向などによって結果が大きく変わるためか、かなりノイジーです。
しかし、明確に重い部分はわかりやすいので、最適化の指針としては十分使えるでしょう。

f:id:monsho:20201122121941p:plain

Miscellaneous Features & Fixes

その他の機能です。

半透明マテリアルのシャドウ対応

UE4本流では半透明マテリアルもシャドウを落とす設定になっています。
オブジェクト単位、マテリアル単位でシャドウキャストフラグを操作する方法ももちろんありますが、r.RayTracing.ExcludeTranslucentsFromShadowsを利用することで一括で半透明マテリアルのシャドウを削除できます。

ただ、エディタ上でON/OFFした場合、何故か即時反映はされず、メッシュのCast ShadowフラグをON/OFFし直したらそのメッシュだけ適用されるという状態になりました。
不具合なのか仕様なのかは不明ですが、やはり明示的にマテリアル側で指定するほうが良いでしょう。

シャドウの遮蔽面の統一

レイトレシャドウなどの遮蔽はデフォルトで表面、裏面ともにシャドウを落とします。これはr.RayTracing.Shadows.EnableTwoSidedGeometryをOFFにすることで片面のみシャドウを落とすようにすることが出来ます。
しかしこのシャドウを落とす面がシャドウマップとレイトレで逆になっているという問題があります。

f:id:monsho:20201122124629p:plain

r.RayTracing.OcclusionCullDirectionをONにすることで、この逆転現象を解消することが出来ます。

f:id:monsho:20201122124759p:plain

メッシュが閉塞されている場合は意味がない機能ではあるのですが、時折ペラ1枚の書き割りなどを利用することがあったりします。
このような場合で両面シャドウで代用できない場合には有効な機能ですが、かなり使用場面は限定されるのではないかと思います。

さいごに

先日ぷちコンゲームジャムでレイトレ半透明を利用してレンズ越しにのみ表示されるマテリアルという特殊な環境を作ってみました。
この際にRayTracingQualitySwitchReplaceを利用したのですが、OpacityMaskに利用したところ半透明越しじゃなくても表示されてしまうという不具合にぶつかりました。
この理由が普通に半透明部分以外もレイトレして、普通にライティング計算しているからだったわけなのですが、エンジン側のシェーダを修正して対応しました。

その後、この記事を書いていて気づいた。

RTXブランチの半透明マスキング使えばエンジン改造しないで済んだじゃん!

NVIDIA様、さすがでございます。

明日はUE4でアニメーションといえばこの人、”無敵の龍”ほげたつさんのControl Rigの記事です。 お楽しみに!