Files
UnrealEngineUWP/Engine/Shaders/Private/LightGridCommon.ush
andrew lauritzen 1dfa763b1f - Generalize one pass projection shadow mask to support up to 32 lights/pixel with 4bpp quantization
- Add some dither noise to both the SMRT result and the shadow mask lookup to minimize banding
- Fall back to a single sample VSM lookup (with a generous static bias) when overflowing the number of lights in one pass projection path
- Fix clamping issue with page dilation that was setting extraneous pages with point lights
- Fix SMRT issue with local lights jammed right next to geometry viewed at a distance
- Separate settings for page dilation for local and directional lights
- Add simple debug output for # lights in one pass projection
- Remove some dead code/parameters

#ROBOMERGE-AUTHOR: andrew.lauritzen
#ROBOMERGE-SOURCE: CL 18279117 via CL 18373418 via CL 18373449
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v895-18170469)

[CL 18373485 by andrew lauritzen in ue5-release-engine-test branch]
2021-12-03 16:23:04 -05:00

278 lines
9.6 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LightGridCommon.ush
=============================================================================*/
// TODO: This is clearly not the right place for these defines! Ideally ought to be exposed from engine somehow...
#define LIGHT_TYPE_DIRECTIONAL 0
#define LIGHT_TYPE_POINT 1
#define LIGHT_TYPE_SPOT 2
#define LIGHT_TYPE_RECT 3
#define LIGHT_TYPE_MAX 4
#if INSTANCED_STEREO
#if MATERIALBLENDING_ANY_TRANSLUCENT
#define ForwardLightDataISR TranslucentBasePass.Shared.ForwardISR
#else
#define ForwardLightDataISR OpaqueBasePass.Shared.ForwardISR
#endif
#endif
struct FLightGridData
{
uint LightGridPixelSizeShift;
float3 LightGridZParams;
int3 CulledGridSize;
};
FLightGridData GetLightGridData(uint EyeIndex)
{
FLightGridData Result;
#if INSTANCED_STEREO
BRANCH
if (EyeIndex == 0)
{
#endif
Result.LightGridPixelSizeShift = ForwardLightData.LightGridPixelSizeShift;
Result.LightGridZParams = ForwardLightData.LightGridZParams;
Result.CulledGridSize = ForwardLightData.CulledGridSize;
#if INSTANCED_STEREO
}
else
{
Result.LightGridPixelSizeShift = ForwardLightDataISR.LightGridPixelSizeShift;
Result.LightGridZParams = ForwardLightDataISR.LightGridZParams;
Result.CulledGridSize = ForwardLightDataISR.CulledGridSize;
}
#endif
return Result;
}
uint3 ComputeLightGridCellCoordinate(uint2 PixelPos, float SceneDepth, uint EyeIndex)
{
const FLightGridData GridData = GetLightGridData(EyeIndex);
uint ZSlice = (uint)(max(0, log2(SceneDepth * GridData.LightGridZParams.x + GridData.LightGridZParams.y) * GridData.LightGridZParams.z));
ZSlice = min(ZSlice, (uint)(GridData.CulledGridSize.z - 1));
return uint3(PixelPos >> GridData.LightGridPixelSizeShift, ZSlice);
}
uint ComputeLightGridCellIndex(uint3 GridCoordinate, uint EyeIndex)
{
const FLightGridData GridData = GetLightGridData(EyeIndex);
return (GridCoordinate.z * GridData.CulledGridSize.y + GridCoordinate.y) * GridData.CulledGridSize.x + GridCoordinate.x;
}
uint ComputeLightGridCellIndex(uint2 PixelPos, float SceneDepth, uint EyeIndex)
{
return ComputeLightGridCellIndex(ComputeLightGridCellCoordinate(PixelPos, SceneDepth, EyeIndex), EyeIndex);
}
uint ComputeLightGridCellIndex(uint2 PixelPos, float SceneDepth)
{
return ComputeLightGridCellIndex(PixelPos, SceneDepth, 0);
}
#ifndef NUM_CULLED_LIGHTS_GRID_STRIDE
#define NUM_CULLED_LIGHTS_GRID_STRIDE 0
#endif
#ifndef LOCAL_LIGHT_DATA_STRIDE
#define LOCAL_LIGHT_DATA_STRIDE 0
#endif
uint GetNumLocalLights(uint EyeIndex)
{
#if INSTANCED_STEREO
return (EyeIndex == 0) ? ForwardLightData.NumLocalLights : ForwardLightDataISR.NumLocalLights;
#else
return ForwardLightData.NumLocalLights;
#endif
}
struct FCulledLightsGridData
{
uint NumLocalLights;
uint DataStartIndex;
};
FCulledLightsGridData GetCulledLightsGrid(uint GridIndex, uint EyeIndex)
{
FCulledLightsGridData Result;
#if INSTANCED_STEREO
BRANCH
if (EyeIndex == 0)
{
#endif
Result.NumLocalLights = min(ForwardLightData.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 0], ForwardLightData.NumLocalLights);
Result.DataStartIndex = ForwardLightData.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 1];
#if INSTANCED_STEREO
}
else
{
Result.NumLocalLights = min(ForwardLightDataISR.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 0], ForwardLightDataISR.NumLocalLights);
Result.DataStartIndex = ForwardLightDataISR.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 1];
}
#endif
return Result;
}
struct FDirectionalLightData
{
uint HasDirectionalLight;
uint DirectionalLightShadowMapChannelMask;
float2 DirectionalLightDistanceFadeMAD;
float3 DirectionalLightColor;
float3 DirectionalLightDirection;
};
FDirectionalLightData GetDirectionalLightData(uint EyeIndex)
{
FDirectionalLightData Result;
#if INSTANCED_STEREO
BRANCH
if (EyeIndex == 0)
{
#endif
Result.HasDirectionalLight = ForwardLightData.HasDirectionalLight;
Result.DirectionalLightShadowMapChannelMask = ForwardLightData.DirectionalLightShadowMapChannelMask;
Result.DirectionalLightDistanceFadeMAD = ForwardLightData.DirectionalLightDistanceFadeMAD;
Result.DirectionalLightColor = ForwardLightData.DirectionalLightColor;
Result.DirectionalLightDirection = ForwardLightData.DirectionalLightDirection;
#if INSTANCED_STEREO
}
else
{
Result.HasDirectionalLight = ForwardLightDataISR.HasDirectionalLight;
Result.DirectionalLightShadowMapChannelMask = ForwardLightDataISR.DirectionalLightShadowMapChannelMask;
Result.DirectionalLightDistanceFadeMAD = ForwardLightDataISR.DirectionalLightDistanceFadeMAD;
Result.DirectionalLightColor = ForwardLightDataISR.DirectionalLightColor;
Result.DirectionalLightDirection = ForwardLightDataISR.DirectionalLightDirection;
}
#endif
return Result;
}
struct FLocalLightData
{
float4 LightPositionAndInvRadius;
float4 LightColorAndFalloffExponent;
float4 SpotAnglesAndSourceRadiusPacked;
float4 LightDirectionAndShadowMask;
float4 LightTangentAndSoftSourceRadius;
float4 RectBarnDoorAndVirtualShadowMapId;
/** Flag is true if clustered deferred is supported for this light. They are always first / together.*/
bool bClusteredDeferredSupported;
/** Flag is true if it is a simple light. They are always first / together.*/
bool bIsSimpleLight;
/** Virtual shadow map ID or INDEX_NONE if not present. */
int VirtualShadowMapId;
};
FLocalLightData GetLocalLightData(uint GridIndex, uint EyeIndex)
{
FLocalLightData Result;
#if INSTANCED_STEREO
BRANCH
if (EyeIndex == 0)
{
#endif
uint LocalLightIndex = ForwardLightData.CulledLightDataGrid[GridIndex];
uint LocalLightBaseIndex = LocalLightIndex * LOCAL_LIGHT_DATA_STRIDE;
Result.bClusteredDeferredSupported = LocalLightIndex < ForwardLightData.ClusteredDeferredSupportedEndIndex;
Result.bIsSimpleLight = LocalLightIndex < ForwardLightData.SimpleLightsEndIndex;
Result.LightPositionAndInvRadius = ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 0];
Result.LightColorAndFalloffExponent = ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 1];
Result.LightDirectionAndShadowMask = ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 2];
Result.SpotAnglesAndSourceRadiusPacked = ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 3];
Result.LightTangentAndSoftSourceRadius = ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 4];
Result.RectBarnDoorAndVirtualShadowMapId = ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 5];
Result.VirtualShadowMapId = int(Result.RectBarnDoorAndVirtualShadowMapId.z);
#if INSTANCED_STEREO
}
else
{
uint LocalLightIndex = ForwardLightDataISR.CulledLightDataGrid[GridIndex];
uint LocalLightBaseIndex = LocalLightIndex * LOCAL_LIGHT_DATA_STRIDE;
Result.bClusteredDeferredSupported = LocalLightIndex < ForwardLightDataISR.ClusteredDeferredSupportedEndIndex;
Result.bIsSimpleLight = LocalLightIndex < ForwardLightDataISR.SimpleLightsEndIndex;
Result.LightPositionAndInvRadius = ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 0];
Result.LightColorAndFalloffExponent = ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 1];
Result.LightDirectionAndShadowMask = ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 2];
Result.SpotAnglesAndSourceRadiusPacked = ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 3];
Result.LightTangentAndSoftSourceRadius = ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 4];
Result.RectBarnDoorAndVirtualShadowMapId = ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 5];
Result.VirtualShadowMapId = int(Result.RectBarnDoorAndVirtualShadowMapId.z);
}
#endif
return Result;
}
/**
* Helper to unpack the shadow mask part of the FLocalLightData::LightDirectionAndShadowMask.w
*/
float4 UnpackShadowMapChannelMask(uint ShadowMapChannelMaskPacked)
{
return float4((ShadowMapChannelMaskPacked & 1) ? 1.0f : 0.0f, (ShadowMapChannelMaskPacked & 2) ? 1.0f : 0.0f, (ShadowMapChannelMaskPacked & 4) ? 1.0f : 0.0f, (ShadowMapChannelMaskPacked & 8) ? 1.0f : 0.0f);
}
/**
* Helpers to pack/unpack the shadow mask for cluster shading and virtual shadow map
* Currently hard-coded for 4 bits per light, up to 32 lights per pixel in a uint4
*/
uint4 InitializePackedShadowMask()
{
return uint(0xffffffff).xxxx;
}
uint GetPackedShadowMaskMaxLightCount()
{
return VirtualShadowMap.PackedShadowMaskMaxLightCount;
}
void PackShadowMask(inout uint4 InOutShadowMask, float InShadowFactor, uint InLightIndex)
{
uint Value = ~uint(round(InShadowFactor * 15.0f)) & 15U;
uint Dword = InLightIndex / 8;
InOutShadowMask.x ^= (Dword == 0U) ? (Value << (InLightIndex ) * 4U) : 0U;
InOutShadowMask.y ^= (Dword == 1U) ? (Value << (InLightIndex - 8U) * 4U) : 0U;
InOutShadowMask.z ^= (Dword == 2U) ? (Value << (InLightIndex - 16U) * 4U) : 0U;
InOutShadowMask.w ^= (Dword == 3U) ? (Value << (InLightIndex - 24U) * 4U) : 0U;
//OutShadowMask ^= (~uint(round(InShadowFactor * 7.0)) & 7u) << (InLightIndex * 3u);
}
float UnpackShadowMask(uint4 InShadowMask, uint InLightIndex)
{
uint Dword = InLightIndex / 8;
return ((InShadowMask[Dword] >> (InLightIndex - Dword*8U) * 4U) & 15U) / 15.0f;
//return ((InShadowMask >> (InLightIndex * 3u)) & 7u) / 7.0;
}
// Unpack with dither to hide some of the quantization
float UnpackShadowMask(uint4 InShadowMask, uint InLightIndex, float Dither)
{
float ShadowFactor = UnpackShadowMask(InShadowMask, InLightIndex);
if (ShadowFactor > 0.0f && ShadowFactor < 1.0f)
{
ShadowFactor = saturate(ShadowFactor + (Dither - 0.5f) * (1.0f / 16.0f));
}
return ShadowFactor;
}