Different materials

This commit is contained in:
Jonathan Flueren 2022-06-08 18:28:45 +02:00
parent 4156756a4f
commit 15d3a50d16
5 changed files with 153 additions and 28 deletions

4
.gitignore vendored
View file

@ -1,4 +1,6 @@
/target
*.ppm
*.jpg
*.png
flamegraph.svg
perf.data*
perf.data*

View file

@ -1,17 +1,25 @@
use super::Point3;
use super::Ray;
use super::Vec3;
use super::{
Point3,
Vec3,
Color,
Ray,
Material,
Arc,
Metal
};
pub struct HitRecord {
pub p: Point3,
pub normal: Vec3,
pub mat_ptr: Arc<dyn Material>,
pub t: f64,
front_face: bool,
pub front_face: bool,
}
pub struct Sphere {
center: Point3,
radius: f64,
pub mat_ptr: Arc<dyn Material>,
}
pub trait Hittable: Sync + Send {
@ -28,10 +36,11 @@ impl HitRecord {
}
}
pub fn new(p: Point3, normal: Vec3, t: f64, front_face: bool) -> Self {
pub fn new(p: Point3, normal: Vec3, m: Arc<dyn Material>, t: f64, front_face: bool) -> Self {
HitRecord {
p: p,
normal: normal,
mat_ptr: m,
t: t,
front_face: front_face,
}
@ -39,8 +48,9 @@ impl HitRecord {
pub fn empty() -> Self {
Self::new(
Point3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 0.0),
Point3::null(),
Vec3::null(),
Arc::new(Metal::new(&Color::null())),
0.0,
false,
)
@ -48,10 +58,11 @@ impl HitRecord {
}
impl Sphere {
pub fn new(cen: Point3, r: f64) -> Self {
pub fn new(cen: Point3, r: f64, m: Arc<dyn Material>) -> Self {
Sphere {
center: cen,
radius: r,
mat_ptr: m,
}
}
}
@ -70,12 +81,12 @@ impl Hittable for Sphere {
let sqrtd = discriminant.sqrt();
let root = (-half_b - sqrtd) / a;
let mut root = (-half_b - sqrtd) / a;
let normal = (r.at(root) - self.center) / self.radius;
if root < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
let root2 = (-half_b + sqrtd) / a;
let normal = (r.at(root2) - self.center) / self.radius;
if root2 < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
root = (-half_b + sqrtd) / a;
let normal = (r.at(root) - self.center) / self.radius;
if root < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
return false;
}
}
@ -84,6 +95,7 @@ impl Hittable for Sphere {
rec.p = r.at(rec.t);
let outward_normal = (rec.p - self.center) / self.radius;
rec.set_face_normal(r, outward_normal);
rec.mat_ptr = self.mat_ptr.clone();
return true;
}

View file

@ -7,6 +7,7 @@ mod hittable_list;
mod ray;
mod utility;
mod vec3;
mod material;
use camera::Camera;
use hittable::{HitRecord, Hittable, Sphere};
@ -18,17 +19,25 @@ use std::env;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use vec3::{Color, Point3, Vec3};
use material::{Material, Lambertian, Metal};
fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
let mut rec = HitRecord::empty();
if depth <= 0 {
return Color::new(0.0, 0.0, 0.0);
return Color::null();
}
if world.hit(r, 0.0, f64::INFINITY, &mut rec) {
let target = rec.p + rec.normal + Vec3::random_unit_vector(); // rec.p + rec.normal.random_in_hemisphere();
return 0.5 * ray_color(&Ray::new(rec.p, target - rec.p), world, depth - 1);
if world.hit(r, 0.001, f64::INFINITY, &mut rec) {
let mut scattered = Ray::new(Point3::null(), Vec3::null());
let mut attenuation = Color::null();
if rec.mat_ptr.scatter(r, &rec, &mut attenuation, &mut scattered) {
return attenuation * ray_color(&scattered, world, depth-1);
}
return Color::null();
//let target = rec.p + rec.normal + Vec3::random_unit_vector(); // rec.p + rec.normal.random_in_hemisphere();
//return 0.5 * ray_color(&Ray::new(rec.p, target - rec.p), world, depth - 1);
}
let unit_direction = r.direction();
let t = 0.5 * (unit_direction.y() + 1.0);
@ -41,32 +50,46 @@ 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;
// World
let mut world = HittableList::new();
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(0.0, 0.0, -1.0),
0.5,
)));
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_left = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8)));
let material_right = Arc::new(Metal::new(&Color::new(0.8, 0.6, 0.2)));
let material_mirror = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.9)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(0.0, -100.5, -1.0),
100.0,
material_ground.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(1.0, 0.0, -1.5),
0.3,
Point3::new(0.0, 0.0, -1.0),
0.5,
material_center.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(1.0, 1.1, -1.5),
0.3,
Point3::new(-1.0, 0.0, -1.0),
0.5,
material_mirror.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-1.0, 1.1, -1.5),
0.3,
Point3::new(1.0, 0.0, -1.0),
0.5,
material_mirror.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-1.0, 1.1, -1.2),
0.4,
material_left.clone(),
)));
/*

63
src/material.rs Normal file
View file

@ -0,0 +1,63 @@
use super::{
Ray,
HitRecord,
Color,
Vec3,
};
pub struct Lambertian {
albedo: Color,
}
pub struct Metal {
albedo: Color,
}
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 {
pub fn new(a: &Color) -> Self {
Metal {
albedo: *a,
}
}
pub fn clone(&self) -> Self {
Self::new(&self.albedo.clone())
}
}
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);
*attenuation = self.albedo.clone();
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
}
}

View file

@ -14,6 +14,14 @@ impl Vec3 {
Vec3 { e: [x, y, z] }
}
pub fn null() -> Self {
Self::new(0.0, 0.0, 0.0)
}
pub fn clone(&self) -> Self {
Self::new(self.x(), self.y(), self.z())
}
pub fn length(&self) -> f64 {
self.length_squared().sqrt()
}
@ -38,6 +46,15 @@ impl Vec3 {
a / a.length()
}
pub fn reflect(v: &Self, n: &Self) -> Self {
*v - 2.0*Self::dot(*v, *n) * *(n)
}
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);
}
pub fn random_f64() -> Vec3 {
Vec3::new(
utility::random_f64(),
@ -128,6 +145,14 @@ impl Mul<Vec3> for f64 {
}
}
impl Mul<Self> for Vec3 {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self::new(self.x()*rhs.x(), self.y()*rhs.y(), self.z()*rhs.z())
}
}
impl MulAssign<f64> for Vec3 {
fn mul_assign(&mut self, rhs: f64) {
self.e[0] *= rhs;