additional materials

This commit is contained in:
Jonathan Flueren 2022-06-21 18:10:52 +02:00
parent d6e92fa2ba
commit 613bf68fb6
4 changed files with 64 additions and 15 deletions

View file

@ -50,7 +50,7 @@ impl HitRecord {
Self::new(
Point3::null(),
Vec3::null(),
Arc::new(Metal::new(&Color::null())),
Arc::new(Metal::new(&Color::null(), 0.0)),
0.0,
false,
)

View file

@ -19,7 +19,7 @@ use std::env;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use vec3::{Color, Point3, Vec3};
use material::{Material, Lambertian, Metal, Mirror};
use material::{Material, Lambertian, Metal, Dielectric};
fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
let mut rec = HitRecord::empty();
@ -50,7 +50,7 @@ fn main() {
// Image
let aspect_ratio = 16.0 / 9.0;
let image_width = 1000;
let image_width = 1920;
let image_height = (image_width as f64 / aspect_ratio) as u32;
let samples_per_pixel = 100_u32;
let max_depth = 50;
@ -60,9 +60,12 @@ fn main() {
let material_ground = Arc::new(Lambertian::new(&Color::new(0.8, 0.8, 0.0)));
let material_center = Arc::new(Lambertian::new(&Color::new(0.7, 0.1, 0.2)));
//let material_center = Arc::new(Dielectric::new(1.5));
let material_blue = Arc::new(Lambertian::new(&Color::new(0.2, 0.1, 0.7)));
let material_metal = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8)));
let _material_mirror = Arc::new(Mirror::new(&Color::new(0.99, 0.99, 0.99)));
let material_metal = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 0.1));
let material_metal_fuzz = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 1.0));
let material_mirror = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 0.0));
let material_dielectric = Arc::new(Dielectric::new(1.5));
@ -72,24 +75,24 @@ fn main() {
material_ground.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(0.0, -0.1, -1.0),
0.4,
Point3::new(0.0, 0.0, -1.0),
0.5,
material_center.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-1.0, 0.0, -1.0),
Point3::new(-1.0, -0.15, -1.0),
0.5,
material_metal.clone(),
material_dielectric.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(1.3, 0.3, -1.5),
0.8,
material_metal.clone(),
Point3::new(1.0, 0.0, -1.0),
-0.4,
material_dielectric.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-1.5, 1.3, -1.7),
0.4,
material_metal.clone(),
material_mirror.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-0.5, 0.5, 1.0),

View file

@ -12,12 +12,17 @@ pub struct Lambertian {
pub struct Metal {
albedo: Color,
fuzz: f64,
}
pub struct Mirror {
albedo: Color,
}
pub struct Dielectric {
ir: f64,
}
pub trait Material: Sync + Send {
fn scatter(&self,r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool;
@ -46,9 +51,10 @@ impl Material for Lambertian {
}
impl Metal {
pub fn new(a: &Color) -> Self {
pub fn new(a: &Color, f: f64) -> Self {
Metal {
albedo: *a,
fuzz: f,
}
}
}
@ -57,7 +63,7 @@ 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);
*scattered = Ray::new(rec.p, reflected);
*scattered = Ray::new(rec.p, reflected + self.fuzz*Vec3::random_in_unit_sphere());
*attenuation = self.albedo.clone();
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
@ -91,3 +97,36 @@ impl Material for Mirror {
};
}
}
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;
}
}

View file

@ -50,6 +50,13 @@ impl Vec3 {
*v - 2.0*Self::dot(*v, *n) * *(n)
}
pub fn refract(uv: &Self, n: &Self, etai_over_etat: f64) -> Self {
let cos_theta = Self::dot(-1.0 * *uv, *n).min(1.0); // Minimum aus 1.0 und Punktprodukt
let r_out_perp = etai_over_etat * (*uv + cos_theta * *n);
let r_out_parallel = -(1.0 - r_out_perp.length_squared()).abs().sqrt() * *n;
return r_out_perp + r_out_parallel;
}
pub fn near_zero(&self) -> bool {
let s = 1e-8;
return (self.e[0].abs() < s) && (self.e[1].abs() < s) && (self.e[2].abs() < s);