FFXVI Shadow Part IV
正文
Part IV :Generate
第 4 阶段使用从原始延迟照明着色器导入的代码计算每个光源的每像素可见性。使用Early Light List buffer中 Shadow Tile 条目中的光源列表,我们迭代它们以使用 Percentage Closer Soft Shadows 生成阴影,但可以用任何其他技术替换它。
Output: VisibilityBuffer
此缓冲区包含 8x8 内存块,用于存储shadow tile的每像素光可见性。这是延迟阴影系统所需的最大中间缓冲区,一旦照明阶段完成,就可以在帧的其余部分丢弃(其他缓冲区也是如此)。每个像素使用 8 位来表示光可见度的百分比,但 4 位可能就足够了,具体取决于项目的需要。
’Generate Deferred Shadows’ compute shader pseudo code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| ByteAddressBuffer tTileShadowSlotIds ByteAddressBuffer tTileLightListEarly ; ByteAddressBuffer tTileLightCountEarly ; RWByteAddressBuffer rw_TileLightListFinal ; RWByteAddressBuffer rw_TileLightCountFinal ; RWByteAddressBuffer rw_TileLightVisibility ;
[ numthreads ( SHADOWTILE_SIZE , SHADOWTILE_SIZE , 1) ] void CS_Phase4_GenerateShadows ( uint inThreadIdx : SV_GroupIndex , uint2 inTileCoord : SV_GroupID , uint2 inPixelCoord : SV_DispatchThreadID ) { const uint tileIdx = GetTileIndex ( inTileCoord ) ; const uint shadowSlotID = tTileShadowSlotIds . Load ( tileIdx *4) ; const uint earlyLightCount = tTileLightCountEarly . Load ( tileIdx *4) ; const float depth = GetDepth ( inPixelCoord ) ; const float3 worldPos = GetWorldPosFromScreen ( inPixelCoord , depth ) ; const bool isValid = ! IsFar ( depth ) && all( inPixelCoord < cCommon . m_Resolution ) ;
uint finalLightCount = 0; uint entryIdx = 0; while ( entryIdx < earlyLightCount ) { uint lightIdx = GetNextEarlyLight ( shadowSlotID , entryIdx ) ;
float viz = ComputeLightVisibility ( lightIdx , worldPos ) ; bool isAllLit = WaveActiveAllTrue (viz > 0.9999 || ! isValid ) ; bool isAllShadow = WaveActiveAllTrue (viz < 0.0001 || ! isValid ) ; bool hasPenumbra = ! isAllLit && ! isAllShadow ;
if( ! isAllShadow ) { uint vizSlotID = SLOTID_ALL_LIT ;
if( hasPenumbra ) { vizSlotID = AllocateVisibilitySlotID () ; StoreVisibility ( vizSlotID , inThreadIdx , visibility ) ; }
uint packedValue = PackLightIndexFinal ( lightIdx , vizSlotID ) ; uint outputAdr = GetListFinalAddress ( shadowSlotID , finalLightCount ) ; rw_TileLightListFinal . Store ( outputAdr , packedValue ) ; finalLightCount ++; } entryIdx ++; }
if( WaveIsFirstLane () ) { rw_TileLightCountFinal . Store ( tileIdx *4 , finalLightCount ) ; } }
|
PDF:http://www.jp.square-enix.com/tech/library/pdf/2023_FFXVIShadowTechPaper.pdf