0%

RayTracing.vol1

  前一阵子因为兴趣看了看 Rust 的教程,感觉上手不容易,即使做完了 rustlings 里所有的练习仍感觉云里雾里。偶然在某网站上看到有人推荐这个网站,学习其内容的同时对其中的 C++ 代码使用 Rust 进行重构。


Github Repo


首先,关于作者使用的图片文件格式 ppm

A PPM file consists of two parts, a header and the image data. The header consists of at least three parts normally delineated by carriage returns and/or linefeeds but the PPM specification only requires white space. The first “line” is a magic PPM identifier, it can be “P3” or “P6” . The next line consists of the width and height of the image as ASCII numbers. The last part of the header gives the maximum value of the colour components for the pixels, this allows the format to describe more than single byte (0..255) colour values.


作者在网页中的举例
ppm文件示例
ppm 在线浏览网址
从生成 ppm 图片文件开始,首先 cargo new ray 新建一个名为 ray 的 cargo

[main.rs] 生成一个 ppm 图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const IMAGE_WIDTH: u16 = 256;
const IMAGE_HEIGHT: u16 = 256;

fn main() {
println! {"P3\n{} {}\n255",IMAGE_WIDTH,IMAGE_HEIGHT};
for j in (0..IMAGE_HEIGHT).rev() {
eprintln!("\rScanlines remaining:{}", j);
//用于将当前进度输出到标准错误中
for i in (0..IMAGE_WIDTH) {
let r = i as f32 / (IMAGE_WIDTH - 1) as f32;
let g = j as f32 / (IMAGE_HEIGHT - 1) as f32;
let b = 0.25 as f32;
let ir = unsafe { (255.999 * r).to_int_unchecked::<u16>() };
let ig = unsafe { (255.999 * g).to_int_unchecked::<u16>() };
let ib = unsafe { (255.999 * b).to_int_unchecked::<u16>() };
println!("{} {} {}", ir, ig, ib);
//将RGB值输入标准输出中
}
}
eprintln!("\nDone");
}

pub unsafe fn to_int_unchecked<Int>(self) -> Int 是 Rust 1.44.0 的新方法,本机原本装的是 Rust 1.42 ,使用 rustup 对Rust 升级无果,发现是包管理器的锅,当初用的 apt install rustc,而 Ubuntu 的 rustc 最新版只有 1.42,卸载后在官网重新下载安装了最新版的 Rust.
运行上面这段代码 cargo run > first.ppm,标准输出会写入 first.ppm,标准错误会显示在屏幕上,生成的是一个256×256的图片,从第 4 行开始,到第 65539 行结束,每 256 行视为图片的一行
输出效果图


定义一个三维向量结构体Vec3来表示方向、色彩,它有两个 type-alias : Point3,Color(Rust 建议 identifier 首字母大写,以及 can't use a type alias as a constructor)(注:接下来的代码是一大段的关于 Vec3 的运算符方法定义,我原本的想法是使用引用 & 来避免运算中 ownership 的转移,但是这样会导致 &(&(&origin - &(&horizontal / 2 as f32)) - &(&vertical / 2 as f32))- &Vec3(0.0, 0.0, focal_length) 或是 &(&(&lower_left_corner + &(u * &horizontal)) + &(v * &vertical)) - &origin这样可读性与美观都十分差的代码,向其他人询问后发现,可以通过在 Vec3 定义时,在 pub struct Vec3(pub f32, pub f32, pub f32); 上一行插入 #[derive(Debug, PartialEq, Clone, Copy)] 在 Vec3 类调用时进行 Copy 从而不转移 ownership,这意味着我需要重构一遍接下来所有的代码)