The Coiled Near-Ring: A Torus's Spiral Cousin

A geometry note supporting Why Our Spheres Were Tearing Apart

← Back to that post


ShoggothOx's NearRing display mode is described in the depth-buffer post as a “coiled near-ring torus,” which is a mouthful if you've never seen the mesh code. It looks like a torus at a glance — a ring with a round tube — but it's built from a spiral, not a circle, and the two ends of that spiral never actually meet. This page is the geometric detour that didn't belong in the middle of a bug-hunting story.

A Plain Torus, Briefly

A standard torus is built from two angles. Walk around the main axis with angle θ, and at every point on that circle, sweep a small circle of fixed radius r around it using angle φ:

let x = (major + minor * phi.cos()) * theta.cos();
let y = minor * phi.sin();
let z = (major + minor * phi.cos()) * theta.sin();

Both angles run 0..2π and then wrap back to where they started. Critically, minor (the tube radius) never changes — so when θ completes a full lap, every value it passed through repeats exactly. The centerline is just a circle:

PLAIN TORUS CENTERLINE
θ=0 ≡ 2π one loop, constant radius
NEAR-RING CENTERLINE
u=0 (r=0.25) u=1 (r=0.5) 8 loops, growing radius, ends don't meet
Both curves plotted from the actual parametric equations, looking down the main axis. Left: a plain torus's centerline is one circle at a fixed radius — end meets start exactly. Right: the near-ring's centerline winds around the same center eight times while its radius grows, so the last point (red) lands on the same ray as the first point (green) but noticeably farther out. There is no way to connect them without a jump.

The Near-Ring's Twist

Here's the actual mesh generator, trimmed to the math that matters (crates/render/src/mesh.rs):

pub fn make_near_ring() -> (
    Vec<Vertex>, Vec<u16>
  ) {
    const TURNS: u16 = 8;
    const SEGMENTS_PER_TURN: u16 = 64;
    const TUBE_SEGMENTS: u16 = 64;
    let nu = TURNS * SEGMENTS_PER_TURN;
    let nv = TUBE_SEGMENTS;
    // ...
    let uu = iu as f32 / nu as f32;       // 0..1, the long axis
    let vv = iv as f32 / nv as f32;       // 0..1, the tube cross-section
    let ff = 0.25 * (1.0 + uu);           // tube radius: 0.25 -> 0.5
    let alpha = f32::from(TURNS) * uu * TAU;
    let beta = vv * TAU;                  // cross-section angle: one full loop
    let rx = 1.0 + ff * beta.sin();
    let pos = [
        alpha.sin() * rx, ff * beta.cos(), alpha.cos() * rx
    ];
    let uv = [uu * f32::from(TURNS) * 2.0, vv * 2.0];

This is the plain torus formula from the section above, with two changes: alpha (the equivalent of θ) sweeps 0..16π instead of 0..2π — eight full turns as uu goes 0 to 1 — and ff (the equivalent of minor) is no longer constant: it grows linearly from 0.25 to 0.5 over the same range.

Ignore the tube's cross-section for a moment and look only at the centerline — the path traced as uu goes from 0 to 1. Since alpha is an angle and ff is a radius that both grow linearly with uu, plotting ff against alpha in polar coordinates traces out exactly an Archimedean spiral — the same curve as a rolled-up garden hose, a coiled watch spring, or the groove on an old vinyl record. The tube's circular cross-section (governed by beta) then rides along that spiral spine the whole way, and — because ff also sets the cross-section's own scale in rx and pos.y — the tube itself gets fatter as it spirals outward, like a chambered nautilus shell.

Why “Near”-Ring, Not Torus

A real torus closes up because both of its angles return to an identical state after one loop: same angle, same radius. Check the near-ring against that test:

Same direction, different distance from center: the end of the strip sits right next to the start, on the same ray, but a visible gap out — exactly what the spiral diagram above shows. The mesh code never tries to stitch uu = 1 back to uu = 0 (there's no closing band of triangles the way there is for a plain torus's θ or the near-ring's own vv), because there is no sensible way to do it without a seam or a distortion. That's the whole reason for the name: it reads as a ring from a distance, but its long axis is an open curve, not a closed loop.

Open geometry does not require a texture to be stretched only once along it. The tube cross-section still uses the texture-wrapping fix: its coordinates mirror across the genuinely closed vv direction. Along uu, the coordinate advances by two units per spiral turn. With MirrorRepeat, those two units form one continuous forward-and-reverse texture cycle. The geometry remains open, but every coil gets a full view of the audio texture instead of sharing one narrow slice across all eight turns. The reactive-material investigation shows the visual difference.

Why It Reads as a Torus on Screen

The mesh now uses nu = 512 columns spread over 8 turns, or 64 columns per revolution. The original 128-column mesh supplied only 16 edges per revolution and produced a visibly polygonal outline; the tessellation and camera-framing investigation explains that upgrade. The geometry itself is unchanged: each turn's radius grows by just (0.5 − 0.25) / 8 = 0.03125 — a little over 3% of the major radius per loop. The coils still nest almost on top of each other. From most camera angles you're not looking at a visible spiral staircase; you're looking through up to eight overlapping layers of tube along a single line of sight, which is exactly why the missing depth buffer produced messier tearing here than on the sphere — a sphere only ever has two candidate surfaces (near and far) fighting over a pixel; the near-ring can have eight.


← Back to the depth-buffer post