163 lines
4.8 KiB
HLSL
163 lines
4.8 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
float Exponential(float sigma, float x)
|
|
{
|
|
// X = 1 - e^(-sigma * x)
|
|
return 1 - exp(-sigma * x);
|
|
}
|
|
|
|
float InverseExponential(float sigma, float X)
|
|
{
|
|
// X = 1 - e^(-sigma * x)
|
|
// x = ln(1 - X) / -sigma
|
|
return log(1 - X) / -sigma;
|
|
}
|
|
|
|
float FindSigma(float x, float X)
|
|
{
|
|
// X = 1 - e^(-sigma * x)
|
|
// e^(-sigma * x) = 1 - X
|
|
// -sigma * x = ln(1 - X)
|
|
// sigma = -ln(1 - X) / x
|
|
return -log(1 - X) / x;
|
|
}
|
|
|
|
float ExponentialRemap(float ViewDepth, float NearPlaneDepth, float FarPlaneDepth)
|
|
{
|
|
float Sigma = FindSigma(FarPlaneDepth, 0.9999);
|
|
float NormalizedDepth = Exponential(Sigma, ViewDepth);
|
|
return NormalizedDepth;
|
|
}
|
|
|
|
float InverseExponentialRemap(float NormalizedDepth, float NearPlaneDepth, float FarPlaneDepth)
|
|
{
|
|
float Sigma = FindSigma(FarPlaneDepth, 0.9999);
|
|
float ViewDepth = InverseExponential(Sigma, NormalizedDepth);
|
|
return ViewDepth;
|
|
}
|
|
|
|
float LinearRemap(float ViewDepth, float NearPlaneDepth, float FarPlaneDepth)
|
|
{
|
|
float NormalizedDepth = (ViewDepth - NearPlaneDepth) / (FarPlaneDepth - NearPlaneDepth);
|
|
return NormalizedDepth;
|
|
}
|
|
|
|
float InverseLinearRemap(float NormalizedDepth, float NearPlaneDepth, float FarPlaneDepth)
|
|
{
|
|
float ViewDepth = NormalizedDepth * (FarPlaneDepth - NearPlaneDepth) + NearPlaneDepth;
|
|
return ViewDepth;
|
|
}
|
|
|
|
float SquareDistanceRemap(float ViewDepth, float NearPlaneDepth, float FarPlaneDepth)
|
|
{
|
|
float NormalizedDepth = ViewDepth / 20.0;
|
|
if (ViewDepth > 2.0)
|
|
{
|
|
float LogDepth = log2(ViewDepth);
|
|
float LogFarPlaneDepth = log2(FarPlaneDepth);
|
|
NormalizedDepth = LogDepth / LogFarPlaneDepth + 0.1;
|
|
}
|
|
|
|
return NormalizedDepth;
|
|
}
|
|
|
|
float InverseSquareDistanceRemap(float NormalizedDepth, float NearPlaneDepth, float FarPlaneDepth)
|
|
{
|
|
float ViewDepth = NormalizedDepth * 20.0;
|
|
if (ViewDepth > 2.0)
|
|
{
|
|
float LogFarPlaneDepth = log2(FarPlaneDepth);
|
|
float LogDepth = (NormalizedDepth - 0.1) * LogFarPlaneDepth;
|
|
ViewDepth = pow(2, LogDepth);
|
|
}
|
|
|
|
return ViewDepth;
|
|
}
|
|
|
|
float3 ScreenToVoxel(float3 ScreenPos, int3 VoxelDimensions)
|
|
{
|
|
float3 NDC = float3(ScreenPos.xy * 0.5 + 0.5, ScreenPos.z);
|
|
float3 VoxelPos = NDC * VoxelDimensions;
|
|
return VoxelPos;
|
|
}
|
|
|
|
float3 VoxelToScreen(float3 VoxelPos, int3 VoxelDimensions)
|
|
{
|
|
float3 NDC = VoxelPos / VoxelDimensions;
|
|
float3 ScreenPos = float3(NDC.xy * 2.0 - 1.0, NDC.z);
|
|
return ScreenPos;
|
|
}
|
|
|
|
float PerspectiveRemap(float ViewDepth, int3 VoxelDimensions)
|
|
{
|
|
float3 VoxelPos = ScreenToVoxel(float3(0, 0, ViewDepth), VoxelDimensions);
|
|
float NormalizedDepth = VoxelPos.z / VoxelDimensions.z;
|
|
return NormalizedDepth;
|
|
}
|
|
|
|
float InversePerspectiveRemap(float NormalizedDepth, int3 VoxelDimensions)
|
|
{
|
|
float3 VoxelPos = ScreenToVoxel(float3(0, 0, NormalizedDepth), VoxelDimensions);
|
|
float ViewDepth = VoxelPos.z;
|
|
return ViewDepth;
|
|
}
|
|
|
|
float3 ViewToVoxel(float3 ViewPos, int3 VoxelDimensions, float NearPlaneDepth, float FarPlaneDepth, float TanHalfFOV)
|
|
{
|
|
//float4 ClipPos = mul(float4(ViewPos, 1), ViewToClip);
|
|
//float3 ScreenPos = ClipPos.xyz / ClipPos.w;
|
|
float2 AspectRatio = VoxelDimensions.xy / float(VoxelDimensions.x);
|
|
float2 ScreenPos = ViewPos.xy / (TanHalfFOV * AspectRatio * ViewPos.z);
|
|
|
|
#if 0
|
|
float NormalizedDepth = SquareDistanceRemap(ViewPos.z, NearPlaneDepth, FarPlaneDepth);
|
|
#elif 0
|
|
float NormalizedDepth = ExponentialRemap(ViewPos.z, NearPlaneDepth, FarPlaneDepth);
|
|
#elif 1
|
|
float NormalizedDepth = LinearRemap(ViewPos.z, NearPlaneDepth, FarPlaneDepth);
|
|
#else
|
|
float NormalizedDepth = PerspectiveRemap(ViewPos.z, VoxelDimensions);
|
|
#endif
|
|
|
|
float3 NDC = float3(ScreenPos.xy * 0.5 + 0.5, NormalizedDepth);
|
|
float3 VoxelPos = NDC * VoxelDimensions;
|
|
return VoxelPos;
|
|
}
|
|
|
|
float3 VoxelToView(float3 VoxelPos, int3 VoxelDimensions, float NearPlaneDepth, float FarPlaneDepth, float TanHalfFOV)
|
|
{
|
|
float3 NDC = VoxelPos / VoxelDimensions;
|
|
float2 ScreenPos = NDC.xy * 2.0 - 1.0;
|
|
#if 0
|
|
float ViewDepth = InverseSquareDistanceRemap(NDC.z, NearPlaneDepth, FarPlaneDepth);
|
|
#elif 0
|
|
float ViewDepth = InverseExponentialRemap(NDC.z, NearPlaneDepth, FarPlaneDepth);
|
|
#elif 1
|
|
float ViewDepth = InverseLinearRemap(NDC.z, NearPlaneDepth, FarPlaneDepth);
|
|
#else
|
|
float ViewDepth = InversePerspectiveRemap(NDC.z, VoxelDimensions);
|
|
#endif
|
|
|
|
// TODO: Guarantee no view-space translation exists..
|
|
float2 AspectRatio = VoxelDimensions.xy / float(VoxelDimensions.x);
|
|
float3 ViewPos = float3(ScreenPos * TanHalfFOV * AspectRatio * ViewDepth, ViewDepth);
|
|
return ViewPos;
|
|
}
|
|
|
|
float2 ClipRay(float3 Origin, float3 Direction, float TMin, float TMax, float4 Plane)
|
|
{
|
|
float3 Normal = Plane.xyz;
|
|
float d = Plane.w;
|
|
float HitT = -(d + dot(Normal, Origin)) * rcp(dot(Normal, Direction));
|
|
|
|
float2 RayT = float2(TMin, TMax);
|
|
if ((HitT > RayT.x) && (HitT < RayT.y))
|
|
{
|
|
float SignedDistance = dot(Origin, Normal) + d;
|
|
RayT = SignedDistance < 0 ? float2(HitT, RayT.y) : float2(RayT.x, HitT);
|
|
}
|
|
|
|
return RayT;
|
|
} |