Skip to content

Mathematical and Physical Foundations

This document outlines the mathematical principles and physics simulations that power the Skewer rendering engine and the Loom deep compositor. Each section explains the theory and points to the exact implementation in our codebase.

Application

The following is an abridged overview. For a more in-depth application of these concepts see Architecture Overview.


1. Geometric Foundations & Linear Algebra

1.1 Vector Operations

Most of our spatial calculations rely on standard 3D vector algebra.

  • Dot Product (ABA \cdot B): Used to calculate the cosine of the angle between vectors, essential for Lambertian shading and visibility checks.

  • Cross Product (A×BA \times B): Used to generate orthogonal vectors, such as calculating surface normals from triangle edges.

  • Implementation: skewer/src/core/math/vec3.h

1.2 Transformations & Quaternions

We use a TRS (Translation, Rotation, Scale) system to place objects in the world.

  • Quaternions: Used for rotations to avoid gimbal lock and ensure smooth animation interpolation.

  • SLERP (Spherical Linear Interpolation): Used to interpolate between two rotation keyframes along the shortest path on a 4D unit sphere.

  • Implementation: skewer/src/core/math/transform.h, skewer/src/core/math/quat.h

1.3 Orthonormal Basis (ONB)

To sample directions on a surface, we construct a local coordinate system (tangent space) where the surface normal is the Z-axis.

  • Application: When a ray hits a surface, we use an ONB to transform a randomly sampled "hemisphere" direction back into world space.

  • Implementation: skewer/src/core/math/onb.h


2. Intersection Algorithms

2.1 Ray-Triangle (Möller–Trumbore)

The engine uses the Möller–Trumbore algorithm, which solves for the intersection using barycentric coordinates (u,vu, v) without needing to pre-calculate the plane equation.

graph TD
    subgraph "Möller–Trumbore Geometry"
    O((Ray Origin O)) -- "Direction D" --> P(Point P)
    V0[Vertex V0] --- V1[Vertex V1]
    V1 --- V2[Vertex V2]
    V2 --- V0
    P -.-> V0
    P -.-> V1
    P -.-> V2
    end

    subgraph "Barycentric Space"
    Formula["P(u,v) = (1-u-v)V0 + uV1 + vV2"]
    Intersection["O + tD = Formula"]
    end
  • Application: Core primitive intersection for all 3D meshes.
  • Implementation: skewer/src/geometry/intersect_triangle.h

2.2 Ray-Sphere

Intersections are found by solving the quadratic equation:

t2(dd)+2t(d(oc))+(oc)(oc)r2=0t^2(d \cdot d) + 2t(d \cdot (o - c)) + (o - c) \cdot (o - c) - r^2 = 0

where oo is the ray origin, dd is the direction, cc is the sphere center, and rr is the radius.

  • Implementation: skewer/src/geometry/intersect_sphere.h

2.3 Ray-AABB (Slab Method)

