~ttt/ray_tracing_in_one_weekend

86e0896bc5b886336361de3e5a41ccb8e8652b94 — Tomasz Kłak 3 years ago d047353
ch 9 done
5 files changed, 125 insertions(+), 8 deletions(-)

M src/hittable.rs
M src/main.rs
A src/material.rs
M src/sphere.rs
M src/vec3.rs
M src/hittable.rs => src/hittable.rs +3 -1
@@ 1,10 1,12 @@
use crate::ray::*;
use crate::vec3::*;
use crate::MaterialPtr;

#[derive(Debug, Clone, Copy, Default)]
#[derive(Debug, Clone)]
pub struct HitRecord {
    pub p: Point3,
    pub normal: Vec3,
    pub mat_ptr: MaterialPtr,
    pub t: f64,
    pub front_face: bool,
}

M src/main.rs => src/main.rs +33 -4
@@ 21,6 21,9 @@ use rtweekend::*;
mod camera;
use camera::*;

mod material;
use material::*;

fn hit_sphere(center: &Point3, radius: f64, r: &Ray) -> f64 {
    let oc = r.origin() - *center;
    let a = r.direction().length_squared();


@@ 41,8 44,10 @@ fn ray_color(r: &Ray, world: &dyn Hittable, depth: isize) -> Color {
        return Color::default();
    }
    if let Some(rec) = world.hit(r, 0.001, INFINITY) {
        let target = rec.p + rec.normal + random_unit_vector();
        return 0.5 * ray_color(&Ray::new(&rec.p, &(target - rec.p)), world, depth - 1);
        if let Some((attenuation, scattered)) = rec.mat_ptr.scatter(&r, &rec) {
            return attenuation * ray_color(&scattered, world, depth - 1);
        }
        return Color::default();
    }
    let unit_direction = unit_vector(r.direction());
    let t = 0.5 * (unit_direction.y() + 1.0);


@@ 56,6 61,7 @@ fn main() {
    // Image
    let aspect_ratio = 16.0 / 9.0;
    let image_width = 400;
    // let image_width = 1000;
    let image_width = 1600;
    let image_height = (image_width as f64 / aspect_ratio) as i32;
    let samples_per_pixel = 100;


@@ 63,8 69,31 @@ fn main() {

    // World
    let mut world = HittableList::empty();
    world.add(Arc::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)));
    world.add(Arc::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)));
    let material_ground: MaterialPtr = Arc::new(Lambertian::new(Color::new(0.8, 0.8, 0.0)));
    let material_center: MaterialPtr = Arc::new(Lambertian::new(Color::new(0.7, 0.3, 0.3)));
    let material_left: MaterialPtr = Arc::new(Metal::new(Color::new(0.8, 0.8, 0.8), 0.3));
    let material_right: MaterialPtr = Arc::new(Metal::new(Color::new(0.8, 0.6, 0.2), 1.0));

    world.add(Arc::new(Sphere::new(
        Point3::new(0.0, -100.5, -1.0),
        100.0,
        material_ground,
    )));
    world.add(Arc::new(Sphere::new(
        Point3::new(0.0, 0.0, -1.0),
        0.5,
        material_center,
    )));
    world.add(Arc::new(Sphere::new(
        Point3::new(-1.0, 0.0, -1.0),
        0.5,
        material_left,
    )));
    world.add(Arc::new(Sphere::new(
        Point3::new(1.0, 0.0, -1.0),
        0.5,
        material_right,
    )));

    // Camera
    let cam = Camera::new();

A src/material.rs => src/material.rs +62 -0
@@ 0,0 1,62 @@
use crate::{
    dot, random_in_unit_sphere, random_unit_vector, reflect, unit_vector, Color, HitRecord, Ray,
};
use std::fmt::Debug;

pub trait Material: Debug {
    fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> Option<(Color, Ray)>;
}

pub type MaterialPtr = std::sync::Arc<dyn Material>;

