// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= LumenCardTileShadowDownsampleFactor.ush: Tracks whether surface tiles were uniformly shadowed in the last lighitng update =============================================================================*/ #pragma once #include "../Visualization.ush" #define LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS 8 #define LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS_MASK (LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS * 32 - 1u) Buffer TileShadowDownsampleFactorAtlas; bool LumenCardTileHasUniformVisibilityToLight(uint TileIndexInPhysicalAtlas, uint LightIndex) { uint BitIndex = LightIndex & LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS_MASK; uint DwordIndex = LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS * TileIndexInPhysicalAtlas + BitIndex / 32; uint MaskPart = TileShadowDownsampleFactorAtlas[DwordIndex]; return BitFieldExtractU32(MaskPart, 1, BitIndex % 32) != 0; } bool LumenCardTileHasUniformVisibilityToLight(uint2 TilePhysicalAtlasCoord, uint PhysicalAtlasWidthInTiles, uint LightIndex) { uint TileIndex = TilePhysicalAtlasCoord.y * PhysicalAtlasWidthInTiles + TilePhysicalAtlasCoord.x; return LumenCardTileHasUniformVisibilityToLight(TileIndex, LightIndex); } struct FTileShadowDownsampleFactor { uint4 Data[2]; }; Buffer TileShadowDownsampleFactorAtlasForResampling; FTileShadowDownsampleFactor LoadLumenCardTileShadowDownsampleFactor(uint TileIndexInPhysicalAtlas) { uint ReadOffset = LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS / 4 * TileIndexInPhysicalAtlas; FTileShadowDownsampleFactor Factor; Factor.Data[0] = TileShadowDownsampleFactorAtlasForResampling[ReadOffset]; Factor.Data[1] = TileShadowDownsampleFactorAtlasForResampling[ReadOffset + 1]; return Factor; } FTileShadowDownsampleFactor LoadLumenCardTileShadowDownsampleFactor(uint2 TilePhysicalAtlasCoord, uint PhysicalAtlasWidthInTiles) { uint TileIndex = TilePhysicalAtlasCoord.y * PhysicalAtlasWidthInTiles + TilePhysicalAtlasCoord.x; return LoadLumenCardTileShadowDownsampleFactor(TileIndex); } float3 GetLumenCardTileShadowDownsampleFactorVisualizationColor(uint2 TilePhysicalAtlasCoord, uint PhysicalAtlasWidthInTiles) { FTileShadowDownsampleFactor Factor = LoadLumenCardTileShadowDownsampleFactor(TilePhysicalAtlasCoord, PhysicalAtlasWidthInTiles); uint NumTrackedLights = 0; for (uint Index = 0; Index < 4; ++Index) { NumTrackedLights += countbits(Factor.Data[0][Index]); NumTrackedLights += countbits(Factor.Data[1][Index]); } float3 Color; switch (NumTrackedLights) { case 0: Color = float3(0.5, 0.5, 0.5); break; default: Color = IntToColor(NumTrackedLights); break; } return Color; } RWBuffer RWTileShadowDownsampleFactorAtlas; void WriteLumenCardTileShadowDownsampleFactor(FTileShadowDownsampleFactor Factor, uint TileIndexInPhysicalAtlas) { uint WriteOffset = LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS / 4 * TileIndexInPhysicalAtlas; RWTileShadowDownsampleFactorAtlas[WriteOffset] = Factor.Data[0]; RWTileShadowDownsampleFactorAtlas[WriteOffset + 1] = Factor.Data[1]; } void WriteLumenCardTileShadowDownsampleFactor(FTileShadowDownsampleFactor Factor, uint2 TilePhysicalAtlasCoord, uint PhysicalAtlasWidthInTiles) { uint TileIndex = TilePhysicalAtlasCoord.y * PhysicalAtlasWidthInTiles + TilePhysicalAtlasCoord.x; WriteLumenCardTileShadowDownsampleFactor(Factor, TileIndex); } void SetLumenCardTileShadowDownsampleFactorForLight(inout FTileShadowDownsampleFactor Factor, uint LightIndex) { uint BitIndex = LightIndex & LUMEN_CARD_TILE_SHADOW_DOWNSAMPLE_FACTOR_DWORDS_MASK; uint DwordIndex = BitIndex / 32; uint Mask = 1u << BitIndex % 32; if (DwordIndex < 4) { Factor.Data[0][DwordIndex] |= Mask; } else { Factor.Data[1][DwordIndex - 4] |= Mask; } }