[Drobot 2017Drobot, M. 2017. Rendering of Call of Duty: Infinite Warfare. Digital Dragons. https://research.activision.com/publications/archives/rendering-of-call-of-dutyinfinite-warfare . ]
url
Voxel Tree#
ワールドスペース八分木。
遮蔽を含めて事前計算する。
ライトは影付けされ、影響のある範囲だけが含まれる。
事前計算/キャッシュされた錐台外の3Dルックアップが簡単にできる。
動的反射プロブのライト、動的ライトマップされたパーティクル、四面体GIライトグリッドで使われる。
高価な走査。
階層の走査の必要性、複数のキャッシュミス、間接読み出し。
非同期コンピュートが良い候補となる。
重大な事前計算時間。
リーフのペイロード。
ライト。
ライトグリッドキャッシングのためのルート。
可視性。
色は各ピクセルにヒットするライトの量を表す。
各ボクセルは事前にカリングされたライトを格納する。
Frustum Space#
タイルベースビットマスク。
8x8のピクセルサイズ。
不透明ジオメトリで使われる。
クラスタベースビットマスク。
ボリューム換算で4x4x4のカーネルと一致するサイズ。
160/4 * 90/4 * 128/4 = 40x25x32 @ 1080p
不透明ジオメトリとボリューメトリックスで使われる。
アイテムはビット列でインデックス付けされる。
ライト。
反射プロブ。
密度ボリューム。
デカール[Sousa and Geffroy 2016Sousa, T. and Geffroy, J. 2016. The Devil is in the Details: idTech 666. Advances in Real-Time Rendering in Games course . ACM SIGGRAPH. https://advances.realtimerendering.com/s2016/ . ] 。
Smodels / Xmodels#
静的モデルと動的モデル。
標準のゲームエンジンメッシュと似ている。
小道具《 props 》 、キャラクター、車両、武器、などで使われる。
BSP#
放射状ブラシベースのジオメトリ。
| 大雑把に示された《 blocking out 》 レベル。
地形《 terrain 》 。
環境の静的な構造部分。
個々のマテリアルを持つ複数のブラシは最適化されたサブメッシュとサブシェーダに一緒にマージされる。
高いパフォーマンスで世界のユニークなディティール付けを可能にする。
テッセレーションとディスプレースメントマッピングをサポートする。
ベースBSPは物理やAIのレイキャストにふさわしい。
単純なジオメトリで、イテレーションが簡単。
Tessellation & Displacement#
ベースBSPは適応型テッセレーションとディスプレースメントマッピングを適用できる。
適応型テッセレーションはディスプレースメントデルタ、カメラへの距離、カメラへのパッチ角度に基づく。
生成されたサブパッチはGPUで錐台、オクルージョン、背面のかリングを通る。
テッセレーションとディスプレースメントは適度な適応的パフォーマンスヒットで大きなビジュアル的インパクトを作る。
ESM Shadow Map Cache : Motivation#
テッセレーションしたジオメトリはシャドウマップレンダリングでは高価になる。
大多数のライトは| 動かない《 stationary 》 。
多くのライト。
多くのシャドウ。
ESM Shadow Map Cache#
PCFはF+では高価すぎる(VGPRプレッシャー)。
静的で高品質な影付けされたライト と キャッシング を重要視。
指数シャドウマップ
512x512の16ビットUNORM。
1024x1024のシャドウマップからダウンサンプリングした。
3x3のガウスフィルタをかける。
一度だけ事前にフィルタリングして、キャッシュする。
Caching algorithm#
ビューごとにシャドウマップを要求する。
カリングテストを通過したビューで見えているすべてのシャドウマップを得る。
更新の必要がない シャドウマップの| 古くなった《 Stale 》 キャッシュをチェックする。
ライトがStaleキャッシュに| ある《 resident 》 か?
最後のフレームでライトが移動したか?
最後のフレームでライト錐台内で何かが移動したか?
更新が強制されたか?
4から8つの最も重要なシャドウマップを選び出す。
優先順位でソートする。
アーティスト駆動の優先順位(プレイヤーのフラッシュライトなど)。
距離、射影サイズ、強度。
選んだライトごとに、
シャドウマップのStaleキャッシュをチェックする --- Staticキャッシュは実際には静的ジオメトリのみを含むD16のシャドウマップを持つ。
ライトがStaticキャッシュにキャッシュされている場合、
Staticキャッシュから静的シャドウマップをActiveキャッシュにコピーする。
ライトがStaticキャッシュにキャッシュされていない 場合、
静的ジオメトリをActiveキャッシュにレンダリングする。
静的ジオメトリのシャドウマップをStaticキャッシュにコピーする。
動的ジオメトリをActiveシャドウマップにレンダリングする --- Activeキャッシュは4から8つのD16シャドウマップである。
技術的には、必要なのは1つだけだが、実際のシャドウマップのレンダリングでは、シャドウキャッシュシステムから複数の非同期コンピュートジョブがオーバーラップする(つまり、コピーして、ESMフィルタリングして、ダウンサンプリングして、クリアする)。そして、シャドウマップ0のCSジョブはシャドウマップ1のレンダリングとオーバーラップさせる。
ActiveシャドウマップをStaleキャッシュにコピーしてESM処理する。
キャッシュのコピーやESMジョブは非同期コンピュートを使う。
‘次’のシャドウマップ生成処理とオーバーラップする。
平均のリアルコスト:レンダリングを除いたシャドウマップあたり0.1ms以下。
Forward+ではサンプリングコストが下がる。
ALUは完全に償却される。
レジスタ(VGPR)インパクトがない。
Deferred Sun Shadows#
以下では高品質なシャドウが必要である。
複数の高解像度のオブジェクトスペースのシャドウマップが必要である。
標準のシャドウマップキャッシュではプレッシャーが強すぎる。
スクリーンスペースシャドウ。
太陽のみのディファードパス。
ビューモデルに最適化される(深度境界/ステンシルテスト)。
シーン全体で実行すると、うまく働く。
SS Shadows#
F+に統合される。
ピクセルごとの一番強い光源を格納する。
キーライトとしてアーティストにより設定されたり、最大値として実行時計算から導いたりする。
キーライト方向に単一のトレースを行う。
Particle Lighting with lightmaps#
各quadは自動的に1x1から32x32のライトマップタイルに割り当てる。
解像度は射影されるスクリーンスペースのquadサイズに依存する。
各テクセルごとに、
各サンプリングポイントの位置を格納する。
CSはアンビエントの寄与のライトグリッドをサンプリングする。
CS主体のライティング。
ワールドスペースのボクセルツリー。
サンプリングポイントは錐台境界の外にすることができる。
RGB SH1として変換して格納する。
Deferred Lightmap#
512x512のRGBのFP11_11_10
3つの512x512のRGBAのFP16_16_16_16
ディレクショナルライティング。
RGB x SH1として格納される(RGBAに係数4つが格納される)。
法線マップを持つ複雑なパーティクル。
法線マッピングされたパーティクルはF+を通したスペキュラ反射をサポートする。
以下をサポートする。
VFX impact marks
デカールメッシュ。
Simple Lit Particles#
全方向ライティングを伴う単純に照らされたパーティクル。
複雑なラティングシナリオ。
明るい天球ライティングと反対の色調を持つ強い太陽光。
合わさって、平坦なレンダリングになる。
No Scattering#
スクリーン上のパーティクルとアンダーサンプリングの結果によるライトマップのテクセルサイズとの間の相対的なサイズの違いのためにブロックのような拡大アーティファクトが発生する可能性がある。
ライトのマルチスキャッタリングが失われている(ライトマップは主要なスキャッタリングのみを格納する)。
これらの問題はライトマップスキャッタリングパスで改善できる。
Scattering#
ライトマップライティングスキャッタリング。
各タイルごとに、
CSスキャッタリングぱす。
スキャッタリングをシミュレートするためにブラ―をかける。
アンチエイリアシングのための逆トーンマッピング。
CSでパッキングして、最も高い占有率に対するタイルサイズでソートする。
加えて、(または、スキャッタリングの代わりに、)パーティクルをレンダリングしている間に高価なキュービックフィルタリングを実装する。
パーティクルのレンダリングごとに最大10%遅くなる。
出荷しなかった。
Particle Lighting : Performance#
すべての処理は非同期コンピュートを利用している。
ほとんどの場合、非透明ジオメトリパス上で償却される。
RGB SH1 512 CS Job 時間[ms] @ PS4 ライティング 0.1〜0.7 スキャッタリング 0.1
Multi-Res Rendering#
密なVFXは著しいオーバードローをもたらす --- 最適化する必要がある。
VFXチームはソートを’そのまま《 as is 》 ’にしておくことを望んでいた。
クラシックな低解像度レンダリングはレンダリング中に注入されるマージパスを必要とする。
ソート順が変化する/複雑化する。
MSAAベースのマルチ解像度レンダリングパイプライン。
レンダリングを’そのまま’にしておくことを可能にする。
個別のエフェクト/マテリアルに’低解像度レンダリング’のためのタグを付けることができる。
現時点ではコンソールのみ(MSAA拡張のIHVサポート待ち)。
Multi-Res Algorithm#
4xMSAAのハーフ解像度のバッファとしてエイリアスされたフレームバッファにレンダリングする。
事前乗算アルファレンダリングを使う。
使うMSAAレベルを描画ごとに決める。
1サンプル => フル解像度の深度テストを伴うハーフ解像度レンダリング。
4サンプル => フル解像度レンダリング。
PSは正しい再構築手法をえらぶためにFMask[Drobot 2014Drobot, M. 2014. Hybrid reconstruction anti-aliasing. Advances in Real-Time Rendering in Games course . ACM SIGGRAPH. https://advances.realtimerendering.com/s2014/drobot/HRAA_notes_final.pdf . ] を読み出す。
すべてのサブサンプルを読み出す。
バイリニアでサンプル0をアップサンプリングする。
メインバッファに合成する。
GCNのレンダターゲットフォーマットは直接のエイリアシングを妨げる。したがって、実際にはCSでデプスバッファを手動で再書き込みと再swizzleを行う必要がある。
このステップは他の深度関連の処理で償却される。
Color Buffer FMask#
ジオメトリのエッジが複数サンプルでマークされていることに注目する。
灰 -> 1サンプル。ブレンディングのためにCMaskに触る。
青/緑 -> 2/3サンプル。深度交差のためにラスタライザに渡される。
赤 -> 4サンプル。フル解像度レンダリング、または、すべてのサブサンプルが深度交差ヒット。
Alpha Buffer FMask#
ジオメトリのエッジが複数サンプルでマークされていることに注目する。
異なるブレンドモードの可能性があるため、色のFMaskとの違いにも注目する。
Dilated Combined Compacted FMask Buffer#
コンパクト化されたFMASK。
カラーのFmask > 0 || アルファのFmask > 0
16ビットバッファにパッキングされる --- ピクセルあたり16個のブール値。
FMask/CMask --- 色とアルファで異なることができる。
ブレンドモードセットアップとハードウェアセットアップに依存する。
アルファブレンド。
加算。
高速ブレンドモード(ハードウェア固有)。
Full Res Glass : 1.3ms#
プレイヤーのヘルメット、バイザー、車両のフロントガラス《 windshield 》 といった、フル解像度の透明物はとても高価になる可能性がある。
Multi Res Glass : 0.4ms#
レンダラは透明物と通常のメッシュの解像度を混ぜることができる。
車両のフロントガラス。
ガラス。
重大なパフォーマンス改善(1.3ms -> 0.4ms)。
質の劣化 --- 主にガラスの傷のような高周波で詳細が見える。
Multi-Res Issues#
‘ポイントサンプルされたビジュアル’になる可能性がある。
低解像度のピクセルは単一の色サンプルとして格納される。
ブレンディングはレンダリング中にハードウェアで起こる。
多いサンプルでのブレンディングが必要とするならば、ブレンダーは少ないサンプルを複製する。
サンプル0に対してのみ実行した場合、ピクセルごとのシェーディングはエイリアシングを含むことがある。
問題を和らげるためテンポラルディザリングを使う。
| 色ビット深度《 color bit-depth 》 の問題に役立つ。
Low Res Effect Seen Through Low Res Grass | Low Res Effect Seen Through High Res Grass#
ピクセルの失敗ケース:
低解像度の描画をレンダリングする --- サンプル0(火のエフェクト)を書き込む。
FMaskが1サンプルにセットされる --- まだバイリニアでアップサンプリングできる。
高解像度の描画をブレンドしてレンダリングする --- サンプル0をソースとして複製して、サンプルごとにブレンドする(火のエフェクトの前のガラス)。
FMaskが1サンプル以上にセットされる --- バイリニアでアップサンプリングできない。
3から3.8倍の低解像度のタグ付けされたマテリアルによるパフォーマンススケーリング。
分散は以下に依存する。
レンダターゲットのマイクロタイルのヒット量。
スクリーン上でのフル解像度と低解像度のパーティクル間のオーバーラップ。
高速ブレンド/MSAA帯域幅の利点はMRTマイクロタイルが伸長のタグが付けられる == フル解像度レンダリングが発生するとすぐに失われる。
常にピクセル処理が少ない。
0.3から0.4msのアップサンプリング/解決/再構築パス。
分散はすべてのサブサンプルを必要とするマイクロタイルの量に起因する。
燃費《 mileage 》 はGPUのMSAA効率に依存して変化する。
Multi-Frequency Rendering : R & D#
8xMSAAでの実験。
1、2、4、8サンプルが可能。
テンポラルスーパーサンプリングを伴う結合《 conjunction 》 でサンプルパターンを変化する。
OITに基づくテンポラル確率的MSAA。
MFRを用いて不透明シーンをレンダリングする。
キャラクターといった、高解像度で関心のあるオブジェクトを選び取る。
重要性の低いオブジェクトでサンプルカウントを無作為に変化する。
Reflections & Refractions#
反射プロブは一級市民である。
静的にも動的にも統一的な方法ですべてのジオメトリにF+を通して適用される。
| 箱射影された反射プロブ《 Box Projected Reflection Probs 》
オブジェクトスペースまたはワールドスペースで可能。
オブジェクトと一緒に移動と回転する --- 輸送機《 dropship 》 の内部。
さまざまな優先順位でネストできる。
GPUのGGXフィルタで畳み込まれる。
XYZブレンドゾーン。
64x128x128のBC6テクスチャのキューブ配列として格納される。
ピクセルごとに任意のプロブ数のブレンディングが可能。
反射プロブボリュームごとに定義されるXYZブレンド領域をサポートする。
画像はオーバーラップする反射プロブとその重みを示している。
画像はキューブマップオーバーラップの効果的なカリング後の領域を示している。
Reflection Probes#
CSのGPUカリング: 分離軸理論《 Separating Axis Theorem 》 。
ビューに最大64個のキューブマップ。
32x24x48 x 64ビット。
毎ピクセル: PS内の追加のカリングステップ。
コストは非同期コンピュートパイプラインで完全に償却される。
シェーダ 時間[ms] @ PS4 32x24x48の平均オープンシーンでの64個の反射プロブのSATカリング 0.185
Relightable Reflection Probes#
ベイク中 --- パックされたキューブマップGバッファを生成する。
組み合わせたアルベド+スペキュラ。
深度。
法線。
エミッシブ/ベースアンビエントライティング。
マップのひとつは、| ライトがひとつもない状態《 full blackout situation 》 を含めた、任意の動的ライト数の動的順列を必要とした。
反射プロブが隣の部屋への連続的なライト変化にどのように反応するかを見ることができる。
天井での銃に備え付けられたライトの反射とその反射プロブに注目。
キャラクターが動くと、リアルタイムで反射が更新したのが分かる。
レンダラは1フレームにプロブを1つ更新する。
すべての処理は非同期コンピュートを利用する。
128x128キューブマップでのコンピュート処理 時間[ms] @ PS4 再ライティング(動的ライト数に依存) 0.1-0.2 全MIPのフィルタリング 0.31 全MIPのBC6圧縮 0.18
Local directional normalization# [Lazarov 2013Lazarov, D. 2013. Getting More Physical in Call of Duty: Black Ops II. Physically Based Shading in Theory and Practice course . ACM SIGGRAPH. https://blog.selfshadow.com/publications/s2013-shading-course/ . ]
localNormalization = Luma ( GetSHLightgrid (worldPos, reflectionDIr)); // refDir方向でGIのSH2を評価する。
probeNormalization = GetProbeNormalization (probeIdx, sampleDir); // sampleDir方向でプロブのSH2を評価する。
normalizationFactor = localNormalization / probeNormalization;
result *= normalizationFactor; // 局所化されたライティングデータに反射を合わせる。 Copy
ライトグリットSHによる局所的方向正規化。
生成時の各プロブは自身のSH輝度を格納する。
フィルタリング処理中に再ライティング可能なプロブはSH輝度を計算する。
ライトグリッド輝度SH値はシェーディング中にGIのためにすでにサンプルされたデータからスペキュラ反射の方向で評価される。
サンプルされた反射プロブのデータは評価されたライトグリッド値に合うようにスケールされる。
Probe Only#
エアダクトの金色のフォイルが不均等に照らされていることに注目。コンソールでも同様。
Probes + LG+ Normalization#
局所的正規化により、シーンの統合がより改善される。
再ライティング可能な反射プロブはさらなる利点を持つ。
すでに各プロブでSH2のアンビエント寄与を計算して正規化で使った。
再ライティング可能な反射プロブはさらなる利点を持つ。
正規化で使ったSH2のアンビエント寄与を再利用する。
動的アンビエントライティングのSH2データでライトグリッドを上書きできる。
粗い動的GI。
プロブは移動するオブジェクトや影響のある環境にアタッチできる。
局所化された動的GIを伴う移動する車両の中のプロブを使うことができる。
反射プロブに基づく粗い動的GI。
プロブからアンビエント項(ライトマップ/ライトグリッド)へデルタライトSH2を追加する。
粗い動的GIの他の視点。無効化した場合。
粗い動的GIの他の視点。有効化した場合。
Probe Assignment#
すべての単一のピクセルは少なくとも1つの反射プロブをサンプルする。
Probe Assignment w/ low gloss optimization#
低光沢表面に対する反射プロブのLOD最適化。
あるしきい値で反射プロブのルックアップをスキップする(ラフネスが0.1より小さい)。
ライトグリッドデータからスペキュラを導く(evalSH(reflectionDir))。
遷移しきい値で反射プロブをブレンドする。
最大平均0.5msの節約(キューブマップの低MIPのフィルタリングはキューブのWRAPフィルタリングモードを使うと本当に高価である --- どんなことをしてでも避けたい)。
画像は様々なラフネスの金属マテリアルの大多数を持つシーンを表す。
Screen Space Reflections / Refractions#
トーンマップの解決に先立ってシーンのMIPチェーンを生成する。
MIPをキューブマップと同様の光沢BRDFに合わせるためにBRDFスクリーンスペースフィルタを使う。
前のフレームのMIPチェーンを再投影する。
反射。
箱射影反射プロブからの交差を再利用する。
追加のトレーシングを必要としない。
マテリアルの光沢やレイの長さに基づいてMIPを選び取る。
反射は箱投影が一致すればするほど良くなる。
すべて混ざって一緒に動作するテクニックを表している。
箱投影された反射プロブ。
再ライティング可能な反射プロブ。
箱投影されたスクリーンスペース反射。
屈折。
深度ピラミッドをサンプルする。
表面のラフネスに基づいてMIPを選び取る。
アンダーサンプリングを隠すためにジッタリング/ディザリングしたサンプリングを用いる。
深度のヒットポイントへのレイの長さにより2Dでレイを射影する。
レイの長さとマテリアルの光沢に基づくシーンMIPを選び取る。
2つの屈折を解決する:
くもりガラスからプラスチックのカーテンまでの範囲の複数の表面で使われる。
武器アーティストとユーザは、スクリーンスペースの光沢反射を用いた半透明《 semi-translucent 》 部品を通して見える内部武器パーツの動作を見ることを愛している。
シェーダ 時間[ms] @ PS4 @ 1080p シーンMIP生成 0.25 フルシーンSS反射表面 +0.3 フルシーンSS屈折表面 +0.5
完全なトレースによる手法と比べてとても安価である。
Volumetric Renderer#
ボリューメトリクスはCoD:IWのルックの重要な部分であった。これなしでは出荷できなかっただろうし、品質設定として使うこともできなかっただろう。
Ambient Lightgrid + Volumetrics#
静的ライティングとGIはライトグリッドを再サンプルする。
Primary Lights + Ambient Lightgrid + Volumetrics#
すべてのライトタイプをサポートする。
静的/アンビエントライト。
動的ライト。
シーンレンダリングの一元的なコード経路を使って評価する。
安定化のためのテンポラルリプロジェクション。
Density Volumes with High Irradiance#
アーティストは局所化された密度(フォグ)ボリュームを手動で配置できる。
各密度ボリュームは以下を持つ。
ワールドスペースのバウンディングボックス
ベースとなる密度
照度
スクリーンショットは高照度の密度ボリュームのレンダリングを示す。
Density Volumes and sun interaction#
マップにフォグを’局所化’するために使われる。
グローバルのフォグ設定に影響を与えないので、しばしばインテリアに配置される。
スクリーンショットは様々な密度の太陽に照らされる密度ボリュームを示す。
密度は最大4つの軸に平行な射影テクスチャでマスクすることができる。
UVスクロールでアニメーションする(膝高さフォグをアニメーションさせる)。
スクリーンショットはさまざまな密度ボリュームを生成するために使われる複数のテクスチャを示す。
Clustered Density Volumes#
クラスタリングのCS処理。
4x4x4のメインCSカーネルにマッチするクラスタ。
錐台内で密度ボリュームをインデックスする最大256ビット。
スクリーンショットは密度ボリュームのクラスタ化した視点を示す。
Volumetrics Only#
ボリューメトリックレンダリングにより低周波なビジュアルが提供される。
Particles Only#
照らされるパーティクルにより高周波なビジュアルが提供される。
Combined#
ブレンディングはボリューメトリクスの3D特徴のためにシームレスである。
不透明/透明は統合されたin-scatter光と統合されたextinctionを伴って3Dテクスチャを単にサンプルする。
Initial Implementation#
複数の順次CS処理。
密度の注入。
スカラ化で最適化されたCS : 4x4x4スレッドカーネルで実行する。
クラスタ化した密度ボリュームバッファから単一のフロクセルサイズを一致させる。
書き込む(密度バッファ)。
ライティングパス。
スカラ化で最適化されたCS : (4x4x4スレッドカーネル)。
クラスタ化されたライトバッファから単一のフロクセルサイズを一致させる。
読み込む(密度バッファ) / 書き込む(In-scatterバッファ / Extinctionバッファ)。
積分パス。
Zスライスで反復する(8x8x1スレッドカーネル)。
スキャッタリングとextinctionを足し合わせる。
読み込む(In-scatterバッファ / Extinctionバッファ) / 書き込む(統合したIn-scatter / 統合したExtinctionバッファ)。
Volumetric Renderer : Initial Implementation#
112x90x128
11_11_10F --- (5150KB) | In-scatterと積分バッファ。
16F --- (2580KB) | 密度とExtinctionバッファ。
各パスは帯域幅/レイテンシー限界であることを示す。
CS処理 コンスタントな読み書きの帯域幅 実行時間 VGPR 最適なカーネル 密度注入 5150KB ~0.4ms 36 4x4x4 ライティングパス 10310KB ~1.1ms 48 4x4x4 積分パス 15460KB ~0.5ms 42 8x8x1 総計 30920KB 2.0ms (ALUのみだと1.2ms)MAX(48)
各パスは帯域幅/レイテンシー限界であることを示す。
3Dテクスチャの読み書きは高レイテンシーである。
CS処理の読み書きパターンを一致させるためにタイルモードを選び取る。
TILE_MODE_1D_THIN -> スライスごとの読み書き(8x8x1)
TILE_MODE_1D_THICK -> 3Dブロックの読み書き(4x4x4)
帯域幅束縛。
より広いVGPRで動作する。
レイテンシー束縛。
冗長なメモリ転送を取り除く。
実験。
すべてのパスを48個のVGPRでキャップする。
パフォーマンスは変化しなかった。
依然としてレイテンシー束縛。
64個のVGPR(4 occupancy)を強制すると、帯域幅により20%のパフォーマンスロスが発生する。
最適な占有率である。
Optimized Implementation#
すべてのパスをマージする。
各パスは’コードブロック’として存在する。
すべての入力メモリ読み込みは帯域幅に最適化される。
書き込むだけ。
In-scatteringの積分。
Extinctionの積分。
スカラ化でカーネルサイズを一致させる必要がある。
4x4x4の3Dクラスタで動くためにすべてのブロックを切り替える。
TILE_MODE_1D_THICK
キャッシュ中で、グループ化したテクスチャはロードとストアを行う。
積分CSは4x4x4のグループで処理するために新しいアルゴリズムを必要とした。
Inclusive Prefix Sum
Lane Swizzleを使って実装した。
// 8x8x1の積分(XYZ順)
float accumulate = 0 ;
for (i = 0 ; i < sliceCount; i ++ ) {
accumulate += ReadData (xy, i);
} Copy // 4x4x4の積分(ZXY順)
float accumulate = 0 ;
uint lane = __XB_GetLaneID ();
bool laneMask0 = (lane >> 0 ) & 1 ;
bool laneMask1 = (lane >> 1 ) & 1 ;
for (i = 0 ; i < sliceCount; i ++ ) {
data = ReadData (xy, i);
// 包括的prefix-sum
sumData = data;
// スレッド: 4番 = 4番 + 3番、2番 = 2番 + 1番
addData0 = QuadSwizzle (sumData, 0 , 0 , 2 , 2 );
sumData += laneMask0 ? addData0 : 0.0 f ;
// スレッド: 4番 + 2番 = 3番 + 4番 + 1番 + 2番
addData1 = QuadSwizzle (sumData, 0 , 0 , 1 , 1 );
sumData += laneMask1 ? addData1 : 0.0 f ;
accumulate += sumData;
// 4番スレッドを1、2、3番にばらまく。
accumulate = GetLastLane (accumulate);
} Copy // GetLastLaneとQuadSwizzleはLaneSwizzleのマクロである。
// QuadSwizzle(v, n0, n1, n2, n3) --- レジスタVの1番、2番、3番、4番すべてのレーンで、1番をn0に、2番をn1に、3番をn2に、4番をn3のレーンにswizzleする。
// GetLastZLane(v) --- 各カーネルでの最後のレーンを返す(今回の場合は4番)。
#define __LANE_SWIZZLE_MASK ( _and , _or , _xor ) ((_and & 0x 1F ) << 0 ) | ((_or &
0x 1F ) << 5 ) | ((_xor & 0x 1F ) << 10 )
#define __QUAD_SWIZZLE_MASK ( _o0 , _o1 , _o2 , _o3 ) ((_o0 & 0x 3 ) << 0 ) | ((_o1
& 0x 3 ) << 2 ) | ((_o2 & 0x 3 ) << 4 ) | ((_o3 & 0x 3 ) << 6 ) | ( 0x 1 << 15 )
#define LaneSwizzle ( _x , _and , _or , _xor ) __LaneSwizzle (_x, __LANE_SWIZZLE_MASK (_and, _or, _xor))
#define QuadSwizzle ( _x , _o0 , _o1 , _o2 , _o3 ) __LaneSwizzle (_x, __QUAD_SWIZZLE_MASK (_o0, _o1, _o2, _o3)) Copy
いくつかのシェーダコンパイラはすぐにQuadSwizzle機能を提供する。
Volumetric Renderer : Final Implementation#
重要な最適化はこのテクニックが実行可能であることを可能にする。
CS処理 固定読み書き帯域幅 実行時間 コスト VGPR カーネル 複数パス 30920KB ~2.0ms 100% MAX(48) 混合 マージ 7730KB 1.2ms 60% 48 4x4x4
カスケードのサポート。
Zスライスは32個のスライスのディープカスケードに分割される。
各カスケードはランタイムで再構成できる線形範囲にマップする。
シェーダの並べ替えをサポート。
ビュー距離は問題だった。我々のビュー範囲は、細い通路、開けた景色、宇宙空間での戦闘の間を動的にスケールできる。
スライスの再構成は実行時に起こることがあり、トランジション、つまり、建物の中からに屋外へ出るときに役立つ。
ボリューメトリクスは、太陽のみ、ライトのみ、アンビエントのみ、又はその順列をサンプルできる、異なる最適化されたシェーダを選び取ることができる。これはあるシチュエーションで最大20%のパフォーマンスブーストをもたらす。
Texture Packer : Motivation#
ディスクとランタイムメモリは限られている。
アーティストに対するアセットパイプラインを複雑にしたくない。
以下は複数のテクスチャサンプルに向いていない。
増大するテクスチャ。
Core Texture Slots#
セマンティックスロット 圧縮タイプ バイト毎ピクセル ディフューズ(RGB)+アルファ(A) BC1 / BC3 0.5 / 1.0 スペキュラ(RGB)+光沢(A) BC3 1.0 法線(XY) BC5 1.0 遮蔽(A) BC4 0.5 Reveal(A) BC4 0.5 総計:4-5テクスチャサンプル 4.0-4.5
Additional Texture Slots#
セマンティックスロット 圧縮タイプ バイト毎ピクセル 厚さ BC4 0.5 吸収 BC1 0.5 蛍光 BC1 0.5 輝き(sheen)と布 BC1 0.5 異方性 BC7 1.0 Reveal BC4 0.5
Converter#
ルールセットに従ってテクスチャをパックする。
表現の間を変換する。
Specular ColorモデルからMetalnessモデルへ。
最適なデータ圧縮スキームを選び取る。
統計的なモーメントを計算する(X及びY上の1次、2次モーメント)。
さまざまな誤差尺度《 error metrics 》 を計算する。
データにマッチする最適な圧縮スキームを選び取るために誤差尺度を使う。
データに関係する尺度を選ぶ --- つまり、法線マップの標準偏差。
色の差分の代わり。
最適なテクスチャ圧縮フォーマットを選ぶ。
Diffuse#
SpecularモデルからMetalnessへのコンバータ。
SpecularとMetalnessのモデルの間を変換するために範囲のカーブを合わせる。
絶縁体の範囲について仮定する。
0.0-0.1の絶縁体 => 単色のスペキュラ。
0.1以上の誘電体 => 有色のす終えキュラ。
シェーダでの伸長処理はALUが5つのみ。
# #define INSULATOR_SPEC_RANGE 0.1 f
void DeriveMetalnessAndFusedAlbedoSpecMap (float3 albedo , float3 specular , out float3 fusedAlbedoSpec , out float metalness ) {
float nonmetal = ( 1.0 f / 3.0 f ) * (albedo.r + albedo.g + albedo.b);
float metal = ( 1.0 f / 3.0 f ) * (specular.r + specular.g + specular.b);
nonmetal = saturate (nonmetal, DATA_FORMAT_FP16_MIN_FLT);
float specE = saturate (metal - INSULATOR_SPEC_RANGE);
float specI = min (metal, INSULATOR_SPEC_RANGE);
metalness = specE / (specE + nonmetal);
fusedAlbedoSpec = ( saturate (specular - INSULATOR_SPEC_RANGE)) + albedo;
metalness = specI + ( 1. f - INSULATOR_SPEC_RANGE) * metalness;
} Copy void DeriveAlbedoAndSpec (float3 fusedAlbedoSpec , float metalness , out float3 albedo , out float3 specular ) {
float m = saturate (metalness, - INSULATOR_SPEC_RANGE);
m = m * ( 1.0 f / ( 1.0 f - INSULATOR_SPEC_RANGE));
float r0 = min (metalness, INSULATOR_SPEC_RANGE);
albedo = saturate ( 1.0 f - m) * fusedAlbedoSpec;
specular = r0 + m * (fusedAlbedoSpec);
} Copy
Data Analysis & Normal Maps#
半八面体法線マップ圧縮。[Cigolle et al. 2014Cigolle, Z. H., Donow, S., Evangelakos, D., Mara, M., McGuire, M. and Meyer, Q. 2014. A survey of efficient representations for independent unit vectors. Journal of Computer Graphics Techniques (JCGT) 3, 2, 1–30. https://jcgt.org/published/0003/02/01/ . ]
データ解析。
“ほぼ平坦”な法線マップに対して二次のスケーリングを使う。
法線ベクトルのスケーリング値はデータパイプラインで決定される。
// xは[-1, 1]の範囲
float EncodeSNormQuadraticScaling ( float x ) {
float sqrtX = sqrt ( abs (x));
return x > 0.0 f ? sqrtX : - sqrtX;
}
// xは[-1, 1]の範囲
float DencodeSNormQuadraticScaling ( float x ) {
float x2 = x * x;
return x > 0.0 f ? x2 : - x2;
} Copy
0.0の周りの二次スケーリング。
‘平坦な法線’にさらなる精度を与える。
Texture Packer#
第1セット(packed_CS) 第2セット(packed_NOG) 第3セット(packed_ART) R 融合したディフューズとスペキュラ色 グロス --- 分散と融合(コンバータにより生成される) アルファ G 融合したディフューズとスペキュラ色 法線X Reveal B 融合したディフューズとスペキュラ色 遮蔽 厚さ A Metalnessマスク(コンバータにより生成される) 法線Y
Packed Texture Sets#
最終的に変換したテクスチャ 圧縮タイプ バイト毎ピクセル CS(第1セット) BC7 1.0 NOG(第2セット) BC7 1.0 A/R/T<optional>(第3セット) BC4/BC1/BC7 0.0-1.0 総計:2-3テクスチャサンプル 2.0-3.0
セマンティックスロット 圧縮タイプ バイト毎ピクセル 総計:4-5テクスチャサンプル BC1-BC5 4.0-4.5
テクスチャサンプル節約率 メモリ節約率 50%-40% 50%-33%
Real world results#
モデルのテクスチャ節約率: 最大30%のメモリ。
BSP(静的マップジオメトリ/地形)節約率: 最大15-20%のメモリ。
シェーダパフォーマンス改善: 最大5%。
償却される起泡性フィルタリングレベル: 4xAF
マップ節約率の例:
PHStreets: 11Gb -> 9Gb = ~19%
Metropolis: 5Gb -> 4Gb = ~20%
現実世界の結果は理論データからはいくらか異なる。
あるケースではアートにより的供されるテクスチャ解像度のミスマッチのためパッキングを使えない。これはパッキングルールの曖昧さ故である。
Bonus Slides# Directional SH Occlusion Lightmap#
ディレクショナルSH1オクルージョンライトマップ。
高いメモリコスト。
追加の4チャンネルが必要。
2xBC5(質重視)か1xBC7(パフォーマンスとメモリ重視)
各’コーン’は格納されたSH1の係数から計算したベントコーンを表す。
出荷しなかった --- 将来の仕事のための準備はできている。
Probes + Directional SH Occlusion Lightmap#
部屋の隅近くの大幅な改善をみせる局所的なシャドウに注目。
// 半球八面体にパックする。
// +Zの半球で正規化された入力を仮定する。[-1, 1]を出力する。
void EncodeHemiOctaNormal ( const float3 v , inout float2 encV ) {
// 半球を半八面体へ射影し、XY平面に入れる。
float rcp_denom = 1.0 f / ( abs ( v [ 0 ]) + abs ( v [ 1 ]) + v [ 2 ]);
float tx = v [ 0 ] * rcp_denom;
float ty = v [ 1 ] * rcp_denom;
encV [ 0 ] = tx + ty;
encV [ 1 ] = tx - ty;
}
void DecodeHemiOctaNormal ( const float2 encV , inout float3 v ) {
// 単位スクエアを中心ダイアモンドに戻すように回転と拡大縮小する。
v [ 0 ] = ( encV [ 0 ] + encV [ 1 ]) * 0.5 f ;
v [ 1 ] = ( encV [ 0 ] - encV [ 1 ]) * 0.5 f ;
v [ 2 ] = 1.0 f - abs ( v [ 0 ]) - abs ( v [ 1 ]);
} Copy