Ray tracing

레이 트레이싱

Rendering by firing a virtual ray backward from the camera through each screen pixel and computing what it hits to decide that pixel’s color.

Also known as: Ray castingRecursive ray tracing
···
html
<canvas id="rt-canvas"></canvas><span class="rt-cap">camera → pixel → object → light</span>
css
#rt-canvas{width:92%;height:82%;display:block}
.rt-cap{position:absolute;left:0;right:0;bottom:4%;text-align:center;font-size:clamp(9px,2.4vmin,12px);color:var(--muted)}
js
const canvas = document.getElementById('rt-canvas');
const ctx = canvas.getContext('2d');
function resize() {
  const r = canvas.getBoundingClientRect();
  canvas.width = Math.round(r.width * devicePixelRatio);
  canvas.height = Math.round(r.height * devicePixelRatio);
}
addEventListener('resize', resize); resize();

const cam = { x: 0.08, y: 0.5 };
const screenX = 0.3;
const sphere = { x: 0.64, y: 0.52, r: 0.15 };
const light = { x: 0.92, y: 0.14 };
const N = 6;

function draw(t) {
  const w = canvas.width, h = canvas.height;
  ctx.clearRect(0, 0, w, h);
  const P = (nx, ny) => [nx * w, ny * h];
  ctx.strokeStyle = '#5f5f70';
  ctx.lineWidth = Math.max(1, w * 0.002);
  ctx.beginPath();
  const [x0, y0] = P(screenX, 0.16), [x1, y1] = P(screenX, 0.84);
  ctx.moveTo(x0, y0); ctx.lineTo(x1, y1); ctx.stroke();

  const [cx, cy] = P(cam.x, cam.y);
  const [lx, ly] = P(light.x, light.y);
  const [scx, scy] = P(sphere.x, sphere.y);
  const rad = sphere.r * Math.min(w, h);

  ctx.fillStyle = '#ffd27a'; ctx.beginPath(); ctx.arc(lx, ly, Math.max(4, w * 0.01), 0, Math.PI * 2); ctx.fill();
  ctx.fillStyle = '#3a4a72'; ctx.beginPath(); ctx.arc(scx, scy, rad, 0, Math.PI * 2); ctx.fill();
  ctx.fillStyle = '#e7ebff'; ctx.beginPath(); ctx.arc(cx, cy, Math.max(3, w * 0.008), 0, Math.PI * 2); ctx.fill();

  const active = Math.floor(t / 700) % N;
  for (let i = 0; i < N; i++) {
    const py = 0.2 + (i / (N - 1)) * 0.6;
    const [px, pyp] = P(screenX, py);
    let dx = px - cx, dy = pyp - cy;
    const dl = Math.hypot(dx, dy) || 1; dx /= dl; dy /= dl;
    const on = i === active;
    ctx.globalAlpha = on ? 1 : 0.3;
    ctx.lineWidth = on ? Math.max(2, w * 0.003) : Math.max(1, w * 0.0015);
    ctx.strokeStyle = '#7c8cff';

    const ox = cx - scx, oy = cy - scy;
    const b = 2 * (dx * ox + dy * oy);
    const c = ox * ox + oy * oy - rad * rad;
    const disc = b * b - 4 * c;
    let hx = px, hy = pyp, reflected = null;
    if (disc >= 0) {
      const th = (-b - Math.sqrt(disc)) / 2;
      if (th > 0) {
        hx = cx + dx * th; hy = cy + dy * th;
        const nx = (hx - scx) / rad, ny = (hy - scy) / rad;
        const dDot = dx * nx + dy * ny;
        reflected = [dx - 2 * dDot * nx, dy - 2 * dDot * ny];
      }
    }
    ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(hx, hy); ctx.stroke();
    if (reflected) {
      ctx.setLineDash(on ? [] : [4, 4]);
      ctx.beginPath(); ctx.moveTo(hx, hy); ctx.lineTo(hx + reflected[0] * w * 0.32, hy + reflected[1] * w * 0.32); ctx.stroke();
      ctx.setLineDash([]);
      if (on) { ctx.fillStyle = '#ff8fb0'; ctx.beginPath(); ctx.arc(hx, hy, Math.max(2, w * 0.006), 0, Math.PI * 2); ctx.fill(); }
    }
  }
  ctx.globalAlpha = 1;
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);

Rasterization — the default for real-time 3D — asks “where on screen does this triangle land?” Ray tracing asks the reverse: “if I fire a ray from this pixel into the scene, what does it hit?” When a ray hits something, that point’s color gets computed; if the material reflects or refracts, a new ray fires and the process repeats recursively.

Because this follows light’s actual path fairly closely, accurate reflections, shadows, and refraction come almost for free — compared to rasterization, where each one needs its own separate trick (an environment map, a shadow map). The tradeoff is that ray-object intersection tests grow expensive fast as a scene gets more complex.

Blender’s Cycles, Maya’s Arnold, and C4D’s Redshift are all ray-tracing-based renderers (or path tracing, next entry). Recent GPUs’ RT cores accelerate this intersection math in hardware, bringing real-time reflections and shadows into games too. Rather than an actual 3D render, this demo shows a top-down diagram: rays fanning out from the camera, hitting a sphere, and bouncing off toward a light source.

When to use

Reach for the concept when a final render needs accurate reflection, refraction, or shadows, or when discussing real-time reflections on RT-capable GPUs.