拙訳
Tiled Rendering
- スクリーンを区切るタイルに合わせた錐台における深度の最小最大値を求める
- タイルごとに、範囲内に入るライトをリスト化する
Depth Bounds
- AtomicなMinとMaxで深度範囲を求める方法はあまり効率的ではない
- Parallel Reductionアルゴリズムを使う
- wave全体で並列に計算して、結果を左側に集めていく
- パスを分ける必要があるので、結果はUAVに書き込む
if (tid < 32) {
depth[tid] = min(depth[tid], depth[tid + 32]);
depth[tid] = min(depth[tid], depth[tid + 16]);
depth[tid] = min(depth[tid], depth[tid + 8]);
depth[tid] = min(depth[tid], depth[tid + 4]);
depth[tid] = min(depth[tid], depth[tid + 2]);
depth[tid] = min(depth[tid], depth[tid + 1]);
}訳注
- 上記のコードは、データレースを回避するため、前の結果を受け取る前にメモリバリアが必要になるかもしれない
- groupが複数のwaveに跨がらなければ、メモリバリアを書かなくても問題ないらしい
- シェーダモデル6.0からはwave intrinsicsを使って同様のことができる
Light Culling
- 錐台と球の交差判定をAABBと球の交差判定で近似する
- [Arvo 1990Arvo, J. 1990. A simple method for box-sphere intersection testing. Graphics gems 335–339.]
bool TestSphereVsAABB(float3 sphereCenter, float sphereRadius, float3 AABBCenter, float3 AABBHalfSize) {
float3 delta = max(0, abs(AABBCenter - sphereCenter) - AABBHalfSize);
float destSq = dot(delta, delta);
return distSq <= sphereRadius * sphereRadius;
}- スポットライトの境界球はピッタリと包むようにする
- 原点を球の中心にしたりしない
Depth Discontinuities
- 深度の最大最小値が大きいと、どのジオメトリも照らさないライトが含まれてしまう
- 2.5D Culling [Harada 2012Harada, T. 2012. A 2.5D Culling for Forward+. Technical Briefs. ACM SIGGRAPH Asia. 10.1145/2407746.2407764. https://www.slideshare.net/slideshow/a-25d-culling-for-forward-siggraph-asia-2012/34909590.]
- 奥行方向に分割した錐台との交差判定結果をビットマスクに格納する
- ジオメトリとライトが同じ範囲内に存在するかを調べるにはビットマスクのANDを取る
- HalfZ
- 深度範囲の前半分と後半分のそれぞれでライトリストを作る
- Modified HalfZ
- 前半分と後ろ半分のそれぞれで深度範囲を計算し、それぞれでライトリストを作る
Clustered Rendering
- スクリーンを区切るタイルに合わせた錐台を奥行方向にも分割する
- 奥行方向は指数関数的に分割する
- 遠方のライトはフェードアウトさせて、グレアに置き換えたり、焼き込んでおいたりする
Light Culling
- ビュー空間の錐台で判定を行う方が良い
- グリッドではないので、AABBは最適とはいえない
- 視錐台との判定の後で、AABBとの判定をやれたらやる
VRAM Usage
- 16x16ピクセルのタイルで32スライスの場合、512個のライトを納めるには:
- 4Kだと、幅240 * 高さ135 * 個数512 * sizeof(uint16_t) * 32スライスで約1GB
- 流石に大きすぎるので、節約する方法を考えたい
- CPUでカリングする方法:
- GPUで生成されるライトには対処できない
- GPUでカリングする方法:
- タイルごとに(最大ライト数 * “safety factor”)だけで済む
- 粗いグリッドを使う方法:
- タイルサイズを64x64ピクセルにすると、16x16とくらべて1/8になる