Computer Graphics · Ray Tracing
Ray Parameter Intervals and the Origin Offset Problem
Why a secondary ray that starts exactly on a surface hits it again, what a scaled epsilon actually moves, and how an interval filter differs from a shadow-ray flag.
A ray leaving a surface begins at the surface. That sentence contains the entire problem: the intersection routine that produced the hit point computed it with finite precision, so the point does not lie exactly on the geometry, it lies within a few ulps of it, in a direction nobody knows. Fire a new ray from there and the same surface is a candidate again. Whether it is reported as a hit depends on which side of the surface the rounding error placed the origin, and on whether the surface’s intersection routine uses a strict or non-strict inequality. The consequences range from a single wrong pixel to an entire render that never terminates.
The origin sits on the wrong side about half the time
A hit point is reconstructed as $p = o + t d$, where $t$ came from an intersection computation whose result carries a relative error of a few ulps. The reconstructed point therefore differs from the true intersection by a distance on the order of $|p| \cdot 2^{-24}$ for single-precision coordinates near unit magnitude, and by far more if the geometry is far from the world origin, since the error scales with the coordinate magnitudes rather than with the triangle’s size. A triangle one metre across, positioned ten kilometres from the origin, evaluated in single precision, yields points with absolute error around a millimetre.
Shadow rays are the most sensitive. The secondary ray starts at $p$ and points toward a light; if $p$ is on the wrong side of the triangle, the shadow ray passes through the geometric plane just after its origin, hits the same triangle at a $t$ of a few ulps of a unit, and reports occlusion. The surface then shades as fully shadowed, producing a black speckled pattern that follows the tessellation and is worst where the view ray grazes the surface. The same failure on a reflection ray causes a reflection to pick up the surface it reflected off, at a distance of essentially zero, which shows as a salt-and-pepper of the surface’s own colour or a lost reflection.
The naive defence is to offset the origin along the surface normal by a small constant, and the naive constant is $10^{-4}$ in world units. It fails in three distinct ways, each worth naming because each has a different repair:
- Scale. A scene whose units are millimetres and whose objects are a few units across has features far below $10^{-4}$; the offset moves the point measurably off the surface and displaces the shadow terminator by a visible amount. A scene modelled in kilometres has rounding error larger than the offset, so the self-hit returns.
- Geometry. Moving along the shading normal is wrong for geometry with a different geometric normal, and for thin geometry the offset can escape to the far side, so a shadow ray from a sheet of paper starts behind it.
- Anisotropy. On a surface viewed at a grazing angle, an offset of magnitude $e$ along the normal changes the ray origin by $e$ but its depth along the ray by about $e / \cos\theta$; at a grazing angle this is enormous, and the shadow ray can start beyond a legitimate occluder.
The interval filter is the repair that does not depend on world scale. Instead of moving the origin, define a lower bound $t_{\min} > 0$ for the ray and reject any intersection with $t \le t_{\min}$. A hit at $t$ less than the bound is the surface the ray just left, by construction: the only geometry within that distance of the origin is the geometry the origin is on. The bound is caused by nothing but the ray’s own precision, so it can be stated in relative terms.
How to choose the bound honestly
There is no universally correct value; there is a value derivable from the error model, plus a floor set by the coordinate precision. Two contributions matter.
The first is the reconstruction error in the origin. It scales with the magnitudes of the coordinates used to form the point, so a bound expressed as a multiple of $|p|$ tracks it: something on the order of a few ulps of the largest coordinate component, multiplied by a small safety factor. That factor is not arbitrary — it must exceed the number of roundings that accumulated in the point’s computation, which for a typical hit point is on the order of ten operations each contributing half an ulp.
The second is the uncertainty in the normal and the geometry’s own size. If the surface is a triangle, the ray’s direction projected onto the plane has an uncertainty from the intersection computation itself, which translates into a distance along the ray direction of the same order as the origin error. Non-planar primitives add the curvature: an offset that moves the origin off a sphere also moves it radially, and the intersection routine for the sphere will find a different $t$ for the same line.
A common practical scheme is a relative bound scaled by the ray origin’s magnitude with a floor for geometry near the world origin, plus a per-surface adjustment for primitives whose intersection routine is less accurate. The important property is not the specific formula but that the bound is larger than the reconstruction error and smaller than the nearest legitimate occluder. In a scene with millimetre-thin glass, that window can be narrow enough that single precision closes it entirely, and the answer is then double precision for the camera and hit points, not a smaller epsilon.
#include <math.h>
/* Lower bound on t for a secondary ray starting at point p (single precision). */
float t_min_for_point(float px, float py, float pz)
{
float m = fmaxf(fabsf(px), fmaxf(fabsf(py), fabsf(pz)));
/* 2^-20 relative: far above accumulation error, below typical feature size.
The absolute floor keeps geometry near the origin from over-filtering. */
return fmaxf(1e-5f, 1e-5f * m);
}
The constants there are illustrative, not normative, and they should not be copied without checking the scene’s scale. What is normative is the shape: proportional to the point’s magnitude, with an absolute floor. A fixed epsilon alone has the failure modes listed above; a proportional-only bound collapses to zero at the world origin and lets self-hits through for any geometry modelled around it.
An interval is not a boolean
It is tempting to treat the lower bound as a property of shadow rays only, since that is where it was first needed. That framing loses information the renderer already has. A general ray carries a half-open interval $(t_{\min}, t_{\max}]$, and every intersection routine returns a $t$ strictly inside it. The interval does three jobs at once.
$t_{\max}$ is a shrinking bound. When a kernel tests candidate primitives and finds a hit, it sets $t_{\max}$ to the hit’s $t$; subsequent tests can reject any primitive whose intersection is beyond it, and a bounding box whose near slab entry exceeds it can be skipped entirely. That is what makes ordered traversal worthwhile — the interest is discussed in ordered traversal and the per-ray stack — and it is why the running interval must be updated with the hit value rather than kept as an original bound.
$t_{\min}$ is a filter that must be per-ray, not per-scene. Primary rays generally start outside all geometry and need no lower bound beyond zero, but a camera inside a glass ball needs the lower bound to be zero and to accept negative roots in a specific order. The same triangle can be a legitimate hit at $t = 10^{-7}$ for a primary ray passing through a far-away object behind a thin wall and an illegitimate hit for a shadow ray that started on it. Nothing about the triangle distinguishes the two; only the ray’s provenance does.
The half-open convention matters for determinism. If both endpoints are inclusive, two adjacent primitives can both report a hit at exactly the same $t$ and the renderer’s choice depends on traversal order, which changes with tree build or thread scheduling. Making the interval $(t_{\min}, t_{\max}]$ and always replacing the current best when the new $t$ is strictly less than $t_{\max}$ gives a deterministic winner among identical values only if ties are broken by a primitive identifier — an ordered tie-break, not a stable one.
Watertightness and intervals together
The watertight triangle test from the earlier derivation guarantees the parity of intersections along an infinite line is correct. That guarantee holds for rays that start anywhere, including on the surface. It says nothing about whether a hit at $t = 10^{-9}$ should be accepted, so the interval filter and the watertight test address different axes of the same problem: one ensures the set of crossings is complete and consistent, the other ensures the renderer only counts the crossings it wants. A renderer needs both. With watertightness alone, the shadow-ray self-hit is now a consistent self-hit — the same triangle at the same tiny $t$ every time — which is arguably worse, because the artifact no longer flickers and is harder to attribute.
The interaction has one subtlety. A watertight test is conservative at shared edges: a ray grazing along an edge may report hits on both adjacent triangles. Those two hits are at the same $t$ to within a tiny amount, and if both pass the interval test, the renderer commits to one and sets $t_{\max}$ to its value; the second hit then fails the strict inequality and is dropped. That is the outcome that matters, and it depends on the interval being closed at the top and compared strictly. If the second hit were accepted because of an inclusive comparison, the point would be shaded twice with two slightly different normals.
Cases where the offset cannot be avoided
Some primitives cannot be handled with a pure interval bound. A plane is infinite and every ray that starts on one immediately intersects it again; with the plane’s $t$ computed as exactly zero for an origin on the plane, the interval filter catches it, but an origin a hair above the plane gives a small positive $t$ that the filter must exceed. Since a plane has no feature scale, the interval bound must come from the origin’s coordinate magnitude alone, and a point at the world origin has a bound of zero. Planes almost always need an explicit offset, usually along the plane normal computed from the hit, or the plane’s intersection routine must be written to never report a hit for a ray whose origin is within a tolerance of the plane.
Thin geometry has the same problem in the other direction. A surface with no thickness, such as a leaf or a sheet of glass with a single layer, has two sides at the same location; offsetting along the geometric normal from one side lands on the other. The renderer must carry the side information with the hit — usually the sign of the normal against the incoming ray — and apply the offset with a sign chosen from that, rather than from the shading normal, which may be flipped by a normal map and point into the surface. Tangents are worse still: a normal map can bend the shading normal by large angles, and an offset along it moves the point laterally across the surface by a comparable amount. For bumpy surfaces the offset should use the geometric normal and be kept small, or the ray origin should not be moved at all and the bound should be pushed above the bump’s height.
Instanced geometry introduces a transform into the same argument. A ray transformed into instance space has its interval scaled by the transform: if the ray is transformed by a matrix that scales lengths by $s$, then every $t$ computed in instance space corresponds to a $t/s$ in world space. The lower bound must be transformed with it, and if the transform is non-uniform the scaling factor depends on the direction. Computing the world-space bound from the world-space origin, then transforming it, is the consistent order; deriving it in instance space and transforming back introduces a second rounding and can produce a bound smaller than the error it is meant to cover. The two-level structure that makes instances cheap is described in two-level hierarchies for instanced scenes.
The stopping condition belongs to the integrator
An interval is also the mechanism that bounds path length. A path tracer cannot recurse indefinitely; it terminates because the ray’s interval is capped, or because a Russian-roulette decision drops the path, or because a maximum depth counter is reached. The interval cap is the only one of the three that is expressed in geometric terms, and it is the one that must be enforced in every intersection routine rather than in the caller, because a routine that ignores $t_{\max}$ can return a hit that the integrator will then use to spawn further rays and extend a path far beyond its intended reach.
The reverse failure — a routine that honours $t_{\max}$ but whose caller never raises it after a reflection — is equally real. A secondary ray for a reflection must be given the remaining budget, not the original one, if the budget is meant to be a maximum path length in world units. If budget is meant as a count of bounces, the interval is the wrong mechanism entirely and the integrator’s depth counter is the right one. Deciding which budget the renderer is enforcing is a design choice made once, and the interval’s semantics should be documented in whatever header declares the ray type.
References
- Ray Tracing Gems — Eric Haines and Tomas Akenine-Möller (eds.), Apress, 2019
- Physically Based Rendering: From Theory to Implementation — Matt Pharr, Wenzel Jakob, Greg Humphreys, MIT Press
- Watertight Ray/Triangle Intersection — Ingo Wald, Sven Woop, Carsten Benthin, Journal of Computer Graphics Techniques 2(1), 2013