0%

RayTracing.vol7

Github Repo


抗锯齿

生成随机数

首先,需要实现一个随机数生成器生成 ${0 \le r < 1}$ 的随机实数,Rust 的 std 里没有可以实现 random 的方法,只能去找其他 crate 实现。在[Cargo.toml]写入

[dependencies]
rand = "0.7"

因为 Rust 既不支持函数重载,也不支持默认实参,所以只能定义实参类型为 Option

[rtweekend.rs]
1
2
3
4
5
6
7
8
9
use rand::{thread_rng, Rng};

...

pub fn random_double(min: Option<f32>, max: Option<f32>) -> f32 {
let mut rng = thread_rng();
let n: f32 = rng.gen_range(min.unwrap_or(0.0), min.unwrap_or(1.0));
n
}

使用多个样本生成像素

对于给定的像素,在该像素内设置几个样本点,发送射线穿过各个样本点。然后平均这些射线的颜色。

创建一个Camera类对虚拟摄像机和与之相关的场景采样进行管理,以下是相机的简单实现

[camera.rs]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use crate::rayh::*;
use ray::*;

pub struct Camera {
pub origin: Point3,
pub lower_left_corner: Point3,
pub horizontal: Vec3,
pub vertical: Vec3,
}

impl Camera {
pub fn new() -> Camera {
let aspect_ratio = 16.0 / 9.0;
let viewport_height = 2.0;
let viewport_width = aspect_ratio * viewport_height;
let focal_length = 1.0;
Camera {
origin: Vec3(0.0, 0.0, 0.0),
horizontal: Vec3(viewport_width, 0.0, 0.0),
vertical: Vec3(0.0, viewport_height, 0.0),
lower_left_corner: Vec3(0.0, 0.0, 0.0)
- Vec3(viewport_width, 0.0, 0.0) / 2.0
- Vec3(0.0, viewport_height, 0.0) / 2.0
- Vec3(0.0, 0.0, focal_length),
}
}

pub fn get_ray(&self, u: f32, v: f32) -> Ray {
Ray {
orig: self.origin,
dir: self.lower_left_corner + u * self.horizontal + v * self.vertical - self.origin,
}
}
}

rtweekend.h中添加clamp(x,min,max)使得输出值在[min,max]范围内

[rtweekend.rs]
1
2
3
4
5
6
7
8
9
10
...

pub fn clamp(x: f32, min: f32, max: f32) -> f32 {
if x < min {
return min;
}
if x > max {
return max;
}
x

重写color.rs内的write_color()以及main.rs中的main()

[color.rs]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use crate::rtweekend::*;
use ray::Color;

pub fn write_color(pixel_color: Color, samples_per_pixel: u16) -> String {
let mut r = pixel_color.x();
let mut g = pixel_color.y();
let mut b = pixel_color.z();

let scale = 1.0 / samples_per_pixel as f32;
r *= scale;
g *= scale;
b *= scale;
unsafe {
format!(
"{} {} {}\n",
(256.0 * clamp(r, 0.0, 0.999)).to_int_unchecked::<u16>(),
(256.0 * clamp(g, 0.0, 0.999)).to_int_unchecked::<u16>(),
(256.0 * clamp(b, 0.0, 0.999)).to_int_unchecked::<u16>(),
)
}
}

[main.rs]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
mod camera;
use camera::*;

...

fn main() {
let IMAGE_HEIGHT = unsafe { (IMAGE_WIDTH as f32 / ASPECT_RATIO).to_int_unchecked::<u16>() };

let mut world = Hittable_list {
objects: Vec::new(),
};
world.add(Sphere {
center: Vec3(0.0, 0.0, -1.0),
radius: 0.5,
});
world.add(Sphere {
center: Vec3(0.0, -100.5, -1.0),
radius: 100.0,
});

let cam = Camera::new();

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 mut pixel_color = Vec3(0.0, 0.0, 0.0);
for s in 0..SAMPLES_PER_PIXEL {
let u = (i as f32 + random_double(None, None)) / (IMAGE_WIDTH - 1) as f32;
let v = (j as f32 + random_double(None, None)) / (IMAGE_HEIGHT - 1) as f32;
let r = cam.get_ray(u, v);
pixel_color += ray_color(&r, &world);
}
print!("{}", write_color(pixel_color, SAMPLES_PER_PIXEL));
}
}
eprintln!("\nDone");
}

运行过后的效果图