493 lines
21 KiB
HLSL
493 lines
21 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
/*=============================================================================
|
|
ClusteredDeferredShadingPixelShader - applies all local lights in the
|
|
LightGrid in a full-screen pass, not directional ones as they are done
|
|
in the traditional deferred passes.
|
|
=============================================================================*/
|
|
|
|
// Following the lead of Tiled Deferred
|
|
#define SUPPORT_CONTACT_SHADOWS 0
|
|
#define USE_IES_PROFILE 1
|
|
#define NON_DIRECTIONAL_DIRECT_LIGHTING 0
|
|
#define SUBSTRATE_SSS_TRANSMISSION USE_TRANSMISSION
|
|
|
|
// Used in RectLight.ush, and requires a per-light texture which we cannot support at present.
|
|
// If the textures are atlased or something like that in the future it should be ok to turn on.
|
|
#define USE_SOURCE_TEXTURE 0
|
|
|
|
#if SUBSTRATE_ENABLED
|
|
#if SUBSTRATE_TILETYPE == 0
|
|
#define SUBSTRATE_FASTPATH 1
|
|
#elif SUBSTRATE_TILETYPE == 1
|
|
#define SUBSTRATE_SINGLEPATH 1
|
|
#elif SUBSTRATE_TILETYPE == 2
|
|
// COMPLEX PATH
|
|
#elif SUBSTRATE_TILETYPE == 3
|
|
// COMPLEX PATH
|
|
#define SUBSTRATE_COMPLEXSPECIALPATH 1
|
|
#else
|
|
#error Substrate tile type non-implemented
|
|
#endif
|
|
#endif
|
|
|
|
#include "HairStrands/HairStrandsVisibilityCommonStruct.ush"
|
|
#include "Common.ush"
|
|
#include "Substrate/Substrate.ush"
|
|
#include "DeferredShadingCommon.ush"
|
|
#include "BRDF.ush"
|
|
#include "ShadingModels.ush"
|
|
#include "LightGridCommon.ush"
|
|
#include "DeferredLightingCommon.ush"
|
|
#include "LightData.ush"
|
|
#include "VirtualShadowMaps/VirtualShadowMapTransmissionCommon.ush"
|
|
#include "VirtualShadowMaps/VirtualShadowMapMaskBitsCommon.ush"
|
|
#include "Substrate/SubstrateEvaluation.ush"
|
|
#include "Substrate/SubstrateDeferredLighting.ush"
|
|
|
|
#if USE_HAIR_LIGHTING == 1
|
|
#include "HairStrands/HairStrandsCommon.ush"
|
|
#include "HairStrands/HairStrandsVisibilityCommon.ush"
|
|
#include "HairStrands/HairStrandsVisibilityUtils.ush"
|
|
#include "HairStrands/HairStrandsDeepTransmittanceCommon.ush"
|
|
#include "HairStrands/HairStrandsDeepTransmittanceDualScattering.ush"
|
|
#endif // USE_HAIR_LIGHTING
|
|
|
|
// Causes the shader to run one pass over the light list per shading model, which cuts down peak register pressure.
|
|
// Moves some overhead out of the inner loop (testing for shading model) which ought to be a good thing also.
|
|
#if SUBSTRATE_ENABLED
|
|
#define USE_PASS_PER_SHADING_MODEL 0
|
|
#else
|
|
// Only enable on non-FXC compilers since FXC takes ages to compile all the shader model passes.
|
|
#define USE_PASS_PER_SHADING_MODEL (COMPILER_DXC == 1 || COMPILER_PSSL == 1 || COMPILER_METAL == 1)
|
|
#endif
|
|
|
|
// Temporary work around for shader compilation issue
|
|
#define SUPPORT_SUBSTRATE_LIGHTING (COMPILER_DXC == 1 || COMPILER_PSSL == 1 || COMPILER_METAL == 1)
|
|
|
|
// Enable cluster debug visualization
|
|
#define GRID_DEBUG_ENABLE 0
|
|
|
|
Texture2D<uint4> ShadowMaskBits;
|
|
|
|
#if USE_HAIR_LIGHTING
|
|
uint HairTransmittanceBufferMaxCount;
|
|
Buffer<uint> HairTransmittanceBuffer;
|
|
#endif
|
|
|
|
/**
|
|
* Debug function for visualizing clusters
|
|
*/
|
|
bool GetClusterDebugColor(float2 LocalPosition, float SceneDepth, FCulledLightsGridHeader GridData, inout float4 OutColor)
|
|
{
|
|
OutColor = 0.0f;
|
|
#if GRID_DEBUG_ENABLE
|
|
uint ZSlice = (uint)(max(0, log2(SceneDepth * GridData.LightGridZParams.x + GridData.LightGridZParams.y) * GridData.LightGridZParams.z));
|
|
ZSlice = min(ZSlice, (uint)(GridData.CulledGridSize.z - 1));
|
|
uint3 GridCoordinate = uint3(uint2(LocalPosition.x, LocalPosition.y) >> GridData.LightGridPixelSizeShift, ZSlice);
|
|
|
|
if (ZSlice % 2)
|
|
{
|
|
OutColor = float(ZSlice) / float(GridData.CulledGridSize.z - 1);
|
|
}
|
|
else
|
|
{
|
|
OutColor = 1.0f - float(ZSlice) / float(GridData.CulledGridSize.z - 1);
|
|
}
|
|
|
|
if (GridCoordinate.x % 2)
|
|
{
|
|
OutColor.xyz = 1.0f - OutColor.xyz;
|
|
}
|
|
if (GridCoordinate.y % 2)
|
|
{
|
|
OutColor.xyz = 1.0f - OutColor.xyz;
|
|
}
|
|
OutColor.w = 0.0f;
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Adds local lighting using the light grid, does not apply directional lights, as they are done elsewhere.
|
|
* Does not support dynamic shadows, as these require the per-light shadow mask.
|
|
*/
|
|
float4 GetLightGridLocalLighting(
|
|
#if SUBTRATE_GBUFFER_FORMAT==1 && USE_HAIR_LIGHTING == 0
|
|
FSubstrateAddressing SubstrateAddressing,
|
|
FSubstratePixelHeader SubstratePixelHeader,
|
|
inout float3 OutOpaqueRoughRefractionSceneColor,
|
|
inout float3 OutSubSurfaceSceneColor,
|
|
#else
|
|
FScreenSpaceData ScreenSpaceData,
|
|
#endif
|
|
const FCulledLightsGridHeader InLightGridHeader,
|
|
float3 TranslatedWorldPosition,
|
|
float3 CameraVector,
|
|
float2 ScreenUV,
|
|
float SceneDepth,
|
|
uint EyeIndex,
|
|
float Dither,
|
|
uint SampleIndex=0,
|
|
uint TotalSampleCount=0,
|
|
uint2 PixelCoord=0,
|
|
uint HairLightChannelMask=0)
|
|
{
|
|
float4 DirectLighting = 0;
|
|
|
|
// Limit max to ForwardLightStruct.NumLocalLights.
|
|
// This prevents GPU hangs when the PS tries to read from uninitialized NumCulledLightsGrid buffer
|
|
const uint NumLightsInGridCell = min(InLightGridHeader.NumLights, GetMaxLightsPerCell());
|
|
|
|
int2 PixelPos = int2( ScreenUV.xy * View.BufferSizeAndInvSize.xy );
|
|
uint4 ShadowMask = ShadowMaskBits[ PixelPos ];
|
|
#if USE_HAIR_LIGHTING
|
|
uint LightChannelMask = HairLightChannelMask;
|
|
#else
|
|
uint LightChannelMask = GetSceneLightingChannel(PixelPos);
|
|
#endif
|
|
|
|
LOOP
|
|
for (uint GridLightListIndex = 0; GridLightListIndex < NumLightsInGridCell; GridLightListIndex++)
|
|
{
|
|
const FLocalLightData LocalLight = GetLocalLightDataFromGrid(InLightGridHeader.DataStartIndex + GridLightListIndex, EyeIndex);
|
|
|
|
// The lights are sorted such that all that support clustered deferred are at the beginning, there might be others
|
|
// (e.g., lights with dynamic shadows) so we break out when the condition fails.
|
|
if (!UnpackIsClusteredDeferredSupported(LocalLight))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!IsLightVisible(LocalLight, TranslatedWorldPosition))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ((LightChannelMask & UnpackLightingChannelMask(LocalLight)) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
FDeferredLightData LightData = ConvertToDeferredLight(LocalLight);
|
|
LightData.ShadowedBits = 1;
|
|
LightData.bRectLight = LightData.bRectLight && USE_RECT_LIGHT;
|
|
#if USE_IES_PROFILE
|
|
LightData.Color *= ComputeLightProfileMultiplier(TranslatedWorldPosition, LightData.TranslatedWorldPosition, -LightData.Direction, LightData.Tangent, LightData.IESAtlasIndex);
|
|
#endif
|
|
float4 LightAttenuation = float4(1, 1, 1, 1);
|
|
|
|
// Find packed VSM projection result if present
|
|
// NOTE: We have to do the search as in the deferred pass again currently as the shadow masks
|
|
// are packed according to a prune light list that contains only shadow-casting lights.
|
|
uint VSMGridLightListIndex = GridLightListIndex;
|
|
if (LocalLight.Internal.VirtualShadowMapId != INDEX_NONE)
|
|
{
|
|
LightAttenuation = GetVirtualShadowMapMaskForLight(
|
|
ShadowMask,
|
|
uint2(PixelPos),
|
|
SceneDepth,
|
|
LocalLight.Internal.VirtualShadowMapId,
|
|
TranslatedWorldPosition,
|
|
VSMGridLightListIndex).xxxx;
|
|
}
|
|
|
|
#if USE_HAIR_LIGHTING
|
|
if (LightAttenuation.x > 0)
|
|
{
|
|
const float3 L = normalize(LightData.TranslatedWorldPosition - TranslatedWorldPosition);
|
|
const float3 V = normalize(-CameraVector);
|
|
|
|
// Fetch precomputed transmittance
|
|
// * Transmittance data are only computed for shadowed lights with VSM
|
|
// * Transmittance mask index is computed using VSM light index remapping. This needs to match HairStrandsDeepTransmittanceMask.usf
|
|
FHairTransmittanceMask TransmittanceMask = InitHairTransmittanceMask();
|
|
if (LocalLight.Internal.VirtualShadowMapId != INDEX_NONE && VSMGridLightListIndex < GetPackedShadowMaskMaxLightCount())
|
|
{
|
|
const uint TransmittanceSampleIndex = SampleIndex + VSMGridLightListIndex * TotalSampleCount;
|
|
const uint TransmittanceSampleMaxCount = TotalSampleCount * GetPackedShadowMaskMaxLightCount();
|
|
if (TransmittanceSampleIndex < TransmittanceSampleMaxCount)
|
|
{
|
|
TransmittanceMask = UnpackTransmittanceMask(HairTransmittanceBuffer[TransmittanceSampleIndex]);
|
|
}
|
|
}
|
|
|
|
// Apply dual scattering
|
|
LightData.HairTransmittance = GetHairTransmittance(
|
|
V,
|
|
L,
|
|
ScreenSpaceData.GBuffer,
|
|
TransmittanceMask,
|
|
View.HairScatteringLUTTexture,
|
|
HairScatteringLUTSampler,
|
|
View.HairComponents);
|
|
|
|
// This shouldn't be needed any more as the virtual shadow map should offer enough spatial precision
|
|
LightAttenuation = min(LightAttenuation, LightData.HairTransmittance.OpaqueVisibility.xxxx);
|
|
}
|
|
#endif
|
|
|
|
#if SUBTRATE_GBUFFER_FORMAT==1 && USE_HAIR_LIGHTING == 0
|
|
|
|
FSubstrateShadowTermInputParameters SubstrateShadowTermInputParameters = GetInitialisedSubstrateShadowTermInputParameters();
|
|
SubstrateShadowTermInputParameters.bEvaluateShadowTerm = true;
|
|
SubstrateShadowTermInputParameters.SceneDepth = CalcSceneDepth(ScreenUV);
|
|
SubstrateShadowTermInputParameters.PrecomputedShadowFactors = SubstrateReadPrecomputedShadowFactors(SubstratePixelHeader, PixelPos, SceneTexturesStruct.GBufferETexture);
|
|
SubstrateShadowTermInputParameters.TranslatedWorldPosition = TranslatedWorldPosition;
|
|
SubstrateShadowTermInputParameters.LightAttenuation = LightAttenuation;
|
|
SubstrateShadowTermInputParameters.Dither = Dither;
|
|
|
|
const float3 V = -CameraVector;
|
|
float3 ToLight, L;
|
|
const float LightMask = GetLocalLightAttenuation(TranslatedWorldPosition, LightData, ToLight, L);
|
|
|
|
FSubstrateDeferredLighting SubstrateLighting = (FSubstrateDeferredLighting)0;
|
|
#if SUPPORT_SUBSTRATE_LIGHTING
|
|
SubstrateLighting = SubstrateDeferredLighting(
|
|
LightData,
|
|
V,
|
|
L,
|
|
ToLight,
|
|
LightMask,
|
|
SubstrateShadowTermInputParameters,
|
|
Substrate.MaterialTextureArray,
|
|
SubstrateAddressing,
|
|
SubstratePixelHeader);
|
|
#endif
|
|
|
|
DirectLighting += SubstrateLighting.SceneColor;
|
|
#if SUBSTRATE_OPAQUE_ROUGH_REFRACTION_ENABLED
|
|
OutOpaqueRoughRefractionSceneColor += SubstrateLighting.OpaqueRoughRefractionSceneColor;
|
|
OutSubSurfaceSceneColor += SubstrateLighting.SubSurfaceSceneColor;
|
|
#endif
|
|
|
|
#elif 1
|
|
// NOTE: uses AO data like tiled deferred (as opposed to forward path)
|
|
// TODO: Passing in 0,0 as SVPos, what is meaning of this? Only used if 'REFERENCE_QUALITY' is on.
|
|
float SurfaceShadow = 1.0f;
|
|
DirectLighting += GetDynamicLighting(TranslatedWorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, LightData,LightAttenuation, Dither, uint2(0, 0), SurfaceShadow);
|
|
#else // 1
|
|
FSimpleDeferredLightData SimpleLightData = (FSimpleDeferredLightData)0;
|
|
SimpleLightData.TranslatedWorldPosition = LightData.TranslatedWorldPosition;
|
|
SimpleLightData.InvRadius = LightData.InvRadius;
|
|
SimpleLightData.Color = LightData.Color;
|
|
SimpleLightData.FalloffExponent = LightData.FalloffExponent;
|
|
SimpleLightData.bInverseSquared = LightData.bInverseSquared;
|
|
DirectLighting += GetSimpleDynamicLighting(TranslatedWorldPosition, CameraVector, ScreenSpaceData.GBuffer.WorldNormal, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.DiffuseColor, ScreenSpaceData.GBuffer.SpecularColor, ScreenSpaceData.GBuffer.Roughness, SimpleLightData);
|
|
#endif // SUBSTRATE_ENABLED
|
|
}
|
|
|
|
// For debugging
|
|
//DirectLighting = InLightGridData.NumLights / (float)ForwardLightStruct.MaxCulledLightsPerCell;
|
|
return DirectLighting;
|
|
}
|
|
|
|
#if USE_PASS_PER_SHADING_MODEL
|
|
|
|
// NOTE: this is a macro since we want to be sure the 'ScreenSpaceData.GBuffer.ShadingModelID = ShadingModelId' is compile time constant
|
|
// The rest sort of follows.
|
|
// NOTE 2: The screen-space data is loaded inside the if to try to minimize register pressure, but not clear if it is respected.
|
|
#define GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(ShadingModelId, PixelShadingModelId, /*inout float4*/ CompositedLighting, ScreenUV, LightGridHeader, Dither) \
|
|
{ \
|
|
BRANCH \
|
|
if (PixelShadingModelId == ShadingModelId) \
|
|
{ \
|
|
float2 ScreenPosition = UVAndScreenPos.zw; \
|
|
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(ScreenUV); \
|
|
float SceneDepth = CalcSceneDepth(ScreenUV); \
|
|
float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, SceneDepth), SceneDepth, 1), PrimaryView.ScreenToTranslatedWorld).xyz; \
|
|
float3 CameraVector = normalize(TranslatedWorldPosition - PrimaryView.TranslatedWorldCameraOrigin); \
|
|
ScreenSpaceData.GBuffer.ShadingModelID = ShadingModelId; \
|
|
CompositedLighting += GetLightGridLocalLighting(ScreenSpaceData, LightGridHeader, TranslatedWorldPosition, CameraVector, ScreenUV, SceneDepth, 0, Dither); \
|
|
} \
|
|
}
|
|
|
|
#endif // USE_PASS_PER_SHADING_MODEL
|
|
|
|
#if SUBTRATE_GBUFFER_FORMAT==1 && USE_HAIR_LIGHTING == 0
|
|
void ClusteredShadingPixelShader(
|
|
float2 ScreenUV : TEXCOORD0,
|
|
float3 ScreenVector : TEXCOORD1,
|
|
in float4 SvPosition : SV_Position,
|
|
out float4 OutColor : SV_Target0
|
|
#if SUBSTRATE_OPAQUE_ROUGH_REFRACTION_ENABLED
|
|
, out float3 OutOpaqueRoughRefractionSceneColor : SV_Target1
|
|
, out float3 OutSubSurfaceSceneColor : SV_Target2
|
|
#endif
|
|
)
|
|
{
|
|
uint2 PixelPos = SvPosition.xy;
|
|
|
|
const float Dither = InterleavedGradientNoise(SvPosition.xy, View.StateFrameIndexMod8);
|
|
const uint EyeIndex = 0;
|
|
const float SceneDepth = CalcSceneDepth(ScreenUV);
|
|
const float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
|
|
|
|
const uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), SceneDepth, EyeIndex);
|
|
const FCulledLightsGridHeader CulledLightGridHeader = GetCulledLightsGridHeader(GridIndex);
|
|
|
|
// Debug output
|
|
#if GRID_DEBUG_ENABLE
|
|
if (GetClusterDebugColor(LocalPosition, SceneDepth, CulledLightGridHeader, OutColor)) return;
|
|
#endif
|
|
|
|
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(PixelPos, uint2(View.BufferSizeAndInvSize.xy), Substrate.MaxBytesPerPixel);
|
|
FSubstratePixelHeader SubstratePixelHeader = UnpackSubstrateHeaderIn(Substrate.MaterialTextureArray, SubstrateAddressing, Substrate.TopLayerTexture);
|
|
|
|
// NOTE: this early out helps with the case where there are no lights in the grid cell.
|
|
if (CulledLightGridHeader.NumLights == 0 || !SubstratePixelHeader.IsSubstrateMaterial())
|
|
{
|
|
OutColor = 0;
|
|
return;
|
|
}
|
|
|
|
float4 CompositedLighting = 0;
|
|
float3 OpaqueRoughRefractionSceneColor = 0;
|
|
float3 SubSurfaceSceneColor = 0;
|
|
|
|
BRANCH
|
|
if (SubstratePixelHeader.ClosureCount > 0 || CulledLightGridHeader.NumLights == 0)
|
|
{
|
|
// Subtrate tile are expressed as buffer dimension rather than view dimension
|
|
const float2 ViewportScreenUV = ScreenUV * View.BufferSizeAndInvSize.xy * View.ViewSizeAndInvSize.zw;
|
|
const float2 ScreenPosition = ViewportUVToScreenPos(ViewportScreenUV);
|
|
const float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, SceneDepth), SceneDepth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
|
|
const float3 CameraVector = normalize(TranslatedWorldPosition - PrimaryView.TranslatedWorldCameraOrigin);
|
|
|
|
// Regular lights
|
|
CompositedLighting += GetLightGridLocalLighting(SubstrateAddressing, SubstratePixelHeader, OpaqueRoughRefractionSceneColor, SubSurfaceSceneColor,
|
|
CulledLightGridHeader, TranslatedWorldPosition, CameraVector, ScreenUV, SceneDepth, EyeIndex, Dither);
|
|
}
|
|
|
|
#if !VISUALIZE_LIGHT_CULLING
|
|
CompositedLighting *= View.PreExposure;
|
|
#endif
|
|
#if SUBSTRATE_OPAQUE_ROUGH_REFRACTION_ENABLED
|
|
OutOpaqueRoughRefractionSceneColor = OpaqueRoughRefractionSceneColor * View.PreExposure;
|
|
OutSubSurfaceSceneColor = SubSurfaceSceneColor * View.PreExposure;
|
|
#endif
|
|
OutColor = CompositedLighting;
|
|
}
|
|
#elif !USE_HAIR_LIGHTING
|
|
void ClusteredShadingPixelShader(
|
|
in noperspective float4 UVAndScreenPos : TEXCOORD0,
|
|
in float4 SvPosition : SV_Position,
|
|
out float4 OutColor : SV_Target0)
|
|
{
|
|
float2 ScreenUV = UVAndScreenPos.xy;
|
|
float2 ScreenPosition = UVAndScreenPos.zw;
|
|
|
|
uint PixelShadingModelID = GetScreenSpaceData(ScreenUV).GBuffer.ShadingModelID;
|
|
|
|
const float Dither = InterleavedGradientNoise(SvPosition.xy, View.StateFrameIndexMod8);
|
|
|
|
// ?
|
|
const uint EyeIndex = 0;
|
|
|
|
float SceneDepth = CalcSceneDepth(ScreenUV);
|
|
float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
|
|
uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), SceneDepth, EyeIndex);
|
|
const FCulledLightsGridHeader CulledLightGridHeader = GetCulledLightsGridHeader(GridIndex);
|
|
|
|
// Debug output
|
|
#if GRID_DEBUG_ENABLE
|
|
if (GetClusterDebugColor(LocalPosition, SceneDepth, CulledLightGridHeader, OutColor)) return;
|
|
#endif
|
|
|
|
// NOTE: this early out helps with the case where there are no lights in the grid cell.
|
|
if (CulledLightGridHeader.NumLights == 0 || PixelShadingModelID == SHADINGMODELID_UNLIT)
|
|
{
|
|
OutColor = 0;
|
|
return;
|
|
}
|
|
|
|
float4 CompositedLighting = 0;
|
|
float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, SceneDepth), SceneDepth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
|
|
float3 CameraVector = normalize(TranslatedWorldPosition - PrimaryView.TranslatedWorldCameraOrigin);
|
|
uint FirstNonSimpleLightIndex = 0;
|
|
|
|
// Regular lights
|
|
#if USE_PASS_PER_SHADING_MODEL
|
|
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_DEFAULT_LIT, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SUBSURFACE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_PREINTEGRATED_SKIN, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_CLEAR_COAT, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SUBSURFACE_PROFILE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_TWOSIDED_FOLIAGE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_HAIR, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_CLOTH, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_EYE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SINGLELAYERWATER, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither);
|
|
// SHADINGMODELID_THIN_TRANSLUCENT - skipping because it can not be opaque
|
|
#else // !USE_PASS_PER_SHADING_MODEL
|
|
CompositedLighting += GetLightGridLocalLighting(GetScreenSpaceData(ScreenUV), CulledLightGridHeader, TranslatedWorldPosition, CameraVector, ScreenUV, SceneDepth, 0, Dither);
|
|
#endif // USE_PASS_PER_SHADING_MODEL
|
|
|
|
#if !VISUALIZE_LIGHT_CULLING
|
|
CompositedLighting *= View.PreExposure;
|
|
#endif
|
|
OutColor = CompositedLighting;
|
|
}
|
|
#else // USE_HAIR_LIGHTING
|
|
void ClusteredShadingPixelShader(
|
|
in float4 SvPosition: SV_Position,
|
|
nointerpolation in uint TotalSampleCount : DISPATCH_NODECOUNT,
|
|
nointerpolation in uint2 Resolution : DISPATCH_RESOLUTION,
|
|
out float4 OutColor : SV_Target0)
|
|
{
|
|
OutColor = 0;
|
|
|
|
const uint EyeIndex = 0;
|
|
|
|
const uint2 InCoord = uint2(SvPosition.xy);
|
|
const uint SampleIndex = InCoord.x + InCoord.y * Resolution.x;
|
|
if (SampleIndex >= TotalSampleCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const uint2 PixelCoord = HairStrands.HairSampleCoords[SampleIndex];
|
|
const float2 ScreenUV = (PixelCoord + float2(0.5f, 0.5f)) / float2(View.BufferSizeAndInvSize.xy);
|
|
const float2 ScreenPosition = (ScreenUV - View.ScreenPositionScaleBias.wz) / View.ScreenPositionScaleBias.xy;
|
|
|
|
const FPackedHairSample PackedSample = HairStrands.HairSampleData[SampleIndex];
|
|
const FHairSample Sample = UnpackHairSample(PackedSample);
|
|
|
|
const float SceneDepth = ConvertFromDeviceZ(Sample.Depth);
|
|
|
|
const float2 LocalPosition = PixelCoord - View.ViewRectMin.xy;
|
|
FScreenSpaceData ScreenSpaceData = (FScreenSpaceData)0;
|
|
{
|
|
ScreenSpaceData.AmbientOcclusion = 1;
|
|
ScreenSpaceData.GBuffer = HairSampleToGBufferData(Sample, HairStrands.HairDualScatteringRoughnessOverride);
|
|
}
|
|
|
|
const float Dither = InterleavedGradientNoise(SvPosition.xy, View.StateFrameIndexMod8);
|
|
|
|
const uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), SceneDepth, EyeIndex);
|
|
const FCulledLightsGridHeader CulledLightGridHeader = GetCulledLightsGridHeader(GridIndex);
|
|
// NOTE: this early out helps with the case where there are no lights in the grid cell.
|
|
if (CulledLightGridHeader.NumLights == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, SceneDepth), SceneDepth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
|
|
const float3 CameraVector = normalize(TranslatedWorldPosition - PrimaryView.TranslatedWorldCameraOrigin);
|
|
|
|
float4 CompositedLighting = 0;
|
|
CompositedLighting += GetLightGridLocalLighting(ScreenSpaceData, CulledLightGridHeader, TranslatedWorldPosition, CameraVector, ScreenUV, SceneDepth, 0, Dither, SampleIndex, TotalSampleCount, PixelCoord, Sample.LightChannelMask);
|
|
#if !VISUALIZE_LIGHT_CULLING
|
|
CompositedLighting *= View.PreExposure;
|
|
#endif
|
|
|
|
// Weight hair sample with its coverage
|
|
const float LocalCoverage = From8bitCoverage(Sample.Coverage8bit);
|
|
OutColor.rgb = CompositedLighting.xyz * LocalCoverage;
|
|
OutColor.a = LocalCoverage;
|
|
}
|
|
#endif // USE_HAIR_LIGHTING
|
|
|