#[derive(Debug)]
pub struct Lambertian {
    albedo: Color,
}

impl Lambertian {
    pub fn new(albedo: Color) -> Self {
        Self { albedo }
    }
}

impl Material for Lambertian {
    fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> Option<(Color, Ray)> {
        let mut scatter_direction = rec.normal + random_unit_vector();
        // Catch degenerate scatter direction
        if scatter_direction.near_zero() {
            scatter_direction = rec.normal;
        }
        let scattered = Ray::new(&rec.p, &scatter_direction);
        let attenuation = self.albedo;
        Some((attenuation, scattered))
    }
}

#[derive(Debug)]
pub struct Metal {
    albedo: Color,
    fuzz: f64,
}

impl Metal {
    pub fn new(albedo: Color, fuzz: f64) -> Self {
        Self {
            albedo,
            fuzz: if fuzz < 1.0 { fuzz } else { 1.0 },
        }
    }
}

impl Material for Metal {
    fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> Option<(Color, Ray)> {
        let reflected = reflect(&unit_vector(r_in.direction()), &rec.normal);
        let scattered = Ray::new(&rec.p, &(reflected + self.fuzz * random_in_unit_sphere()));
        let attenuation = self.albedo;
        if dot(&scattered.direction(), &rec.normal) > 0.0 {
            Some((attenuation, scattered))
        } else {
            None
        }
    }
}

M src/sphere.rs => src/sphere.rs +11 -3
@@ 1,16 1,22 @@
use crate::hittable::*;
use crate::ray::*;
use crate::vec3::*;
use crate::MaterialPtr;

#[derive(Debug, Clone, Copy, Default)]
#[derive(Debug, Clone)]
pub struct Sphere {
    center: Point3,
    radius: f64,
    mat_ptr: MaterialPtr,
}

impl Sphere {
    pub fn new(center: Point3, radius: f64) -> Self {
        Self { center, radius }
    pub fn new(center: Point3, radius: f64, mat_ptr: MaterialPtr) -> Self {
        Self {
            center,
            radius,
            mat_ptr,
        }
    }
}



@@ 34,6 40,7 @@ impl Hittable for Sphere {
                    p,
                    normal: (p - self.center) / self.radius,
                    front_face: false,
                    mat_ptr: self.mat_ptr.clone(),
                };
                let outward_normal = (rec.p - self.center) / self.radius;
                rec.set_face_normal(r, &outward_normal);


@@ 49,6 56,7 @@ impl Hittable for Sphere {
                    p,
                    normal: (p - self.center) / self.radius,
                    front_face: false,
                    mat_ptr: self.mat_ptr.clone(),
                };
                let outward_normal = (rec.p - self.center) / self.radius;
                rec.set_face_normal(r, &outward_normal);

M src/vec3.rs => src/vec3.rs +16 -0
@@ 43,6 43,11 @@ impl Vec3 {
            random_double_range(r.clone()),
        )
    }

    pub fn near_zero(&self) -> bool {
        const S: f64 = 1e-8;
        ((self.e[0]).abs() < S) && ((self.e[1]).abs() < S) && ((self.e[2]).abs() < S)
    }
}

impl std::ops::Neg for &Vec3 {


@@ 130,6 135,13 @@ impl std::ops::Mul<Vec3> for f64 {
    }
}

impl std::ops::Mul<&Vec3> for f64 {
    type Output = Vec3;
    fn mul(self, rhs: &Vec3) -> Vec3 {
        *rhs * self
    }
}

impl std::ops::MulAssign<f64> for Vec3 {
    fn mul_assign(&mut self, rhs: f64) {
        self.e[0] *= rhs;


@@ 212,3 224,7 @@ pub fn random_in_unit_sphere() -> Vec3 {
pub fn random_unit_vector() -> Vec3 {
    unit_vector(random_in_unit_sphere())
}

pub fn reflect(v: &Vec3, n: &Vec3) -> Vec3 {
    *v - 2.0 * dot(v, n) * n
}