110 lines
3.2 KiB
HLSL
Raw Normal View History

2026-02-02 21:07:49 +08:00
#include "MomentOutput.hlsl"
// DONTBLOWUP is NOT part of the original paper, this is a hack i had to do to make this implementation usable
//#define ABSORPTION_EPSILON max(REAL_MIN, 1e-5)
#if _MOMENT_HALF_PRECISION
//#define DONTBLOWUP HALF_MIN
#define DONTBLOWUP HALF_EPS
#else
//#define DONTBLOWUP FLT_MIN
#define DONTBLOWUP FLT_EPS
#endif
float4 _WrappingZoneParameters;
/*! This function implements complex multiplication.*/
float2 Multiply(float2 LHS, float2 RHS) {
return float2(LHS.x * RHS.x - LHS.y * RHS.y, LHS.x * RHS.y + LHS.y * RHS.x);
}
// if ROV, set to the stored moments from the rasterizer order view and write the new moments back
// no ROVs so only single precision works - needs further changes for quantized to read/write moments
MomentOutput GenerateMoments(float vd, float t)
{
t = max(t, DONTBLOWUP); // we have a blowup issue when t (1 - alpha) is close to 0, empirically it happens above 0.99 alpha so let's lock it around there (no visual issues, at that point its pretty indiscernable from opaque)
// Return early if the surface is fully transparent
clip(0.9999999f - t);
float a = -log(t);
float d = WarpDepth(vd);
MomentOutput output;
output.b0 = a;
#ifdef _TRIGONOMETRIC
float p = mad(d, _WrappingZoneParameters.y, _WrappingZoneParameters.y);
float2 c;
sincos(p, c.y, c.x);
float2 c2 = Multiply(c, c);
output.b1 = float4(c, c2) * a;
#ifdef _MOMENT8
output.b2 = float4(Multiply(c, c2), Multiply(c2, c2)) * a;
#elif defined(_MOMENT6)
output.b2 = Multiply(c, c2) * a;
#endif
#else // not _TRIGONOMETRIC
float d2 = d * d;
float d4 = d2 * d2;
#if _MOMENT_HALF_PRECISION // QUANTIZE (ROVs ONLY)
#ifdef _MOMENT8
float4 b_even = (float4) 0;
float4 b_odd = (float4) 0;;
offsetMoments(b_even, b_odd, -1.0);
b_even *= output.b0;
b_odd *= output.b0;
float d6 = d4 * d2;
float4 b_even_new = float4(d2, d4, d6, d6 * d2);
float4 b_odd_new = float4(d, d2 * d, d4 * d, d6 * d);
float4 b_even_new_q, b_odd_new_q;
#elif defined(_MOMENT6)
float3 b_even = (float3) 0;
float3 b_odd = (float3) 0;
offsetMoments(b_even, b_odd, -1.0);
b_even *= output.b0;
b_odd *= output.b0;
float3 b_even_new = float3(d2, d4, d4 * d2);
float3 b_odd_new = float3(d, d2 * d, d4 * d);
float3 b_even_new_q, b_odd_new_q;
#else // _MOMENT4
float2 b_even = (float2) 0;
float2 b_odd = (float2) 0;
offsetMoments(b_even, b_odd, -1.0);
b_even *= output.b0;
b_odd *= output.b0;
float2 b_even_new = float2(d2, d4);
float2 b_odd_new = float2(d, d2 * d);
float2 b_even_new_q, b_odd_new_q;
#endif
quantizeMoments(b_even_new_q, b_odd_new_q, b_even_new, b_odd_new);
// combine moments
b_even += b_even_new_q * a;
b_odd += b_odd_new_q * a;
// go back to interval [0, 1]
b_even /= a;
b_odd /= a;
offsetMoments(b_even, b_odd, 1.0);
output.b1 = float4(b_odd.x, b_even.x, b_odd.y, b_even.y);
#ifdef _MOMENT8
output.b2 = float4(b_odd.z, b_even.z, b_odd.w, b_even.w);
#elif defined(_MOMENT6)
output.b2 = float2(b_odd.z, b_even.z);
#endif
#else // _MOMENT_SINGLE_PRECISION
output.b1 = float4(d, d2, d2 * d, d4) * a;
#ifdef _MOMENT8
output.b2 = output.b1 * d4;
#elif defined(_MOMENT6)
output.b2 = output.b1.xy * d4;
#endif
#endif // precision end
#endif // TRIGONOMETRIC end
return output;
}