Power Moments in Moment-Based OIT Using GLSL

This article provides a mathematical breakdown and GLSL implementation of power moments within Moment-Based Order-Independent Transparency (MBOIT). It covers the generation of power moment vectors during additive rendering passes, matrix conditioning to prevent numerical instability, and the mathematical reconstruction of the transmittance function via Cholesky decomposition to resolve proper alpha blending without sorting fragments.

Mathematical Formulation of Power Moments

In order-independent transparency, the goal is to evaluate the net transmittance function \(T(z)\) along a view ray up to depth \(z\):

\[T(z) = \exp\left(-\int_0^z \sigma(t) \, dt\right)\]

where \(\sigma(t)\) represents the continuous extinction or absorption coefficient. In discrete rendering, each transparent fragment \(i\) provides an optical depth (absorbance) \(a_i = -\ln(1.0 - \alpha_i)\) and a normalized depth \(z_i \in [0, 1]\).

MBOIT models the distribution of optical thickness using a moment vector of degree \(N\). The \(k\)-th power moment \(b_k\) over depth distribution is defined as:

\[b_k = \sum_{i} a_i z_i^k, \quad k \in \{0, 1, \dots, N\}\]

For a four-moment configuration (\(N = 4\)), the moment vector \(\mathbf{b} = (b_0, b_1, b_2, b_3, b_4)^T\) requires:

  • Zeroth moment: \(b_0 = \sum_i a_i\), which represents the total integrated optical thickness along the ray.
  • Higher moments: \(b_k = \sum_i a_i z_i^k\), capturing the spatial concentration of depth values.

Moment Accumulation Pass in GLSL

During the geometry pass, fragments are rendered without depth writing, and hardware additive blending (GL_SRC_ALPHA, GL_ONE with GL_FUNC_ADD) is enabled. Fragments write their absorbance-weighted power moments into floating-point framebuffer textures (typically two RGBA32F targets).

// Fragment Shader: Moment Generation
layout(location = 0) out vec4 outMoments0; // b0, b1, b2, b3
layout(location = 1) out float outMoments1; // b4

in float v_linearDepth; // Depth normalized to [0.0, 1.0]
uniform float u_alpha;

void main() {
    // Clamp alpha to avoid log(0)
    float alpha = clamp(u_alpha, 0.0, 0.999);
    float a = -log(1.0 - alpha);

    float z = clamp(v_linearDepth, 0.0, 1.0);
    float z2 = z * z;
    float z3 = z2 * z;
    float z4 = z2 * z2;

    outMoments0 = a * vec4(1.0, z, z2, z3);
    outMoments1 = a * z4;
}

Reconstruction and Transmittance Evaluation

During the resolve pass, a fragment at query depth \(z_f\) estimates the fraction of optical depth situated in front of it:

\[S(z_f) = \frac{1}{b_0} \int_0^{z_f} \sigma(t) \, dt \in [0, 1]\]

The transmittance up to depth \(z_f\) is reconstructed as:

\[T(z_f) = \exp(-b_0 \cdot S(z_f))\]

To approximate \(S(z_f)\), the normalized moments \(\mu_k = \frac{b_k}{b_0}\) define a Hankel matrix:

\[\mathbf{M} = \begin{pmatrix} 1 & \mu_1 & \mu_2 \\ \mu_1 & \mu_2 & \mu_3 \\ \mu_2 & \mu_3 & \mu_4 \end{pmatrix}\]

Matrix Regularization and Cholesky Factorization

Floating-point precision limits and steep depth gradients can cause \(\mathbf{M}\) to become non-positive definite. A regularization parameter \(\epsilon\) (typically \(10^{-7}\) to \(10^{-5}\)) is blended with an identity-like bias:

\[\mathbf{M}_{\text{reg}} = (1 - \epsilon)\mathbf{M} + \epsilon \mathbf{I}\]

Performing an \(L D L^T\) or standard Cholesky decomposition \(\mathbf{M}_{\text{reg}} = \mathbf{L} \mathbf{L}^T\) yields a lower triangular matrix \(\mathbf{L}\):

\[\mathbf{L} = \begin{pmatrix} l_{00} & 0 & 0 \\ l_{10} & l_{11} & 0 \\ l_{20} & l_{21} & l_{22} \end{pmatrix}\]

The values of \(\mathbf{L}\) are computed directly:

  • \(l_{00} = 1.0\)
  • \(l_{10} = \mu_1\)
  • \(l_{11} = \sqrt{\mu_2 - l_{10}^2}\)
  • \(l_{20} = \mu_2\)
  • \(l_{21} = \frac{\mu_3 - l_{20} l_{10}}{l_{11}}\)
  • \(l_{22} = \sqrt{\mu_4 - l_{20}^2 - l_{21}^2}\)

Evaluating the Cumulative Distribution

Using the decomposition, the vector of monomial powers at query depth \(\mathbf{q}(z_f) = (1, z_f, z_f^2)^T\) is transformed by forward substitution into vector \(\mathbf{c} = \mathbf{L}^{-1} \mathbf{q}(z_f)\):

\[c_0 = 1.0\] \[c_1 = \frac{z_f - l_{10}}{l_{11}}\] \[c_2 = \frac{z_f^2 - l_{20} - l_{21} c_1}{l_{22}}\]

The upper bound of the normalized cumulative optical depth \(S(z_f)\) is computed via the Hamburger moment bound:

\[S(z_f) \approx \frac{\sum_{j=0}^{m} c_j^2 \cdot H(z_f - z_j)}{\sum_{j=0}^{m} c_j^2}\]

In practical four-moment MBOIT implementations, this simplifies to evaluating the quadratic polynomial derived from the inverted Cholesky system to compute the step distribution:

// GLSL evaluation function for transmittance
float evaluateTransmittance(vec4 b0_to_b3, float b4, float z_f) {
    float b0 = b0_to_b3.x;
    if (b0 <= 1e-6) return 1.0; // No occlusion

    // Normalized moments
    vec4 mu = vec4(b0_to_b3.yzw, b4) / b0;

    // Regularization
    float overestimation = 0.1;
    float reg = 1e-5;
    mu = mix(mu, vec4(0.5, 1.0/3.0, 0.25, 0.2), reg);

    // Cholesky factors
    float l00 = 1.0;
    float l10 = mu.x;
    float l11 = sqrt(max(1e-6, mu.y - l10 * l10));
    float l20 = mu.y;
    float l21 = (mu.z - l20 * l10) / l11;
    float l22 = sqrt(max(1e-6, mu.w - l20 * l20 - l21 * l21));

    // Solve L * c = q
    float c0 = 1.0;
    float c1 = (z_f - l10) / l11;
    float c2 = (z_f * z_f - l20 - l21 * c1) / l22;

    // Estimate step function S(z)
    float sumSq = c0 * c0 + c1 * c1 + c2 * c2;
    float S = clamp(1.0 - (1.0 / sumSq), 0.0, 1.0);

    // Optical depth integration
    return exp(-b0 * S);
}

This mathematical evaluation enables smooth, artifact-free transmittance estimation across arbitrary overlapping geometry without relying on runtime per-fragment sorting.