430 lines
17 KiB
HLSL
430 lines
17 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#define MOBILE_DEFERRED_LIGHTING 1
|
|
|
|
#if SUBSTRATE_ENABLED
|
|
// This is needed when lights are rendered deferred on mobile with Substrate because we use the legacy GBuffer representation and code process.
|
|
#define ALLOW_LOCAL_LIGHT_DISTANCE_ATTENUATION 1
|
|
#endif
|
|
|
|
#include "Common.ush"
|
|
#include "SHCommon.ush"
|
|
|
|
// Reroute MobileSceneTextures uniform buffer references to the base pass uniform buffer
|
|
#define MobileSceneTextures MobileBasePass.SceneTextures
|
|
#define ForwardLightStruct MobileBasePass.Forward
|
|
#define PlanarReflectionStruct MobileBasePass.PlanarReflection
|
|
#define ReflectionStruct MobileBasePass.ReflectionsParameters
|
|
#define PreIntegratedGF ReflectionStruct.PreIntegratedGF
|
|
#define PreIntegratedGFSampler ReflectionStruct.PreIntegratedGFSampler
|
|
|
|
#if MATERIAL_SHADER
|
|
#include "/Engine/Generated/Material.ush"
|
|
#endif
|
|
|
|
#include "MobileLightingCommon.ush"
|
|
#if MATERIAL_SHADER
|
|
#include "LightFunctionCommon.ush"
|
|
#endif
|
|
#include "LightDataUniforms.ush"
|
|
#include "LightShaderParameters.ush"
|
|
|
|
#ifndef USE_HAIR_COMPLEX_TRANSMITTANCE
|
|
#define USE_HAIR_COMPLEX_TRANSMITTANCE 0
|
|
#endif
|
|
#include "HairStrands/HairStrandsEnvironmentLightingCommon.ush"
|
|
|
|
#if APPLY_SKY_SHADOWING
|
|
#include "SkyLightingDiffuseShared.ush"
|
|
#include "DistanceFieldAOShared.ush"
|
|
#endif
|
|
|
|
float4x4 TranslatedWorldToLight;
|
|
float2 LightFunctionParameters2;
|
|
|
|
half ComputeLightFunctionMultiplier(float3 TranslatedWorldPosition)
|
|
{
|
|
#if USE_LIGHT_FUNCTION
|
|
float4 LightVector = mul(float4(TranslatedWorldPosition, 1.0), TranslatedWorldToLight);
|
|
LightVector.xyz /= LightVector.w;
|
|
|
|
half3 LightFunction = GetLightFunctionColor(LightVector.xyz, TranslatedWorldPosition);
|
|
half GreyScale = dot(LightFunction, .3333f);
|
|
// Calculate radial view distance for stable fading
|
|
float ViewDistance = length(PrimaryView.TranslatedWorldCameraOrigin - TranslatedWorldPosition);
|
|
half DistanceFadeAlpha = saturate((LightFunctionParameters2.x - ViewDistance) / (LightFunctionParameters2.x * .2f));
|
|
// Fade to disabled based on LightFunctionFadeDistance
|
|
GreyScale = lerp(LightFunctionParameters2.y, GreyScale, DistanceFadeAlpha);
|
|
// Fade to disabled based on ShadowFadeFraction
|
|
GreyScale = lerp(LightFunctionParameters2.y, GreyScale, LightFunctionParameters.y);
|
|
return GreyScale;
|
|
#else
|
|
return 1.0;
|
|
#endif
|
|
}
|
|
|
|
half3 SkyLightDiffuseMobile(FGBufferData GBuffer, half3 DiffuseColor, half3 V, inout half IndirectIrradiance)
|
|
{
|
|
half3 Lighting = 0;
|
|
half3 SkyDiffuseLookUpNormal = GBuffer.WorldNormal;
|
|
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE)
|
|
{
|
|
half3 SubsurfaceLookup = GetSkySHDiffuseSimple(-GBuffer.WorldNormal) * View.SkyLightColor.rgb;
|
|
half3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
|
|
Lighting += SubsurfaceLookup * SubsurfaceColor;
|
|
}
|
|
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE || GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
|
|
{
|
|
half3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
|
|
// Add subsurface energy to diffuse
|
|
DiffuseColor += SubsurfaceColor;
|
|
}
|
|
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
|
|
{
|
|
const half3 N = GBuffer.WorldNormal;
|
|
DiffuseColor = EvaluateEnvHair(GBuffer, V, N, SkyDiffuseLookUpNormal);
|
|
}
|
|
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_CLOTH)
|
|
{
|
|
half3 ClothFuzz = ExtractSubsurfaceColor(GBuffer);
|
|
DiffuseColor += ClothFuzz * GBuffer.CustomData.a;
|
|
}
|
|
|
|
// Compute the preconvolved incoming lighting with the bent normal direction
|
|
half3 DiffuseLookup = GetSkySHDiffuseSimple(SkyDiffuseLookUpNormal) * View.SkyLightColor.rgb;
|
|
|
|
// And accumulate the lighting
|
|
Lighting += DiffuseLookup * DiffuseColor * GBuffer.GBufferAO;
|
|
|
|
#if ALLOW_STATIC_LIGHTING
|
|
IndirectIrradiance += Luminance(DiffuseLookup);
|
|
#endif
|
|
|
|
return Lighting;
|
|
}
|
|
|
|
void ReflectionEnvironmentSkyLighting(
|
|
FGBufferData GBuffer,
|
|
half4 SvPosition,
|
|
half3 CameraVector,
|
|
float3 TranslatedWorldPosition,
|
|
half3 ReflectionVector,
|
|
uint GridIndex,
|
|
half GatheredAmbientOcclusion,
|
|
inout FLightAccumulator DirectLighting)
|
|
{
|
|
half IndirectIrradiance = GBuffer.IndirectIrradiance;
|
|
|
|
#if ENABLE_SKY_LIGHT
|
|
|
|
half3 N = GBuffer.WorldNormal;
|
|
half3 V = -CameraVector;
|
|
half NoV = saturate(abs(dot(N, V)) + 1e-5);
|
|
#if APPLY_SKY_SHADOWING
|
|
half3 BentNormal = GBuffer.WorldNormal;
|
|
const float2 BentNormalUV = (SvPosition.xy - View.ViewRectMin.xy) * View.BufferSizeAndInvSize.zw;
|
|
BentNormal = UpsampleDFAO(BentNormalUV, GBuffer.Depth, GBuffer.WorldNormal);
|
|
#endif
|
|
|
|
half3 DiffuseColor = GBuffer.DiffuseColor;
|
|
half3 SpecularColor = GBuffer.SpecularColor;
|
|
RemapClearCoatDiffuseAndSpecularColor(GBuffer, NoV, DiffuseColor, SpecularColor);
|
|
#if APPLY_SKY_SHADOWING
|
|
//const float3 DiffuseColor = GBuffer.BaseColor; // not used
|
|
const float2 BufferUV = SvPosition * View.BufferSizeAndInvSize.zw; // not used
|
|
float2 ScreenPosition = SvPositionToScreenPosition(SvPosition).xy;
|
|
// Sky lighting (already pre-exposed)
|
|
half3 SkyLighting = SkyLightDiffuse(GBuffer, GatheredAmbientOcclusion, BufferUV, ScreenPosition, BentNormal, DiffuseColor);
|
|
#else
|
|
half3 SkyLighting = SkyLightDiffuseMobile(GBuffer, DiffuseColor, V, IndirectIrradiance);
|
|
#endif
|
|
const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID);
|
|
LightAccumulator_Add(DirectLighting, SkyLighting, SkyLighting, 1.0f, bNeedsSeparateSubsurfaceLightAccumulation);
|
|
#endif // ENABLE_SKY_LIGHT
|
|
|
|
// IBL
|
|
AccumulateReflection(GBuffer
|
|
, SvPosition
|
|
, CameraVector
|
|
, TranslatedWorldPosition
|
|
, ReflectionVector
|
|
, IndirectIrradiance
|
|
, GridIndex
|
|
, DirectLighting);
|
|
}
|
|
|
|
void MobileDirectionalLightPS(
|
|
noperspective float4 UVAndScreenPos : TEXCOORD0,
|
|
#if INSTANCED_STEREO && MOBILE_MULTI_VIEW
|
|
in nointerpolation uint EyeIndex : VIEW_ID,
|
|
#elif MOBILE_MULTI_VIEW
|
|
in nointerpolation uint ViewId : SV_ViewID,
|
|
#endif
|
|
float4 SvPosition : SV_POSITION,
|
|
#if USE_GLES_FBF_DEFERRED
|
|
out HALF4_TYPE OutProxyAdditive : SV_Target0,
|
|
out HALF4_TYPE OutGBufferA : SV_Target1,
|
|
out HALF4_TYPE OutGBufferB : SV_Target2,
|
|
out HALF4_TYPE OutGBufferC : SV_Target3
|
|
#else
|
|
out HALF4_TYPE OutColor : SV_Target0
|
|
#endif
|
|
)
|
|
{
|
|
#if INSTANCED_STEREO && MOBILE_MULTI_VIEW
|
|
ResolvedView = ResolveView(EyeIndex);
|
|
#elif MOBILE_MULTI_VIEW
|
|
ResolvedView = ResolveView(ViewId);
|
|
const uint EyeIndex = ViewId;
|
|
#else
|
|
ResolvedView = ResolveView();
|
|
const uint EyeIndex = 0;
|
|
#endif
|
|
|
|
FGBufferData GBuffer = MobileFetchAndDecodeGBuffer(UVAndScreenPos.xy, UVAndScreenPos.zw);
|
|
float2 ScreenPos = UVAndScreenPos.zw;
|
|
float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPos, GBuffer.Depth), GBuffer.Depth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
|
|
|
|
half3 CameraVector = normalize(TranslatedWorldPosition);
|
|
half3 V = -CameraVector;
|
|
half NoV = dot(GBuffer.WorldNormal, V);
|
|
half3 ReflectionVector = GBuffer.WorldNormal * (NoV * 2.0) - V;
|
|
|
|
FLightAccumulator DirectLighting = (FLightAccumulator)0;
|
|
|
|
float4 ScreenPosition = SvPositionToScreenPosition(float4(SvPosition.xyz, GBuffer.Depth));
|
|
|
|
half GatheredAmbientOcclusion = 1;
|
|
#if ENABLE_AMBIENT_OCCLUSION
|
|
GatheredAmbientOcclusion = Texture2DSample(MobileBasePass.AmbientOcclusionTexture, MobileBasePass.AmbientOcclusionSampler, UVAndScreenPos.xy).r;
|
|
GatheredAmbientOcclusion = lerp(1.0, GatheredAmbientOcclusion, MobileBasePass.AmbientOcclusionStaticFraction);
|
|
GBuffer.GBufferAO *= GatheredAmbientOcclusion;
|
|
#endif
|
|
|
|
// Directional light
|
|
half4 DynamicShadowFactors = 1.0f;
|
|
float DirectionalLightShadow = 1.0f;
|
|
AccumulateDirectionalLighting(GBuffer, TranslatedWorldPosition, CameraVector, ScreenPosition, SvPosition, DynamicShadowFactors, DirectionalLightShadow, DirectLighting, 0);
|
|
// LightFunction should only affect direct lighting result
|
|
DirectLighting.TotalLight *= ComputeLightFunctionMultiplier(TranslatedWorldPosition);
|
|
|
|
float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
|
|
uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), GBuffer.Depth, EyeIndex);
|
|
// Local lights
|
|
#if ENABLE_CLUSTERED_LIGHTS
|
|
{
|
|
const FCulledLightsGridHeader CulledLightGridHeader = GetCulledLightsGridHeader(GridIndex);
|
|
half4 LocalLightDynamicShadowFactors = 1.0f;
|
|
AccumulateLightGridLocalLighting(CulledLightGridHeader, GBuffer, TranslatedWorldPosition, CameraVector, EyeIndex, 0, LocalLightDynamicShadowFactors, DirectLighting);
|
|
}
|
|
#endif
|
|
|
|
#if ENABLE_CLUSTERED_REFLECTION || ENABLE_SKY_LIGHT || ENABLE_PLANAR_REFLECTION || MOBILE_SSR_ENABLED
|
|
// If we have a single directional light, apply relfection and sky contrubution here
|
|
ReflectionEnvironmentSkyLighting(GBuffer, SvPosition, CameraVector, TranslatedWorldPosition, ReflectionVector, GridIndex, GatheredAmbientOcclusion, DirectLighting);
|
|
#endif
|
|
|
|
half3 Color = DirectLighting.TotalLight;
|
|
// MobileHDR applies PreExposure in tonemapper
|
|
Color *= View.PreExposure;
|
|
|
|
Color = SafeGetOutColor(Color);
|
|
#if USE_GLES_FBF_DEFERRED
|
|
OutProxyAdditive.rgb = Color;
|
|
#else
|
|
OutColor.rgb = Color;
|
|
// Blend is enabled only for static skylights
|
|
OutColor.a = GatheredAmbientOcclusion;
|
|
#endif
|
|
}
|
|
|
|
#if SUPPORT_SPOTLIGHTS_SHADOW
|
|
float4 SpotLightShadowSharpenAndFadeFractionAndReceiverDepthBiasAndSoftTransitionScale;
|
|
float4 SpotLightShadowmapMinMax;
|
|
float4x4 SpotLightShadowWorldToShadowMatrix;
|
|
Texture2D LocalLightShadowTexture;
|
|
SamplerState LocalLightShadowSampler;
|
|
float4 LocalLightShadowBufferSize;
|
|
#endif
|
|
|
|
FDeferredLightData InitDeferredLightFromLightParameters(FLightShaderParameters In, uint InLightType)
|
|
{
|
|
FDeferredLightData Out = (FDeferredLightData)0;
|
|
Out.TranslatedWorldPosition = In.TranslatedWorldPosition;
|
|
Out.InvRadius = In.InvRadius;
|
|
Out.Color = In.Color;
|
|
Out.FalloffExponent = In.FalloffExponent;
|
|
Out.Direction = In.Direction;
|
|
Out.Tangent = In.Tangent;
|
|
Out.SpotAngles = In.SpotAngles;
|
|
Out.SpecularScale = In.SpecularScale;
|
|
Out.DiffuseScale = In.DiffuseScale;
|
|
Out.SourceRadius = In.SourceRadius;
|
|
Out.SoftSourceRadius = In.SoftSourceRadius;
|
|
Out.SourceLength = In.SourceLength;
|
|
|
|
Out.RectLightData.BarnCosAngle = In.RectLightBarnCosAngle;
|
|
Out.RectLightData.BarnLength = In.RectLightBarnLength;
|
|
Out.RectLightData.AtlasData.AtlasUVOffset = In.RectLightAtlasUVOffset;
|
|
Out.RectLightData.AtlasData.AtlasUVScale = In.RectLightAtlasUVScale;
|
|
Out.RectLightData.AtlasData.AtlasMaxLevel = In.RectLightAtlasMaxLevel;
|
|
|
|
Out.IESAtlasIndex = In.IESAtlasIndex;
|
|
Out.LightFunctionAtlasLightIndex = In.LightFunctionAtlasLightIndex;
|
|
Out.bAffectsTranslucentLighting = In.bAffectsTranslucentLighting;
|
|
|
|
Out.bInverseSquared = In.FalloffExponent == 0;
|
|
Out.bRadialLight = true;
|
|
Out.bSpotLight = InLightType == LIGHT_TYPE_SPOT;
|
|
Out.bRectLight = InLightType == LIGHT_TYPE_RECT;
|
|
Out.HairTransmittance = InitHairTransmittanceData();
|
|
|
|
#if SUPPORT_SPOTLIGHTS_SHADOW
|
|
Out.ShadowedBits = 1;
|
|
Out.ShadowMapChannelMask = 1.f;
|
|
#endif
|
|
return Out;
|
|
}
|
|
|
|
void MobileRadialLightPS(
|
|
float4 InScreenPosition : TEXCOORD0,
|
|
float4 SVPos : SV_POSITION,
|
|
#if USE_GLES_FBF_DEFERRED
|
|
out HALF4_TYPE OutProxyAdditive : SV_Target0,
|
|
out HALF4_TYPE OutGBufferA : SV_Target1,
|
|
out HALF4_TYPE OutGBufferB : SV_Target2,
|
|
out HALF4_TYPE OutGBufferC : SV_Target3
|
|
#else
|
|
out HALF4_TYPE OutColor : SV_Target0
|
|
#endif
|
|
)
|
|
{
|
|
ResolvedView = ResolveView();
|
|
|
|
float2 ScreenUV = InScreenPosition.xy / InScreenPosition.w * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
|
|
FGBufferData GBuffer = MobileFetchAndDecodeGBuffer(ScreenUV, SVPos.xy);
|
|
// With a perspective projection, the clip space position is NDC * Clip.w
|
|
// With an orthographic projection, clip space is the same as NDC
|
|
float2 ClipPosition = GetScreenPositionForProjectionType(InScreenPosition.xy / InScreenPosition.w, GBuffer.Depth);
|
|
float3 TranslatedWorldPosition = mul(float4(ClipPosition, GBuffer.Depth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
|
|
half3 CameraVector = normalize(TranslatedWorldPosition);
|
|
|
|
FLightAccumulator DirectLighting = (FLightAccumulator)0;
|
|
FDeferredLightData LightData = InitDeferredLightFromLightParameters(GetRootLightShaderParameters(), RADIAL_LIGHT_TYPE);
|
|
|
|
// Affect the light color by any other shadow/transmittance before the lighting is evaluated
|
|
{
|
|
half Attenuation = ComputeLightProfileMultiplier(TranslatedWorldPosition, LightData.TranslatedWorldPosition, -LightData.Direction, LightData.Tangent, LightData.IESAtlasIndex);
|
|
LightData.Color *= Attenuation;
|
|
}
|
|
|
|
half Shadow = 1.0;
|
|
#if SUPPORT_SPOTLIGHTS_SHADOW
|
|
float3 ToLight = LightData.TranslatedWorldPosition - TranslatedWorldPosition;
|
|
float3 LocalPosition = -ToLight;
|
|
float DistanceSqr = dot(ToLight, ToLight);
|
|
half3 L = ToLight * rsqrt(DistanceSqr);
|
|
half3 N = GBuffer.WorldNormal;
|
|
half NoL = saturate(dot(N, L));
|
|
|
|
FPCFSamplerSettings Settings;
|
|
Settings.ShadowDepthTexture = LocalLightShadowTexture;
|
|
Settings.ShadowDepthTextureSampler = LocalLightShadowSampler;
|
|
Settings.ShadowBufferSize = LocalLightShadowBufferSize;
|
|
Settings.bSubsurface = false;
|
|
Settings.bTreatMaxDepthUnshadowed = false;
|
|
Settings.DensityMulConstant = 0;
|
|
Settings.ProjectionDepthBiasParameters = 0;
|
|
|
|
float SpotLightShadowSharpen = SpotLightShadowSharpenAndFadeFractionAndReceiverDepthBiasAndSoftTransitionScale.x;
|
|
float SpotLightFadeFraction = SpotLightShadowSharpenAndFadeFractionAndReceiverDepthBiasAndSoftTransitionScale.y;
|
|
float SpotLightReceiverDepthBias = SpotLightShadowSharpenAndFadeFractionAndReceiverDepthBiasAndSoftTransitionScale.z;
|
|
float SpotLightSoftTransitionScale = SpotLightShadowSharpenAndFadeFractionAndReceiverDepthBiasAndSoftTransitionScale.w;
|
|
|
|
float4 HomogeneousShadowPosition = mul(float4(LocalPosition, 1), SpotLightShadowWorldToShadowMatrix);
|
|
float2 ShadowUVs = HomogeneousShadowPosition.xy / HomogeneousShadowPosition.w;
|
|
if (all(ShadowUVs >= SpotLightShadowmapMinMax.xy && ShadowUVs <= SpotLightShadowmapMinMax.zw))
|
|
{
|
|
// Clamp pixel depth in light space for shadowing opaque, because areas of the shadow depth buffer that weren't rendered to will have been cleared to 1
|
|
// We want to force the shadow comparison to result in 'unshadowed' in that case, regardless of whether the pixel being shaded is in front or behind that plane
|
|
// Invert ShadowZ as the shadow space has been changed (but not yet the filtering code)
|
|
float ShadowZ = 1.0f - HomogeneousShadowPosition.z;
|
|
float LightSpacePixelDepthForOpaque = min(ShadowZ, 0.99999f);
|
|
Settings.SceneDepth = LightSpacePixelDepthForOpaque;
|
|
Settings.TransitionScale = SpotLightSoftTransitionScale * lerp(SpotLightReceiverDepthBias, 1.0, NoL);
|
|
|
|
Shadow = MobileShadowPCF(ShadowUVs, Settings);
|
|
Shadow = saturate((Shadow - 0.5) * SpotLightShadowSharpen + 0.5f);
|
|
Shadow = lerp(1.0f, Square(Shadow), SpotLightFadeFraction);
|
|
}
|
|
#endif
|
|
|
|
half4 LightAttenuation = half4(1, 1, Shadow, Shadow);
|
|
|
|
float SurfaceShadow = 0;
|
|
DirectLighting = AccumulateDynamicLighting(TranslatedWorldPosition, CameraVector, GBuffer, 1, LightData, LightAttenuation, 0, uint2(0, 0), SurfaceShadow);
|
|
|
|
half3 Color = DirectLighting.TotalLight * ComputeLightFunctionMultiplier(TranslatedWorldPosition);
|
|
// MobileHDR applies PreExposure in tonemapper
|
|
Color *= View.PreExposure;
|
|
Color = SafeGetOutColor(Color);
|
|
|
|
#if USE_GLES_FBF_DEFERRED
|
|
OutProxyAdditive.rgb = Color;
|
|
#else
|
|
OutColor.rgb = Color;
|
|
OutColor.a = 1;
|
|
#endif
|
|
}
|
|
|
|
void MobileReflectionEnvironmentSkyLightingPS(
|
|
noperspective float4 UVAndScreenPos : TEXCOORD0
|
|
, float4 SvPosition : SV_POSITION
|
|
#if USE_GLES_FBF_DEFERRED
|
|
, out HALF4_TYPE OutProxyAdditive : SV_Target0
|
|
, out HALF4_TYPE OutGBufferA : SV_Target1
|
|
, out HALF4_TYPE OutGBufferB : SV_Target2
|
|
, out HALF4_TYPE OutGBufferC : SV_Target3
|
|
#else
|
|
, out HALF4_TYPE OutColor : SV_Target0
|
|
#endif
|
|
)
|
|
{
|
|
ResolvedView = ResolveView();
|
|
FGBufferData GBuffer = MobileFetchAndDecodeGBuffer(UVAndScreenPos.xy, UVAndScreenPos.zw);
|
|
float2 ScreenPos = UVAndScreenPos.zw;
|
|
float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPos, GBuffer.Depth), GBuffer.Depth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
|
|
half3 CameraVector = normalize(TranslatedWorldPosition);
|
|
half3 V = -CameraVector;
|
|
half NoV = max(0, dot(GBuffer.WorldNormal, V));
|
|
half3 ReflectionVector = GBuffer.WorldNormal * (NoV * 2.0) - V;
|
|
|
|
const uint EyeIndex = 0;
|
|
float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
|
|
uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), GBuffer.Depth, EyeIndex);
|
|
|
|
half GatheredAmbientOcclusion = 1;
|
|
#if ENABLE_AMBIENT_OCCLUSION
|
|
GatheredAmbientOcclusion = Texture2DSample(MobileBasePass.AmbientOcclusionTexture, MobileBasePass.AmbientOcclusionSampler, UVAndScreenPos.xy).r;
|
|
GatheredAmbientOcclusion = lerp(1.0, GatheredAmbientOcclusion, MobileBasePass.AmbientOcclusionStaticFraction);
|
|
GBuffer.GBufferAO *= GatheredAmbientOcclusion;
|
|
#endif
|
|
|
|
FLightAccumulator DirectLighting = (FLightAccumulator)0;
|
|
ReflectionEnvironmentSkyLighting(GBuffer, SvPosition, CameraVector, TranslatedWorldPosition, ReflectionVector, GridIndex, GatheredAmbientOcclusion, DirectLighting);
|
|
half3 ReflectionAndSky = DirectLighting.TotalLight;
|
|
|
|
ReflectionAndSky *= View.PreExposure;
|
|
|
|
#if USE_GLES_FBF_DEFERRED
|
|
OutProxyAdditive.rgb = ReflectionAndSky.rgb;
|
|
#else
|
|
OutColor.rgb = ReflectionAndSky.rgb;
|
|
// Blend is enabled only for static skylights
|
|
OutColor.a = GatheredAmbientOcclusion;
|
|
#endif
|
|
} |