You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- 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]
278 lines
9.6 KiB
Plaintext
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;
|
|
}
|