Renderer/src/material.rs

194 lines
4.5 KiB
Rust
Raw Normal View History

2022-06-29 16:17:28 +02:00
use super::{utility, Color, HitRecord, Ray, Vec3};
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-08-02 18:30:39 +02:00
pub struct Rainbow {}
2022-08-02 17:07:49 +02:00
2022-06-08 18:28:45 +02:00
pub trait Material: Sync + Send {
2022-06-29 16:17:28 +02:00
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool;
2022-06-08 18:28:45 +02:00
}
impl Lambertian {
pub fn new(a: &Color) -> Self {
2022-06-29 16:17:28 +02:00
Lambertian { albedo: a.clone() }
2022-06-08 18:28:45 +02:00
}
}
impl Material for Lambertian {
2022-06-29 16:17:28 +02:00
fn scatter(
&self,
_r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
2022-06-08 18:28:45 +02:00
let mut scatter_direction = rec.normal + Vec3::random_unit_vector();
2022-06-29 16:17:28 +02:00
2022-06-08 18:28:45 +02:00
if scatter_direction.near_zero() {
scatter_direction = rec.normal;
}
2022-06-29 16:17:28 +02:00
2022-06-08 18:28:45 +02:00
*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 {
2022-06-29 16:17:28 +02:00
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
2022-06-08 18:28:45 +02:00
let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal);
2022-06-29 16:17:28 +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();
2022-09-13 23:30:17 +02:00
return true;//Vec3::dot(scattered.direction(), rec.normal) > 0.0;
2022-06-08 18:28:45 +02:00
}
2022-06-08 19:53:37 +02:00
}
impl Mirror {
pub fn new(a: &Color) -> Self {
2022-06-29 16:17:28 +02:00
Mirror { albedo: *a }
2022-06-08 19:53:37 +02:00
}
}
impl Material for Mirror {
2022-06-29 16:17:28 +02:00
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
if utility::random_f64() > 0.8 {
// Reflektiert
2022-09-13 23:30:17 +02:00
let reflected = Vec3::reflect(&r_in.direction(), &rec.normal);
2022-06-08 19:53:37 +02:00
*scattered = Ray::new(rec.p, reflected);
*attenuation = self.albedo.clone();
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
2022-06-29 16:17:28 +02:00
} else {
// Geht geradeaus durch
2022-06-08 19:53:37 +02:00
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 {
2022-06-29 16:17:28 +02:00
let r0 = ((1.0 - ref_idx) / (1.0 + ref_idx)).powi(2);
return r0 + (1.0 - r0) * (1.0 - cosine).powi(5);
2022-06-21 18:10:52 +02:00
}
}
impl Material for Dielectric {
2022-06-29 16:17:28 +02:00
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
2022-06-21 18:10:52 +02:00
*attenuation = Color::new(1.0, 1.0, 1.0);
2022-06-29 16:17:28 +02:00
let refraction_ratio = if rec.front_face {
1.0 / self.ir
} else {
self.ir
};
2022-06-21 18:10:52 +02:00
let unit_direction = Vec3::unit_vector(r_in.direction());
let cos_theta = Vec3::dot(-1.0 * unit_direction, rec.normal).min(1.0);
2022-06-29 16:17:28 +02:00
let sin_theta = (1.0 - cos_theta * cos_theta).sqrt();
2022-06-21 18:10:52 +02:00
let mut direction = Vec3::refract(&unit_direction, &rec.normal, refraction_ratio); // can reflect
2022-06-29 16:17:28 +02:00
if refraction_ratio * sin_theta > 1.0
|| Dielectric::reflectance(cos_theta, refraction_ratio) > utility::random_f64()
{
// must reflect
2022-06-21 18:10:52 +02:00
direction = Vec3::reflect(&unit_direction, &rec.normal);
}
*scattered = Ray::new(rec.p, direction);
return true;
}
2022-06-29 16:17:28 +02:00
}
2022-08-02 17:07:49 +02:00
impl Rainbow {
pub fn new() -> Self {
Rainbow {}
}
}
impl Material for Rainbow {
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);
2022-08-02 18:30:39 +02:00
let color = 0.5
* Color::new(
rec.normal.x() + 1.0,
rec.normal.y() + 1.0,
rec.normal.z() + 1.0,
);
2022-08-02 17:07:49 +02:00
*attenuation = color;
return true;
}
2022-08-02 18:30:39 +02:00
}