ポストプロセス - 非数または無限の値の伝播
非数 (NaN) および無限 (Inf) の値は、シェーダー操作で未定義の結果が出た際に発生します。視覚的には、真っ黒または真っ白なピクセルとして表示されます。
NaN/Inf を生じさせる操作例は以下の通りです。
- 平方根 (sqrt) または対数 (log/log2) をマイナス値で実行すると NaN が発生します。
- A が無限または B が 0 のモジュロ演算、A % B を実行すると NaN が発生します。
- いずれかの数字を 0 で割ると Inf が発生します (あるベクトルを長さ 0 で正規化するなど)。
シェーダー操作とは別に、初期化されていないメモリーも NaN または Inf が含まれたり生成されたりします。プラットフォームの中には、新たに作成された レンダーテクスチャ 状のピクセル値が、0 の値では初期化されないものがあります。つまり、書き込んだり消去する前に新しい Render Textures にアクセスすると、NaN/Inf が生成される場合があるということになります。一般的なルールとして、 Render Textures を常に消去してから使うか、読みたいすべての値に書き込みを行ってから読むようにしてください。
NaN/Inf の伝播
NaN または Inf を被作用子として持つ演算も、結果として NaN/Inf を生み出します。これは、HDRP が行うフィルタリングやブラー処理に NaN/Inf 値が含まれていると、無効な値がさらに広がってしまうため、HD レンダーパイプライン (High Definition Render Pipeline、HDRP) において非常に重要となります。
ブルーム が黒い画面を生成するという HDRP の問題は、頻繁に報告されます。ブルームエフェクトは NaN/Inf そのものを生み出すことはありませんが、画面一体で生成される NaN/Inf を広げてしまいます。これはブルームを計算するために HDRP がシーンをダウンサンプル/フィルタリングしてから希望する解像度にアップサンプルして戻すためです。画面に 1 つ NaN/Inf があると、ダウンサンプルプロセスにより、テクスチャ全体をカバーするまで無効な値を広げてしまい、その後アップサンプリングには NaN 値のみが含まれるため、全画面が黒くなってしまいます。
HDRP がブルームを計算する際に、マテリアル問題によって生じた NaN がシーン全体に広がる様子を以下に例として挙げます。
HDRP が スクリーンスペースリフレクション、スクリーンスペース屈折、および歪みなどの機能が使う、カラーピラミッドを生成する際に、同様の問題が起こります。
ブルームを無効にして黒い画面が解消された場合、黒い画面の原因は、実際には視認できない単一の NaN/Inf ピクセルが存在しており、ブルームがそれを画面全体に伝播させたためと考えられます。これはブルームが無効な値を作成したからでは ありません。
NaN と無数の修正
ブルームやその他の HDRP 機能が NaN/Inf 値を伝播しないようにする最善策は、NaN/Inf 値のソースを修復することです。この方法は、NaN と Inf を見つける を参照してください。
NaN/Inf 値のソースを修復できない場合は、HDRP カメラ に NaN and Inf 値を黒いピクセルで置き換える機能が含まれています。これはブルームなどのエフェクトが NaN and Inf 値を伝播するのを制止しますが、かなりリソース負荷の高いプロセスです。この機能を有効にするには、Camera を選択し、Inspector で Stop NaNs のチェックボックスをオンにします。こちらは NaN/Inf 値の根本的な原因を修復できない場合にのみ使用してください。
NaN と Inf を見つける
NaN/Inf の根本的な原因を見つけるために、HDRP には NaN/Inf を含むピクセルを判別できる色で表示する、デバッグモードが含まれています。このデバッグモードを使うには、
- Render Pipeline Debug ウィンドウを開きます (メニュー: Window > Render Pipeline > Render Pipeline Debug)。
- Rendering へ移動し、Fullscreen Debug Mode を NanTracker に設定します。
これは画面上で実際に NaN/Inf が存在し、どのマテリアルが原因であるかを確認するのに便利です。ただし、どのドローコールが問題を起こしたかなど、より詳細な情報が必要な場合は、RenderDoc などのフレームデバッグツールを使ってください。Unity で RenderDoc を使ってフレームをキャプチャする方法については、RenderDoc 統合 を参照してください。
NaN を引き起こすよくある状況としては、ゼロベクトルに等しい法線など、明確に定義されていない法線を使用してメッシュがインポートされた時などが挙げられます。 これらの法線を見つけるために、Render Pipeline Debug ウィンドウの Material パネル 内にある、法線可視化モードを使うことができます。
RenderDoc
フレームをキャプチャした後、RenderDoc は NaN/Inf 値を持つピクセルを赤い色で表示します。これは HDRP が無効値に対してレンダリングする、標準の白黒ピクセルよりもはるかに見やすいため、NaN/Inf 値を見つけるのに役立ちます。手順としては、Texture Viewer で Overlay ドロップダウンを開き、NaN/Inf/-ve Display オプションをクリックします。
これで NaN/Inf 値が見やすくなるため、検索を開始できます。NaN/Inf 値がまだ不鮮明な場合は、ブルームディスパッチを確認し、ブルームが NaN/Inf ピクセルをどこから伝播しているのかを見つけて、問題を引き起こしているピクセルを特定してください。NaN/Inf の伝播 セクションにある画像例を見ると、ブルームがどのように NaN/Inf 値を拡大しているかによって、ソースがスフィアのマテリアル上で画面中央付近にあることを確認できます。
どのマテリアル/シェーダーが NaN/Inf を生じさせているかを発見したら、今度はデバッグを行い、どの操作が無効値を発生させているのかを特定します。