256 lines
8.6 KiB
HLSL
256 lines
8.6 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#ifndef THREADGROUP_SIZE
|
|
#define THREADGROUP_SIZE 1
|
|
#endif
|
|
|
|
#include "../Common.ush"
|
|
#include "LumenCardCommon.ush"
|
|
#include "LumenCardTile.ush"
|
|
#define SUPPORT_CONTACT_SHADOWS 0
|
|
#include "../DeferredLightingCommon.ush"
|
|
#include "../VolumeLightingCommon.ush"
|
|
#include "../ForwardShadowingCommon.ush"
|
|
#include "../LightGridCommon.ush"
|
|
#define DISTANCE_FIELD_IN_VIEW_UB 1
|
|
#define DF_SHADOW_QUALITY 2
|
|
#include "LumenTracingCommon.ush"
|
|
#include "LumenSoftwareRayTracing.ush"
|
|
#include "../DistanceFieldShadowingShared.ush"
|
|
#include "LumenSceneDirectLightingPerLightShadowCommon.ush"
|
|
#include "../LightDataUniforms.ush"
|
|
|
|
// Bias
|
|
float HeightfieldShadowRayBias;
|
|
float MeshSDFShadowRayBias;
|
|
float GlobalSDFShadowRayBias;
|
|
|
|
float MaxTraceDistance;
|
|
float SDFSurfaceBiasScale;
|
|
|
|
float ShadowTraceHeightfield(
|
|
float3 WorldRayStart,
|
|
float3 TranslatedWorldRayStart,
|
|
float3 WorldRayDirection,
|
|
float MaxTraceDistance)
|
|
{
|
|
float ConeAngle = 0.0f;
|
|
float MinSampleRadius = 0.0f;
|
|
FConeTraceInput ConeTraceInput;
|
|
ConeTraceInput.Setup(
|
|
WorldRayStart,
|
|
TranslatedWorldRayStart,
|
|
WorldRayDirection,
|
|
ConeAngle,
|
|
MinSampleRadius,
|
|
/*MinTraceDistance*/ 0.0f,
|
|
MaxTraceDistance,
|
|
/*StepFactor*/ 1.0f
|
|
);
|
|
|
|
uint NumIntersectingObjects = 0;
|
|
uint CulledDataStart = 0;
|
|
GetHeightfieldShadowTileCulledData(TranslatedWorldRayStart, CulledDataStart, NumIntersectingObjects);
|
|
|
|
for (uint IndexInCulledList = 0; IndexInCulledList < NumIntersectingObjects; ++IndexInCulledList)
|
|
{
|
|
const uint HeightfieldObjectIndex = HeightfieldShadowTileArrayData.Load(IndexInCulledList + CulledDataStart);
|
|
FLumenHeightfieldData LumenHeightfield = GetLumenHeightfieldData(HeightfieldObjectIndex);
|
|
if (LumenHeightfield.bValid)
|
|
{
|
|
FConeTraceHeightfieldSimpleResult SimpleResult = ConeTraceHeightfieldSimple(ConeTraceInput, HeightfieldObjectIndex);
|
|
if (SimpleResult.bIsHit)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1.0f;
|
|
}
|
|
|
|
float TraceOffscreenShadows(FLumenCardData CardData, uint2 TexelCoord, float3 WorldPosition, float3 TranslatedWorldPosition, float3 L, float3 ToLight, float3 WorldNormal, bool bLocalLight)
|
|
{
|
|
float ShadowFactor = 1.0f;
|
|
|
|
// Offscreen shadowing, trace to light
|
|
float TraceDistance = MaxTraceDistance;
|
|
|
|
#if LIGHT_TYPE != LIGHT_TYPE_DIRECTIONAL
|
|
TraceDistance = min(length(ToLight), MaxTraceDistance);
|
|
#endif
|
|
|
|
#if (LIGHT_TYPE == LIGHT_TYPE_DIRECTIONAL) && (OFFSCREEN_SHADOWING_TRACE_MESH_SDF || OFFSCREEN_SHADOWING_TRACE_HEIGHTFIELDS)
|
|
{
|
|
#if OFFSCREEN_SHADOWING_TRACE_MESH_SDF
|
|
{
|
|
float3 TranslatedWorldPositionForShadowing = GetCardWorldPositionForShadowing(TranslatedWorldPosition, L, WorldNormal, MeshSDFShadowRayBias);
|
|
float3 TranslatedWorldRayStart = TranslatedWorldPositionForShadowing;
|
|
float3 TranslatedWorldRayEnd = TranslatedWorldRayStart + L * TraceDistance;
|
|
|
|
uint NumIntersectingObjects = GetCulledNumObjects();
|
|
uint CulledDataParameter = 0;
|
|
GetShadowTileCulledData(TranslatedWorldRayStart, CulledDataParameter, NumIntersectingObjects);
|
|
|
|
float SubsurfaceDensity = 0;
|
|
bool bUseSubsurfaceTransmission = false;
|
|
|
|
ShadowFactor = ShadowRayTraceThroughCulledObjects(
|
|
TranslatedWorldRayStart,
|
|
TranslatedWorldRayEnd,
|
|
TraceDistance,
|
|
0, //@todo - TanLightSourceAngle - causes mismatch with CSM which doesn't support LightSourceAngle
|
|
0,
|
|
100,
|
|
SubsurfaceDensity,
|
|
CulledDataParameter,
|
|
NumIntersectingObjects,
|
|
true,
|
|
true,
|
|
bUseSubsurfaceTransmission,
|
|
/*bExpandSurface*/ true);
|
|
}
|
|
#endif
|
|
|
|
#if OFFSCREEN_SHADOWING_TRACE_HEIGHTFIELDS
|
|
{
|
|
float3 WorldPositionForShadowing = GetCardWorldPositionForShadowing(WorldPosition, L, WorldNormal, HeightfieldShadowRayBias * CardData.TexelSize);
|
|
float3 TranslatedWorldPositionForShadowing = GetCardWorldPositionForShadowing(TranslatedWorldPosition, L, WorldNormal, HeightfieldShadowRayBias * CardData.TexelSize);
|
|
|
|
ShadowFactor *= ShadowTraceHeightfield(
|
|
WorldPositionForShadowing,
|
|
TranslatedWorldPositionForShadowing,
|
|
L,
|
|
TraceDistance);
|
|
}
|
|
#endif
|
|
}
|
|
#elif OFFSCREEN_SHADOWING_TRACE_GLOBAL_SDF
|
|
{
|
|
FGlobalSDFTraceInput TraceInput = SetupGlobalSDFTraceInput(TranslatedWorldPosition, L, 0.0f, TraceDistance, 1.0f, 1.0f);
|
|
|
|
// Bias away from the starting point on surface
|
|
TraceInput.VoxelSizeRelativeBias = GetCardBiasForShadowing(L, WorldNormal, GlobalSDFShadowRayBias);
|
|
TraceInput.DitherScreenCoord = TexelCoord;
|
|
|
|
if (bLocalLight)
|
|
{
|
|
// Bias also the end point (local light position) in case if light is near the geometry
|
|
TraceInput.VoxelSizeRelativeRayEndBias = GlobalSDFShadowRayBias;
|
|
}
|
|
|
|
FGlobalSDFTraceResult SDFResult = RayTraceGlobalDistanceField(TraceInput);
|
|
|
|
//@todo - approximate cone trace from SDF for antialiasing
|
|
ShadowFactor = GlobalSDFTraceResultIsHit(SDFResult) ? 0.0f : 1.0f;
|
|
}
|
|
#endif
|
|
|
|
return ShadowFactor;
|
|
}
|
|
|
|
#ifdef LIGHT_TYPE
|
|
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
|
|
void LumenSceneDirectLightingTraceDistanceFieldShadowsCS(
|
|
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;
|
|
uint2 CoordInCardTile = GroupThreadId.xy + uint2(0, GroupId.x % 2 ? 0 : 4);
|
|
uint ShadowMaskSize = SHADOW_MASK_CARD_TILE_DWORDS / 2;
|
|
uint ShadowMaskOffset = GroupId.x % 2 ? 0 : 1;
|
|
#else
|
|
uint LocalLightTileIndex = GroupId.x;
|
|
uint2 CoordInCardTile = GroupThreadId.xy;
|
|
uint ShadowMaskSize = SHADOW_MASK_CARD_TILE_DWORDS;
|
|
uint ShadowMaskOffset = 0;
|
|
#endif
|
|
|
|
uint SlotIndex = bUseLightTilesPerLightType != 0 && LIGHT_TYPE > 0 ? LIGHT_TYPE - 1 : NUM_BATCHABLE_LIGHT_TYPES + LightIndex;
|
|
uint LightTileIndex = LocalLightTileIndex + LightTileOffsetsPerLight[SlotIndex * NumViews + ViewIndex];
|
|
|
|
if (LinearGroupThreadId < ShadowMaskSize)
|
|
{
|
|
SharedShadowMask[LinearGroupThreadId] = RWShadowMaskTiles[SHADOW_MASK_CARD_TILE_DWORDS * LightTileIndex + ShadowMaskSize * ShadowMaskOffset + LinearGroupThreadId];
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
FLightTileForShadowMaskPass LightTile = UnpackLightTileForShadowMaskPass(LightTiles[LightTileIndex]);
|
|
uint2 TexelInCardPageCoord = LightTile.TileCoord * CARD_TILE_SIZE + CoordInCardTile;
|
|
|
|
FLumenCardPageData CardPage = GetLumenCardPageData(LightTile.CardPageIndex + DummyZeroForFixingShaderCompilerBug);
|
|
float2 AtlasUV = CardPage.PhysicalAtlasUVRect.xy + CardPage.PhysicalAtlasUVTexelScale * (TexelInCardPageCoord + 0.5f);
|
|
float2 CardUV = CardPage.CardUVRect.xy + CardPage.CardUVTexelScale * (TexelInCardPageCoord + 0.5f);
|
|
|
|
FShadowMaskRay ShadowMaskRay;
|
|
ReadSharedShadowMaskRay(GroupThreadId.xy, ShadowMaskRay);
|
|
|
|
if (!ShadowMaskRay.bShadowFactorComplete)
|
|
{
|
|
FDeferredLightData LightData;
|
|
if (bUseLightTilesPerLightType != 0)
|
|
{
|
|
LightData = LoadLumenLight(LightTile.LightIndex, DFHackToFloat(PrimaryView.PreViewTranslation), ViewExposure[ViewIndex]).DeferredLightData;
|
|
}
|
|
else
|
|
{
|
|
LightData = InitDeferredLightFromUniforms(LIGHT_TYPE);
|
|
}
|
|
|
|
FLumenCardData CardData = GetLumenCardData(CardPage.CardIndex);
|
|
FLumenSurfaceCacheData SurfaceCacheData = GetSurfaceCacheData(CardData, CardUV, AtlasUV);
|
|
|
|
float3 WorldPosition = SurfaceCacheData.WorldPosition;
|
|
float3 TranslatedWorldPosition = WorldPosition + DFHackToFloat(PrimaryView.PreViewTranslation); // LUMEN_LWC_TODO
|
|
float3 WorldNormal = SurfaceCacheData.WorldNormal;
|
|
|
|
float3 L = LightData.Direction;
|
|
float3 ToLight = L;
|
|
bool bLocalLight = false;
|
|
|
|
#if LIGHT_TYPE != LIGHT_TYPE_DIRECTIONAL
|
|
if (LightData.bRadialLight)
|
|
{
|
|
ToLight = LightData.TranslatedWorldPosition - TranslatedWorldPosition;
|
|
L = normalize(ToLight);
|
|
bLocalLight = true;
|
|
}
|
|
#endif
|
|
|
|
ShadowMaskRay.bShadowFactorComplete = true;
|
|
ShadowMaskRay.ShadowFactor *= TraceOffscreenShadows(CardData, TexelInCardPageCoord, WorldPosition, TranslatedWorldPosition, L, ToLight, WorldNormal, bLocalLight);
|
|
|
|
WriteSharedShadowMaskRay(ShadowMaskRay, GroupThreadId.xy, true);
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (LinearGroupThreadId < ShadowMaskSize)
|
|
{
|
|
RWShadowMaskTiles[SHADOW_MASK_CARD_TILE_DWORDS * LightTileIndex + ShadowMaskSize * ShadowMaskOffset + LinearGroupThreadId] = SharedShadowMask[LinearGroupThreadId];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
RWBuffer<uint> RWShadowTraceIndirectArgs;
|
|
StructuredBuffer<uint> ShadowTraceAllocator;
|
|
|
|
[numthreads(THREADGROUP_SIZE, 1, 1)]
|
|
void InitShadowTraceIndirectArgsCS(
|
|
uint3 GroupId : SV_GroupID,
|
|
uint3 DispatchThreadId : SV_DispatchThreadID,
|
|
uint3 GroupThreadId : SV_GroupThreadID)
|
|
{
|
|
if (all(DispatchThreadId.xyz == 0))
|
|
{
|
|
uint NumShadowTraces = ShadowTraceAllocator[0];
|
|
|
|
// One thread per card tile
|
|
WriteDispatchIndirectArgs(RWShadowTraceIndirectArgs, 0, DivideAndRoundUp64(NumShadowTraces), 1, 1);
|
|
}
|
|
} |