Skip to content

Latest commit

 

History

History
278 lines (235 loc) · 18.4 KB

File metadata and controls

278 lines (235 loc) · 18.4 KB

RayTracing — Project Knowledge Base

Generated: 2026-05-28 Updated: 2026-06-22 (Phase 1 完成 — Golden Image 测试, PR #55) Commit: ea8b7fe Branch: master

OVERVIEW

GPU-accelerated real-time path tracer — C++23 + CUDA + Vulkan via Peanut (ImGui) framework. Single light source: emissive materials. No sky/env light.

STRUCTURE

RayTracing/
├── RayTracing/src/        # All application code (24 files)
│   ├── PeanutApp.cpp      # Entry: scene setup, ImGui UI, render dispatch
│   ├── Renderer.cpp/h     # Orchestrator: owns FinalImage, frame counter, delegates to IRenderBackend
│   ├── IRenderBackend.h    # Abstract backend interface (OnResize, Render, OutputDelivered, InvalidateRayDirs)
│   ├── CUDABackend.cpp/h   # GPU backend: wraps CUDARenderer_* C API + Vulkan interop + OptiX denoiser
│   ├── CPUBackend.cpp/h    # CPU backend: PerPixel path tracer + ISPC SIMD + C++ fallback
│   ├── PathTracerCore.h    # Shared GGX BRDF inline functions (CPU + Catch2 tests)
│   ├── Camera.cpp/h       # Camera: ray direction pre-computation, FPS controls
│   ├── CUDARenderer.cuh/.cu/.h  # GPU: kernels, device code, host wrappers
│   ├── CUDATypes.cuh      # GPU struct definitions (must match CUDARenderer.h)
│   ├── VkCUDAInterop.h/cpp # Vulkan-CUDA zero-copy memory sharing (external memory)
│   ├── OptiXDenoiser.h/cpp # OptiX AI denoiser integration
│   ├── Scene.h            # Material, Sphere, Scene data structures
│   ├── Ray.h              # Ray struct (origin + direction)
│   ├── Constants.h         # Shared constexpr constants (kPi, 7 epsilon/roughness/threshold values)
│   └── PathTracer_ispc.h  # ISPC-generated header (auto-generated by ISPC compiler)
├── xmake.lua              # Root workspace: Peanut + RayTracing + CUDA/OptiX/ISPC + xrepo packages
├── Directory.Build.props   # VS IntelliSense config (auto-discovered by MSBuild)
├── scripts/
│   ├── Setup.bat             # xmake build + vsxmake solution generator
│   └── golden/               # Python Golden Image 测试 (uv 管理)
├── test/golden/              # CPU 参考图像
├── RayTracing/tools/         # 无头渲染器 (GoldenRenderer)

WHERE TO LOOK

Task Location Notes
ImGui scene controls PeanutApp.cpp:93-197 Accumulate, Reset, Denoise, Vulkan-CUDA Interop checkboxes; scene/material editing; MaxBounces slider (1-20)
CPU path tracing (C++) CPUBackend.cpp PerPixel() + ISPC SIMD or std::execution::par fallback
CPU path tracing (ISPC) PathTracer.ispc:167-357 ISPC SIMD path tracer with GGX microfacet BRDF
GPU path tracing CUDARenderer.cuh:238-367 PerPixel() device function with GGX VNDF sampling
GPU kernel launch CUDARenderer.cuh:374 (RenderKernel), :399 (PostProcessKernel) 16×16 blocks, two-stage pipeline
Scene→GPU upload CUDABackend.cpp Packing from glm→GPU structs, version-tracked cudaMemcpy
Material definition Scene.h:7-19 Albedo, Roughness, Metallic, EmissionColor, EmissionPower
Camera ray generation Camera.cpp:138-166 Pre-computed ray directions per pixel
GGX Microfacet BRDF (GPU) CUDARenderer.cuh:58-125 FresnelSchlick, GGX_D, GGX_G1, GGX_G, SampleGGX_VNDF, BuildONB
GGX Microfacet BRDF (CPU) Renderer.cpp:63-130 FresnelSchlick, GGX_D, GGX_G1, GGX_G, SampleGGX_VNDF, BuildONB
GGX Microfacet BRDF (ISPC) PathTracer.ispc:55-122 ISPC SIMD GGX implementation matching CPU/GPU paths
Shared constants Constants.h:1-13 kPi + 7 epsilon/roughness/threshold constexpr values — included by Renderer.cpp and CUDARenderer.cuh
Vulkan-CUDA interop VkCUDAInterop.h/.cpp VkBuffer export→Win32 handle→cudaImportExternalMemory→mapped device ptr
OptiX AI denoiser OptiXDenoiser.h:28-39, OptiXDenoiser.cpp:72-168 HDR float4 denoising; runs after PostProcessKernel, before RGBA conversion
CUDA architecture targets xmake.lua:130-133 compute_75/sm_75, compute_86/sm_86, compute_89/sm_89, compute_120/sm_120
ISPC SIMD targets xmake.lua:142-165 avx2, avx512skx-i32x16
Build config (CUDA) xmake.lua:117-140 PN_CUDA define, CUDA SDK detection, NVCC flags
Build config (OptiX) xmake.lua:167-204 PN_OPTIX define, OptiX SDK detection
Build config (ISPC) xmake.lua:142-165 PN_ISPC define, ISPC binary detection

CODE MAP

Symbol Type File:Lines Role
Renderer::PerPixel() method Renderer.cpp:438 CPU path trace per pixel (GGX BRDF) — moved to CPUBackend
Renderer::RenderGPU() method Renderer.cpp:639 GPU render dispatch — moved to CUDABackend
IRenderBackend::Render() virtual IRenderBackend.h:28 Abstract backend render entry point
CUDABackend::Render() method CUDABackend.h:45 GPU backend: upload scene → launch kernel → denoise → output
CPUBackend::Render() method CPUBackend.h:20 CPU backend: ISPC SIMD or C++ PerPixel loop
CUDABackend::UploadSceneToGPU() method CUDABackend.h:59 Host→GPU scene data packing + cudaMemcpy
::PerPixel() device fn CUDARenderer.cuh:238 GPU path trace per pixel (GGX BRDF)
::RenderKernel() kernel CUDARenderer.cuh:374 CUDA raw sample kernel (16×16 blocks)
::PostProcessKernel() kernel CUDARenderer.cuh:399 Accumulate + average + clamp + RGBA conversion
::ConvertToRGBAKernel() kernel CUDARenderer.cuh:452 Post-denoise float4→RGBA8 conversion
::ClearAccumulationKernel() kernel CUDARenderer.cuh:479 Reset accumulation buffer to zero
::DebugFillKernel() kernel CUDARenderer.cuh:495 Checkerboard diagnostic fill
::FresnelSchlick() device fn CUDARenderer.cuh:58 Schlick Fresnel approximation (GPU)
::GGX_D() device fn CUDARenderer.cuh:68 GGX Normal Distribution Function (GPU)
::GGX_G1() / ::GGX_G() device fn CUDARenderer.cuh:75-85 GGX Smith geometry function (GPU)
::SampleGGX_VNDF() device fn CUDARenderer.cuh:88 GGX Visible Normal Distribution sampling (GPU)
::BuildONB() device fn CUDARenderer.cuh:43 Orthonormal basis construction (Duff et al. 2017)
::TraceRay() device fn CUDARenderer.cuh:187 GPU ray-sphere intersection
Renderer::TraceRay() method Renderer.cpp:525 CPU ray-sphere intersection
Material struct Scene.h:7 Albedo + emission + roughness + metallic properties
Sphere struct Scene.h:22 Position, radius, material index
Scene::Version field Scene.h:34 Incremental counter for GPU upload dedup
kPi, kRoughnessMin, etc. constexpr Constants.h:1-13 Shared compile-time constants (pi, 7 epsilon/roughness/threshold values)
GPUPackedMaterial struct CUDARenderer.h:108 Host-side GPU material (must match GPUMaterial)
GPUPackedSphere struct CUDARenderer.h:97 Host-side GPU sphere (must match GPUSphere)
GPUMaterial struct CUDATypes.cuh:27 Device-side material
GPUSphere struct CUDATypes.cuh:16 Device-side sphere
GPUScene struct CUDATypes.cuh:52 Device-side scene descriptor (pointers + counts)
GPUCamera struct CUDATypes.cuh:64 Device-side camera descriptor
GPURenderSettings struct CUDATypes.cuh:77 Device-side render settings
VkCUDAInterop class VkCUDAInterop.h:8 RAII Vulkan-CUDA external memory wrapper
OptiXDenoiser class OptiXDenoiser.h:17 RAII OptiX AI denoiser wrapper
CUDARenderStateDeleter struct CUDARenderer.h:85 RAII custom deleter for unique_ptr<CUDARenderState>
Camera::OnUpdate() method Camera.cpp:18 FPS camera controls
Camera::RecalculateRayDirections() method Camera.cpp:138 Pre-compute ray grid
::ISPCRenderPixels() export PathTracer.ispc:167 ISPC SIMD path tracer entry point
Renderer::Settings::EnableDenoising field Renderer.h:34 ImGui toggle for OptiX denoiser
Renderer::Settings::EnableInterop field Renderer.h:37 ImGui toggle for Vulkan-CUDA interop

CONVENTIONS

Conditional Compilation

  • #ifdef PN_CUDA — gates ALL CUDA code. Defined in xmake.lua when CUDA_PATH is set.
  • #ifdef PN_OPTIX — gates OptiX denoiser code. Defined in xmake.lua when OptiX SDK detected.
  • #ifdef PN_ISPC — gates ISPC SIMD code. Defined in xmake.lua when vendor/ispc/bin/ispc.exe exists.
  • #ifdef PN_DEBUG / PN_RELEASE / PN_DIST — per-configuration defines.
  • #ifndef PN_CUDA — CPU-only path (Renderer.cpp). ISPC path is nested inside this block when PN_ISPC is also defined.

Memory Layout Contracts (CRITICAL)

  • GPUPackedMaterial (host, CUDARenderer.h:108) ↔ GPUMaterial (device, CUDATypes.cuh:27) — 36 bytes, identical layout
  • GPUPackedSphere (host, CUDARenderer.h:97) ↔ GPUSphere (device, CUDATypes.cuh:16) — 20 bytes, identical layout
  • float3 (host, CUDARenderer.h:89) ↔ CUDA float3 — both 12 bytes, 4-byte alignment
  • ANY layout change must update BOTH sides simultaneously.

Scene Data Flow

  • ImGui modifies Scene directly via structured bindings (glm::value_ptr)
  • CPU path reads m_ActiveScene pointer → always gets latest data
  • GPU path: UploadSceneToGPU() called when scene.Version changes → cudaMemcpy host→device
  • GPU realloc only when sphere/material counts change (CUDARenderer.cu:158-219)
  • Scene version tracking: Scene::Version incremented on any ImGui change; m_LastSceneVersion compared to skip uploads

Rendering Pipeline (Multi-Backend)

  1. Renderer::Render orchestrates: stores scene/camera pointers, delegates to m_Backend->Render()
  2. GPU path (CUDABackend): Scene data upload (version-tracked) → camera upload → ray dirs upload (dirty-tracked) → RenderKernelPostProcessKernel → (OptiX denoise) → output (interop zero-copy or D2H)
  3. CPU path (CPUBackend): ISPC SIMD SoA packing → ISPCRenderPixels kernel → unpack + accumulate, or C++ std::execution::par fallback with PerPixel()
  4. Factory CreateBackend() selects GPU if PN_CUDA defined, falls back to CPU
  5. Renderer handles output delivery: checks Backend->OutputDelivered() to decide between interop path (GPU) or SetData path

Emission Integration Order

  • Both CPU and GPU: light += contribution * emission BEFORE BRDF updates contribution
  • Matches path tracing integral: Le · prod(previous BSDFs)
  • With GGX BRDF: contribution updated via (spec + diff) * NdotL / pdf (replaces old contribution *= albedo)

Naming

  • PascalCase for classes/structs, camelCase for methods/members
  • m_ prefix for member variables (m_Camera, m_FrameIndex)
  • k prefix (no underscore) for compile-time constants (kPi, kRoughnessMin, kMultithreaded, kMaxBounces)
  • GPU types prefixed with GPU (GPUSphere, GPUMaterial, GPUScene, GPUHitPayload)
  • Host-side GPU packing structs prefixed with GPUPacked
  • CUDA interop: C API functions prefixed with CUDARenderer_; RAII class VkCUDAInterop

ANTI-PATTERNS

  • Peanut may be modified freely — it is an independent fork (diverged from Walnut), no upstream merge requirement. Changes should prioritize general-purpose improvements (new features, performance, bugfixes) usable by any Peanut application. Avoid RayTracing-specific logic in Peanut; keep domain-specific code in RayTracing/src/.
  • NEVER suppress CUDA errors — always check cudaMalloc/cudaMemcpy/cudaStreamCreate return values
  • NEVER assume scene data is synced to GPU — increment Scene::Version on any scene change
  • NEVER change GPUPacked* struct layout without updating GPUMaterial/GPUSphere in CUDATypes.cuh
  • NEVER use --remote on git submodule update — vendor deps are pinned by Peanut
  • NEVER create/destroy VkCUDAInterop during CUDA kernel execution — set up before render, destroy after sync
  • NEVER call OptiXDenoiser::Denoise before Initialize — check IsValid() first
  • NEVER assume non-interop output path is active — check m_InteropEnabled before using CUDARenderer_GetOutput

UNIQUE STYLES

  • Structured bindings for sphere/material field access: auto& [Position, Radius, MaterialIndex] = spheres[i]
  • Box-drawing comment separators: // --- Section Title ---
  • No sky/environment light — all illumination from emissive materials only
  • m_NeedsRender flag for conditional re-render (ImGui change detection)
  • m_RayDirsDirty flag for lazy camera ray direction re-upload
  • Scene::Version for dirty-tracked GPU scene upload dedup
  • Two-stage GPU pipeline: raw sample → accumulation + post-process (separate kernels on same stream)
  • Dual output path: interop (zero-copy Vulkan buffer) vs legacy D2H copy
  • OptiX denoiser runs after accumulation, before RGBA conversion

COMMANDS

# Generate VS2026 solution + build
scripts\Setup.bat
xmake f -m release
xmake build

# Build (Release)
xmake f -m release && xmake build RayTracing

# Build (Debug)
xmake f -m debug && xmake build RayTracing

# Run
xmake run RayTracing

# VS solution generation (via xmake)
xmake project -k vsxmake -y -m release
dotnet sln vsxmake2026\RayTracing.sln migrate

NOTES

  • Catch2 unit tests (28 cases) — covers GGX BRDF, TraceRay, PCGHash, ConvertToRGBA; CI Debug+Release pass
  • Single light source — only emissive materials illuminate the scene; no env/sky light
  • GPU accumulation — old samples persist in buffer; use Reset button or disable Accumulate for clean re-render after ImGui changes

Build System

  • 100% xmake — all premake5.lua files deleted. Peanut has standalone xmake.lua for independent builds.
  • xrepo packages (feat/xmake-packages branch, PR #11): glm 1.0.3, stb 2026.03.18, glfw 3.4 via add_requires(). ImGui stays as vendor submodule (xrepo lacks docking branch).
  • VS IntelliSense: Directory.Build.props at project root auto-discovered by MSBuild. Contains only GLFW_INCLUDE_NONE and IMGUI_DEFINE_MATH_OPERATORS defines, plus C++23 standard. Include paths delegated to xmake-generated vcxproj XmakeIncludeDirs.
  • set_default(true) on target("RayTracing") sets it as VS startup project in .sln (lost in .slnx migration).

Dependencies

Dep Version Source
ImGui v1.91+ (docking) ocornut/imgui:docking (vendor submodule)
GLFW 3.4 glfw/glfw (vendor submodule on master / xrepo on feat/xmake-packages)
glm 1.0.3 g-truc/glm (vendor submodule on master / xrepo on feat/xmake-packages)
stb_image latest nothings/stb (vendored on master / xrepo on feat/xmake-packages)

Known Quirks

  • glm 1.0.3 requires GLM_ENABLE_EXPERIMENTAL — added before #include <glm/gtx/quaternion.hpp> in Camera.cpp:3.
  • PN_ macros* (formerly WL_*) — PN_CUDA, PN_OPTIX, PN_ISPC, PN_PLATFORM_WINDOWS, PN_DEBUG, PN_RELEASE.
  • CUDA arch fallback — if nvcc fails, check GPU compute capability matches sm_XX in xmake.lua:130-133
  • ISPC arch fallback — if ISPC not found, CPU path falls back to C++ std::execution::par (no SIMD)
  • Peanut submodule — independent fork: https://github.com/Cle2ment/Peanut (diverged from Walnut; freely modifiable for general-purpose improvements)
  • ISPC downloadscripts\Setup.bat auto-downloads to vendor\ispc\; manual: https://github.com/ispc/ispc/releases/tag/v1.30.0
  • OptiX denoiser — requires OptiX SDK 7.0+; detected via OptiX_ROOT or OPTIX_PATH env var
  • Vulkan-CUDA interop — Windows-only (Win32 external memory handles); toggle via ImGui checkbox
  • GGX Microfacet BRDF — replaces Lambertian diffuse on all three paths (CUDA, CPU C++, ISPC SMID)

重构完成概要

短期重构已全部完成(Phase 0-12 + 后续补充 #30-#53),代码库达到质量规范标准。

阶段 内容 PRs
Phase 0 紧急 Bug 修复 (9 bugfixes) #13
Phase 1-3 C++ 现代化 (std::vector, CUDA_CHECK RAII, Peanut 内存) #14, #15
Phase 4-5 CUDA 性能优化 + ISPC 缓存 + MaxBounces #16, #17
Phase 6-7 C-style casts, Constants.h, noexcept #18, #19
Phase 8-9 IRenderBackend 后端抽象, Peanut 静态全局 #22, #21
Phase 10-12 GPU/CPU/ISPC 三后端 BVH 加速, OptiX 修复 #23, #24, #25
后续补充 CUDA 错误检查, ISPC 溢出, Camera constexpr, 大函数拆分等 #30-#53

质量现状

  • 28 Catch2 测试通过 (Debug + Release CI)
  • 三后端一致性: CPU / GPU / ISPC 均使用 GGX VNDF BRDF + BVH 加速
  • GPU 故障自动 CPU 回退 (IRenderBackend)
  • 48 处 C-style casts -> static/reinterpret_cast
  • 0 个 open issue

Shared Constants (Constants.h)

  • kPi = 3.14159265358979323846f — replaces 11 literal occurrences + 3 glm::pi<float>() calls
  • 7 epsilon/roughness/threshold constexpr values
  • Included by: PathTracerCore.h, CUDARenderer.cuh. ISPC path uses local static const float equivalents.

远期方向

详见 docs/superpowers/analysis/2026-06-22-multi-language-feasibility.md

推荐路线(按阶段)

阶段 方向 说明
P0 — 完成 Golden Image 回归测试 ✅ PR #55 — Python (Pillow+scikit-image) + CI 自洽比对
P1 TypeScript 场景 DSL Deno builder API -> .ray.json -> C++ Scene::LoadFromJSON,场景可复现/版本控制
P1 Rust 场景编译器 CLI clap+serde+rayon 接收 .ray.json+glTF,离线 BVH 构建,输出二进制 .rayscene
P1 NEE / MIS 重要性采样 Next Event Estimation + Multiple Importance Sampling,大幅降噪
P1 Glass / Transmission BRDF 玻璃、透明材质折射/透射
P2 glTF 场景加载 标准 glTF 2.0 三角网格+PBR 材质导入
P2 Rust 资产管线 glTF 解析 + BVH 烘焙独立 CLI
P2 Rust 程序化场景生成 noise+rand 生态生成地形/城市/植被散射
P2 CI 迁移 Python / zig cc 实验 跨平台 CI,uv 已接入,Zig 可选验证 C++23 兼容性

Rust 策略

  • 推荐:独立 CLI 工具链(场景编译器、资产管线、BVH 构建库、程序化场景生成)— 零 FFI 耦合
  • 不推荐:替代 CUDA/ISPC/C++ 核心渲染路径、wgpu 渲染后端

不推荐

  • Rust/Zig 替代 CUDA 内核或 ISPC — 现有方案已是最优
  • Rust wgpu 渲染后端 — 需完整重写 GPU 路径
  • Web 预览 / 远程控制 — 与核心目标正交