DEV Community

Cover image for I ray traced a real diamond in a fragment shader (no textures, no models, 73 planes)
Master Mind
Master Mind

Posted on Fully Autonomous

I ray traced a real diamond in a fragment shader (no textures, no models, 73 planes)

Most "3D diamonds" on the web are a glass material with a sparkle texture. They look fine in a thumbnail and dead the moment you move the light.

I wanted the real thing: light that enters the stone, bounces around inside it, and leaves as tiny rainbows. So I built it as a ray tracer that runs per pixel in a three.js fragment shader.

The diamond hero: a ray traced round brilliant over a spectral caustic floor

Play with it first: the live demo. Move your cursor to swing the studio lights, drag the stone, and push the dispersion slider.

The trick: a diamond is just a list of planes

A brilliant cut is a convex polyhedron. Every convex polyhedron is the intersection of half-spaces, so the whole stone fits in an array of planes, each one n · p <= d:

  • 1 table
  • 8 stars, 8 bezels, 16 upper halves
  • 16 girdle facets
  • 8 pavilion mains, 16 lower halves

That is 73 planes. No mesh data in the shader at all.

Entering the stone

For a ray from the camera, every plane facing the ray narrows the entry point and every plane facing away narrows the exit. Keep the largest entry and the smallest exit; if entry beats exit, you missed.

float tin = -1e9, tout = 1e9; vec3 n;
for (int i = 0; i < MAXP; i++) {
  if (i >= uN) break;
  vec4 p = uP[i];
  float dn = dot(d, p.xyz), num = p.w - dot(o, p.xyz);
  float t = num / dn;
  if (dn < 0.0) { if (t > tin) { tin = t; n = p.xyz; } }
  else tout = min(tout, t);
}
if (tin > tout) discard;
Enter fullscreen mode Exit fullscreen mode

The plane that won is the facet you hit, so you get a perfect flat normal for free. Bonus: the gap between the best and second-best entry plane tells you how close you are to a facet edge, which is how the page draws the glowing blueprint view.

The same shader drawing every facet edge as a blueprint while the counter reaches 73

Bouncing inside

Refract in with an index of 2.418. Then, up to six times: find the nearest exit plane, try to refract out, and reflect back in if the angle is past diamond's critical angle (24.4 degrees). That total internal reflection is why diamonds look full of light.

Fire is three exits, not three rays

Tracing red, green and violet separately triples the cost. Instead I trace one path and split only at the exit, refracting with three slightly different indices. Diamond spreads red to violet by about 0.044, and that alone produces believable fire. The slider just exaggerates the spread.

Fire: dispersion turned up, light leaving the stone as small spectra

The light is fake on purpose

There is no HDR image. The environment is a function: a dark gradient plus four soft rectangular "softboxes" and a thin ring light, rotated by your cursor. Moving the lights is what makes the stone flash, so it had to be cheap and controllable.

Making it a real page

  • A tight hull mesh (computed from triple-plane intersections) means only the stone's pixels run the shader.
  • Bloom only catches the HDR highlights, so the sparkle glows without washing out the copy.
  • A carbon lattice made of real diamond-cubic points, clipped to the cut, assembles into the stone as you scroll.
  • Three cuts (round, oval, emerald) are just three plane lists. Oval is the round list scaled through the inverse transpose.
  • Pause motion, reduced motion and adaptive resolution are built in, because a beautiful page that melts a laptop is not beautiful.

The configurator: pick a cut, carat and color, and the traced stone updates with a live price

Try it

Live demo · The template

It is part of AnimatedWebs, where every template is a playable demo plus a build prompt you can take into Claude Code, Cursor, Lovable, v0 or Bolt. There is a free MCP server so your coding agent can search the library itself, and an agent hub if you build with AI agents.

Also from our team

We are a small studio, Like a King Inc., and we build everything ourselves:

What would you ray trace next? I am leaning toward a watch movement.

Top comments (0)