// Copyright Epic Games, Inc. All Rights Reserved. #include "../Common.ush" #include "LumenCardCommon.ush" #include "LumenCardTile.ush" #include "LumenCardTileShadowDownsampleFactor.ush" #include "SurfaceCache/LumenSurfaceCache.ush" #define SUPPORT_CONTACT_SHADOWS 0 #define USE_IES_PROFILE 1 #include "../DeferredLightingCommon.ush" #include "../VolumeLightingCommon.ush" #define FILTER_DIRECTIONAL_LIGHT_SHADOWING 1 #include "../ForwardShadowingCommon.ush" #include "LumenSceneDirectLighting.ush" #include "LumenFloatQuantization.ush" FDeferredLightData GetLumenDirectLightingLightData(uint LightIndex, float3 PreViewTranslation, float Exposure) { FDeferredLightData Out; #if USE_LIGHT_UNIFORM_BUFFER Out = InitDeferredLightFromUniforms(LIGHT_TYPE); #else FLumenLight LumenLight = LoadLumenLight(LightIndex, PreViewTranslation, Exposure); Out = LumenLight.DeferredLightData; Out.bRectLight = HAS_RECT_LIGHTS && Out.bRectLight; #endif return Out; } float3 GetIrradianceForLight( uint LightIndex, FLumenSurfaceCacheData SurfaceCacheData, float3 PreViewTranslation, // LUMEN_LWC_TODO float Exposure, float3 ShadowFactor) { FDeferredLightData LightData = GetLumenDirectLightingLightData(LightIndex, PreViewTranslation, Exposure); float3 TranslatedWorldPosition = SurfaceCacheData.WorldPosition + PreViewTranslation; return GetIrradianceForLight(LightData, SurfaceCacheData.WorldNormal, TranslatedWorldPosition, true /*bSupportRectLight*/) * ShadowFactor; } #ifndef HAS_MULTIPLE_VIEWS #define HAS_MULTIPLE_VIEWS 0 #endif RWTexture2D RWDirectLightingAtlas; StructuredBuffer CardTiles; StructuredBuffer LightTileOffsetNumPerCardTile; StructuredBuffer LightTilesPerCardTile; float CachedLightingPreExposure; #if WAVE_OP_WAVE_SIZE > 0 && COMPILER_SUPPORTS_WAVE_SIZE WAVESIZE(WAVE_OP_WAVE_SIZE) #endif [numthreads(CARD_TILE_SIZE, CARD_TILE_SIZE, 1)] void LumenCardBatchDirectLightingCS( uint3 GroupId : SV_GroupID, uint3 GroupThreadId : SV_GroupThreadID) { uint CardTileIndex = GroupId.x; uint2 TexelCoordInTile = GroupThreadId.xy; uint PackedOffsetNum = LightTileOffsetNumPerCardTile[CardTileIndex]; uint LightTilesOffset = BitFieldExtractU32(PackedOffsetNum, 24, 0); uint NumLightTiles = BitFieldExtractU32(PackedOffsetNum, 8, 24); FCardTileData CardTile = UnpackCardTileData(CardTiles[CardTileIndex]); FLumenCardPageData CardPage = GetLumenCardPageData(CardTile.CardPageIndex); uint2 CoordInCardPage = CARD_TILE_SIZE * CardTile.TileCoord + TexelCoordInTile; uint2 AtlasCoord = CardPage.PhysicalAtlasCoord + CoordInCardPage; float2 AtlasUV = CardPage.PhysicalAtlasUVRect.xy + CardPage.PhysicalAtlasUVTexelScale * (CoordInCardPage + 0.5); float2 CardUV = CardPage.CardUVRect.xy + CardPage.CardUVTexelScale * (CoordInCardPage + 0.5); FLumenCardData Card = GetLumenCardData(CardPage.CardIndex); FLumenSurfaceCacheData SurfaceCacheData = GetSurfaceCacheData(Card, CardUV, AtlasUV); if (NumLightTiles == 0 || !SurfaceCacheData.bValid) { RWDirectLightingAtlas[AtlasCoord] = 0; return; } float3 Irradiance = 0.0f; uint4 TileShadowDownsampleFactorLow = 0; uint4 TileShadowDownsampleFactorHigh = 0; for (uint CulledLightIndex = 0; CulledLightIndex < NumLightTiles; ++CulledLightIndex) { FLightTileForLightPass LightTile = UnpackLightTileForLightPass(LightTilesPerCardTile[LightTilesOffset + CulledLightIndex]); FShadowMaskRay ShadowMaskRay; ShadowMaskRay.bShadowFactorComplete = true; ShadowMaskRay.ShadowFactor = 1.0f; if (LightTile.ShadowMaskIndex != 0xffffffff) { ReadShadowMaskRay(LightTile.ShadowMaskIndex, TexelCoordInTile, ShadowMaskRay); } if (any(ShadowMaskRay.ShadowFactor > 0.0f)) { uint ViewIndex = HAS_MULTIPLE_VIEWS ? LightTile.ViewIndex : 0; const FDFVector3 PreViewTranslation = GetPreViewTranslation(ViewIndex); Irradiance += GetIrradianceForLight(LightTile.LightIndex, SurfaceCacheData, DFHackToFloat(PreViewTranslation), ViewExposure[ViewIndex], ShadowMaskRay.ShadowFactor); //Irradiance += bShadowFactorValid ? float3(0, 1, 0) : float3(0.2f, 0.0f, 0.0f); } #if WAVE_OP_WAVE_SIZE == 64 if (WaveActiveAllTrue(!IsVisibleToLight(ShadowMaskRay.ShadowFactor)) || WaveActiveAllTrue(IsVisibleToLight(ShadowMaskRay.ShadowFactor))) { SetLumenCardTileShadowDownsampleFactorForLight(TileShadowDownsampleFactorLow, TileShadowDownsampleFactorHigh, LightTile.LightIndex); } #elif WAVE_OP_WAVE_SIZE == 32 // TODO: add wave32 support #endif } #if WAVE_OP_WAVE_SIZE == 64 if (WaveIsFirstLane()) #elif WAVE_OP_WAVE_SIZE == 32 // TODO: add wave32 support #endif { WriteLumenCardTileShadowDownsampleFactor(TileShadowDownsampleFactorLow, TileShadowDownsampleFactorHigh, AtlasCoord / CARD_TILE_SIZE, LumenCardScene.PhysicalAtlasSize.x / CARD_TILE_SIZE); } RWDirectLightingAtlas[AtlasCoord] = QuantizeForFloatRenderTarget(Irradiance * CachedLightingPreExposure, int3(AtlasCoord, View.StateFrameIndexMod8 + 1)); }