Files
UnrealEngine/Engine/Shaders/Private/DistanceFieldAOShared.ush
2025-05-18 13:04:45 +08:00

232 lines
7.4 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DistanceFieldAOShared.ush
=============================================================================*/
#include "IntersectionUtils.ush"
// Must match C++
#define NUM_CONE_STEPS 10
// Must match C++
#define NUM_CONE_DIRECTIONS 9
// Must match C++
#define AO_DOWNSAMPLE_FACTOR 2
float AOObjectMaxDistance;
float AOStepScale;
float AOStepExponentScale;
float AOMaxViewDistance;
float DistanceFadeScale; // 1 / ((1 - FadeDistanceFraction) * AOMaxViewDistance)
float AOGlobalMaxOcclusionDistance;
// Gives the max occlusion distance regardless of whether the global distance field is in use
float GetAOMaxDistance()
{
return max(AOObjectMaxDistance, AOGlobalMaxOcclusionDistance);
}
float GetStepOffset(float StepIndex)
{
// Original heuristic
//return AOStepScale * exp2(AOStepExponentScale * StepIndex);
float temp = AOStepExponentScale * StepIndex;
return AOStepScale * (temp * temp + 1);
}
uint2 TileListGroupSize;
Texture2D DistanceFieldNormalTexture;
SamplerState DistanceFieldNormalSampler;
float4 EncodeDownsampledGBuffer(in float3 WorldNormal, float SceneDepth)
{
#if METAL_ES3_1_PROFILE
// clamp max depth to avoid #inf
SceneDepth = min(SceneDepth, 65500.0f);
#endif
return float4(WorldNormal, SceneDepth);
}
void GetDownsampledGBuffer(float2 ScreenUV, out float3 OutNormal, out float OutDepth)
{
float4 TextureValue = Texture2DSampleLevel(DistanceFieldNormalTexture, DistanceFieldNormalSampler, ScreenUV, 0);
OutNormal = TextureValue.xyz;
OutDepth = TextureValue.w;
}
float GetDownsampledDepth(float2 ScreenUV)
{
return abs(Texture2DSampleLevel(DistanceFieldNormalTexture, DistanceFieldNormalSampler, ScreenUV, 0).w);
}
float2 BaseLevelTexelSize;
Texture2D BentNormalAOTexture;
SamplerState BentNormalAOSampler;
Buffer<float> RecordConeVisibility;
float4 SampleDirections[NUM_CONE_DIRECTIONS];
float BentNormalNormalizeFactor;
void FindBestAxisVectors2(float3 InZAxis, out float3 OutXAxis, out float3 OutYAxis )
{
float3 UpVector = abs(InZAxis.z) < 0.999 ? float3(0,0,1) : float3(1,0,0);
OutXAxis = normalize( cross( UpVector, InZAxis ) );
OutYAxis = cross( InZAxis, OutXAxis );
}
float3 ComputeBentNormal(float3 RecordWorldNormal, uint RelativeRecordIndex)
{
float3 TangentX;
float3 TangentY;
FindBestAxisVectors2(RecordWorldNormal, TangentX, TangentY);
float3 UnoccludedDirection = 0;
for (uint ConeIndex = 0; ConeIndex < NUM_CONE_DIRECTIONS; ConeIndex++)
{
float3 ConeDirection = SampleDirections[ConeIndex].xyz;
float3 RotatedConeDirection = ConeDirection.x * TangentX + ConeDirection.y * TangentY + ConeDirection.z * RecordWorldNormal;
float ConeVisibility = RecordConeVisibility[RelativeRecordIndex * NUM_CONE_DIRECTIONS + ConeIndex];
UnoccludedDirection += ConeVisibility * RotatedConeDirection;
}
float InvNumSamples = 1.0f / (float)NUM_CONE_DIRECTIONS;
UnoccludedDirection = UnoccludedDirection * (BentNormalNormalizeFactor * InvNumSamples);
return UnoccludedDirection;
}
float2 AOBufferBilinearUVMax;
struct FUpsampleDFAOOutput
{
float3 BentNormal;
float FadeAlpha;
};
FUpsampleDFAOOutput UpsampleDFAO(float2 BufferUV, float SceneDepth)
{
FUpsampleDFAOOutput UpsampleDFAOOutput;
float2 DistanceFieldUVs = min(BufferUV, AOBufferBilinearUVMax);
#define BILATERAL_UPSAMPLE 1
#if BILATERAL_UPSAMPLE
float2 LowResBufferSize = floor(View.BufferSizeAndInvSize.xy / AO_DOWNSAMPLE_FACTOR);
float2 LowResTexelSize = 1.0f / LowResBufferSize;
float2 Corner00UV = floor(DistanceFieldUVs * LowResBufferSize - .5f) / LowResBufferSize + .5f * LowResTexelSize;
float2 BilinearWeights = (DistanceFieldUVs - Corner00UV) * LowResBufferSize;
float4 TextureValues00 = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, Corner00UV, 0);
float4 TextureValues10 = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, Corner00UV + float2(LowResTexelSize.x, 0), 0);
float4 TextureValues01 = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, Corner00UV + float2(0, LowResTexelSize.y), 0);
float4 TextureValues11 = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, Corner00UV + LowResTexelSize, 0);
float4 CornerWeights = float4(
(1 - BilinearWeights.y) * (1 - BilinearWeights.x),
(1 - BilinearWeights.y) * BilinearWeights.x,
BilinearWeights.y * (1 - BilinearWeights.x),
BilinearWeights.y * BilinearWeights.x);
float Epsilon = .0001f;
float4 CornerDepths = float4(TextureValues00.w, TextureValues10.w, TextureValues01.w, TextureValues11.w);
float4 DepthWeights = 1.0f / (abs(CornerDepths - SceneDepth.xxxx) + Epsilon);
float4 FinalWeights = CornerWeights * DepthWeights;
float InvWeight = 1.0f / dot(FinalWeights, 1);
float3 InterpolatedResult =
(FinalWeights.x * TextureValues00.xyz
+ FinalWeights.y * TextureValues10.xyz
+ FinalWeights.z * TextureValues01.xyz
+ FinalWeights.w * TextureValues11.xyz)
* InvWeight;
float3 BentNormal = InterpolatedResult.xyz;
#else
float3 BentNormal = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, DistanceFieldUVs, 0).xyz;
#endif
UpsampleDFAOOutput.BentNormal = BentNormal;
// Fade to unoccluded in the distance
UpsampleDFAOOutput.FadeAlpha = saturate((AOMaxViewDistance - SceneDepth) * DistanceFadeScale);
return UpsampleDFAOOutput;
}
float3 ApplyDFAO(FUpsampleDFAOOutput UpsampleDFAOOutput, float3 WorldNormal)
{
return lerp(WorldNormal, UpsampleDFAOOutput.BentNormal, UpsampleDFAOOutput.FadeAlpha);
}
float3 UpsampleDFAO(float2 BufferUV, float SceneDepth, float3 WorldNormal)
{
FUpsampleDFAOOutput UpsampleDFAOOutput = UpsampleDFAO(BufferUV, SceneDepth);
return ApplyDFAO(UpsampleDFAOOutput, WorldNormal);
}
#ifndef CULLED_TILE_SIZEX
#define CULLED_TILE_SIZEX 4
#endif
#ifndef TRACE_DOWNSAMPLE_FACTOR
#define TRACE_DOWNSAMPLE_FACTOR 1
#endif
#ifndef CONE_TRACE_OBJECTS_THREADGROUP_SIZE
#define CONE_TRACE_OBJECTS_THREADGROUP_SIZE 16
#endif
// Size of a culled tile at the resolution that cone tracing is done, in one dimension
#define CONE_TILE_SIZEX (CULLED_TILE_SIZEX / TRACE_DOWNSAMPLE_FACTOR)
// Number of culled tiles per cone tracing threadgroup
#define CONE_TRACE_TILES_PER_THREADGROUP (CONE_TRACE_OBJECTS_THREADGROUP_SIZE / (CONE_TILE_SIZEX * CONE_TILE_SIZEX))
uint2 ScreenGridConeVisibilitySize;
float2 JitterOffset;
uint2 ComputeTileCoordinateFromScreenGrid(uint2 OutputCoordinate)
{
uint2 TileCoordinate = OutputCoordinate * TRACE_DOWNSAMPLE_FACTOR / CULLED_TILE_SIZEX;
return TileCoordinate;
}
float2 GetBaseLevelScreenUVFromScreenGrid(uint2 OutputCoordinate, float JitterScale)
{
float2 BaseLevelScreenUV = (OutputCoordinate * TRACE_DOWNSAMPLE_FACTOR + JitterOffset * JitterScale + float2(.5f, .5f)) * BaseLevelTexelSize;
return BaseLevelScreenUV;
}
float2 GetBaseLevelScreenUVFromScreenGrid(uint2 OutputCoordinate)
{
return GetBaseLevelScreenUVFromScreenGrid(OutputCoordinate, 1);
}
float2 GetScreenUVFromScreenGrid(uint2 OutputCoordinate, float JitterScale)
{
float2 ScreenUV = ((OutputCoordinate * TRACE_DOWNSAMPLE_FACTOR + JitterOffset * JitterScale) * AO_DOWNSAMPLE_FACTOR + View.ViewRectMin.xy + float2(.5f, .5f)) * View.BufferSizeAndInvSize.zw;
return ScreenUV;
}
float2 GetScreenUVFromScreenGrid(uint2 OutputCoordinate)
{
return GetScreenUVFromScreenGrid(OutputCoordinate, 1);
}
StructuredBuffer<uint> CulledTilesStartOffsetArray;
#define INVALID_TILE_INDEX 0xFFFF
#ifndef CULLED_TILE_DATA_STRIDE
#define CULLED_TILE_DATA_STRIDE 1
#endif