Files
UnrealEngineUWP/Engine/Shaders/Private/LightmapCommon.ush

275 lines
11 KiB
Plaintext

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "ShadingCommon.ush"
#include "/Engine/Generated/UniformBuffers/PrecomputedLightingBuffer.ush"
#include "VolumetricLightmapShared.ush"
#include "VirtualTextureCommon.ush"
#include "LightmapData.ush"
#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)
half4 SampleLightmapVT(float2 UV, Texture2D CacheTexture, SamplerState CacheSampler, float2 SvPositionXY, out uint Request)
{
#if LIGHTMAP_VT_ENABLED
VTSampleInfo VTInfo = GetVTSampleInfo(PrecomputedLightingBuffer.LightmapVirtualTextureUniformData, UV, LIGHTMAP_VT_16BIT, SvPositionXY);
uint2 pPage;
uint vPagesWideInLevel;
#if LIGHTMAP_VT_16BIT
PageTable2DTranslation16( PrecomputedLightingBuffer.LightmapVirtualTexturePageTable, GetVirtualTexturePageTableSize(PrecomputedLightingBuffer.LightmapVirtualTextureUniformData), VTInfo.vPage, VTInfo.Level, pPage, vPagesWideInLevel );
#else
PageTable2DTranslation32( PrecomputedLightingBuffer.LightmapVirtualTexturePageTable, PrecomputedLightingBuffer.LightmapVirtualTexturePageTableSampler, UV, VTInfo.Level, pPage, vPagesWideInLevel );
#endif
const float vPageSize = GetVirtualTexturePageSize(PrecomputedLightingBuffer.LightmapVirtualTextureUniformData);
const float pPageBorder = GetVirtualTexturePageBorder(PrecomputedLightingBuffer.LightmapVirtualTextureUniformData);
const float pPageSize = vPageSize + 2 * pPageBorder;
const float2 pTextureSize = GetVirtualTextureCacheSize(PrecomputedLightingBuffer.LightmapVirtualTextureUniformData);
const float2 pUV = VirtualToPhysical2D( pTextureSize, vPageSize, pPageSize, pPage, vPagesWideInLevel, UV, VTInfo.dUVdx, VTInfo.dUVdy );
Request = VTInfo.Request;
return CacheTexture.SampleGrad( CacheSampler, pUV, VTInfo.dUVdx, VTInfo.dUVdy );
#else
Request = 0xffffffff;
return Texture2DSample( CacheTexture, CacheSampler, UV );
#endif
}
half4 GetLightMapColorLQ( float2 LightmapUV0, float2 LightmapUV1, uint LightmapDataIndex, half3 WorldNormal )
{
half4 Lightmap0 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV0 );
half4 Lightmap1 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV1 );
// 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
#else
half Directionality = 0.6;
#endif
half Luma = L * Directionality;
half3 Color = LogRGB * (Luma / LogL); // 1 rcp, 1 smul, 1 vmul
return half4( Color, Luma );
}
void GetLightMapColorHQ( float2 LightmapUV0, float2 LightmapUV1, uint LightmapDataIndex, half3 WorldNormal, float2 SvPositionXY, uint ShadingModel, out half3 OutDiffuseLighting, out half3 OutSubsurfaceLighting, out uint VTRequest )
{
OutSubsurfaceLighting = 0;
#if LIGHTMAP_VT_ENABLED
LightmapUV0 *= float2(1, 2);
#endif
half4 Lightmap0 = SampleLightmapVT( LightmapUV0 , LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, SvPositionXY, VTRequest);
uint VTRequest_notused = 0;
half4 Lightmap1 = SampleLightmapVT(
#if LIGHTMAP_VT_ENABLED
LightmapUV0, LightmapResourceCluster.LightMapTexture_1,
#else
LightmapUV1, LightmapResourceCluster.LightMapTexture,
#endif
LightmapResourceCluster.LightMapSampler, SvPositionXY, VTRequest_notused);
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 MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE
if (ShadingModel == SHADINGMODELID_TWOSIDED_FOLIAGE)
{
half SubsurfaceDirectionality = max(0.0, dot(SH, float4(-WorldNormal.yzx, 1)));
OutSubsurfaceLighting = L * SubsurfaceDirectionality * UVW;
}
#endif
#else
half Directionality = 0.6;
#if MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE
if (ShadingModel == SHADINGMODELID_TWOSIDED_FOLIAGE)
{
OutSubsurfaceLighting = L * Directionality * UVW;
}
#endif
#endif
half Luma = L * Directionality;
half3 Color = Luma * UVW;
OutDiffuseLighting = Color;
}
float4 GetSkyBentNormalAndOcclusion(float2 LightmapUV, float2 SvPositionXY)
{
uint VTRequest_notused;
#if SUPPORTS_INDEPENDENT_SAMPLERS
// Share sampler with lightmaps to give artists more available
float4 TextureValue = SampleLightmapVT( LightmapUV.xy , LightmapResourceCluster.SkyOcclusionTexture, LightmapResourceCluster.LightMapSampler, SvPositionXY, VTRequest_notused);
#else
float4 TextureValue = SampleLightmapVT( LightmapUV.xy , LightmapResourceCluster.SkyOcclusionTexture, LightmapResourceCluster.SkyOcclusionSampler, SvPositionXY, VTRequest_notused);
#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(float2 LightmapUV, float2 SvPositionXY)
{
uint VTRequest_notused;
#if SUPPORTS_INDEPENDENT_SAMPLERS
// Share sampler with lightmaps to give artists more available
float TextureValue = SampleLightmapVT( LightmapUV.xy , LightmapResourceCluster.AOMaterialMaskTexture, LightmapResourceCluster.LightMapSampler, SvPositionXY, VTRequest_notused).x;
#else
float TextureValue = SampleLightmapVT( LightmapUV.xy , LightmapResourceCluster.AOMaterialMaskTexture, LightmapResourceCluster.AOMaterialMaskSampler, SvPositionXY, VTRequest_notused).x;
#endif
// Undo sqrt which allocated more precision toward 0
return TextureValue * TextureValue;
}
#endif
// Used by deferred renderer only
half4 GetPrecomputedShadowMasks(FVertexFactoryInterpolantsVSToPS Interpolants, uint PrimitiveId, float3 WorldPosition, float3 VolumetricLightmapBrickTextureUVs)
{
// Note: WRITES_PRECSHADOWFACTOR_ZERO have to match the logic here
#if STATICLIGHTING_TEXTUREMASK && STATICLIGHTING_SIGNEDDISTANCEFIELD
float2 ShadowMapCoordinate;
uint LightmapDataIndex;
GetShadowMapCoordinate(Interpolants, ShadowMapCoordinate, LightmapDataIndex);
// Fetch the 4 channels of distance field data
half4 DistanceField = Texture2DSample(LightmapResourceCluster.StaticShadowTexture, LightmapResourceCluster.StaticShadowTextureSampler, ShadowMapCoordinate);
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;
#else
float DirectionalLightShadowing = 1.0f;
#if CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
if (GetPrimitiveData(PrimitiveId).UseSingleSampleShadowFromStationaryLights > 0 && View.IndirectLightingCacheShowFlag > 0.0f)
{
DirectionalLightShadowing = IndirectLightingCache.DirectionalLightShadowing;
}
#endif
BRANCH
if (GetPrimitiveData(PrimitiveId).UseVolumetricLightmapShadowFromStationaryLights > 0)
{
#if !PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
// Compute brick UVs if we haven't already
VolumetricLightmapBrickTextureUVs = ComputeVolumetricLightmapBrickTextureUVs(WorldPosition);
#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);
#endif
}
// Used by mobile renderer only
half GetPrimaryPrecomputedShadowMask(FVertexFactoryInterpolantsVSToPS Interpolants)
{
#if STATICLIGHTING_TEXTUREMASK && STATICLIGHTING_SIGNEDDISTANCEFIELD
float2 ShadowMapCoordinate;
uint LightmapDataIndex;
GetShadowMapCoordinate(Interpolants, ShadowMapCoordinate, LightmapDataIndex);
// Fetch the distance field data
half DistanceField = Texture2DSample(LightmapResourceCluster.StaticShadowTexture, LightmapResourceCluster.StaticShadowTextureSampler, ShadowMapCoordinate).r;
float4 InvUniformPenumbraSizes = GetLightmapData(LightmapDataIndex).InvUniformPenumbraSizes;
float DistanceFieldBias = -.5f * InvUniformPenumbraSizes.x + .5f;
// Compute shadow factors by scaling and biasing the distance
half ShadowFactor = saturate( DistanceField * InvUniformPenumbraSizes.x + DistanceFieldBias );
return GetLightmapData(LightmapDataIndex).StaticShadowMapMasks.r * ShadowFactor * ShadowFactor;
#elif MOVABLE_DIRECTIONAL_LIGHT
// Do this before checking for lightmaps as we might have a lightmap + directional light
//@mw todo
// TODO: Filter shadowmap
return 1;
#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;
#else
#if CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
// output per-primitive directional light shadowing if requested
if (GetPrimitiveData(Interpolants.PrimitiveId).UseSingleSampleShadowFromStationaryLights > 0 && ResolvedView.IndirectLightingCacheShowFlag > 0.0f)
{
return IndirectLightingCache.DirectionalLightShadowing;
}
#endif
return 1;
#endif
}