2022-06-08 18:28:45 +02:00
|
|
|
use super::{
|
|
|
|
Ray,
|
|
|
|
HitRecord,
|
|
|
|
Color,
|
|
|
|
Vec3,
|
2022-06-08 19:53:37 +02:00
|
|
|
utility,
|
2022-06-08 18:28:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
pub struct Lambertian {
|
|
|
|
albedo: Color,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Metal {
|
|
|
|
albedo: Color,
|
2022-06-21 18:10:52 +02:00
|
|
|
fuzz: f64,
|
2022-06-08 18:28:45 +02:00
|
|
|
}
|
|
|
|
|
2022-06-08 19:53:37 +02:00
|
|
|
pub struct Mirror {
|
|
|
|
albedo: Color,
|
|
|
|
}
|
|
|
|
|
2022-06-21 18:10:52 +02:00
|
|
|
pub struct Dielectric {
|
|
|
|
ir: f64,
|
|
|
|
}
|
|
|
|
|
2022-06-08 19:53:37 +02:00
|
|
|
|
2022-06-08 18:28:45 +02:00
|
|
|
pub trait Material: Sync + Send {
|
|
|
|
fn scatter(&self,r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Lambertian {
|
|
|
|
pub fn new(a: &Color) -> Self {
|
|
|
|
Lambertian {
|
|
|
|
albedo: a.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Material for Lambertian {
|
|
|
|
fn scatter(&self, _r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
|
|
|
let mut scatter_direction = rec.normal + Vec3::random_unit_vector();
|
|
|
|
|
|
|
|
if scatter_direction.near_zero() {
|
|
|
|
scatter_direction = rec.normal;
|
|
|
|
}
|
|
|
|
|
|
|
|
*scattered = Ray::new(rec.p, scatter_direction);
|
|
|
|
*attenuation = self.albedo.clone();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Metal {
|
2022-06-21 18:10:52 +02:00
|
|
|
pub fn new(a: &Color, f: f64) -> Self {
|
2022-06-08 18:28:45 +02:00
|
|
|
Metal {
|
|
|
|
albedo: *a,
|
2022-06-21 18:10:52 +02:00
|
|
|
fuzz: f,
|
2022-06-08 18:28:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Material for Metal {
|
|
|
|
fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
|
|
|
let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal);
|
|
|
|
|
2022-06-21 18:10:52 +02:00
|
|
|
*scattered = Ray::new(rec.p, reflected + self.fuzz*Vec3::random_in_unit_sphere());
|
2022-06-08 18:28:45 +02:00
|
|
|
*attenuation = self.albedo.clone();
|
|
|
|
|
|
|
|
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
|
|
|
|
}
|
2022-06-08 19:53:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Mirror {
|
|
|
|
pub fn new(a: &Color) -> Self {
|
|
|
|
Mirror {
|
|
|
|
albedo: *a,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Material for Mirror {
|
|
|
|
fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
|
|
|
if utility::random_f64() > 0.8 { // Reflektiert
|
|
|
|
let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal);
|
|
|
|
*scattered = Ray::new(rec.p, reflected);
|
|
|
|
*attenuation = self.albedo.clone();
|
|
|
|
|
|
|
|
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
|
|
|
|
|
|
|
|
} else { // Geht geradeaus durch
|
|
|
|
let reflected = r_in.direction().clone();
|
|
|
|
*scattered = Ray::new(rec.p, reflected);
|
|
|
|
|
|
|
|
*attenuation = self.albedo.clone();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
}
|
2022-06-21 18:10:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Dielectric {
|
|
|
|
pub fn new(index_of_refraction: f64) -> Self {
|
|
|
|
Dielectric {
|
|
|
|
ir: index_of_refraction,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reflectance(cosine: f64, ref_idx: f64) -> f64 {
|
|
|
|
let r0 = ((1.0-ref_idx) / (1.0+ref_idx)).powi(2);
|
|
|
|
return r0 + (1.0-r0)*(1.0 - cosine).powi(5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Material for Dielectric {
|
|
|
|
fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
|
|
|
*attenuation = Color::new(1.0, 1.0, 1.0);
|
|
|
|
let refraction_ratio = if rec.front_face { 1.0 / self.ir } else { self.ir };
|
|
|
|
|
|
|
|
let unit_direction = Vec3::unit_vector(r_in.direction());
|
|
|
|
let cos_theta = Vec3::dot(-1.0 * unit_direction, rec.normal).min(1.0);
|
|
|
|
let sin_theta = (1.0 - cos_theta*cos_theta).sqrt();
|
|
|
|
|
|
|
|
let mut direction = Vec3::refract(&unit_direction, &rec.normal, refraction_ratio); // can reflect
|
|
|
|
|
|
|
|
if refraction_ratio * sin_theta > 1.0 || Dielectric::reflectance(cos_theta, refraction_ratio) > utility::random_f64() { // must reflect
|
|
|
|
direction = Vec3::reflect(&unit_direction, &rec.normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
*scattered = Ray::new(rec.p, direction);
|
|
|
|
return true;
|
|
|
|
}
|
2022-06-08 18:28:45 +02:00
|
|
|
}
|