Back to Devoured - July 09, 2026
DEVOURED
RayTracer (GitHub Repo)

RayTracer (GitHub Repo)

Data GitHub
ClickHouse developers created a full path tracer that renders complex 3D scenes using only standard SQL queries without external code or UDFs.
What: The RayTracer repository demonstrates high-performance rendering of procedural terrain, shadows, and reflections by treating pixels as table rows. The engine uses ClickHouse vector math, arrayFold loops for light bounces, and ray-marched signed-distance fields to generate imagery at resolutions like 2560x1200.
Why it matters: This showcases how modern analytical databases can perform arbitrary computation outside of traditional data warehousing by treating the engine as a massively parallel processing core for non-relational math.
Takeaway: Test the engine by installing clickhouse-local and running `python3 generators/gen_fold.py 640 256 16 4 "HELLO SQL" > hello.sql` to render your own text.
Deep dive
  • Pixels are mapped as rows in a massive table generated by numbers_mt.
  • Linear algebra is handled using native ClickHouse Tuple types and lambda aliases.
  • Bounces are computed using arrayFold, allowing for parallel execution across all CPU cores.
  • Let-bindings are simulated using one-element arrayMap patterns to avoid expression re-expansion.
  • Geometry uses Constructive Solid Geometry (CSG) primitives like tori, spheres, and cylinders.
  • Terrain is rendered via a height field using Perlin-style noise and ray-marching.
  • The system supports runtime parameters for resolution and sampling while generating scenes via Python scripts.
Decoder
  • Path Tracer: A rendering technique that simulates light transport to create realistic imagery by tracing rays from the camera through a scene.
  • UDF (User-Defined Function): Custom code, often written in C++ or Python, that a database calls to extend its functionality.
  • Signed-Distance Field (SDF): A mathematical representation where each point in space returns the shortest distance to the surface of a defined shape.
  • CSG (Constructive Solid Geometry): A technique where complex 3D shapes are created by combining simpler primitives (spheres, cubes) using Boolean operations like union or subtraction.
Original article

RayTracer — a ray tracer in ClickHouse SQL

A path tracer written entirely as ClickHouse SQL queries, rendering straight to a PNG via ClickHouse's PNG output format. No UDFs and no external code — a single SELECT computes every pixel.

It renders the word ClickHouse as glassy, chrome lettering — in the spirit of Andrew Kensler's famous Pixar business-card ray tracer — and, in the scene above, sets it floating over a procedurally generated landscape, reflecting the terrain and casting shadows on the hills.

See also:

  • NoiSQL — Generating Music With SQL Queries
  • SQL Mandelbrot Benchmark
  • Click-V: A RISC-V emulator built with ClickHouse SQL
  • DOOMHouse is a "Doom-like" game engine that renders the 3D graphics entirely in ClickHouse SQL

How it works

The whole renderer lives in one query:

  • Pixels are rows. numbers_mt(width * height * samples) produces one row per (pixel, sample); samples are averaged with GROUP BY pixel, and the output columns r, g, b (in [0, 1]) plus explicit x, y coordinate columns (pixel % width, intDiv(pixel, width)) are written to the PNG output format. The explicit coordinates let the writer place each pixel by its position, so the rows need no ORDER BY and the heavy per-pixel work stays parallel across all cores.
  • 3D math on tuples. Vectors are Tuple(Float64, Float64, Float64); dotProduct, L2Normalize, tuplePlus, tupleMultiplyByNumber, … do the linear algebra, wrapped in short lambda aliases (va, vs, vm, vd, vn, vc, vref).
  • The bounce loop is arrayFold. Every ray is advanced exactly one mirror bounce per fold step over range(maxDepth) — a loop inside each row, so rows stay independent and the render parallelizes across all CPU cores. (The first version used a WITH RECURSIVE CTE instead — see the queries below.)
  • let-bindings via arrayMap. ClickHouse WITH lambdas are call-by-name, so passing a value as a parameter re-expands the expression and blows up the query tree. Intermediates are therefore bound by value with arrayMap(x -> body, [expr])[1], a one-element-array "let".

