C++20을 기반으로 외부 종속성 없이 처음부터 직접 구현한 'Luz'라는 고성능 몬테카를로 패스 트레이서(Monte Carlo Path Tracer) 프로젝트가 해커뉴스에 공개되었습니다. 이 프로젝트는 글로벌 일루미네이션, BVH 가속, 적응형 샘플링, 노이즈 제거(Denoising) 등 상용 렌더러에 필적하는 고급 기능들을 제공하며, 블렌더(Blender) 익스포터와 크로스 플랫폼 빌드를 지원합니다. AI의 코드 생성 능력에 의존하지 않고 개발자의 순수한 엔지니어링 역량만으로 구현되었다는 점이 그래픽스 및 시스템 프로그래밍 실무자들에게 큰 인상을 주고 있습니다.
번역된 본문
원문 제목: Show HN: AI의 도움 없이 순수 C++로 레이 트레이서를 처음부터 직접 구현했습니다.
Luz는 서드파티(Third-party) 종속성을 전혀 사용하지 않고 C++20을 사용해 처음부터 직접 개발된 패스 트레이서(Path Tracer)입니다. 몬테카를로 패스 트레이싱, 글로벌 일루미네이션(Global illumination), BVH 가속, 적응형 샘플링(Adaptive sampling), 노이즈 제거(Denoising), 대기 산란(Atmospheric scattering), 커스텀 씬 파일, 그리고 Blender에서 Luz로 내보내기(Export)하는 기능을 지원합니다.
BVH 가속 (Binned SAH 구축 및 근접 우선 순회(Near-first traversal) 방식의 패키징된 메시 BVH 포함)
산란(Scattering) 효과를 적용한 대기 시뮬레이션
피사계 심도(Depth of field), 안티앨리어싱, 노출, 대비, 톤 매핑, 감마 보정, 블룸(Bloom) 효과
BMP 및 TIFF 출력
렌더링, 노이즈 제거, 후처리 및 점수 분류를 포함한 결정론적(Deterministic) 벤치마크 환경
요구 사항
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.csvmake benchmark BENCH_CPUS=1 BENCH_THREADS=1 > after.csvmake benchmark-compare BEFORE=before.csv AFTER=after.csv
자세한 내용은 docs/benchmarks.md를 참조하세요.
플랫폼 지원
지원 플랫폼: macOS, Linux, Windows
macOS 및 Linux에서는 Makefile을 기본으로 사용합니다. Windows에서는 MSVC와 함께 CMake를 사용하거나 MinGW 기반의 Makefile 타겟을 사용하세요: make windows. WSL(Windows Subsystem for Linux) 환경도 지원됩니다.
빌드 최적화
릴리스 빌드는 기본적으로 빌드를 실행하는 머신에 맞게 최적화됩니다. Makefile은 -O3, -march=native를 통한 CPU 고유 명령어 튜닝, -flto를 통한 링크 타임 최적화를 활성화합니다. 또한 컴파일러/플랫폼이 지원하는 경우 빠른 부동소수점 모드를 활성화합니다.
CMake도 동일한 릴리스 의도로 -O3, 네이티브 CPU 튜닝 및 지원되는 경우 프로시저 간 최적화/LTO를 사용합니다.
이러한 기본값은 로컬 렌더링 속도를 높여주지만, -march=native로 빌드된 바이너리는 오래되거나 다른 아키텍처의 CPU에서 실행되지 않을 수 있으며, LTO는 특정 툴체인의 링커 문제를 발생시킬 수 있습니다.
명령어 오류(Illegal-instruction) 크래시나 링커 오류가 발생하거나, 이식성이 높은 바이너리가 필요한 경우 강력한 옵션을 비활성화하고 처음부터 다시 빌드하세요:
make cleanmake NATIVE=0 LTO=0
CMake 빌드의 경우 최적화 토글을 끄고 구성하세요:
cmake -S . -B build -DLUZ_NATIVE_OPTIMIZATIONS=OFF -DLUZ_ENABLE_LTO=OFFcmake --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: 최대 광선 튕김(Light bounces) 횟수 재정의
Luz Luz is a C++20 Path Tracer developed from scratch with zero third-party dependencies. It supports Monte Carlo path tracing, global illumination, BVH acceleration, adaptive sampling, denoising, atmospheric scattering, custom scene files, and a Blender-to-Luz exporter. Features Monte Carlo path tracing Global illumination Multithreaded CPU rendering Adaptive sampling Denoiser (NFOR-style) Spheres, planes, rectangles, triangles, cubes, volumes, and OBJ meshes Lambertian, metal, dielectric, emissive, and isotropic materials Area, point, sphere and directional lights Custom .luz scene files .blend to .luz converter Fully customizable render parameters via CLI or scene file Importance sampling with PDFs BVH acceleration, including packed mesh BVHs with binned SAH construction and near-first traversal Atmospheric simulation w/ scattering Depth of field, antialiasing, exposure, contrast, tone mapping, gamma correction, and bloom BMP and TIFF output Deterministic benchmark harness with render, denoise, post-process, and score breakdowns Requirements C++20 compiler Make or CMake 3.16+ Python 3, only for optional tools/scripts Quick Start Build with the Makefile: make Render a bundled example scene: ./Luz --file examples/scenes/blender_monkey.luz --samples 50 --resolution 300x300 The default output is render.bmp . Scene files can set outputfilename=... , and the CLI can override common render settings. Run the test suite: make test Benchmarking Luz includes deterministic benchmarks for render, denoise, post-process, and overall score comparisons. 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 For details, see docs/benchmarks.md . CMake A CMake build is also available: cmake -S . -B build cmake --build build ctest --test-dir build Platform Support Supported platforms: macOS Linux Windows On macOS and Linux, the Makefile is the primary path. On Windows, use CMake with MSVC or the MinGW-based Makefile target: make windows WSL is also supported as a Linux build environment. Build Optimizations Release builds are tuned for the machine doing the build by default. The Makefile enables -O3 , native CPU tuning with -march=native , and link-time optimization with -flto . It also enables a fast floating-point mode where the compiler/platform supports it. CMake uses the same release intent: -O3 , native CPU tuning, and interprocedural optimization/LTO when supported. These defaults produce faster local renders, but binaries built with -march=native may not run on older or different CPUs, and LTO can expose toolchain-specific linker issues. If you hit an illegal-instruction crash, linker error, or need a more portable binary, disable the aggressive options and rebuild from clean objects: make clean make NATIVE=0 LTO=0 For CMake builds, configure with the optimization toggles off: cmake -S . -B build -DLUZ_NATIVE_OPTIMIZATIONS=OFF -DLUZ_ENABLE_LTO=OFF cmake --build build --clean-first CLI Usage: ./Luz [options] -f, --file PATH Load a .luz scene file -r, --resolution WxH Override render resolution -s, --samples N Override samples per pixel --adaptive [true|false] Enable adaptive per-pixel sampling --no-adaptive Disable adaptive sampling --adaptive-min-samples N Minimum samples before adaptive stopping --adaptive-threshold F Relative adaptive noise threshold --adaptive-check-interval N Adaptive convergence check interval -mlb, --maxLightBounces N Override maximum light bounces --max-light-bounces N Alias for --maxLightBounces -t, --threads N Render with N worker threads --seed N Seed random sampling --gamma true|false Toggle gamma correction -tm, --tonemapping true|false Toggle tone mapping --bloom true|false Toggle bloom --exposure EV Exposure compensation in stops --contrast F Display contrast multiplier --denoise [true|false] Write a denoised companion render --no-denoise Disable denoising -o, --output PATH Override render output path --denoise-output PATH Override denoised output path --render-times Write renderTime.bmp --benchmark Run the built-in benchmark scene --benchmark-case NAME Benchmark case: default, many-objects, mesh-bvh, diffuse, postprocess, atmosphere, lights, emissive-geometry, primitives-materials, volumes, obj-mesh Adaptive Sampling --adaptive treats --samples as the maximum samples per pixel. Each pixel uses a progressive per-pixel sample sequence, renders at least --adaptive-min-samples , then periodically checks luminance and RGB confidence intervals. Very dark pixels use a conservative minimum before they can stop, so rare light contributions are less likely to be mistaken for converged black. Lower thresholds keep more detail and cost more time. For final renders, start with a high max sample count and tune with values like: ./Luz --file exports/stormtroopers.luz --samples 4096 --adaptive --adaptive-min-samples 512 --adaptive-check-interval 64 --adaptive-threshold 0.005 --denoise Denoising --denoise enables Luz's NFOR-style feature-buffer denoiser and writes a separate companion image. By default, render.bmp becomes render_denoised.bmp ; use --denoise-output PATH to choose the exact path. The denoiser has no hard minimum resolution or sample count, but it needs enough signal to estimate useful color and feature statistics. One sample per pixel is mainly a stress test: there is no per-pixel variance estimate, so the denoised image can look almost unchanged or can smooth the wrong details. Use at least a few samples per pixel for previews, and prefer roughly 16+ samples per pixel when judging denoiser quality. Very low resolutions also make evaluation misleading because each local filter window covers too much of the image. Scene Files Example scenes live in examples/scenes/ . Mesh assets live in assets/objects/ . The scene-file format is documented in docs/scene-files.md . Object paths in .luz files are resolved relative to the scene file first, then relative to the current working directory, then under assets/objects/ . This means examples/scenes/blender_monkey.luz can reference ../../assets/objects/blender_monkey.obj and still run from the repository root. OBJ meshes can also be offset and assigned a scene material: obj=mesh.obj,(x,y,z),material[ metal=(0.8,0.8,0.8),0.1 ] Blender Exporter Blender scenes can be exported through Blender's Python API: " /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 The exporter writes a .luz file plus OBJ meshes. Usage and current fidelity limits are documented in docs/blender-exporter.md . Repository Layout include/luz/ Public headers src/core/ Math, geometry, materials, image, and sampling code src/renderer/ Rendering implementation src/scene/ Scene model and scene helpers src/io/ Scene-file, OBJ, BMP, and TIFF loading/writing src/cli/ Command-line entry point and flags examples/scenes/ Example .luz scene files assets/objects/ OBJ assets used by examples docs/images/ Compressed showcase images tools/ Export and utility scripts tests/ Standard-library-only test program docker/ Benchmark container Showcase Personal Note Special thanks to the Ray Tracing in One Weekend book series. It was a great source of inspiration and information during a big part of the development of Luz, specially since those were times before AI. Attribution Stormtrooper Scene by @ ScottGraham on BlendSwap . Bust Statue by @ geoffreymarchal on BlendSwap . License MIT. See LICENSE .