Ray Tracer in SQL
AI 深度解读
背景
在数据库领域,ClickHouse 以其极致的 OLAP 查询性能著称,通常用于海量数据分析。然而,一个极具实验性质的项目展示了 ClickHouse 的另一面:完全用 ClickHouse SQL 实现路径追踪(Path Tracing)渲染器,无需用户自定义函数(UDF),无需外部代码,仅靠一条 SELECT 语句就能逐像素计算并直接输出 PNG 图像。
该项目灵感来源于 Andrew Kensler 著名的 Pixar 名片光线追踪器(用 C++ 写成,代码精简到可印在名片上)以及 Paul Heckbert 的极简光线追踪器。作者将其重新构想为纯 ClickHouse SQL 实现,渲染了玻璃质感、铬合金风格的 "ClickHouse" 字样,漂浮在程序生成的地形之上,反射地表并在山丘上投下阴影。
核心内容
整体架构
整个渲染器由一条 SQL 查询构成,核心思路是将像素映射为数据行:
numbers_mt(width * height * samples)为每个(像素, 采样)组合生成一行数据- 通过
GROUP BY pixel对多次采样取平均,得到最终像素颜色 - 输出列
r, g, b(范围[0, 1])配合显式x, y坐标列(pixel % width与intDiv(pixel, width))写入 ClickHouse 的 PNG 输出格式 - 显式坐标让写入器按位置放置像素,因此行无需
ORDER BY,重计算工作可跨所有 CPU 核心并行
3D 数学与光线追踪
- 向量运算:向量表示为
Tuple(Float64, Float64, Float64),线性代数操作(点积、L2 归一化、向量加减、标量乘法等)通过短 lambda 别名实现(va、vs、vm、vd、vn、vc、vref) - 光线反弹循环:使用
arrayFold实现,每次折叠步骤将光线推进一次镜面反弹,循环在每一行内部执行,保持行间独立,渲染可跨所有 CPU 核心并行。早期版本使用WITH RECURSIVECTE 实现 - let 绑定:由于 ClickHouse 的
WITHlambda 采用传名调用(call-by-name),传参会导致表达式重复展开、查询树膨胀。因此使用arrayMap(x -> body, [expr])[1]实现按值绑定(one-element-array "let")
场景几何体
场景综合运用了多种几何体与 CSG(构造实体几何)操作:
- 圆柱体(Cylinders):用于直线笔画(
l、i、k、H、u、e的横杆) - 圆环(Tori):用于圆形字母(
C、c、o、u、s、e),通过有符号距离场(SDF)进行光线步进(ray-marched);C/c/s/e的开口通过从环中减去一个盒子实现 - 球体(Spheres):
i上的点,以及一个铬合金"行星"(球体减去球体) - 方向盒子/平行六面体(Oriented boxes / parallelepipeds):用于平面笔画
整体场景涵盖了盒子、圆柱体、圆环、球体,以及 CSG 并集、差集和光线步进距离场。
地形与着色
- 高度场:
z = amp · fBm(x, y),其中 fBm 对多个八度的晶格值噪声求和 - 光线步进:相机光线对高度场进行光线步进,从光线首次降至地形最大高度处开始,跳过空白空气,线性插值求交,既快速又无步进带状伪影
- 着色模型:高度颜色渐变(水 → 沙 → 草 → 岩石 → 雪)、暖色太阳光加冷色天空环境光、步进阴影(地形自阴影与文字投射阴影)、向天空的距离雾
ClickBulb 动画
一个完全由球体构成的台灯(ClickBulb)会在场景中跳跃,从横幅后方探出,光线穿过字母缝隙,然后探头看向观众。每一帧都是相同的 ClickHouse SQL 查询,逐帧运行(全质量视频)。
参数化与生成
queries/目录下的每个文件都是完整且自包含的,
查看原文 →github.com
