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

62 lines
2.3 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../Common.ush"
#include "../SceneTexturesCommon.ush"
#ifndef SCREEN_RAY_SAMPLES
#define SCREEN_RAY_SAMPLES 4
#endif
// Screen space ray trace to attempt to skip over ambiguous regions near the receiver surface
// Returns length at which to start the virtual shadow map ray; usually this is where the screen ray ended or went behind a surface
float VirtualShadowMapScreenRayCast(
float3 RayOriginTranslatedWorld,
float3 RayDirection,
float RayLength,
float Dither)
{
float4 RayStartClip = mul(float4(RayOriginTranslatedWorld, 1), View.TranslatedWorldToClip);
float4 RayDirClip = mul(float4(RayDirection * RayLength, 0), View.TranslatedWorldToClip);
float4 RayEndClip = RayStartClip + RayDirClip;
float3 RayStartScreen = RayStartClip.xyz / RayStartClip.w;
float3 RayEndScreen = RayEndClip.xyz / RayEndClip.w;
float3 RayStepScreen = RayEndScreen - RayStartScreen;
float3 RayStartUVz = float3(RayStartScreen.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz, RayStartScreen.z);
float3 RayStepUVz = float3(RayStepScreen.xy * View.ScreenPositionScaleBias.xy, RayStepScreen.z);
float4 RayDepthClip = RayStartClip + mul(float4(0, 0, RayLength, 0), View.ViewToClip);
float3 RayDepthScreen = RayDepthClip.xyz / RayDepthClip.w;
const int Steps = SCREEN_RAY_SAMPLES;
float StepOffset = Dither - 0.5f;
const float Step = 1.0 / Steps;
float SampleTime = StepOffset * Step + Step;
const float StartDepth = SceneTexturesStruct.SceneDepthTexture.SampleLevel(SceneTexturesStruct_SceneDepthTextureSampler, RayStartUVz.xy, 0).r;
UNROLL
for (int i = 0; i < Steps; i++)
{
float3 SampleUVz = RayStartUVz + RayStepUVz * SampleTime;
float SampleDepth = SceneTexturesStruct.SceneDepthTexture.SampleLevel(SceneTexturesStruct_SceneDepthTextureSampler, SampleUVz.xy, 0).r;
// Avoid self-intersection with the start pixel (exact comparison due to point sampling depth buffer)
if (SampleDepth != StartDepth)
{
if (SampleUVz.z < SampleDepth)
{
// Behind geometry. Back up a bit along the ray and do the VSM sample from there.
return RayLength * max(0.0, SampleTime - 1.5f * Step);
}
}
SampleTime += Step;
}
// Got to the end of the ray without going behind or hitting anything
return RayLength;
}