128 lines
3.4 KiB
HLSL
128 lines
3.4 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
float SmoothMin( float a, float b, float k )
|
|
{
|
|
float h = saturate( 0.5 + (0.5 / k) * (b - a) );
|
|
return lerp( b, a, h ) - k * (h - h*h);
|
|
}
|
|
|
|
float SmoothMax( float a, float b, float k )
|
|
{
|
|
return SmoothMin( a, b, -k );
|
|
}
|
|
|
|
float SmoothClamp( float x, float Min, float Max, float k )
|
|
{
|
|
return SmoothMin( SmoothMax( x, Min, k ), Max, k );
|
|
//return min( max( x, Min ), Max );
|
|
}
|
|
|
|
struct FCapsuleLight
|
|
{
|
|
float3 LightPos[2];
|
|
float Length;
|
|
float Radius;
|
|
float SoftRadius;
|
|
float DistBiasSqr;
|
|
};
|
|
|
|
void ClipToHorizon( inout float3 Line0, inout float3 Line1, float3 N )
|
|
{
|
|
float NoP0 = dot( N, Line0 );
|
|
float NoP1 = dot( N, Line1 );
|
|
if( NoP0 < 0 ) Line0 = ( Line0 * NoP1 - Line1 * NoP0 ) / ( NoP1 - NoP0 );
|
|
if( NoP1 < 0 ) Line1 = ( -Line0 * NoP1 + Line1 * NoP0 ) / ( -NoP1 + NoP0 );
|
|
}
|
|
|
|
// Closest point on line segment to point
|
|
float3 ClosestPointLineToPoint( float3 Line0, float3 Line1, float Length )
|
|
{
|
|
float3 Line01 = Line1 - Line0;
|
|
return Line0 + Line01 * saturate( -dot( Line01, Line0 ) / Pow2( Length ) );
|
|
//return Line0 + Line01 * SmoothClamp( -dot( Line01, Line0 ) / Pow2( Length ), 0, 1, 0.5 );
|
|
}
|
|
|
|
// Closest point on line segment to ray
|
|
float3 ClosestPointLineToRay( float3 Line0, float3 Line1, float Length, float3 R )
|
|
{
|
|
float3 L0 = Line0;
|
|
float3 L1 = Line1;
|
|
float3 Line01 = Line1 - Line0;
|
|
|
|
// Shortest distance
|
|
float A = Square( Length );
|
|
float B = dot( R, Line01 );
|
|
float t = saturate( dot( Line0, B*R - Line01 ) / (A - B*B) );
|
|
|
|
return Line0 + t * Line01;
|
|
}
|
|
|
|
float3 SmallestAnglePointOnLineToRay( float3 Line0, float3 Line1, float Length, float3 R )
|
|
{
|
|
float3 L0 = Line0;
|
|
float3 L1 = Line1;
|
|
float3 Line01 = Line1 - Line0;
|
|
|
|
float A = Square( Length );
|
|
float B = 2 * dot( Line0, Line01 );
|
|
float C = dot( Line0, Line0 );
|
|
float D = dot( R, Line0 );
|
|
float E = dot( R, Line01 );
|
|
float t = saturate( (B*D - 2*C*E) / (B*E - 2*A*D) );
|
|
|
|
return Line0 + t * Line01;
|
|
}
|
|
|
|
float3 LineIrradiance( float3 N, float3 Line0, float3 Line1, float DistanceBiasSqr, out float CosSubtended, out float BaseIrradiance, out float NoL )
|
|
{
|
|
float LengthSqr0 = dot( Line0, Line0 );
|
|
float LengthSqr1 = dot( Line1, Line1 );
|
|
float InvLength0 = rsqrt( LengthSqr0 );
|
|
float InvLength1 = rsqrt( LengthSqr1 );
|
|
float InvLength01 = InvLength0 * InvLength1;
|
|
|
|
CosSubtended = dot( Line0, Line1 ) * InvLength01;
|
|
BaseIrradiance = InvLength01 / ( CosSubtended * 0.5 + 0.5 + DistanceBiasSqr * InvLength01 );
|
|
NoL = 0.5 * ( dot(N, Line0) * InvLength0 + dot(N, Line1) * InvLength1 );
|
|
|
|
float3 VectorIrradiance = ( BaseIrradiance * 0.5 ) * ( Line0 * InvLength0 + Line1 * InvLength1 );
|
|
return VectorIrradiance;
|
|
}
|
|
|
|
// Alpha is half of angle of spherical cap
|
|
float SphereHorizonCosWrap( float NoL, float SinAlphaSqr )
|
|
{
|
|
#if 1
|
|
float SinAlpha = sqrt( SinAlphaSqr );
|
|
|
|
if( NoL < SinAlpha )
|
|
{
|
|
NoL = max( NoL, -SinAlpha );
|
|
#if 0
|
|
// Accurate sphere irradiance
|
|
float CosBeta = NoL;
|
|
float SinBeta = sqrt( 1 - CosBeta * CosBeta );
|
|
float TanBeta = SinBeta / CosBeta;
|
|
|
|
float x = sqrt( 1 / SinAlphaSqr - 1 );
|
|
float y = -x / TanBeta;
|
|
float z = SinBeta * sqrt(1 - y*y);
|
|
|
|
NoL = NoL * acos(y) - x * z + atan( z / x ) / SinAlphaSqr;
|
|
NoL /= PI;
|
|
#else
|
|
// Hermite spline approximation
|
|
// Fairly accurate with SinAlpha < 0.8
|
|
// y=0 and dy/dx=0 at -SinAlpha
|
|
// y=SinAlpha and dy/dx=1 at SinAlpha
|
|
NoL = Pow2( SinAlpha + NoL ) / ( 4 * SinAlpha );
|
|
#endif
|
|
}
|
|
#else
|
|
NoL = saturate( ( NoL + SinAlphaSqr ) / ( 1 + SinAlphaSqr ) );
|
|
#endif
|
|
|
|
return NoL;
|
|
} |