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

181 lines
4.7 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "../RayTracing/RayTracingCapsuleLight.ush"
#include "../RayTracing/RayTracingSphereLight.ush"
#include "../RayTracing/RayTracingRectLight.ush"
#include "../RayTracing/RayTracingDirectionalLight.ush"
uint2 NumSamplesPerPixelDivideShift;
uint2 SampleCoordToDownsampledScreenCoord(uint2 SampleCoord)
{
// SampleCoord / NumSamplesPerPixel
return SampleCoord >> NumSamplesPerPixelDivideShift;
}
uint3 NumSamplesPerVoxelDivideShift;
uint3 SampleCoordToDownsampledVolumeCoord(uint3 SampleCoord)
{
// SampleCoord / NumSamplesPerVoxel
return SampleCoord >> NumSamplesPerVoxelDivideShift;
}
uint2 SampleCoordToScreenCoord(uint2 SampleCoord)
{
uint2 DownsampledScreenCoord = SampleCoordToDownsampledScreenCoord(SampleCoord);
return (DownsampledScreenCoord << DownsampleFactorMultShift) + GetSampleScreenCoordJitter(DownsampledScreenCoord);
}
bool GenerateShadowRay(
FLightShaderParameters LightParameters,
bool bSpotLight,
bool bRectLight,
bool bDirLight,
float3 TranslatedWorldPosition,
float3 WorldNormal,
float2 RandSample,
out float3 RayOrigin,
out float3 RayDirection,
out float RayTMin,
out float RayTMax)
{
float RayPdf = 0.0;
if (bRectLight)
{
return GenerateRectLightOcclusionRay(
LightParameters,
TranslatedWorldPosition, WorldNormal,
RandSample,
/* out */ RayOrigin,
/* out */ RayDirection,
/* out */ RayTMin,
/* out */ RayTMax,
/* out */ RayPdf);
}
else if (bDirLight)
{
GenerateDirectionalLightOcclusionRay(
LightParameters,
TranslatedWorldPosition, WorldNormal,
RandSample,
/* out */ RayOrigin,
/* out */ RayDirection,
/* out */ RayTMin,
/* out */ RayTMax);
return true;
}
else
{
// point or spot light
if (LightParameters.SourceLength > 0.0)
{
return GenerateCapsuleLightOcclusionRayWithSolidAngleSampling(
LightParameters,
TranslatedWorldPosition, WorldNormal,
RandSample,
/* out */ RayOrigin,
/* out */ RayDirection,
/* out */ RayTMin,
/* out */ RayTMax,
/* out */ RayPdf);
}
return GenerateSphereLightOcclusionRayWithSolidAngleSampling(
LightParameters,
TranslatedWorldPosition, WorldNormal,
RandSample,
/* out */ RayOrigin,
/* out */ RayDirection,
/* out */ RayTMin,
/* out */ RayTMax,
/* out */ RayPdf);
}
}
struct FLightSampleTrace
{
float3 Direction;
float Distance;
};
/**
* Compute shadow ray direction and distance for a given light sample.
*/
FLightSampleTrace GetLightSampleTrace(float3 TranslatedWorldPosition, uint LocalLightIndex, float2 LightSampleUV)
{
FLightSampleTrace LightSampleTrace;
LightSampleTrace.Direction = 0.0f;
LightSampleTrace.Distance = 0.0f;
if (LocalLightIndex != MAX_LOCAL_LIGHT_INDEX)
{
const FForwardLightData ForwardLightData = GetForwardLightData(LocalLightIndex, 0);
const FDeferredLightData LightData = ConvertToDeferredLight(ForwardLightData);
const FLightShaderParameters LightParameters = ConvertToLightShaderParameters(LightData);
float3 Unused;
float Unused2;
bool bValid = GenerateShadowRay(
LightParameters,
LightData.bSpotLight,
LightData.bRectLight,
!LightData.bRadialLight,
TranslatedWorldPosition,
float3(0, 0, 0),
LightSampleUV,
Unused,
LightSampleTrace.Direction,
Unused2,
LightSampleTrace.Distance);
if (!bValid)
{
// MegaLight pipeline is not really set up to handle invalid samples.
// Replace what we got with a valid sample so that the rest of the code can
// still estimate a valid shadow fraction. Forcing the sample to be always
// occluded would add noise in unshadowed regions, and forcing the sample to
// count as un-occluded would add light leaks in occluded regions.
// This seems like the simplest workaround for now.
float3 ToLight = LightParameters.TranslatedWorldPosition - TranslatedWorldPosition;
LightSampleTrace.Distance = length(ToLight);
LightSampleTrace.Direction = ToLight * rcp(LightSampleTrace.Distance);
}
}
return LightSampleTrace;
}
uint PackTraceTexel(uint2 SampleCoord)
{
uint PackedTraceTexel = SampleCoord.y & 0xFFFF;
PackedTraceTexel |= (SampleCoord.x & 0xFFFF) << 16;
return PackedTraceTexel;
}
uint2 UnpackTraceTexel(uint PackedTraceTexel)
{
uint2 SampleCoord;
SampleCoord.x = PackedTraceTexel >> 16;
SampleCoord.y = PackedTraceTexel & 0xFFFF;
return SampleCoord;
}
uint PackTraceVoxel(uint3 SampleCoord)
{
uint PackedTraceVoxel = SampleCoord.z & 0x3FF;
PackedTraceVoxel |= (SampleCoord.y & 0x3FF) << 10;
PackedTraceVoxel |= (SampleCoord.x & 0x3FF) << 20;
return PackedTraceVoxel;
}
uint3 UnpackTraceVoxel(uint PackedTraceVoxel)
{
uint3 SampleCoord;
SampleCoord.x = (PackedTraceVoxel >> 20) & 0x3FF;
SampleCoord.y = (PackedTraceVoxel >> 10) & 0x3FF;
SampleCoord.z = PackedTraceVoxel & 0x3FF;
return SampleCoord;
}