269 lines
8.8 KiB
HLSL
269 lines
8.8 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#ifndef VIRTUAL_SHADOW_MAP
|
|
#define VIRTUAL_SHADOW_MAP 0
|
|
#endif
|
|
#ifndef DENSE_SHADOW_MAP
|
|
#define DENSE_SHADOW_MAP 0
|
|
#endif
|
|
|
|
#include "../Common.ush"
|
|
#include "LumenCardCommon.ush"
|
|
#include "LumenCardTile.ush"
|
|
#include "LumenCardTileShadowDownsampleFactor.ush"
|
|
#define SUPPORT_CONTACT_SHADOWS 0
|
|
#include "../DeferredLightingCommon.ush"
|
|
#include "../VolumeLightingCommon.ush"
|
|
#include "../ForwardShadowingCommon.ush"
|
|
#include "../LightDataUniforms.ush"
|
|
#include "SurfaceCache/LumenSurfaceCache.ush"
|
|
#if LIGHT_FUNCTION
|
|
#include "/Engine/Generated/Material.ush"
|
|
#include "../LightFunctionCommon.ush"
|
|
#endif
|
|
#include "LumenSceneDirectLightingPerLightShadowCommon.ush"
|
|
#if USE_CLOUD_TRANSMITTANCE
|
|
#include "../VolumetricCloudCommon.ush"
|
|
#endif
|
|
|
|
#define SUPPORT_ADAPTIVE_SHADOW_TRACING (FEATURE_LEVEL >= FEATURE_LEVEL_SM6 || PLATFORM_SUPPORTS_SM6_0_WAVE_OPERATIONS)
|
|
|
|
RWStructuredBuffer<uint> RWShadowTraces;
|
|
RWStructuredBuffer<uint> RWShadowTraceAllocator;
|
|
|
|
float HeightfieldShadowReceiverBias;
|
|
int bAdaptiveShadowTracing;
|
|
|
|
groupshared uint SharedNumShadowTraces;
|
|
groupshared uint SharedShadowTraces[THREADGROUP_SIZE_X * THREADGROUP_SIZE_Y];
|
|
groupshared uint SharedGlobalShadowTraceOffset;
|
|
|
|
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
|
|
void LumenSceneDirectLightingShadowMaskFromLightAttenuationCS(
|
|
uint3 GroupId : SV_GroupID,
|
|
uint3 DispatchThreadId : SV_DispatchThreadID,
|
|
uint3 GroupThreadId : SV_GroupThreadID)
|
|
{
|
|
uint LinearGroupThreadId = GroupThreadId.x + GroupThreadId.y * THREADGROUP_SIZE_X;
|
|
|
|
#if THREADGROUP_SIZE_32
|
|
uint LocalLightTileIndex = GroupId.x / 2;
|
|
uint ShadowMaskSize = SHADOW_MASK_CARD_TILE_DWORDS / 2;
|
|
uint ShadowMaskOffset = GroupId.x % 2 ? 1 : 0;
|
|
#else
|
|
uint LocalLightTileIndex = GroupId.x;
|
|
uint ShadowMaskSize = SHADOW_MASK_CARD_TILE_DWORDS;
|
|
uint ShadowMaskOffset = 0;
|
|
#endif
|
|
|
|
if (LinearGroupThreadId < ShadowMaskSize)
|
|
{
|
|
SharedShadowMask[LinearGroupThreadId] = 0;
|
|
}
|
|
|
|
if (LinearGroupThreadId == 0)
|
|
{
|
|
SharedNumShadowTraces = 0;
|
|
SharedGlobalShadowTraceOffset = 0;
|
|
SharedShadowTraces[0] = 0;
|
|
}
|
|
|
|
// Need to resolve view for light function computations
|
|
ResolvedView = ResolveView();
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
uint SlotIndex = bUseLightTilesPerLightType != 0 && LIGHT_TYPE > 0 ? LIGHT_TYPE - 1 : NUM_BATCHABLE_LIGHT_TYPES + LightIndex;
|
|
uint LightTileIndex = LocalLightTileIndex + LightTileOffsetsPerLight[SlotIndex * NumViews + ViewIndex];
|
|
FLightTileForShadowMaskPass LightTile = UnpackLightTileForShadowMaskPass(LightTiles[LightTileIndex]);
|
|
|
|
FLumenCardPageData CardPage = GetLumenCardPageData(LightTile.CardPageIndex + DummyZeroForFixingShaderCompilerBug);
|
|
|
|
#if SUPPORT_ADAPTIVE_SHADOW_TRACING
|
|
bool bTileHasUniformlyVisibility = false;
|
|
if (bAdaptiveShadowTracing != 0)
|
|
{
|
|
uint2 TilePhysicalAtlasCoord = CardPage.PhysicalAtlasCoord / CARD_TILE_SIZE + LightTile.TileCoord;
|
|
uint PhysicalAtlasWidthInTiles = LumenCardScene.PhysicalAtlasSize.x / CARD_TILE_SIZE;
|
|
bTileHasUniformlyVisibility = LumenCardTileHasUniformVisibilityToLight(TilePhysicalAtlasCoord, PhysicalAtlasWidthInTiles, LightTile.LightIndex);
|
|
}
|
|
#endif
|
|
|
|
uint2 CoordInCardTile = Unflatten2D(LinearGroupThreadId, uint2(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y)) + uint2(0, ShadowMaskOffset ? 4 : 0);
|
|
uint2 TexelInCardPageCoord = LightTile.TileCoord * CARD_TILE_SIZE + CoordInCardTile;
|
|
float2 AtlasUV = CardPage.PhysicalAtlasUVRect.xy + CardPage.PhysicalAtlasUVTexelScale * (TexelInCardPageCoord + 0.5f);
|
|
float2 CardUV = CardPage.CardUVRect.xy + CardPage.CardUVTexelScale * (TexelInCardPageCoord + 0.5f);
|
|
|
|
FShadowMaskRay ShadowMaskRay;
|
|
ShadowMaskRay.ShadowFactor = 0.0f;
|
|
ShadowMaskRay.bShadowFactorComplete = true;
|
|
|
|
FLumenCardData Card = GetLumenCardData(CardPage.CardIndex);
|
|
FLumenSurfaceCacheData SurfaceCacheData = GetSurfaceCacheData(Card, CardUV, AtlasUV);
|
|
|
|
if (SurfaceCacheData.bValid)
|
|
{
|
|
FDeferredLightData LightData;
|
|
if (bUseLightTilesPerLightType != 0)
|
|
{
|
|
LightData = LoadLumenLight(LightTile.LightIndex, DFHackToFloat(PrimaryView.PreViewTranslation), PrimaryView.PreExposure).DeferredLightData;
|
|
}
|
|
else
|
|
{
|
|
LightData = InitDeferredLightFromUniforms(LIGHT_TYPE);
|
|
}
|
|
|
|
float3 WorldNormal = SurfaceCacheData.WorldNormal;
|
|
float3 WorldPosition = SurfaceCacheData.WorldPosition;
|
|
float3 TranslatedWorldPosition = WorldPosition + DFHackToFloat(PrimaryView.PreViewTranslation);
|
|
|
|
float3 L = LightData.Direction;
|
|
float3 ToLight = L;
|
|
float CombinedAttenuation = 1.0f;
|
|
float Attenuation = 1.0f;
|
|
float LightMask = 1.0f;
|
|
|
|
#if LIGHT_TYPE != LIGHT_TYPE_DIRECTIONAL
|
|
if (LightData.bRadialLight)
|
|
{
|
|
LightMask = GetLocalLightAttenuation(TranslatedWorldPosition, LightData, ToLight, L);
|
|
}
|
|
|
|
if (LightData.bRectLight)
|
|
{
|
|
FRect Rect = GetRect(ToLight, LightData);
|
|
Attenuation = IntegrateLight(Rect);
|
|
}
|
|
else
|
|
{
|
|
FCapsuleLight Capsule = GetCapsule(ToLight, LightData);
|
|
Capsule.DistBiasSqr = 0;
|
|
Attenuation = IntegrateLight(Capsule, LightData.bInverseSquared);
|
|
}
|
|
|
|
CombinedAttenuation *= Attenuation * LightMask;
|
|
#endif
|
|
|
|
CombinedAttenuation *= saturate(dot(WorldNormal, L));
|
|
|
|
if (CombinedAttenuation > 0)
|
|
{
|
|
ShadowMaskRay.ShadowFactor = 1.0f;
|
|
ShadowMaskRay.bShadowFactorComplete = false;
|
|
|
|
#if USE_LIGHT_FUNCTION_ATLAS
|
|
if (!ShadowMaskRay.bShadowFactorComplete && LightData.LightFunctionAtlasLightIndex > 0)
|
|
{
|
|
ShadowMaskRay.ShadowFactor *= GetLocalLightFunctionCommon(TranslatedWorldPosition, LightData.LightFunctionAtlasLightIndex);
|
|
ShadowMaskRay.bShadowFactorComplete = !IsVisibleToLight(ShadowMaskRay.ShadowFactor);
|
|
}
|
|
#elif LIGHT_FUNCTION
|
|
if (!ShadowMaskRay.bShadowFactorComplete)
|
|
{
|
|
ShadowMaskRay.ShadowFactor *= GetLumenLightFunction(TranslatedWorldPosition);
|
|
ShadowMaskRay.bShadowFactorComplete = !IsVisibleToLight(ShadowMaskRay.ShadowFactor);
|
|
}
|
|
#endif
|
|
|
|
#if USE_CLOUD_TRANSMITTANCE
|
|
if (!ShadowMaskRay.bShadowFactorComplete)
|
|
{
|
|
float OutOpticalDepth = 0.0f;
|
|
ShadowMaskRay.ShadowFactor *= lerp(1.0f, GetCloudVolumetricShadow(TranslatedWorldPosition, CloudShadowmapTranslatedWorldToLightClipMatrix, CloudShadowmapFarDepthKm, CloudShadowmapTexture, CloudShadowmapSampler, OutOpticalDepth), CloudShadowmapStrength);
|
|
ShadowMaskRay.bShadowFactorComplete = !IsVisibleToLight(ShadowMaskRay.ShadowFactor);
|
|
}
|
|
#endif
|
|
|
|
if (!ShadowMaskRay.bShadowFactorComplete && LightData.IESAtlasIndex >= 0)
|
|
{
|
|
ShadowMaskRay.ShadowFactor *= ComputeLightProfileMultiplier(TranslatedWorldPosition, LightData.TranslatedWorldPosition, -LightData.Direction, LightData.Tangent, LightData.IESAtlasIndex);
|
|
ShadowMaskRay.bShadowFactorComplete = !IsVisibleToLight(ShadowMaskRay.ShadowFactor);
|
|
}
|
|
|
|
const bool bCastShadows = LightData.ShadowedBits >= 3;
|
|
if (!bCastShadows)
|
|
{
|
|
ShadowMaskRay.bShadowFactorComplete = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShadowMaskRay.ShadowFactor = 0.0f;
|
|
ShadowMaskRay.bShadowFactorComplete = true;
|
|
}
|
|
}
|
|
|
|
GroupThreadId.xy = Unflatten2D(LinearGroupThreadId, uint2(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y));
|
|
|
|
WriteSharedShadowMaskRay(ShadowMaskRay, GroupThreadId.xy, false);
|
|
|
|
#if COMPACT_SHADOW_TRACES
|
|
{
|
|
bool bWriteTrace = !ShadowMaskRay.bShadowFactorComplete;
|
|
uint DownSampleLevel = 0;
|
|
|
|
#if SUPPORT_ADAPTIVE_SHADOW_TRACING
|
|
if (bAdaptiveShadowTracing != 0)
|
|
{
|
|
if (bTileHasUniformlyVisibility)
|
|
{
|
|
const uint2 QuadId = GroupThreadId.xy / 2;
|
|
const uint QuadIndex = QuadId.y * (THREADGROUP_SIZE_X / 2) + QuadId.x;
|
|
uint Ballot = ~((bWriteTrace ? 0u : 1u) << QuadIndex);
|
|
Ballot = WaveActiveBitAnd(Ballot);
|
|
DownSampleLevel = (Ballot & (1u << QuadIndex)) != 0 ? 1 : 0;
|
|
}
|
|
|
|
if (DownSampleLevel > 0)
|
|
{
|
|
const uint2 SubQuadId = GroupThreadId.xy % 2;
|
|
const uint SubQuadIndex = SubQuadId.y * 2 + SubQuadId.x;
|
|
bWriteTrace = SubQuadIndex == CardPage.DirectLightingTemporalIndex % 4;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (bWriteTrace)
|
|
{
|
|
uint ShadowTraceIndex = 0;
|
|
InterlockedAdd(SharedNumShadowTraces, 1, ShadowTraceIndex);
|
|
|
|
FShadowTrace ShadowTrace;
|
|
ShadowTrace.LightTileIndex = LightTileIndex;
|
|
ShadowTrace.LightTileCoord = GroupThreadId.xy + uint2(0, ShadowMaskOffset ? 4 : 0);
|
|
ShadowTrace.DownSampleLevel = DownSampleLevel;
|
|
|
|
SharedShadowTraces[ShadowTraceIndex] = PackShadowTrace(ShadowTrace);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
#if COMPACT_SHADOW_TRACES
|
|
{
|
|
if (LinearGroupThreadId == 0)
|
|
{
|
|
InterlockedAdd(RWShadowTraceAllocator[0], SharedNumShadowTraces, SharedGlobalShadowTraceOffset);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
#if COMPACT_SHADOW_TRACES
|
|
{
|
|
if (LinearGroupThreadId < SharedNumShadowTraces)
|
|
{
|
|
RWShadowTraces[SharedGlobalShadowTraceOffset + LinearGroupThreadId] = SharedShadowTraces[LinearGroupThreadId];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (LinearGroupThreadId < ShadowMaskSize)
|
|
{
|
|
RWShadowMaskTiles[SHADOW_MASK_CARD_TILE_DWORDS * LightTileIndex + ShadowMaskSize * ShadowMaskOffset + LinearGroupThreadId] = SharedShadowMask[LinearGroupThreadId];
|
|
}
|
|
}
|
|
|