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

91 lines
2.7 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "../LightShaderParameters.ush"
bool GenerateSphereLightOcclusionRayWithAreaSampling(
FLightShaderParameters LightParameters,
float3 TranslatedWorldPosition,
float3 WorldNormal,
float2 RandSample,
out float3 RayOrigin,
out float3 RayDirection,
out float RayTMin,
out float RayTMax,
out float RayPdf
)
{
float4 Result = UniformSampleSphere(RandSample);
float3 LightNormal = Result.xyz;
float3 TranslatedLightPosition = LightParameters.TranslatedWorldPosition + LightNormal * LightParameters.SourceRadius;
float3 LightDirection = TranslatedLightPosition - TranslatedWorldPosition;
float RayLength = length(LightDirection);
LightDirection /= RayLength;
RayOrigin = TranslatedWorldPosition;
RayDirection = LightDirection;
RayTMin = 0.0;
RayTMax = RayLength;
float SolidAnglePdf = Result.w * saturate(dot(LightNormal, -LightDirection)) / (RayLength * RayLength);
RayPdf = SolidAnglePdf;
return true;
}
bool GenerateSphereLightOcclusionRayWithSolidAngleSampling(
FLightShaderParameters LightParameters,
float3 TranslatedWorldPosition,
float3 WorldNormal,
float2 RandSample,
out float3 RayOrigin,
out float3 RayDirection,
out float RayTMin,
out float RayTMax,
out float RayPdf
)
{
RayOrigin = 0.0;
RayDirection = 0.0;
RayTMin = 0.0;
RayTMax = 0.0;
RayPdf = 0.0;
// Determine if shading point is contained within sphere light
float3 LightDirection = LightParameters.TranslatedWorldPosition - TranslatedWorldPosition;
float RayLength2 = dot(LightDirection, LightDirection);
float Radius2 = LightParameters.SourceRadius * LightParameters.SourceRadius;
BRANCH
if (RayLength2 <= Radius2)
{
return GenerateSphereLightOcclusionRayWithAreaSampling(LightParameters, TranslatedWorldPosition, WorldNormal, RandSample,
RayOrigin, RayDirection, RayTMin, RayTMax, RayPdf);
}
// Sample uniformly about a cone aligned with the z-axis
float SinThetaMax2 = Radius2 / RayLength2;
#if 0
float4 DirAndPdf = UniformSampleCone(RandSample, sqrt(1.0 - SinThetaMax2));
#elif 0
float4 DirAndPdf = UniformSampleConeRobust(RandSample, SinThetaMax2);
#else
float4 DirAndPdf = UniformSampleConeConcentricRobust(RandSample, SinThetaMax2);
#endif
float CosTheta = DirAndPdf.z;
float SinTheta2 = 1.0 - CosTheta * CosTheta;
RayOrigin = TranslatedWorldPosition;
// Project ray direction to world-space, such that z-axis aligns with LightDirection
float RayLength = sqrt(RayLength2);
LightDirection *= rcp(RayLength + 1e-4);
RayDirection = TangentToWorld(DirAndPdf.xyz, LightDirection);
RayTMin = 0.0;
// Clip length to closest intersection with the sphere
RayTMax = RayLength * (CosTheta - sqrt(max(SinThetaMax2 - SinTheta2, 0.0)));
RayPdf = DirAndPdf.w;
return true;
}