Show HN:我从零开始用 C++ 写了一个光线追踪器,没有借助 AI
Luz 是一个完全从零开发的 C++20 路径追踪器,没有任何第三方依赖。它支持蒙特卡洛路径追踪、全局光照、BVH 加速、自适应采样、降噪、大气散射、自定义场景文件,以及一个 Blender 到 Luz 的导出器。
luz-render-vs-clay-model.mp4
特性
- 蒙特卡洛路径追踪
- 全局光照
- 多线程 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 构建环境。
构建优化
发布版本默认针对构建机器进行调优。Makefile 启用了 -O3、通过 -march=native 进行原生 CPU 调优,以及通过 -flto 进行链接时优化。在编译器/平台支持的情况下,还会启用快速浮点模式。CMake 使用相同的发布意图:-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 用法
用法: ./Luz [选项]
-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 文件中的对象路径相对于场景文件所在目录进行解析。