You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb none #preflight https://horde.devtools.epicgames.com/job/62960217d86c0bf739a111ef [CL 20435765 by Sebastien Hillaire in ue5-main branch]
553 lines
24 KiB
Plaintext
553 lines
24 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
ForwardLightingCommon.ush
|
|
=============================================================================*/
|
|
|
|
#define NON_DIRECTIONAL_DIRECT_LIGHTING (TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL)
|
|
#define SUPPORT_CONTACT_SHADOWS (MATERIAL_CONTACT_SHADOWS && !FORWARD_SHADING)
|
|
|
|
#include "DeferredLightingCommon.ush"
|
|
#include "LightGridCommon.ush"
|
|
|
|
#define FILTER_DIRECTIONAL_LIGHT_SHADOWING 1
|
|
#include "ForwardShadowingCommon.ush"
|
|
|
|
#ifndef DISABLE_FORWARD_DIRECTIONAL_LIGHT_SHADOW
|
|
#define DISABLE_FORWARD_DIRECTIONAL_LIGHT_SHADOW 0
|
|
#endif
|
|
|
|
#if USE_HAIR_COMPLEX_TRANSMITTANCE
|
|
#include "HairStrands/HairStrandsCommon.ush"
|
|
#include "HairStrands/HairStrandsDeepTransmittanceCommon.ush"
|
|
#include "HairStrands/HairStrandsDeepTransmittanceDualScattering.ush"
|
|
#endif
|
|
|
|
#ifndef VIRTUAL_SHADOW_MAP
|
|
#define VIRTUAL_SHADOW_MAP 0
|
|
#endif
|
|
|
|
#if VIRTUAL_SHADOW_MAP
|
|
#include "VirtualShadowMaps/VirtualShadowMapProjectionCommon.ush"
|
|
#endif
|
|
|
|
#if SUPPORT_CLOUD_SHADOW_ON_FORWARD_LIT_TRANSLUCENT
|
|
#include "VolumetricCloudCommon.ush"
|
|
#endif
|
|
|
|
float PrevSceneColorPreExposureInv;
|
|
|
|
void UpdateNearestSample(float Z, float2 UV, float FullResZ, inout float MinDist, inout float2 NearestUV)
|
|
{
|
|
float DepthDelta = abs(Z - FullResZ);
|
|
|
|
FLATTEN
|
|
if (DepthDelta < MinDist)
|
|
{
|
|
MinDist = DepthDelta;
|
|
NearestUV = UV;
|
|
}
|
|
}
|
|
|
|
float2 CalculateNearestResolvedDepthScreenUV(float2 ScreenUV, float SceneDepth)
|
|
{
|
|
float2 EffectiveScreenUV = ScreenUV;
|
|
|
|
if (View.NumSceneColorMSAASamples > 1)
|
|
{
|
|
int2 IntScreenUV = int2(trunc(ScreenUV * View.BufferSizeAndInvSize.xy));
|
|
|
|
float DeferredShadowingDepth = ConvertFromDeviceZ(OpaqueBasePass.ResolvedSceneDepthTexture.Load(int3(IntScreenUV, 0)).r);
|
|
float RelativeDepthThreshold = .01f;
|
|
|
|
// Fragment depth doesn't match what we used for deferred shadowing, search neighbors in cross pattern
|
|
// Even with this nearest depth upsampling there can be edge artifacts from deferred shadowing,
|
|
// Since depth testing and stencil testing used during shadow projection are done per-sample and we're fetching from the resolved light attenuation
|
|
if (abs(DeferredShadowingDepth - SceneDepth) / SceneDepth > RelativeDepthThreshold)
|
|
{
|
|
float2 TexelSize = View.BufferSizeAndInvSize.zw;
|
|
float MinDist = 1.e8f;
|
|
|
|
float2 LeftUV = ScreenUV + float2(-TexelSize.x, 0);
|
|
float LeftDepth = ConvertFromDeviceZ(OpaqueBasePass.ResolvedSceneDepthTexture.Load(int3(IntScreenUV.x - 1, IntScreenUV.y, 0)).r);
|
|
UpdateNearestSample(LeftDepth, LeftUV, SceneDepth, MinDist, EffectiveScreenUV);
|
|
|
|
float2 UpUV = ScreenUV + float2(0, TexelSize.y);
|
|
float UpDepth = ConvertFromDeviceZ(OpaqueBasePass.ResolvedSceneDepthTexture.Load(int3(IntScreenUV.x, IntScreenUV.y + 1, 0)).r);
|
|
UpdateNearestSample(UpDepth, UpUV, SceneDepth, MinDist, EffectiveScreenUV);
|
|
|
|
float2 RightUV = ScreenUV + float2(TexelSize.x, 0);
|
|
float RightDepth = ConvertFromDeviceZ(OpaqueBasePass.ResolvedSceneDepthTexture.Load(int3(IntScreenUV.x + 1, IntScreenUV.y, 0)).r);
|
|
UpdateNearestSample(RightDepth, RightUV, SceneDepth, MinDist, EffectiveScreenUV);
|
|
|
|
float2 BottomUV = ScreenUV + float2(0, -TexelSize.y);
|
|
float BottomDepth = ConvertFromDeviceZ(OpaqueBasePass.ResolvedSceneDepthTexture.Load(int3(IntScreenUV.x, IntScreenUV.y - 1, 0)).r);
|
|
UpdateNearestSample(BottomDepth, BottomUV, SceneDepth, MinDist, EffectiveScreenUV);
|
|
}
|
|
}
|
|
|
|
return EffectiveScreenUV;
|
|
}
|
|
|
|
float4 GetForwardDynamicShadowFactors(float2 ScreenUV)
|
|
{
|
|
int2 IntScreenUV = int2(trunc(ScreenUV * View_BufferSizeAndInvSize.xy));
|
|
float4 Value = 1.0f;
|
|
// Avoid sampling the white texture fallback because Load returns 0 when out-of-bound.
|
|
BRANCH
|
|
if (OpaqueBasePass.UseForwardScreenSpaceShadowMask)
|
|
{
|
|
Value = OpaqueBasePass.ForwardScreenSpaceShadowMaskTexture.Load(int3(IntScreenUV, 0));
|
|
}
|
|
return DecodeLightAttenuation(Value);
|
|
}
|
|
|
|
float GetIndirectOcclusion(float2 ScreenUV, bool bHasDynamicIndirectShadowCasterRepresentation)
|
|
{
|
|
float IndirectOcclusion;
|
|
|
|
uint IndirectOcclusionWidth, IndirectOcclusionHeight;
|
|
OpaqueBasePass.IndirectOcclusionTexture.GetDimensions(IndirectOcclusionWidth, IndirectOcclusionHeight);
|
|
|
|
int2 IntScreenUV = int2(trunc(ScreenUV * float2(IndirectOcclusionWidth, IndirectOcclusionHeight)));
|
|
IndirectOcclusion = OpaqueBasePass.IndirectOcclusionTexture.Load(int3(IntScreenUV, 0)).x;
|
|
|
|
// Reduce self shadowing intensity on characters (reuse distance field bit, really should be HasCapsuleShadowRepresentation)
|
|
IndirectOcclusion = lerp(1, IndirectOcclusion, bHasDynamicIndirectShadowCasterRepresentation ? View.IndirectCapsuleSelfShadowingIntensity : 1);
|
|
|
|
return IndirectOcclusion;
|
|
}
|
|
|
|
FDeferredLightingSplit GetForwardDirectLightingSplit(
|
|
uint GridIndex, float3 TranslatedWorldPosition, float3 CameraVector, FGBufferData GBufferData, float2 ScreenUV, uint PrimitiveId, uint EyeIndex, float Dither,
|
|
float InDirectionalLightCloudShadow, float3 InDirectionalLightAtmosphereTransmittance, inout float OutDirectionalLightShadow,
|
|
bool bSeparateMainDirLightLuminance, inout float3 SeparatedMainDirLightLuminance)
|
|
{
|
|
float3 WorldPosition = TranslatedWorldPosition - LWCHackToFloat(PrimaryView.PreViewTranslation);
|
|
|
|
float4 DynamicShadowFactors = 1;
|
|
|
|
#if MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED
|
|
DynamicShadowFactors = GetForwardDynamicShadowFactors(ScreenUV);
|
|
#endif
|
|
|
|
FDeferredLightingSplit DirectLighting;
|
|
DirectLighting.DiffuseLighting = 0;
|
|
DirectLighting.SpecularLighting = 0;
|
|
|
|
float SpecularScale = 1;
|
|
#if TRANSLUCENCY_ANY_VOLUMETRIC
|
|
// No specular on volumetric translucency lighting modes
|
|
SpecularScale = 0;
|
|
#endif
|
|
|
|
uint LightingChannelMask = GetPrimitive_LightingChannelMask(PrimitiveId);
|
|
|
|
const FDirectionalLightData DirectionalLightData = GetDirectionalLightData(EyeIndex);
|
|
|
|
BRANCH
|
|
if (DirectionalLightData.HasDirectionalLight)
|
|
{
|
|
FDeferredLightData LightData = (FDeferredLightData)0;
|
|
LightData.Color = DirectionalLightData.DirectionalLightColor;
|
|
LightData.FalloffExponent = 0;
|
|
LightData.Direction = DirectionalLightData.DirectionalLightDirection;
|
|
LightData.DistanceFadeMAD = DirectionalLightData.DirectionalLightDistanceFadeMAD;
|
|
LightData.bRadialLight = false;
|
|
LightData.SpecularScale = SpecularScale;
|
|
|
|
LightData.ShadowedBits = (DirectionalLightData.DirectionalLightShadowMapChannelMask & 0xFF) != 0 ? 1 : 0;
|
|
// Static shadowing uses ShadowMapChannel, dynamic shadows are packed into light attenuation using PreviewShadowMapChannel
|
|
LightData.ShadowMapChannelMask = UnpackShadowMapChannelMask(DirectionalLightData.DirectionalLightShadowMapChannelMask);
|
|
LightData.HairTransmittance = InitHairTransmittanceData();
|
|
#if USE_HAIR_COMPLEX_TRANSMITTANCE
|
|
if (GBufferData.ShadingModelID == SHADINGMODELID_HAIR)
|
|
{
|
|
LightData.HairTransmittance = EvaluateDualScattering(GBufferData, -CameraVector, LightData.Direction);
|
|
}
|
|
#endif
|
|
// We want to force the directional light shadow when using water material to see shadow on the water. This could be an option later.
|
|
#if DISABLE_FORWARD_DIRECTIONAL_LIGHT_SHADOW
|
|
float4 LightAttenuation = float4(1, 1, 1, 1);
|
|
#elif ((MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER)
|
|
float4 PreviewShadowMapChannelMask = UnpackShadowMapChannelMask(DirectionalLightData.DirectionalLightShadowMapChannelMask >> 4);
|
|
float DynamicShadowing = dot(PreviewShadowMapChannelMask, DynamicShadowFactors);
|
|
|
|
// In the forward shading path we can't separate per-object shadows from CSM, since we only spend one light attenuation channel per light
|
|
// If CSM is enabled (distance fading to precomputed shadowing is active), treat all of our dynamic shadowing as whole scene shadows that will be faded out at the max CSM distance
|
|
// If CSM is not enabled, allow our dynamic shadowing to coexist with precomputed shadowing
|
|
float PerObjectShadowing = LightData.DistanceFadeMAD.y < 0.0f ? 1.0f : DynamicShadowing;
|
|
float WholeSceneShadowing = LightData.DistanceFadeMAD.y < 0.0f ? DynamicShadowing : 1.0f;
|
|
|
|
float4 LightAttenuation = float4(WholeSceneShadowing.xx, PerObjectShadowing.xx);
|
|
#else
|
|
LightData.ShadowedBits = 1;
|
|
LightData.ShadowMapChannelMask.x = 1;
|
|
#if TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING
|
|
GBufferData.PrecomputedShadowFactors.x = ComputeDirectionalLightStaticShadowing(TranslatedWorldPosition).x;
|
|
#else
|
|
GBufferData.PrecomputedShadowFactors.x = 1;
|
|
#endif
|
|
bool bUnused = false;
|
|
float DynamicShadowFactor = ComputeDirectionalLightDynamicShadowing(TranslatedWorldPosition, GBufferData.Depth, bUnused);
|
|
|
|
#if VIRTUAL_SHADOW_MAP
|
|
BRANCH
|
|
if ( ForwardLightData.DirectionalLightVSM != INDEX_NONE )
|
|
{
|
|
FVirtualShadowMapSampleResult VirtualShadowMapSample = SampleVirtualShadowMapTranslatedWorld( ForwardLightData.DirectionalLightVSM, TranslatedWorldPosition );
|
|
DynamicShadowFactor *= VirtualShadowMapSample.ShadowFactor;
|
|
}
|
|
#endif
|
|
|
|
float4 LightAttenuation = float4(DynamicShadowFactor.x, DynamicShadowFactor.x, 1, 1);
|
|
#endif
|
|
|
|
FDeferredLightingSplit NewLighting = GetDynamicLightingSplit(TranslatedWorldPosition, -CameraVector, GBufferData, 1, GBufferData.ShadingModelID, LightData, LightAttenuation, Dither, uint2(0,0), OutDirectionalLightShadow);
|
|
|
|
FLATTEN
|
|
if ((DirectionalLightData.DirectionalLightShadowMapChannelMask >> 8) & LightingChannelMask)
|
|
{
|
|
#if SUPPORT_CLOUD_SHADOW_ON_FORWARD_LIT_TRANSLUCENT
|
|
// This cannot go into LightAttenuation due to some distance based attenuation math being applied.
|
|
NewLighting.DiffuseLighting *= InDirectionalLightCloudShadow;
|
|
NewLighting.SpecularLighting *= InDirectionalLightCloudShadow;
|
|
#endif
|
|
NewLighting.DiffuseLighting.rgb *= InDirectionalLightAtmosphereTransmittance;
|
|
NewLighting.SpecularLighting.rgb *= InDirectionalLightAtmosphereTransmittance;
|
|
|
|
if (bSeparateMainDirLightLuminance)
|
|
{
|
|
SeparatedMainDirLightLuminance += NewLighting.DiffuseLighting.rgb;
|
|
SeparatedMainDirLightLuminance += NewLighting.SpecularLighting.rgb;
|
|
}
|
|
else
|
|
{
|
|
DirectLighting.DiffuseLighting += NewLighting.DiffuseLighting;
|
|
DirectLighting.SpecularLighting += NewLighting.SpecularLighting;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !DISABLE_FORWARD_LOCAL_LIGHTS
|
|
|
|
const FCulledLightsGridData CulledLightsGrid = GetCulledLightsGrid(GridIndex, EyeIndex);
|
|
|
|
|
|
// Limit max to ForwardLightData.NumLocalLights.
|
|
// This prevents GPU hangs when the PS tries to read from uninitialized NumCulledLightsGrid buffer
|
|
const uint NumLocalLights = min(CulledLightsGrid.NumLocalLights, GetNumLocalLights(EyeIndex));
|
|
|
|
LOOP
|
|
for (uint LocalLightListIndex = 0; LocalLightListIndex < NumLocalLights; LocalLightListIndex++)
|
|
{
|
|
const FLocalLightData LocalLight = GetLocalLightData(CulledLightsGrid.DataStartIndex + LocalLightListIndex, EyeIndex);
|
|
|
|
FDeferredLightData LightData = (FDeferredLightData)0;
|
|
LightData.TranslatedWorldPosition = LocalLight.LightPositionAndInvRadius.xyz;
|
|
LightData.InvRadius = LocalLight.LightPositionAndInvRadius.w;
|
|
LightData.Color = LocalLight.LightColorAndFalloffExponent.xyz;
|
|
LightData.FalloffExponent = LocalLight.LightColorAndFalloffExponent.w;
|
|
LightData.Direction = LocalLight.LightDirectionAndShadowMask.xyz;
|
|
LightData.SpotAngles = LocalLight.SpotAnglesAndSourceRadiusPacked.xy;
|
|
LightData.SourceRadius = LocalLight.SpotAnglesAndSourceRadiusPacked.z;
|
|
LightData.SourceLength = f16tof32(asuint(LocalLight.SpotAnglesAndSourceRadiusPacked.w));
|
|
LightData.Tangent = LocalLight.LightTangentAndSoftSourceRadius.xyz;
|
|
LightData.SoftSourceRadius = LocalLight.LightTangentAndSoftSourceRadius.w;
|
|
LightData.bInverseSquared = LightData.FalloffExponent == 0;
|
|
LightData.bRadialLight = true;
|
|
LightData.bSpotLight = LightData.SpotAngles.x > -2.0f;
|
|
LightData.SpecularScale = SpecularScale;
|
|
// Initialize rect light once parameters are supported onto FLocalLightData
|
|
// LightData.RectLightAtlasMaxLevel = LocalLight.RectLightAtlasMaxLevel;
|
|
// LightData.RectLightAtlasUVOffset = LocalLight.RectLightAtlasUVOffset;
|
|
// LightData.RectLightAtlasUVScale = LocalLight.RectLightAtlasUVScale;
|
|
// LightData.RectLightBarnCosAngle = DeferredLightUniforms.RectLightBarnCosAngle;
|
|
// LightData.RectLightBarnLength = DeferredLightUniforms.RectLightBarnLength;
|
|
LightData.HairTransmittance = InitHairTransmittanceData();
|
|
#if USE_HAIR_COMPLEX_TRANSMITTANCE
|
|
if (GBufferData.ShadingModelID == SHADINGMODELID_HAIR)
|
|
{
|
|
LightData.HairTransmittance = EvaluateDualScattering(GBufferData, -CameraVector, LightData.Direction);
|
|
}
|
|
#endif
|
|
|
|
// LightType=bits[17:16], LightingChannelMask=[15:8], DynShadowMask=[7:4] ShadowMapChannelMask=[3:0]
|
|
uint LightTypeAndPackedShadowMapChannelMask = asuint(LocalLight.LightDirectionAndShadowMask.w);
|
|
|
|
// TODO: currently LightType is ignored and the code always sets 'LightData.bRectLight' to false (initialization)
|
|
// but the light grid adds rect lights as well so this probably leads to artifacts.
|
|
uint LightType = LightTypeAndPackedShadowMapChannelMask >> 16;
|
|
|
|
LightData.ShadowedBits = (LightTypeAndPackedShadowMapChannelMask & 0xFF) != 0 ? 1 : 0;
|
|
// Static shadowing uses ShadowMapChannel, dynamic shadows are packed into light attenuation using PreviewShadowMapChannel
|
|
LightData.ShadowMapChannelMask = UnpackShadowMapChannelMask(LightTypeAndPackedShadowMapChannelMask);
|
|
float4 PreviewShadowMapChannelMask = UnpackShadowMapChannelMask(LightTypeAndPackedShadowMapChannelMask >> 4);
|
|
float DynamicShadowing = dot(PreviewShadowMapChannelMask, DynamicShadowFactors);
|
|
float4 LightAttenuation = float4(1, 1, DynamicShadowing.x, DynamicShadowing.x);
|
|
float SurfaceShadow = 1.0f;
|
|
FDeferredLightingSplit NewLighting = GetDynamicLightingSplit(TranslatedWorldPosition, -CameraVector, GBufferData, 1, GBufferData.ShadingModelID, LightData, LightAttenuation, Dither, uint2(0,0), SurfaceShadow);
|
|
|
|
FLATTEN
|
|
if ((LightTypeAndPackedShadowMapChannelMask >> 8) & LightingChannelMask)
|
|
{
|
|
DirectLighting.DiffuseLighting += NewLighting.DiffuseLighting;
|
|
DirectLighting.SpecularLighting += NewLighting.SpecularLighting;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
// Zero out direct lighting if show flag is disabled
|
|
if (ForwardLightData.DirectLightingShowFlag == 0)
|
|
{
|
|
DirectLighting.DiffuseLighting = 0.0f;
|
|
DirectLighting.SpecularLighting = 0.0f;
|
|
}
|
|
|
|
return DirectLighting;
|
|
}
|
|
|
|
float3 GetForwardDirectLightingForVertexLighting(uint GridIndex, float3 TranslatedWorldPosition, float SceneDepth, float3 WorldNormal, uint EyeIndex, float InDirectionalLightCloudShadow)
|
|
{
|
|
float3 DirectLighting = 0;
|
|
// Using white for diffuse color, real diffuse color will be incorporated per-pixel
|
|
float3 DiffuseColor = 1.0f;
|
|
|
|
const FDirectionalLightData DirectionalLightData = GetDirectionalLightData(EyeIndex);
|
|
|
|
BRANCH
|
|
if (DirectionalLightData.HasDirectionalLight)
|
|
{
|
|
float3 N = WorldNormal;
|
|
float3 L = DirectionalLightData.DirectionalLightDirection;
|
|
float NoL = saturate(dot(N, L));
|
|
|
|
float3 LightColor = DirectionalLightData.DirectionalLightColor;
|
|
|
|
#if NON_DIRECTIONAL_DIRECT_LIGHTING
|
|
NoL = 1.0f;
|
|
#endif
|
|
|
|
float ShadowFactor = ComputeDirectionalLightStaticShadowing(TranslatedWorldPosition);
|
|
bool bUnused = false;
|
|
ShadowFactor *= ComputeDirectionalLightDynamicShadowing(TranslatedWorldPosition, SceneDepth, bUnused);
|
|
|
|
#if SUPPORT_CLOUD_SHADOW_ON_FORWARD_LIT_TRANSLUCENT
|
|
ShadowFactor *= InDirectionalLightCloudShadow;
|
|
#endif
|
|
|
|
// No specular for vertex lighting
|
|
float3 DiffuseLighting = Diffuse_Lambert(DiffuseColor);
|
|
DirectLighting += LightColor * (NoL * ShadowFactor) * DiffuseLighting;
|
|
}
|
|
|
|
const FCulledLightsGridData CulledLightsGrid = GetCulledLightsGrid(GridIndex, EyeIndex);
|
|
|
|
// Limit max to ForwardLightData.NumLocalLights.
|
|
// This prevents GPU hangs when the PS tries to read from uninitialized NumCulledLightsGrid buffer
|
|
const uint NumLocalLights = min(CulledLightsGrid.NumLocalLights, GetNumLocalLights(EyeIndex));
|
|
|
|
LOOP
|
|
for (uint LocalLightListIndex = 0; LocalLightListIndex < NumLocalLights; LocalLightListIndex++)
|
|
{
|
|
const FLocalLightData LocalLight = GetLocalLightData(CulledLightsGrid.DataStartIndex + LocalLightListIndex, EyeIndex);
|
|
|
|
FSimpleDeferredLightData LightData = (FSimpleDeferredLightData)0;
|
|
LightData.TranslatedWorldPosition = LocalLight.LightPositionAndInvRadius.xyz;
|
|
LightData.InvRadius = LocalLight.LightPositionAndInvRadius.w;
|
|
LightData.Color = LocalLight.LightColorAndFalloffExponent.xyz;
|
|
LightData.FalloffExponent = LocalLight.LightColorAndFalloffExponent.w;
|
|
LightData.bInverseSquared = LightData.FalloffExponent == 0;
|
|
|
|
// No specular for vertex lighting
|
|
float3 CameraVector = 0;
|
|
float3 SpecularColor = 0;
|
|
float Roughness = 1.0f;
|
|
DirectLighting += GetSimpleDynamicLighting(TranslatedWorldPosition, CameraVector, WorldNormal, 1, DiffuseColor, SpecularColor, Roughness, LightData);
|
|
}
|
|
|
|
// Zero out direct lighting if show flag is disabled
|
|
if (ForwardLightData.DirectLightingShowFlag == 0)
|
|
{
|
|
DirectLighting = 0.0f;
|
|
}
|
|
|
|
return DirectLighting;
|
|
}
|
|
|
|
uint MortonCode( uint x )
|
|
{
|
|
//x = (x ^ (x << 8)) & 0x00ff00ff;
|
|
//x = (x ^ (x << 4)) & 0x0f0f0f0f;
|
|
x = (x ^ (x << 2)) & 0x33333333;
|
|
x = (x ^ (x << 1)) & 0x55555555;
|
|
return x;
|
|
}
|
|
|
|
// Translucency Surface per-pixel uses blended reflection captures by default in the deferred renderer
|
|
// Have to opt-in to blended reflection captures in the forward renderer
|
|
#define USE_BLENDED_REFLECTION_CAPTURES_DEFERRED (!FORWARD_SHADING && (TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME))
|
|
#define USE_BLENDED_REFLECTION_CAPTURES_FORWARD (FORWARD_SHADING && MATERIAL_HQ_FORWARD_REFLECTION_CAPTURES)
|
|
#define REFLECTION_COMPOSITE_USE_BLENDED_REFLECTION_CAPTURES ((USE_BLENDED_REFLECTION_CAPTURES_DEFERRED || USE_BLENDED_REFLECTION_CAPTURES_FORWARD) && FEATURE_LEVEL >= FEATURE_LEVEL_SM5)
|
|
// REFLECTION_COMPOSITE_SUPPORT_SKYLIGHT_BLEND covers forward rendered material for deferred and forward shading pathes.
|
|
#define REFLECTION_COMPOSITE_SUPPORT_SKYLIGHT_BLEND (MATERIAL_FORWARD_BLENDS_SKYLIGHT_CUBEMAPS)
|
|
#define REFLECTION_COMPOSITE_HAS_BOX_CAPTURES 1
|
|
#define REFLECTION_COMPOSITE_HAS_SPHERE_CAPTURES 1
|
|
#include "ReflectionEnvironmentComposite.ush"
|
|
|
|
half3 GetImageBasedReflectionSpecular(FMaterialPixelParameters MaterialParameters, float3 RayDirection, half Roughness, half IndirectIrradiance, uint GridIndex, int SingleCaptureIndex, uint EyeIndex)
|
|
{
|
|
float3 SpecularIBL;
|
|
bool bUseLumenFrontLayerReflection = false;
|
|
|
|
#if (TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME) && MATERIALBLENDING_ANY_TRANSLUCENT && !FORWARD_SHADING
|
|
|
|
bUseLumenFrontLayerReflection = UseFrontLayerReflection(MaterialParameters.ViewBufferUV, MaterialParameters.ScreenPosition.w);
|
|
|
|
FRadianceCacheCoverage LumenRadianceCacheCoverage;
|
|
LumenRadianceCacheCoverage.bValid = false;
|
|
|
|
// Lumen Radiance Cache for reflections on translucency
|
|
if (TranslucentBasePass_FinalProbeResolution > 0 && !bUseLumenFrontLayerReflection)
|
|
{
|
|
float ClipmapDitherRandom = InterleavedGradientNoise(MaterialParameters.SvPosition.xy, View.StateFrameIndexMod8);
|
|
LumenRadianceCacheCoverage = GetRadianceCacheCoverage(LWCHackToFloat(MaterialParameters.AbsoluteWorldPosition), RayDirection, ClipmapDitherRandom);
|
|
}
|
|
|
|
if (bUseLumenFrontLayerReflection)
|
|
{
|
|
SpecularIBL = SampleFrontLayerReflection(MaterialParameters.ViewBufferUV);
|
|
}
|
|
else if (LumenRadianceCacheCoverage.bValid)
|
|
{
|
|
float ConeHalfAngle = 0;
|
|
SpecularIBL = SampleRadianceCacheInterpolated(LumenRadianceCacheCoverage, LWCHackToFloat(MaterialParameters.AbsoluteWorldPosition), RayDirection, ConeHalfAngle);
|
|
}
|
|
// Fallback to unshadowed skylight if no valid Radiance Cache
|
|
else
|
|
#endif
|
|
{
|
|
uint NumLocalReflectionCaptures = 0;
|
|
uint DataStartIndex = 0;
|
|
|
|
#if REFLECTION_COMPOSITE_USE_BLENDED_REFLECTION_CAPTURES
|
|
#if INSTANCED_STEREO
|
|
BRANCH
|
|
if (EyeIndex == 0)
|
|
{
|
|
#endif
|
|
|
|
uint NumCulledEntryIndex = (ForwardLightData.NumGridCells + GridIndex) * NUM_CULLED_LIGHTS_GRID_STRIDE;
|
|
NumLocalReflectionCaptures = min(ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 0], ForwardLightData.NumReflectionCaptures);
|
|
DataStartIndex = ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 1];
|
|
|
|
#if INSTANCED_STEREO
|
|
}
|
|
else
|
|
{
|
|
uint NumCulledEntryIndex = (ForwardLightDataISR.NumGridCells + GridIndex) * NUM_CULLED_LIGHTS_GRID_STRIDE;
|
|
NumLocalReflectionCaptures = min(ForwardLightDataISR.NumCulledLightsGrid[NumCulledEntryIndex + 0], ForwardLightDataISR.NumReflectionCaptures);
|
|
DataStartIndex = ForwardLightDataISR.NumCulledLightsGrid[NumCulledEntryIndex + 1];
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
const bool bCompositeSkylight = true;
|
|
SpecularIBL = CompositeReflectionCapturesAndSkylightTWS(
|
|
1.0f,
|
|
MaterialParameters.WorldPosition_CamRelative,
|
|
RayDirection,
|
|
Roughness,
|
|
IndirectIrradiance,
|
|
1.0f,
|
|
0.0f,
|
|
NumLocalReflectionCaptures,
|
|
DataStartIndex,
|
|
SingleCaptureIndex,
|
|
bCompositeSkylight,
|
|
EyeIndex);
|
|
}
|
|
|
|
#if MATERIAL_SSR && !FORWARD_SHADING
|
|
if( View.CameraCut == 0 && TranslucentBasePass.SSRQuality > 0 && !bUseLumenFrontLayerReflection)
|
|
{
|
|
float StepOffset = InterleavedGradientNoise( MaterialParameters.SvPosition.xy, View.StateFrameIndexMod8 );
|
|
StepOffset -= 0.5;
|
|
|
|
bool bDebugPrint = false;
|
|
|
|
float3 HitUVz;
|
|
float Level = 0;
|
|
|
|
bool bHit = RayCast(
|
|
TranslucentBasePass.HZBTexture, TranslucentBasePass.HZBSampler,
|
|
MaterialParameters.WorldPosition_CamRelative, RayDirection, Roughness, MaterialParameters.ScreenPosition.w,
|
|
12, StepOffset,
|
|
TranslucentBasePass.HZBUvFactorAndInvFactor,
|
|
bDebugPrint,
|
|
HitUVz,
|
|
Level
|
|
);
|
|
|
|
BRANCH if( bHit )
|
|
{
|
|
float2 SampleUV;
|
|
float Vignette;
|
|
ReprojectHit(TranslucentBasePass.PrevScreenPositionScaleBias, HitUVz, SampleUV, Vignette);
|
|
|
|
SampleUV = clamp(SampleUV, TranslucentBasePass.PrevSceneColorBilinearUVMin, TranslucentBasePass.PrevSceneColorBilinearUVMax);
|
|
|
|
float4 SSR = SampleScreenColor(
|
|
TranslucentBasePass.PrevSceneColor,
|
|
TranslucentBasePass.PrevSceneColorSampler,
|
|
SampleUV);
|
|
|
|
SSR *= Vignette * saturate( 2 - 6.6 * Roughness );
|
|
|
|
SSR.rgb *= TranslucentBasePass.PrevSceneColorPreExposureInv;
|
|
SpecularIBL.rgb = SpecularIBL.rgb * (1 - SSR.a) + SSR.rgb;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
float3 SpecularLighting = SpecularIBL.rgb;
|
|
|
|
// Have to opt-in to receiving planar reflections with forward shading
|
|
#if !FORWARD_SHADING || MATERIAL_PLANAR_FORWARD_REFLECTIONS
|
|
// Plane normal will be zero if the feature is disabled
|
|
BRANCH
|
|
if (abs(dot(PlanarReflectionStruct.ReflectionPlane.xyz, 1)) > .0001f)
|
|
{
|
|
// Reuse ReflectionCubemapSampler to avoid reducing the sampler count available to artists
|
|
float4 PlanarReflection = ComputePlanarReflections(MaterialParameters.WorldPosition_CamRelative, MaterialParameters.WorldNormal, Roughness, ReflectionStruct.ReflectionCubemapSampler);
|
|
// Planar reflections win over SSR and reflection environment
|
|
SpecularLighting = PlanarReflection.rgb + (1 - PlanarReflection.a) * SpecularLighting;
|
|
}
|
|
#endif
|
|
|
|
return SpecularLighting;
|
|
}
|
|
|
|
half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameters, half Roughness, half3 SpecularColor, half IndirectIrradiance, uint GridIndex, int SingleCaptureIndex, uint EyeIndex)
|
|
{
|
|
float3 N = MaterialParameters.WorldNormal;
|
|
float3 V = MaterialParameters.CameraVector;
|
|
|
|
float3 RayDirection = 2 * dot(V, N) * N - V;
|
|
half NoV = saturate(dot(N, V));
|
|
|
|
const float3 SpecularLighting = GetImageBasedReflectionSpecular(MaterialParameters, RayDirection, Roughness, IndirectIrradiance, GridIndex, SingleCaptureIndex, EyeIndex);
|
|
|
|
#if MATERIAL_USE_PREINTEGRATED_GF
|
|
SpecularColor = EnvBRDF(SpecularColor, Roughness, NoV);
|
|
#else
|
|
SpecularColor = EnvBRDFApprox(SpecularColor, Roughness, NoV);
|
|
#endif
|
|
return SpecularLighting * SpecularColor;
|
|
}
|
|
|
|
half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameters, half Roughness, half3 SpecularColor, half IndirectIrradiance, uint GridIndex, int SingleCaptureIndex)
|
|
{
|
|
return GetImageBasedReflectionLighting(MaterialParameters, Roughness, SpecularColor, IndirectIrradiance, GridIndex, SingleCaptureIndex, 0);
|
|
} |