technique

Ray-cast hidden-line removal

Determine which parts of a 3D scene's paths are visible from the camera by ray-testing each point for occlusion, then draw only unoccluded segments as 2D vector lines.

Also called: ray-solid intersection visibility test

Run it

Deciding which lines a plotter would actually draw ray/solid intersection (sphere & box) · per-point visibility vs. per-edge visibility · the self-intersection epsilon ("shadow acne")
What it looks like when it goes wrong (3)
  • Visibility is only ever decided at the sampled points, not continuously along the edge. With this few samples per line, a run can straddle the exact spot where the surface turns away from camera — so the silhouette goes ragged and gap-toothed, and the occasional hidden segment slips through as if it were visible.
  • Every sampled point sits exactly on its own surface, so a naive ray toward the camera immediately re-intersects that same surface at t≈0 — floating-point rounding in the point's own construction decides, essentially by chance, whether that trivial self-hit reads as slightly positive ("blocked") or slightly negative ("clear"). Without a margin to step past it, roughly a quarter of the genuinely visible surface is wrongly shadowed by itself and drops out — the classic ray-tracer "shadow acne" bug.
  • Every visibility ray assumes the camera sits outside every solid. Pull it inside one and the assumption breaks: a straight line from any point on a convex solid's surface to a camera embedded inside it never crosses that solid's boundary again, so nothing on that shape can ever block anything else on it. The whole solid renders as if it had no surface at all — see-through, not solid.

Clean-room implementation — written from the described algorithm, not from source. Reuse policy

What it is

A pen plotter draws lines and has no fill call, so tone comes from hatching rather than shading — and geometry the camera cannot see has to be pruned rather than overdrawn. Ray-cast hidden-line removal decides, point by point along a shape’s 3D paths, which points the camera can actually see, and throws the rest away before anything reaches 2D. It’s the visibility algorithm at the core of Michael Fogleman’s ln, a renderer that turns 3D scenes into vector output instead of rasterizing them.

How it works

  1. Every shape supplies 3D polylines rather than a mesh to shade.
  2. Chop each path into points at a chosen step size.
  3. From each point, cast a ray toward the camera.
  4. If anything else intersects that ray before the camera, the point is hidden and dropped; otherwise it survives.
  5. Reassemble the surviving points into visible sub-segments of the path.
  6. Project the survivors into 2D — the source says only that surviving geometry is “transformed into 2D space using transformation”.
  7. Write the surviving 2D paths out as SVG.

Parameters & tuning

Step size is the knob that matters. Chop coarsely and the render is fast, but a sample can land right where a surface turns away from the camera, leaving a ragged silhouette or a hidden segment that slips through as if visible. Chop finely and edges clean up, at the cost of one ray test per point.

CSG combinations (union, difference, intersection) are applied before hidden-line rendering, so visibility is computed against the combined solid rather than its parts.

Where it’s been used

Fogleman built ln to drive a physical machine — elsewhere in the same project he calls the AxiDraw V3 “a very nice modern pen plotter.” The same toolkit solves adjacent problems differently: hill climbing for image-to-primitive approximation reduces a photo to shapes by optimizing pixels, not rays; turtle graphics generates 2D paths directly, skipping hidden-line removal entirely.

Variants & neighbours

Vector-based texturing runs first — it decides what paths exist on a surface (a grid, a hatch, scattered dots); hidden-line removal only decides which of those already-chosen points survive.

CSG operations change what shape gets tested, combining primitives before any ray is cast — the visibility pass itself is unchanged.

Triangle meshes (OBJ & STL) change where the geometry comes from: an imported mesh implements the same interface as a coded primitive, so it gets hidden-line removal for free.

Go deeper

The full description lives in one place — fogleman/ln’s README, in the section documenting how the renderer works. There’s no separate paper behind this technique in the current evidence.

Connected to

Pioneered by: Michael Fogleman

Requires: Vector-based Texturing

Try it yourself

A hidden-line render of a lat/long-textured sphere shows small notches right along the terminator — where the surface curves away from the camera — rather than in the clearly-visible or clearly-hidden regions. What causes that, and what does the fix cost?

The step size. Visibility is decided per sampled point, not per continuous edge, so near the terminator neighbouring samples are the ones most likely to disagree about whether they're occluded. Chopping the path finer resolves it, at the cost of one extra ray test per added point — render time scales with the number of sampled points, and each test also costs more as the scene gains solids.


Revision 2 · 1 source · Something wrong? Tell us.