Geometry (Constructive Solid Geometry)

  • Cylinders — round rods with flat caps for the straight strokes (l, i, k, H, u, the bar of e).
  • Tori — the round letters (C, c, o, u, s, e), ray-marched through their signed-distance field; the openings of C/c/s/e are a box subtracted from the ring.
  • Spheres — the dot on i, plus a chrome "planet" that is a sphere minus a sphere.
  • Oriented boxes / parallelepipeds — available for flat-faced strokes.

So the scene exercises boxes, cylinders, tori and spheres, with CSG union, difference (the planet and the letter openings) and a ray-marched distance field (the tori).

Terrain

A height field z = amp · fBm(x, y), where fBm sums several octaves of lattice value-noise. Camera rays are ray-marched against it — the march skips the empty air (it starts where the ray first drops to the terrain's maximum height) and linearly interpolates the surface crossing, so it is both fast and free of step-banding. It is shaded with a height color ramp (water → sand → grass → rock → snow), a warm sun plus cool sky-ambient model, marched shadows (terrain self-shadow and the letters' cast shadows), and distance fog into the sky.

Gallery

ClickBulb — a desk lamp built entirely from spheres hops in, leaps behind the banner, rakes its light through the letter gaps, then pokes its head through to peer at you. Every frame is the same ClickHouse SQL query, run once per frame.

Pixar homage — the letters as a union of sphere primitives, chrome over a checkerboard. CSG primitives — the letters carved from cylinders, tori and spheres.
Perlin terrain — a standalone ray-marched height field. Combined — ClickHouse over the terrain (the hero image above).

Running

Every file is complete and self-contained, and parameterized: the image size comes from ClickHouse's image-output settings (read in SQL with getSetting) and the samples per pixel from a {SAMPLES:UInt32} query parameter — one query renders any resolution. Render one with:

clickhouse local --output_format_image_width 2560 --output_format_image_height 1200 \
                 --param_SAMPLES 8 --queries-file queries/clickhouse_terrain.sql > out.png

The queries are emitted by the Python generators; the scene and bounce depth are baked at generation time, while image size and samples per pixel stay runtime parameters of the emitted query. For example, to re-create the hero image:

python3 generators/gen_combined.py 2560 1200 8 2 > scene.sql   # depth 2; W/H/samples are runtime
clickhouse local --output_format_image_width 2560 --output_format_image_height 1200 \
                 --param_SAMPLES 8 --queries-file scene.sql > scene.png

Rendering arbitrary text

The sphere-banner generators take an optional 5th argument: the text to render. It is laid out from the 7-row bitmap font (uppercase A–Z, digits, and common punctuation; the original mixed-case "ClickHouse" glyphs are preserved, so the default render is unchanged), and the camera, light, and chrome sphere are recentered on the banner automatically.

python3 generators/gen_fold.py 640 256 16 4 "HELLO SQL" > hello.sql
clickhouse local --output_format_image_width 640 --output_format_image_height 256 \
                 --param_SAMPLES 16 --queries-file hello.sql > hello.png

Preview a banner as ASCII art without rendering: python3 generators/font.py "HELLO SQL".

Trying with other databases

  • 🐛 CedarDB: works, but 33 times slower and with bugs.
  • ☠️ DuckDB: does not work, tried multiple ways - with arrays and recursive CTE, but it can't process even the smallest resolution image.

Credits

Inspired by Andrew Kensler's business-card ray tracer and Paul Heckbert's minimal ray tracers — re-imagined as pure ClickHouse SQL.

License

Creative Commons Attribution-NonCommercial-ShareAlike 4.0, the same license as ClickBench.

Explore all 57 articles in today's digest

Fresh dev news, AI-digested daily. Never miss a trend at devoured.fyi