0202-透明材质的折射

环境

  • Time 2022-11-16
  • WSL-Ubuntu 22.04
  • Rust 1.65.0

前言

说明

参考:https://raytracing.github.io/books/RayTracingInOneWeekend.html

目标

再新增一种材质,实现折射功能。

增加朝向

pub struct HitRecord {
    pub point: Point3,
    pub normal: Vector3,
    pub t: f64,
    pub material: Rc<dyn Material>,
    pub face: bool,
}

设置朝向

fn nearest(&self, ray: &Ray, temp: Temp) -> Option<HitRecord> {
    //  找到最近的点
    let a = ray.direction().dot(ray.direction());

    let mut t = (-temp.b - temp.sqrt) / a;
    if t < temp.min || temp.max < t {
        t = (-temp.b + temp.sqrt) / a;
        if t < temp.min || temp.max < t {
            return None;
        }
    }

    let point = ray.at(t);
    let mut normal = (point - self.center) / self.radius;

    let face = ray.direction().dot(normal) < 0.0;
    if !face {
        normal = (-1.0) * normal
    };
    Some(HitRecord {
        t,
        point,
        normal,
        material: Rc::clone(&self.material),
        face,
    })
}

增加材质

pub struct Dielectric {
    // 折射率
    refraction: f64,
}

impl Dielectric {
    pub fn new(refraction: f64) -> Dielectric {
        Dielectric { refraction }
    }

    // 折射
    fn refract(uv: Vector3, n: Vector3, f: f64) -> Vector3 {
        let cos_theta = ((-1.0) * uv).dot(n).min(1.0);
        let r = f * (uv + cos_theta * n);
        r - (1.0 - r.dot(r)).abs().sqrt() * n
    }
}

impl Material for Dielectric {
    fn scatter(&self, ray: &Ray, record: &HitRecord) -> Option<(Color, Ray)> {
        let ratio = match record.face {
            true => 1.0 / self.refraction,
            false => self.refraction,
        };

        let direction = ray.direction().unit();
        let refracted = Self::refract(direction, record.normal, ratio);
        let scattered = Ray::new(record.point, refracted);

        Some((Color::new(1.0, 1.0, 1.0), scattered))
    }
}

显示

let ground = Rc::new(Lambert::new(Color::new(0.8, 0.8, 0.0)));
let center = Rc::new(Dielectric::new(1.5));
let left = Rc::new(Dielectric::new(1.5));
let right = Rc::new(Metal::new(Color::new(0.8, 0.6, 0.2), 1.0));

let world: World = vec![
    Box::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0, ground)),
    Box::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5, center)),
    Box::new(Sphere::new(Point3::new(-1.0, 0.0, -1.0), 0.5, left)),
    Box::new(Sphere::new(Point3::new(1.0, 0.0, -1.0), 0.5, right)),
];

效果

折射

总结

新增了折射功能。

附录

posted @ 2024-07-22 09:19  波尔  阅读(1)  评论(0编辑  收藏  举报