Bounding box intersections use the "Slab Method," which checks the overlap of three 1D intervals (the "slabs" between the box's parallel faces).

t_min t_max AABB t
Figure 1: Ray-AABB intersection via interval overlap.
  • Application: Essential for traversing the BVH (Bounding Volume Hierarchy) and TLAS quickly.
  • Implementation: skewer/src/geometry/boundbox.h

3. Light & Surface Physics (BSDFs)

3.1 The Rendering Equation

The core of our path tracer is the evaluation of the Kajiya Rendering Equation:

Lo(p,ωo)=Le(p,ωo)+S2fr(p,ωi,ωo)Li(p,ωi)cosθidωiL_o(p, \omega_o) = L_e(p, \omega_o) + \int_{\mathcal{S}^2} f_r(p, \omega_i, \omega_o) L_i(p, \omega_i) \cos \theta_i \mathrm{d}\omega_i

We use Monte Carlo integration to approximate this integral by tracing thousands of random paths.

  • Implementation: skewer/src/kernels/path_kernel.cc

3.2 GGX Microfacet BRDF

For metallic and rough surfaces, we use the Cook-Torrance model with the GGX (Trowbridge-Reitz) distribution. This model is preferred over older ones (like Beckmann) because its "long tails" better simulate the hazy glow around highlights.

GGX (Long Tails) θ = 0 (Normal)
  • DD (Normal Distribution): Models the concentration of micro-mirrors aligned with the half-vector.
  • GG (Shadowing-Masking): Models how microfacets shadow each other at grazing angles (using Smith's approximation).
  • Implementation: skewer/src/materials/bsdf.cc

3.3 Dielectric Fresnel & Snell's Law

We model glass and water using exact Fresnel equations for reflectance (FF) and Snell's Law for refraction.

  • Dispersion: We use Cauchy's Equation (n(λ)=A+B/λ2n(\lambda) = A + B/\lambda^2) to make the Index of Refraction wavelength-dependent, creating "rainbow" prisms.

  • Implementation: SampleDielectric in skewer/src/materials/bsdf.cc


4. Participating Media (Volume Rendering)

4.1 Beer-Lambert Law

Light passing through a volume (like fog) is attenuated exponentially based on density and distance.

Tr(d)=eσtdT_r(d) = e^{-\sigma_t \cdot d}
Transmittance Distance (d)
  • Implementation: SampleHomogeneous in skewer/src/kernels/sample_media.cc

4.2 Woodcock Tracking (Delta Tracking)

To render non-uniform volumes (VDB clouds), we use Woodcock tracking. It uses a "majorant" (maximum density) to probabilistically decide whether a photon collides with a particle or passes through as a "null collision."

  • Implementation: SampleNanoVDB in skewer/src/kernels/sample_media.cc

4.3 Henyey-Greenstein Phase Function

Unlike surfaces that use BSDFs, volumes use Phase Functions to describe scattering. We implement the Henyey-Greenstein function to model anisotropic scattering (light bending forward or backward).

Forward (g > 0) Particle
  • Implementation: skewer/src/kernels/utils/volume_tracking.cc

5. Monte Carlo & Sampling

5.1 Multiple Importance Sampling (MIS)

To reduce noise, we combine two sampling techniques: Next Event Estimation (NEE) (sampling lights directly) and BSDF Sampling (following the material's physical properties). We weight them using the Power Heuristic (β=2\beta=2):

wf(p)=f(p)βf(p)β+g(p)βw_f(p) = \frac{f(p)^\beta}{f(p)^\beta + g(p)^\beta}
  • Implementation: skewer/src/core/sampling/sampling.h

5.2 Hero Wavelength Sampling

For spectral rendering, we sample 4 wavelengths per ray. One is the "Hero," used to make discrete decisions (like reflecting vs refracting), while the others ("Companions") are evaluated at the same spatial path to minimize variance.

  • Implementation: skewer/src/core/sampling/wavelength_sampler.h

6. Animation Math

6.1 Cubic Bezier Interpolation

Animations follow Bezier paths. Since time (uu) is linear but the curve parameter (tt) is not, we use the Newton-Raphson Method to iteratively solve for tt such that X(t)=uX(t) = u.

  • Implementation: skewer/src/scene/interp_curve.cc

7. Deep Compositing (Loom)

7.1 Alpha Power Law

When Loom merges two volumetric layers, it must sometimes split a sample into two. To maintain physical correctness, the alpha of the new fragments is calculated using the power law.

gantt
    title Sample Splitting Logic (Z-depth)
    dateFormat  X
    axisFormat  %s
    section Layer A (Vol)
    Original Sample    :a1, 0, 50
    section Result
    Front Fragment (Split) :done, r1, 0, 25
    Back Fragment (Split)  :r2, 25, 50
αnew=1(1αorig)TnewTorig\alpha_{new} = 1 - (1 - \alpha_{orig})^{\frac{T_{new}}{T_{orig}}}

This ensures the combined transmittance of the split fragments equals the original.

  • Implementation: loom/src/deep_volume.cc

7.2 The Over Operator

The final 2D image is generated by flattening deep pixels front-to-back using the recursive "Over" operator:

Cout=Cfront+(1αfront)CbackC_{out} = C_{front} + (1 - \alpha_{front}) \cdot C_{back}
  • Implementation: FlattenRow in loom/src/deep_row.h

See Also