Show HN: 从零编写C++光线追踪器,无AI依赖
摘要
一位开发者从零构建了Luz,这是一个零依赖的C++20路径追踪器,具备蒙特卡洛路径追踪、全局光照、BVH加速以及Blender到Luz导出器功能。
查看缓存全文
缓存时间: 2026/06/15 11:57
themartiano/luz 源码: https://github.com/themartiano/luz
Luz
Luz 是一个使用 C++20 从零开发、无任何第三方依赖的路径追踪器。它支持蒙特卡洛路径追踪、全局光照、BVH 加速、自适应采样、降噪、大气散射、自定义场景文件以及 Blender 到 Luz 的导出器。
特性
- 蒙特卡洛路径追踪
- 全局光照
- 多线程 CPU 渲染
- 自适应采样
- 降噪器(NFOR 风格)
- 球体、平面、矩形、三角形、立方体、体积以及 OBJ 网格
- 朗伯、金属、电介质、自发光和各向同性材质
- 面光源、点光源、球面光源和定向光
- 自定义
.luz场景文件 - .blend 到 .luz 的转换器
- 通过 CLI 或场景文件完全自定义渲染参数
- 基于 PDF 的重要性采样
- BVH 加速,包括带分箱 SAH 构建和近邻优先遍历的打包网格 BVH
- 带散射的大气模拟
- 景深、抗锯齿、曝光、对比度、色调映射、伽马校正和泛光
- BMP 和 TIFF 输出
- 确定性基准测试框架,包含渲染、降噪、后期处理和分数分解
要求
- C++20 编译器
- Make 或 CMake 3.16+
- Python 3(仅用于可选工具/脚本)
快速开始
使用 Makefile 构建:
make
渲染一个内置的示例场景:
./Luz --file examples/scenes/blender_monkey.luz --samples 50 --resolution 300x300
默认输出文件为 render.bmp。场景文件可以设置 outputfilename=...,CLI 也可以覆盖常见的渲染设置。
运行测试套件:
make test
基准测试
Luz 包含用于渲染、降噪、后期处理和整体分数比较的确定性基准测试。
make benchmark BENCH_CPUS=1 BENCH_THREADS=1 > before.csv
make benchmark BENCH_CPUS=1 BENCH_THREADS=1 > after.csv
make benchmark-compare BEFORE=before.csv AFTER=after.csv
详细信息请参阅 docs/benchmarks.md。
CMake
CMake 构建方式也同样可用:
cmake -S . -B build
cmake --build build
ctest --test-dir build
平台支持
支持的平台:
- macOS
- Linux
- Windows
在 macOS 和 Linux 上,Makefile 是主要构建方式。在 Windows 上,使用 CMake 搭配 MSVC 或基于 MinGW 的 Makefile 目标:
make windows
WSL 也受支持(作为 Linux 构建环境)。
构建优化
默认情况下,Release 构建会根据构建机器进行调优。Makefile 启用 -O3、-march=native(原生 CPU 调优)以及 -flto(链接时优化)。在编译器/平台支持的情况下,还会启用快速浮点模式。
CMake 使用相同的 Release 意图:-O3、原生 CPU 调优以及(支持时)过程间优化/LTO。
这些默认设置能产生更快的本地渲染结果,但带有 -march=native 的二进制文件可能无法在较旧或不同 CPU 上运行,而 LTO 可能会暴露特定工具链的链接器问题。如果您遇到非法指令崩溃、链接器错误或需要更可移植的二进制文件,请禁用这些激进选项并从干净对象重新构建:
make clean
make NATIVE=0 LTO=0
对于 CMake 构建,关闭优化开关进行配置:
cmake -S . -B build -DLUZ_NATIVE_OPTIMIZATIONS=OFF -DLUZ_ENABLE_LTO=OFF
cmake --build build --clean-first
CLI
Usage: ./Luz [options]
-f, --file PATH 加载 .luz 场景文件
-r, --resolution WxH 覆盖渲染分辨率
-s, --samples N 覆盖每像素采样数
--adaptive [true|false] 启用自适应逐像素采样
--no-adaptive 禁用自适应采样
--adaptive-min-samples N 自适应停止前的最小采样数
--adaptive-threshold F 自适应相对噪声阈值
--adaptive-check-interval N 自适应收敛检查间隔
-mlb, --maxLightBounces N 覆盖最大光反弹次数
--max-light-bounces N --maxLightBounces 的别名
-t, --threads N 使用 N 个工作线程渲染
--seed N 随机采样种子
--gamma true|false 切换伽马校正
-tm, --tonemapping true|false 切换色调映射
--bloom true|false 切换泛光
--exposure EV 曝光补偿(以档为单位)
--contrast F 显示对比度乘数
--denoise [true|false] 写入降噪后的伴随渲染
--no-denoise 禁用降噪
-o, --output PATH 覆盖渲染输出路径
--denoise-output PATH 覆盖降噪输出路径
--render-times 写入 renderTime.bmp
--benchmark 运行内置基准场景
--benchmark-case NAME 基准测试案例:default, many-objects, mesh-bvh, diffuse, postprocess, atmosphere, lights, emissive-geometry, primitives-materials, volumes, obj-mesh
自适应采样
--adaptive 将 --samples 视为每像素的最大采样数。每个像素使用渐进式逐像素采样序列,至少渲染 --adaptive-min-samples 个采样,然后定期检查亮度和 RGB 置信区间。非常暗的像素会使用保守的最小值才能停止,因此罕见的光贡献不太可能被误认为已收敛的黑色。较低的阈值能保留更多细节,但会花费更多时间。
对于最终渲染,从高最大采样数开始,并用类似以下的值进行调整:
./Luz --file exports/stormtroopers.luz --samples 4096 --adaptive --adaptive-min-samples 512 --adaptive-check-interval 64 --adaptive-threshold 0.005 --denoise
降噪
--denoise 启用 Luz 的 NFOR 风格特征缓冲区降噪器,并写入一个单独的伴随图像。默认情况下,render.bmp 会变成 render_denoised.bmp;使用 --denoise-output PATH 选择确切路径。
降噪器没有严格的最小分辨率或采样数要求,但它需要足够的信号来估计有用的颜色和特征统计。每像素一个采样主要是压力测试:没有逐像素方差估计,因此降噪后的图像可能看起来几乎没有变化,或者平滑了错误的细节。预览时至少使用每像素几个采样;评估降噪器质量时,最好使用大约 16 个或更多采样。非常低的分辨率也会使评估产生误导,因为每个局部滤波窗口覆盖了图像过多的部分。
场景文件
示例场景位于 examples/scenes/。网格资产位于 assets/objects/。场景文件格式在 docs/scene-files.md 中有文档说明。
.luz 文件中的对象路径首先相对于场景文件解析,然后相对于当前工作目录,最后在 assets/objects/ 下查找。这意味着 examples/scenes/blender_monkey.luz 可以引用 ../../assets/objects/blender_monkey.obj,并且仍然可以从仓库根目录运行。
OBJ 网格也可以进行偏移并分配场景材质:
obj=mesh.obj,(x,y,z),material[ metal=(0.8,0.8,0.8),0.1 ]
Blender 导出器
可以通过 Blender 的 Python API 导出 Blender 场景:
"/Applications/Blender.app/Contents/MacOS/Blender" -b scene.blend --python tools/blender_export_luz.py -- --output exports/scene.luz
./Luz --file exports/scene.luz --threads 8
导出器会写入一个 .luz 文件以及 OBJ 网格。用法和当前的保真度限制在 docs/blender-exporter.md 中有文档说明。
仓库布局
include/luz/ 公共头文件
src/core/ 数学、几何、材质、图像和采样代码
src/renderer/ 渲染实现
src/scene/ 场景模型和场景辅助
src/io/ 场景文件、OBJ、BMP 和 TIFF 加载/写入
src/cli/ 命令行入口和标志
examples/scenes/ 示例 .luz 场景文件
assets/objects/ 示例使用的 OBJ 资产
docs/images/ 压缩的展示图片
tools/ 导出和实用脚本
tests/ 仅使用标准库的测试程序
docker/ 基准测试容器
展示
个人说明
特别感谢《Ray Tracing in One Weekend》(https://github.com/RayTracing/raytracing.github.io)系列书籍。在 Luz 的很大一部分开发过程中,它(尤其是在 AI 时代之前)是灵感和信息的重要来源。
署名
Stormtrooper 场景由 BlendSwap 上的 @ScottGraham (https://blendswap.com/profile/120125) 提供(https://blendswap.com/blend/13953)。
Bust Statue 由 BlendSwap 上的 @geoffreymarchal (https://blendswap.com/profile/180520) 提供(https://blendswap.com/blend/21704)。
许可
MIT。参见 LICENSE。
相似文章
基于SQL的光线追踪器
完全使用ClickHouse SQL查询实现的光线追踪器,无需任何外部代码或UDF即可将图像渲染为PNG格式。演示了程序化地形、CSG几何体以及并行像素计算。
无头截图循环使得本地30B智能体用纯C完成光线追踪FPS演示
一个使用300亿参数模型的AI智能体利用无头截图循环,自主完成了一个用C语言编写的光线追踪第一人称射击演示,展示了先进的自主编程和调试能力。
用500行纯C++实现软件渲染
一个教程系列,通过用500行C++从零构建软件渲染器(无需外部库),演示OpenGL、Vulkan、Metal和DirectX的工作原理。
用500行纯C++实现软件渲染
本教程系列教你如何用500行C++从头编写一个软件渲染器,并解释现代3D图形API的内部工作原理。
使用四面体笼对大量动画几何体进行光线追踪
本文介绍了一种通过使用四面体笼将动画与三角形数量解耦,从而对大量动画三角形进行光线追踪的技术,使得在消费级GPU上以60 FPS处理包含数亿个动画三角形的场景成为可能。