Rust 实现2d raytracing

Rust light2d

简介

light2d-rs 是一个基于 Rust 的 2D 光照模拟项目,在叶老师的light2d教程基础上使用Rust语言进行重构。添加了并行渲染。它实现了光线追踪(raytracing)技术来生成高质量的光照效果。本教程将带你了解如何在这个项目中实现 raytracing。

项目结构回顾

.
├── src
│   ├── color.rs       # 颜色类型定义
│   ├── lib.rs         # 核心渲染逻辑
│   ├── main.rs        # 程序入口和命令行参数处理
│   ├── render_config.rs # 渲染配置管理
│   ├── sdf.rs         # Signed Distance Field (SDF) 计算
│   └── vec2.rs        # 二维向量类型定义
└── Cargo.toml       # 项目配置

步骤 1: 理解数学基础

在实现 raytracing 之前,我们需要理解一些基本的数学概念:

Vec2 结构体

查看 vec2.rs 文件,我们定义了一个二维向量结构体,它支持基本的数学运算,如加法、减法、点积和长度计算。

// 示例代码结构(实际代码请查看 vec2.rs 文件)
#[derive(Clone, Copy)]
struct Vec2 {
    x: f64,
    y: f64,
}

impl Vec2 {
    fn new(x: f64, y: f64) -> Self {
        Self { x, y }
    }
    
    fn length(&self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
    
    fn dot(&self, other: &Self) -> f64 {
        self.x * other.x + self.y * other.y
    }
}

步骤 2: 理解 SDF(Signed Distance Field)

SDF 是 raytracing 的核心概念之一。它定义了一个函数,该函数对于空间中的每个点,返回该点到最近物体表面的距离。

查看 sdf.rs 文件,我们可以看到多种几何形状的 SDF 实现:

// 圆形的 SDF
circle_sdf(center: Vec2, point: Vec2, radius: f64) -> f64

// 平面的 SDF
plane_sdf(o: Vec2, p: Vec2, normal: Vec2) -> f64

// 盒子形状的 SDF
box_sdf(o: Vec2, c: Vec2, theta: f64, s: Vec2) -> f64

这些函数用于定义场景中的物体几何形状。

步骤 3: 理解渲染流程

lib.rs 文件中,我们实现了核心的渲染逻辑。

pub fn render(config: &RenderConfig) {
    // 创建图像缓冲区
    let mut img = ImageBuffer::new(config.width, config.height);

    // 并行处理每个像素
    img.par_enumerate_pixels_mut().for_each(|(x, y, pixel)| {
        // 计算归一化坐标
        let u = x as f64 / config.width as f64;
        let v = y as f64 / config.height as f64;
        
        // 执行光线追踪采样
        let color = sample(Vec2::new(u, v), config.sample_count);
        
        // 将颜色值转换为 8 位整数
        let r = (color.r.min(1.0) * 255.0) as u8;
        let g = (color.g.min(1.0) * 255.0) as u8;
        let b = (color.b.min(1.0) * 255.0) as u8;
        *pixel = image::Rgb([r, g, b]);
    });

    // 保存图像文件
    img.save(&filename).unwrap();
}

步骤 4: 实现光线追踪核心算法

sdf.rs 文件中,我们找到了 sample 函数,它是 raytracing 的核心实现。

// 光线追踪采样函数
pub fn sample(ray_origin: Vec2, sample_count: usize) -> Color {
    // 实现光线追踪算法
}

算法具体的实现细节以及讲解请参照叶老师的教程,这里不再赘述。大体上整个sample函数会执行以下步骤:

  1. 从给定的起点发射光线
  2. 跟踪光线与场景中物体的交点
  3. 计算光照效果(包括reflect、 refract、 fresnel、schlick、beerlambert等)
  4. 返回最终的颜色值

步骤 5: 配置和运行

使用 render_config.rs 文件中定义的配置,我们可以控制渲染参数:

#[derive(Clone)]
pub struct RenderConfig {
    pub output_name: String,     // 输出文件名
    pub sample_count: usize,     // 每像素采样数
    pub width: u32,              // 输出宽度
    pub height: u32,             // 输出高度
}

你可以通过命令行参数来调整这些设置,如:

cargo run -- --width 1024 --height 768 --samples 2048 output_filename

结论

通过这个教程,你已经了解了 light2d-rs 项目中 raytracing 的实现流程。该项目展示了如何将光线追踪技术应用于 2D 光照模拟,并利用 Rust 的性能优势和并行计算能力来加速渲染过程。

要深入理解完整的 raytracing 实现,建议你:

  1. 查看 sdf.rs 文件中的完整 sample 函数实现
  2. 探索项目中与光线追踪相关的其他辅助函数
  3. 尝试修改场景配置,观察不同设置对渲染效果的影响
  4. 实验不同的 SDF 函数组合,创建新的光照场景

效果展示

output_N1024_beerlambert_20250303004511

参考 & 引用

  1. light2d
posted @ 2025-07-19 12:27  trickyrat  阅读(13)  评论(0)    收藏  举报