329 lines
14 KiB
HLSL
329 lines
14 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ShadingCommon.ush"
|
|
#include "/Engine/Generated/UniformBuffers/PrecomputedLightingBuffer.ush"
|
|
#include "VolumetricLightmapShared.ush"
|
|
|
|
#if !NUM_VIRTUALTEXTURE_SAMPLES && !LIGHTMAP_VT_ENABLED
|
|
#define VTPageTableResult float
|
|
#endif
|
|
|
|
#if LIGHTMAP_VT_ENABLED
|
|
#include "VirtualTextureCommon.ush"
|
|
#endif
|
|
#include "LightmapData.ush"
|
|
|
|
#if IS_NANITE_PASS
|
|
#define LightmapUVType FloatDeriv2
|
|
#else
|
|
#define LightmapUVType float2
|
|
#endif
|
|
|
|
float2 ScaleLightmapUV(float2 UV, float2 Scale)
|
|
{
|
|
return UV * Scale;
|
|
}
|
|
|
|
FloatDeriv2 ScaleLightmapUV(FloatDeriv2 UV, float2 Scale)
|
|
{
|
|
UV.Value *= Scale;
|
|
UV.Ddx *= Scale;
|
|
UV.Ddy *= Scale;
|
|
return UV;
|
|
}
|
|
|
|
#if HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP
|
|
|
|
#ifndef MATERIAL_USE_LM_DIRECTIONALITY
|
|
#define MATERIAL_USE_LM_DIRECTIONALITY 1
|
|
#endif
|
|
|
|
// Material quality overrides
|
|
#ifndef QL_FORCEDISABLE_LM_DIRECTIONALITY
|
|
#define QL_FORCEDISABLE_LM_DIRECTIONALITY 0
|
|
#endif
|
|
|
|
#define USE_LM_DIRECTIONALITY (MATERIAL_USE_LM_DIRECTIONALITY && !QL_FORCEDISABLE_LM_DIRECTIONALITY)
|
|
|
|
#define LIGHTMAP_VTADDRESSMODE VTADDRESSMODE_CLAMP
|
|
|
|
#if LIGHTMAP_VT_ENABLED
|
|
VTPageTableResult LightmapGetVTSampleInfo(float2 UV, uint LightmapDataIndex, float2 SvPositionXY)
|
|
{
|
|
UV = ScaleLightmapUV(UV, float2(1.0f, 2.0f)); // Undo transform used to pack 2 lightmap coeffs in 1 texture for the non-VT default case
|
|
|
|
return TextureLoadVirtualPageTable(LightmapResourceCluster.LightmapVirtualTexturePageTable0, LightmapResourceCluster.LightmapVirtualTexturePageTable1,
|
|
VTPageTableUniform_Unpack(GetLightmapData(LightmapDataIndex).LightmapVTPackedPageTableUniform[0], GetLightmapData(LightmapDataIndex).LightmapVTPackedPageTableUniform[1]),
|
|
UV, LIGHTMAP_VTADDRESSMODE, LIGHTMAP_VTADDRESSMODE, 0, SvPositionXY);
|
|
}
|
|
|
|
VTPageTableResult LightmapGetVTSampleInfo(FloatDeriv2 UV, uint LightmapDataIndex, float2 SvPositionXY)
|
|
{
|
|
UV = ScaleLightmapUV(UV, float2(1.0f, 2.0f)); // Undo transform used to pack 2 lightmap coeffs in 1 texture for the non-VT default case
|
|
|
|
return TextureLoadVirtualPageTableGrad(LightmapResourceCluster.LightmapVirtualTexturePageTable0, LightmapResourceCluster.LightmapVirtualTexturePageTable1,
|
|
VTPageTableUniform_Unpack(GetLightmapData(LightmapDataIndex).LightmapVTPackedPageTableUniform[0], GetLightmapData(LightmapDataIndex).LightmapVTPackedPageTableUniform[1]),
|
|
UV.Value, LIGHTMAP_VTADDRESSMODE, LIGHTMAP_VTADDRESSMODE, UV.Ddx, UV.Ddy, SvPositionXY);
|
|
}
|
|
|
|
half4 SampleLightmapVT(VTPageTableResult LightmapVTPageTableResult, uint LayerIndex, uint LightmapDataIndex, Texture2D CacheTexture, SamplerState CacheSampler)
|
|
{
|
|
return TextureVirtualSample(
|
|
CacheTexture, CacheSampler,
|
|
LightmapVTPageTableResult, LayerIndex,
|
|
VTUniform_Unpack(GetLightmapData(LightmapDataIndex).LightmapVTPackedUniform[LayerIndex]));
|
|
}
|
|
#endif // LIGHTMAP_VT_ENABLED
|
|
|
|
void GetLightMapColorLQ( VTPageTableResult LightmapVTPageTableResult, LightmapUVType LightmapUV0, LightmapUVType LightmapUV1, uint LightmapDataIndex, half3 WorldNormal, bool bEvaluateBackface, out half3 OutDiffuseLighting, out half3 OutSubsurfaceLighting)
|
|
{
|
|
OutSubsurfaceLighting = 0;
|
|
|
|
#if LIGHTMAP_VT_ENABLED
|
|
half4 Lightmap0 = SampleLightmapVT(LightmapVTPageTableResult, 0u, LightmapDataIndex, LightmapResourceCluster.VTLightMapTexture, LightmapResourceCluster.LightMapSampler);
|
|
half4 Lightmap1 = SampleLightmapVT(LightmapVTPageTableResult, 1u, LightmapDataIndex, LightmapResourceCluster.VTLightMapTexture_1, LightmapResourceCluster.LightMapSampler_1);
|
|
#else
|
|
half4 Lightmap0 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV0 );
|
|
half4 Lightmap1 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV1 );
|
|
#endif
|
|
|
|
// Range scale
|
|
half3 LogRGB = Lightmap0.rgb * GetLightmapData(LightmapDataIndex).LightMapScale[0].xyz + GetLightmapData(LightmapDataIndex).LightMapAdd[0].xyz; // 1 vmad
|
|
|
|
half LogL = Luminance( LogRGB ); // 1 dot
|
|
|
|
// LogL -> L
|
|
const half LogBlackPoint = 0.00390625; // exp2(-8);
|
|
half L = exp2( LogL * 16 - 8 ) - LogBlackPoint; // 1 exp2, 1 smad, 1 ssub
|
|
|
|
#if USE_LM_DIRECTIONALITY
|
|
// Alpha doesn't matter, will scaled by zero
|
|
float4 SH = Lightmap1 * GetLightmapData(LightmapDataIndex).LightMapScale[1] + GetLightmapData(LightmapDataIndex).LightMapAdd[1]; // 1 vmad
|
|
|
|
// Sample SH with normal
|
|
half Directionality = max( 0.0, dot( SH, float4(WorldNormal.yzx, 1) ) ); // 1 dot, 1 smax
|
|
|
|
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
|
|
if (bEvaluateBackface)
|
|
{
|
|
half SubsurfaceDirectionality = max(0.0, dot(SH, float4(-WorldNormal.yzx, 1)));
|
|
half SubsurfaceLuma = L * SubsurfaceDirectionality;
|
|
OutSubsurfaceLighting = LogRGB * (SubsurfaceLuma / LogL);
|
|
}
|
|
#endif
|
|
#else
|
|
half Directionality = 0.6;
|
|
|
|
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
|
|
if (bEvaluateBackface)
|
|
{
|
|
half SubsurfaceLuma = L * Directionality;
|
|
OutSubsurfaceLighting = LogRGB * (SubsurfaceLuma / LogL);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
half Luma = L * Directionality;
|
|
half3 Color = LogRGB * (Luma / max(0.00001f, LogL)); // 1 smax, 1 rcp, 1 smul, 1 vmul
|
|
|
|
OutDiffuseLighting = Color;
|
|
}
|
|
|
|
void GetLightMapColorHQ( VTPageTableResult LightmapVTPageTableResult, LightmapUVType LightmapUV0, LightmapUVType LightmapUV1, uint LightmapDataIndex, half3 WorldNormal, float2 SvPositionXY, bool bEvaluateBackface, out half3 OutDiffuseLighting, out half3 OutSubsurfaceLighting )
|
|
{
|
|
OutSubsurfaceLighting = 0;
|
|
|
|
half4 Lightmap0;
|
|
half4 Lightmap1;
|
|
#if LIGHTMAP_VT_ENABLED
|
|
Lightmap0 = SampleLightmapVT( LightmapVTPageTableResult, 0u, LightmapDataIndex, LightmapResourceCluster.VTLightMapTexture, LightmapResourceCluster.LightMapSampler);
|
|
Lightmap1 = SampleLightmapVT( LightmapVTPageTableResult, 1u, LightmapDataIndex, LightmapResourceCluster.VTLightMapTexture_1, LightmapResourceCluster.LightMapSampler);
|
|
#else
|
|
Lightmap0 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV0 );
|
|
Lightmap1 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV1 );
|
|
#endif
|
|
|
|
half LogL = Lightmap0.w;
|
|
|
|
// Add residual
|
|
LogL += Lightmap1.w * (1.0 / 255) - (0.5 / 255);
|
|
|
|
// Range scale LogL
|
|
LogL = LogL * GetLightmapData(LightmapDataIndex).LightMapScale[0].w + GetLightmapData(LightmapDataIndex).LightMapAdd[0].w;
|
|
|
|
// Range scale UVW
|
|
half3 UVW = Lightmap0.rgb * Lightmap0.rgb * GetLightmapData(LightmapDataIndex).LightMapScale[0].rgb + GetLightmapData(LightmapDataIndex).LightMapAdd[0].rgb;
|
|
|
|
// LogL -> L
|
|
const half LogBlackPoint = 0.01858136;
|
|
half L = exp2( LogL ) - LogBlackPoint;
|
|
|
|
#if USE_LM_DIRECTIONALITY
|
|
// Range scale SH. Alpha doesn't matter, will scale with zero
|
|
float4 SH = Lightmap1 * GetLightmapData(LightmapDataIndex).LightMapScale[1] + GetLightmapData(LightmapDataIndex).LightMapAdd[1];
|
|
|
|
// Sample SH with normal
|
|
half Directionality = max( 0.0, dot( SH, float4(WorldNormal.yzx, 1) ) );
|
|
|
|
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
|
|
if (bEvaluateBackface)
|
|
{
|
|
half SubsurfaceDirectionality = max(0.0, dot(SH, float4(-WorldNormal.yzx, 1)));
|
|
OutSubsurfaceLighting = L * SubsurfaceDirectionality * UVW;
|
|
}
|
|
#endif
|
|
#else
|
|
half Directionality = 0.6;
|
|
|
|
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
|
|
if (bEvaluateBackface)
|
|
{
|
|
OutSubsurfaceLighting = L * Directionality * UVW;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
half Luma = L * Directionality;
|
|
half3 Color = Luma * UVW;
|
|
|
|
OutDiffuseLighting = Color;
|
|
}
|
|
|
|
#if SUPPORTS_INDEPENDENT_SAMPLERS
|
|
#define LIGHTMAP_SHARED_SAMPLER( Sampler ) LightmapResourceCluster.LightMapSampler
|
|
#else
|
|
#define LIGHTMAP_SHARED_SAMPLER( Sampler ) LightmapResourceCluster.Sampler
|
|
#endif
|
|
|
|
float4 GetSkyBentNormalAndOcclusion(VTPageTableResult LightmapVTPageTableResult, LightmapUVType LightmapUV, uint LightmapDataIndex, float2 SvPositionXY)
|
|
{
|
|
float4 TextureValue;
|
|
#if LIGHTMAP_VT_ENABLED
|
|
TextureValue = SampleLightmapVT( LightmapVTPageTableResult, 3u, LightmapDataIndex, LightmapResourceCluster.VTSkyOcclusionTexture, LIGHTMAP_SHARED_SAMPLER(SkyOcclusionSampler));
|
|
#else
|
|
TextureValue = Texture2DSample( LightmapResourceCluster.SkyOcclusionTexture, LIGHTMAP_SHARED_SAMPLER(SkyOcclusionSampler), LightmapUV );
|
|
#endif
|
|
|
|
// Unpack vector
|
|
TextureValue.rgb = TextureValue.rgb * 2 - 1;
|
|
// Undo sqrt which allocated more precision toward 0
|
|
TextureValue.a = TextureValue.a * TextureValue.a;
|
|
return TextureValue;
|
|
}
|
|
|
|
float GetAOMaterialMask(VTPageTableResult LightmapVTPageTableResult, LightmapUVType LightmapUV, uint LightmapDataIndex, float2 SvPositionXY)
|
|
{
|
|
float TextureValue;
|
|
#if LIGHTMAP_VT_ENABLED
|
|
TextureValue = SampleLightmapVT( LightmapVTPageTableResult, 4u, LightmapDataIndex, LightmapResourceCluster.VTAOMaterialMaskTexture, LIGHTMAP_SHARED_SAMPLER(AOMaterialMaskSampler)).x;
|
|
#else
|
|
TextureValue = Texture2DSample( LightmapResourceCluster.AOMaterialMaskTexture, LIGHTMAP_SHARED_SAMPLER(AOMaterialMaskSampler), LightmapUV ).x;
|
|
#endif
|
|
|
|
// Undo sqrt which allocated more precision toward 0
|
|
return TextureValue * TextureValue;
|
|
}
|
|
|
|
#endif
|
|
|
|
// Used by deferred renderer only
|
|
half4 GetPrecomputedShadowMasks(VTPageTableResult LightmapVTPageTableResult, FVertexFactoryInterpolantsVSToPS Interpolants, FMaterialPixelParameters MaterialParameters, float3 VolumetricLightmapBrickTextureUVs)
|
|
{
|
|
// Note: WRITES_PRECSHADOWFACTOR_ZERO have to match the logic here
|
|
#if STATICLIGHTING_TEXTUREMASK && STATICLIGHTING_SIGNEDDISTANCEFIELD
|
|
|
|
// VT doesn't need ShadowMapCoordinate (instead shared lightmap UV), but still needs LightmapDataIndex
|
|
LightmapUVType ShadowMapCoordinate;
|
|
uint LightmapDataIndex;
|
|
GetShadowMapCoordinate(Interpolants, ShadowMapCoordinate, LightmapDataIndex);
|
|
|
|
// Fetch the 4 channels of distance field data
|
|
half4 DistanceField;
|
|
#if LIGHTMAP_VT_ENABLED
|
|
DistanceField = SampleLightmapVT( LightmapVTPageTableResult, 2u, LightmapDataIndex, LightmapResourceCluster.VTStaticShadowTexture, LIGHTMAP_SHARED_SAMPLER(StaticShadowTextureSampler));
|
|
#else
|
|
DistanceField = Texture2DSample(LightmapResourceCluster.StaticShadowTexture, LIGHTMAP_SHARED_SAMPLER(StaticShadowTextureSampler), ShadowMapCoordinate);
|
|
#endif
|
|
|
|
float4 InvUniformPenumbraSizes = GetLightmapData(LightmapDataIndex).InvUniformPenumbraSizes;
|
|
float4 DistanceFieldBias = -.5f * InvUniformPenumbraSizes + .5f;
|
|
|
|
// Compute shadow factors by scaling and biasing the distance
|
|
half4 ShadowFactors = saturate(DistanceField * InvUniformPenumbraSizes + DistanceFieldBias);
|
|
return GetLightmapData(LightmapDataIndex).StaticShadowMapMasks * ShadowFactors * ShadowFactors;
|
|
|
|
#elif HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP
|
|
|
|
// Mark as shadowed for lightmapped objects with no shadowmap
|
|
// This is necessary because objects inside a light's influence that were determined to be completely shadowed won't be rendered with STATICLIGHTING_TEXTUREMASK==1
|
|
return 0;
|
|
|
|
#elif ALLOW_STATIC_LIGHTING
|
|
|
|
float DirectionalLightShadowing = 1.0f;
|
|
|
|
#if CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
|
|
if ((GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_USE_SINGLE_SAMPLE_SHADOW_SL) != 0 && View.IndirectLightingCacheShowFlag > 0.0f)
|
|
{
|
|
DirectionalLightShadowing = IndirectLightingCache.DirectionalLightShadowing;
|
|
}
|
|
#endif
|
|
|
|
BRANCH
|
|
if ((GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_USE_VOLUMETRIC_LM_SHADOW_SL) != 0)
|
|
{
|
|
#if !PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
|
|
// Compute brick UVs if we haven't already
|
|
VolumetricLightmapBrickTextureUVs = ComputeVolumetricLightmapBrickTextureUVs(WSHackToFloat(GetWorldPosition(MaterialParameters)));
|
|
#endif
|
|
|
|
DirectionalLightShadowing = GetVolumetricLightmapDirectionalLightShadowing(VolumetricLightmapBrickTextureUVs);
|
|
}
|
|
|
|
// Directional light is always packed into the first static shadowmap channel, so output the per-primitive directional light shadowing there if requested
|
|
return half4(DirectionalLightShadowing, 1, 1, 1);
|
|
|
|
#else
|
|
|
|
return half4(1, 1, 1, 1);
|
|
|
|
#endif
|
|
}
|
|
|
|
// Used by mobile renderer only
|
|
half4 GetPrimaryPrecomputedShadowMask(VTPageTableResult LightmapVTPageTableResult, FVertexFactoryInterpolantsVSToPS Interpolants, FMaterialPixelParameters MaterialParameters)
|
|
{
|
|
#if STATICLIGHTING_TEXTUREMASK && STATICLIGHTING_SIGNEDDISTANCEFIELD
|
|
|
|
LightmapUVType ShadowMapCoordinate;
|
|
uint LightmapDataIndex;
|
|
GetShadowMapCoordinate(Interpolants, ShadowMapCoordinate, LightmapDataIndex);
|
|
|
|
// Fetch the distance field data
|
|
#if LIGHTMAP_VT_ENABLED
|
|
half4 DistanceField = SampleLightmapVT(LightmapVTPageTableResult, 2u, LightmapDataIndex, LightmapResourceCluster.VTStaticShadowTexture, LightmapResourceCluster.StaticShadowTextureSampler);
|
|
#else
|
|
half4 DistanceField = Texture2DSample(LightmapResourceCluster.StaticShadowTexture, LightmapResourceCluster.StaticShadowTextureSampler, ShadowMapCoordinate);
|
|
#endif
|
|
float4 InvUniformPenumbraSizes = GetLightmapData(LightmapDataIndex).InvUniformPenumbraSizes;
|
|
float4 DistanceFieldBias = -.5f * InvUniformPenumbraSizes + .5f;
|
|
// Compute shadow factors by scaling and biasing the distance
|
|
half4 ShadowFactor = saturate( DistanceField * InvUniformPenumbraSizes + DistanceFieldBias );
|
|
return GetLightmapData(LightmapDataIndex).StaticShadowMapMasks * ShadowFactor * ShadowFactor;
|
|
#elif HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP
|
|
// Mark as shadowed for lightmapped objects with no shadowmap
|
|
// This is necessary because objects inside a light's influence that were determined to be completely shadowed won't be rendered with STATICLIGHTING_TEXTUREMASK==1
|
|
return 0.0f;
|
|
#else
|
|
#if CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
|
|
// output per-primitive directional light shadowing if requested
|
|
if ((GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_USE_SINGLE_SAMPLE_SHADOW_SL) != 0 && ResolvedView.IndirectLightingCacheShowFlag > 0.0f)
|
|
{
|
|
return half4(IndirectLightingCache.DirectionalLightShadowing, 1, 1, 1);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return 1.0f;
|
|
}
|