🦀

RustでRayTracing (チャプター3、4)

2021/01/10に公開

はじめに

Ray Tracing in One Weekend
をRustで実装していく過程を記録しています。
どなたかの参考になれば。

チャプター3

記事ではVec3を定義して、CGに必要な関数も定義してたけど、rustにはcgmathがあるので、それを使って実装しました。

use cgmath::prelude::*;
use cgmath::{Vector3, vec3};

fn pixel_color(r: f32, g: f32, b: f32) -> Vector3<i32>
{
    const scale: f32 = 255.99;

    return vec3((scale * r) as i32, (scale * g) as i32, (scale * b) as i32)
}

fn main() {

    const image_width: u32 = 256;
    const image_height: u32 = 256;

    println!("P3\n {} {} \n255", image_width, image_height);

    for j in (0..image_height).rev() {
        for i in 0..image_width {
            let rbg = pixel_color(i as f32/(image_width - 1) as f32, j as f32/(image_height - 1) as f32, 0.25f32);
            println!("{} {} {}", rbg.x, rbg.y, rbg.z);
        }
    }
}

前に実装した関数で返り値がタプルだったところが、Vector3となって、コードが見やすくなりました。

チャプター4

lerpのところをcgmathの関数で書き直したぐらいです。
やはり画像が出てくるとモチベがあがりますね。

use std::fmt;
use cgmath::prelude::*;
use cgmath::{Vector3, vec3};

struct Ray {
    pub origin: Vector3<f32>,
    pub direction: Vector3<f32>
}

impl Ray {
    pub fn new(o:Vector3<f32>, d:Vector3<f32>) -> Self {
        Ray{origin: o, direction: d}
    }

    pub fn at(&self, t: f32) -> Vector3<f32> {
        self.origin + self.direction * t
    }
}

impl fmt::Debug for Ray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({:?}, {:?})", self.origin, self.direction)
    }
}

fn to_color(v: Vector3<f32>) -> Vector3<i32>
{
    const scale: f32 = 255.99;
    return vec3((scale * v.x) as i32, (scale * v.y) as i32, (scale * v.z) as i32)
}

fn ray_color(ray: &Ray) -> Vector3<i32>
{
    const white: Vector3<f32> = vec3(1.0, 1.0, 1.0);
    const blue: Vector3<f32> = vec3(0.5, 0.7, 1.0);

    let unit_direction = &ray.direction.normalize();
    let t = 0.5 * (unit_direction.y + 1.0);
    let rgb = white.lerp(blue, t);

    return to_color(rgb);
}


fn main() {

    // Image

    const aspect_ratio: f32 = 16.0 / 9.0;
    const image_width: i32 = 400;
    const image_height: i32 = (image_width as f32 / aspect_ratio) as i32;

    // Camera

    let viewport_height: f32 = 2.0;
    let viewport_width = aspect_ratio * viewport_height;
    let focal_length = 1.0;

    let origin: Vector3<f32> = Vector3::zero();
    let horizontal: Vector3<f32> = vec3(viewport_width, 0.0, 0.0);
    let vertical: Vector3<f32> = vec3(0.0, viewport_height, 0.0);
    let lower_left_corner = origin - horizontal / 2.0 - vertical / 2.0 - vec3(0.0, 0.0, focal_length);

    // Render

    println!("P3\n {} {} \n255", image_width, image_height);

    for j in (0..image_height).rev() {
        for i in 0..image_width {
            let u = i as f32/(image_width - 1) as f32;
            let v = j as f32/(image_height - 1) as f32;
            let r = Ray::new(origin, lower_left_corner + u * horizontal + v * vertical - origin);
            let pixel_color= ray_color(&r);
            println!("{} {} {}", pixel_color.x, pixel_color.y, pixel_color.z);

        }
    }
}

Discussion