一个纯 CUDA 实现的光线追踪器,支持 Phong 光照和路径追踪。不依赖任何图形 API(OpenGL/Vulkan),完全使用 CUDA 计算光线与物体的交点。
- 几何体: 球体、平面
- 光照模型: Phong 光照(环境光 + 漫反射 + 镜面反射)
- 路径追踪: 蒙特卡洛全局光照
- 加速结构: BVH(层次包围盒)
- Warp Divergence 优化: 光线排序、BVH 栈式遍历
- 材质: 漫反射、塑料、金属、镜面
- 色调映射: Reinhard、ACES
- 输出: PPM 图像格式
- CUDA Toolkit 11.0+ (推荐 12.0+)
- CMake 3.18+
- C++17 编译器 (GCC 9+, Clang 10+, MSVC 2019+)
- NVIDIA GPU (Compute Capability 7.5+)
# 克隆项目
git clone <repository-url>
cd cuda-ray-tracer
# 构建
mkdir build && cd build
cmake ..
make -j$(nproc)# 基本渲染(Phong 光照)
./bin/ray_tracer
# 高分辨率 + 多采样
./bin/ray_tracer -w 1920 -h 1080 -s 16
# 路径追踪模式
./bin/ray_tracer -p -s 100
# 选择场景
./bin/ray_tracer --scene cornell
./bin/ray_tracer --scene random -p -s 50
# 自定义输出
./bin/ray_tracer -o my_render.ppm| 参数 | 说明 | 默认值 |
|---|---|---|
-w <width> |
图像宽度 | 800 |
-h <height> |
图像高度 | 600 |
-s <samples> |
每像素采样数 | 1 |
-d <depth> |
最大光线深度 | 5 |
-p |
启用路径追踪 | 关闭 |
-o <file> |
输出文件名 | output.ppm |
--scene <name> |
场景名称 | demo |
--sort |
启用光线排序(仅 Phong + 单采样) | 关闭 |
demo- 默认演示场景,多个彩色球体和地面cornell- Cornell Box 经典场景random- 随机球体场景(类似 Ray Tracing in One Weekend 封面)
cuda-ray-tracer/
├── include/ # 头文件
│ ├── vec3.cuh # 3D 向量数学库
│ ├── ray.cuh # 光线结构
│ ├── camera.cuh # 相机系统
│ ├── geometry.cuh # 几何体(球体、平面)
│ ├── hit_record.cuh # 命中记录
│ ├── material.cuh # 材质定义
│ ├── texture.cuh # 纹理支持
│ ├── light.cuh # 点光源
│ ├── phong.cuh # Phong 光照模型
│ ├── scene.cuh # 场景管理和 GPU 内存
│ ├── aabb.cuh # 轴对齐包围盒
│ ├── bvh.cuh # BVH 加速结构
│ ├── ray_sort.cuh # 光线排序(Warp 优化)
│ ├── random.cuh # GPU 随机数生成
│ ├── kernels.cuh # CUDA 渲染核心
│ ├── renderer.cuh # 渲染器封装
│ ├── render_config.cuh # 渲染配置
│ ├── image.cuh # 色调映射和图像输出
│ └── cuda_utils.cuh # CUDA 错误检查宏
├── src/
│ ├── main.cu # 主程序入口
│ └── scenes.cuh # 预设场景定义
├── tests/
│ ├── unit/ # 单元测试 (58 个)
│ │ ├── test_vec3.cu
│ │ ├── test_ray.cu
│ │ ├── test_camera.cu
│ │ ├── test_geometry.cu
│ │ ├── test_material.cu
│ │ ├── test_aabb.cu
│ │ └── test_phong.cu
│ └── property/ # 属性测试 (59 个)
│ ├── test_vec3_props.cu
│ ├── test_ray_props.cu
│ ├── test_geometry_props.cu
│ ├── test_phong_props.cu
│ ├── test_bvh_props.cu
│ ├── test_scene_props.cu
│ ├── test_ray_sort_props.cu
│ ├── test_sampling_props.cu
│ └── test_image_props.cu
├── .kiro/specs/ # 设计规范文档
│ └── cuda-ray-tracer/
│ ├── requirements.md # 需求文档
│ ├── design.md # 设计文档
│ └── tasks.md # 实现任务
├── CMakeLists.txt # CMake 构建配置
└── README.md # 本文档
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 光线生成 │ -> │ BVH 遍历 │ -> │ 着色计算 │ -> │ 图像输出 │
│ Kernel │ │ 相交测试 │ │ Phong/PT │ │ 色调映射 │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
- Camera - 相机系统,支持视场角和宽高比配置
- Geometry - 几何体相交测试(球体、平面)
- BVH - 层次包围盒加速结构,O(log n) 相交查询
- Phong - Blinn-Phong 光照模型
- Scene - 场景管理,处理 CPU/GPU 内存传输
- Renderer - 渲染器,协调所有组件
// 场景构建(CPU 端)
SceneBuilder builder;
builder.add_material(Material::plastic(vec3(1, 0, 0)));
builder.add_sphere(vec3(0, 0, -1), 0.5f, 0);
builder.add_light(vec3(0, 5, 0), vec3(1, 1, 1), 1.0f);
// 构建并传输到 GPU
Scene scene = builder.build(); // 自动分配 GPU 内存
// 渲染完成后释放
free_scene(scene); // 释放 GPU 内存光线追踪中,同一 Warp(32 线程)内的光线可能击中不同物体,导致执行路径分歧。本项目通过以下方式优化:
BVH 加速结构
- 使用中点分割构建 BVH
- 栈式遍历避免递归,使用固定大小栈(最大深度 64)
- 早期剔除:先测试包围盒,再测试几何体
光线排序
- 按命中物体 ID 排序光线
- 使相邻线程处理相似光线
- 当前实现使用奇偶转置排序,便于演示(可替换为 Thrust sort_by_key)
// 光线排序示例
struct RaySortKey {
int object_id; // 命中物体 ID
int pixel_index; // 原始像素索引
};
// 排序后,相同 object_id 的光线连续存储实现完整的 Blinn-Phong 光照:
// 环境光
vec3 ambient = mat.ambient * mat.albedo * light_color;
// 漫反射(Lambertian)
float diff = max(dot(normal, light_dir), 0.0f);
vec3 diffuse = mat.diffuse * diff * mat.albedo * light_color;
// 镜面反射(Blinn-Phong)
vec3 halfway = normalize(light_dir + view_dir);
float spec = pow(max(dot(normal, halfway), 0.0f), mat.shininess);
vec3 specular = mat.specular * spec * light_color;蒙特卡洛路径追踪实现全局光照:
- 俄罗斯轮盘赌终止
- 余弦加权半球采样
- 多采样抗锯齿(MSAA)
- 渐进式渲染
支持两种色调映射算法:
// Reinhard 色调映射
vec3 reinhard = color / (color + vec3(1.0f));
// ACES 电影色调映射
vec3 aces = (color * (2.51f * color + 0.03f)) /
(color * (2.43f * color + 0.59f) + 0.14f);项目包含完整的测试套件:
cd build
# 运行单元测试(58 个)
./unit_tests
# 运行属性测试(59 个)
./property_tests
# 运行所有测试
ctest --output-on-failure| 属性 | 描述 | 验证需求 |
|---|---|---|
| Property 1 | 光线生成正确性 | 1.1, 1.4 |
| Property 2 | 球体相交点验证 | 2.1 |
| Property 3 | 平面相交点验证 | 2.2 |
| Property 4 | 法向量方向一致性 | 2.5 |
| Property 5 | Phong 漫反射计算 | 3.2 |
| Property 6 | Phong 镜面反射计算 | 3.3 |
| Property 7 | 多光源叠加线性性 | 3.6 |
| Property 8 | 路径追踪采样平均 | 4.5 |
| Property 9 | 光线排序连续性 | 5.1 |
| Property 10 | BVH 包围盒包含性 | 5.2, 5.3 |
| Property 11 | BVH 相交等价性 | 5.2 |
| Property 12 | 色调映射范围约束 | 6.4 |
| Property 13 | 场景物体计数一致性 | 7.2, 7.3 |
| Property 14 | 向量运算不变量 | 1.4 |
| Property 15 | 反射向量对称性 | 3.3 |
在 NVIDIA GeForce RTX 3060 Laptop GPU 上的测试结果:
| 模式 | 分辨率 | 采样数 | 光线数/秒 |
|---|---|---|---|
| Phong | 800x600 | 1 | ~1200 M |
| Phong | 640x480 | 8 | ~2900 M |
| Path Tracing | 640x480 | 16 | ~295 M |
- 增加采样数 - 路径追踪需要更多采样减少噪点
- 调整光线深度 - 深度越大,间接光照越准确,但更慢
- 使用 BVH - 场景物体越多,BVH 加速效果越明显
- 批量渲染 - 高分辨率时,GPU 利用率更高
vec3 v(1.0f, 2.0f, 3.0f);
float len = v.length();
vec3 n = v.normalized();
float d = dot(v1, v2);
vec3 c = cross(v1, v2);
vec3 r = reflect(incident, normal);Camera camera;
camera.setup(
vec3(0, 1, 3), // lookfrom
vec3(0, 0, 0), // lookat
vec3(0, 1, 0), // vup
60.0f, // vfov (度)
16.0f / 9.0f // aspect_ratio
);
Ray ray = camera.get_ray(u, v); // u, v ∈ [0, 1]// 预设材质
Material mat = Material::matte(vec3(0.8f, 0.2f, 0.2f));
Material mat = Material::plastic(vec3(0.2f, 0.8f, 0.2f));
Material mat = Material::metal(vec3(0.8f, 0.8f, 0.8f));
Material mat = Material::mirror();
// 自定义材质
Material mat(
albedo, // 基础颜色
ambient, // 环境光系数
diffuse, // 漫反射系数
specular, // 镜面反射系数
shininess, // 光泽度
reflectivity // 反射率
);SceneBuilder builder;
// 添加材质(返回材质 ID)
int mat_id = builder.add_material(Material::plastic(vec3(1, 0, 0)));
// 添加几何体
builder.add_sphere(center, radius, mat_id);
builder.add_plane(normal, distance, mat_id);
// 添加光源
builder.add_light(position, color, intensity);
// 构建场景(传输到 GPU)
Scene scene = builder.build();
// 清理
free_scene(scene);- 在
geometry.cuh中定义结构和相交函数 - 在
aabb.cuh中添加包围盒计算 - 在
bvh.cuh中更新 BVH 构建 - 在
scene.cuh中添加场景支持 - 添加对应的测试
- 在
material.cuh中扩展 Material 结构 - 在
phong.cuh中更新着色计算 - 在
kernels.cuh中更新渲染核心
MIT License
本项目参考了 Peter Shirley 的 "Ray Tracing in One Weekend" 系列教程,并使用 CUDA 进行了 GPU 加速实现。