// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= LumenTranslucencyLightingShared.ush =============================================================================*/ #pragma once #include "../BlueNoise.ush" #include "../HZB.ush" #define PROBE_SOURCE_MODE_NONE 0 #define PROBE_SOURCE_MODE_RADIANCE_CACHE 1 #define PROBE_SOURCE_MODE_FROXEL 2 uint TranslucencyVolumeTracingOctahedronResolution; uint3 TranslucencyGIGridSize; float3 TranslucencyGIGridZParams; uint TranslucencyGIGridPixelSizeShift; int FroxelDirectionJitterFrameIndex; float3 FrameJitterOffset; float4x4 UnjitteredClipToTranslatedWorld; float GridCenterOffsetFromDepthBuffer; float GridCenterOffsetThresholdToAcceptDepthBufferOffset; float ComputeDepthFromZSlice(float ZSlice) { float SliceDepth = (exp2(ZSlice / TranslucencyGIGridZParams.z) - TranslucencyGIGridZParams.y) / TranslucencyGIGridZParams.x; return SliceDepth; } float ComputeZSliceFromDepth(float SliceDepth) { float ZSlice = log2(SliceDepth * TranslucencyGIGridZParams.x + TranslucencyGIGridZParams.y) * TranslucencyGIGridZParams.z; return ZSlice; } float3 ComputeCellTranslatedWorldPosition(uint3 GridCoordinate, float3 CellOffset, out float SceneDepth) { float2 VolumeUV = (GridCoordinate.xy + CellOffset.xy) / TranslucencyGIGridSize.xy; float2 VolumeNDC = (VolumeUV * 2 - 1) * float2(1, -1); SceneDepth = ComputeDepthFromZSlice(GridCoordinate.z + CellOffset.z); float TileDeviceZ = ConvertToDeviceZ(SceneDepth); float4 CenterPosition = mul(float4(VolumeNDC, TileDeviceZ, 1), UnjitteredClipToTranslatedWorld); return CenterPosition.xyz / CenterPosition.w; } float3 ComputeCellTranslatedWorldPosition(uint3 GridCoordinate, float3 CellOffset) { float Unused; return ComputeCellTranslatedWorldPosition(GridCoordinate, CellOffset, Unused); } float3 ComputeCellWorldPosition(uint3 GridCoordinate, float3 CellOffset) { return ComputeCellTranslatedWorldPosition(GridCoordinate, CellOffset) - DFHackToFloat(PrimaryView.PreViewTranslation); } float3 ComputeTranslucencyGIVolumeUV(float3 WorldPosition, float4x4 WorldToClip) { float4 NDCPosition = mul(float4(WorldPosition, 1), WorldToClip); NDCPosition.xy /= NDCPosition.w; float NormalizedZSlice = log2(NDCPosition.w * TranslucencyGIGridZParams.x + TranslucencyGIGridZParams.y) * TranslucencyGIGridZParams.z / (float)TranslucencyGIGridSize.z; return float3(NDCPosition.xy * float2(.5f, -.5f) + .5f, NormalizedZSlice); } void GetProbeTracingUV( float2 TracingTexelCoord, float2 ProbeTexelCenter, out float2 ProbeUV, out float ConeHalfAngle) { ProbeUV = (TracingTexelCoord + ProbeTexelCenter) / float(TranslucencyVolumeTracingOctahedronResolution); // Evenly distributing the sphere solid angle among all cones ConeHalfAngle = acosFast(1.0f - 1.0f / (float)(TranslucencyVolumeTracingOctahedronResolution * TranslucencyVolumeTracingOctahedronResolution)); } float2 GetProbeTexelCenter(uint2 GridCoordinate) { return BlueNoiseVec2(GridCoordinate, FroxelDirectionJitterFrameIndex < 0 ? 0 : FroxelDirectionJitterFrameIndex); } float HZBMipLevel; float GetMaxVisibleDepth(uint2 GridCoordinate) { float2 HZBScreenUV = (GridCoordinate.xy + .5f) * (1U << TranslucencyGIGridPixelSizeShift) * View.ViewSizeAndInvSize.zw * ViewportUVToHZBBufferUV; float TrilinearFootprintMipBias = 1.0f; return ConvertFromDeviceZ(FurthestHZBTexture.SampleLevel(GlobalPointClampedSampler, HZBScreenUV, HZBMipLevel + TrilinearFootprintMipBias).x); } bool IsFroxelVisible(uint3 GridCoordinate) { #define HZB_OCCLUSION_TEST 1 #if HZB_OCCLUSION_TEST float MaxVisibleDepth = GetMaxVisibleDepth(GridCoordinate.xy); float TrilinearFootprintBias = -1.0f; float FroxelMinSceneDepth = ComputeDepthFromZSlice(max((float)GridCoordinate.z + TrilinearFootprintBias, 0.0f)); return FroxelMinSceneDepth < MaxVisibleDepth; #else return true; #endif } float MaxTraceDistance; float MaxMeshSDFTraceDistance; float StepFactor; float VoxelTraceStartDistanceScale; float MaxRayIntensity;