Skip to content

Commit

Permalink
Merge pull request #8 from soumyasen1809/tasks
Browse files Browse the repository at this point in the history
Add dielectric  material
  • Loading branch information
soumyasen1809 authored Aug 14, 2024
2 parents d582f7b + 28985d3 commit 039f435
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 69 deletions.
7 changes: 0 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ authors = ["Sen"]
lib ={ path = "lib"} # needed for the tests to work

[[bin]]
name = "project_bin"
name = "bin"
path = "src/main.rs"

# Check https://rust-classes.com/chapter_4_3
[workspace]
members = [
"lib",
"project_bin",
]
resolver = "2"

Expand Down
24 changes: 0 additions & 24 deletions lib/src/utilities/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,33 +92,9 @@ impl Camera {

fn ray_color(ray: Ray, depth: i32, world: &[Box<dyn Hittable>]) -> Color {
// If we've exceeded the ray bounce limit, no more light is gathered.
// Problem: Recursion long enough to blow the stack
// Solution: To guard against that, let's limit the maximum recursion depth,
// returning no light contribution at the maximum depth.
if depth <= 0 {
return Color::default();
}
// let mut record: HitRecord = HitRecord::default(); // needed since to mut this, we need to initialize it
// if world.hit(ray, Interval::new(0.001, std::f64::INFINITY), &mut record) {
// // let ray_bounce_direction: Vector3 = record.normal + Vector3::random_unit_vector();
// // return (Self::ray_color(
// // // note recursion here
// // &Ray::new(record.point, ray_bounce_direction),
// // depth - 1,
// // world,
// // )) * 0.5;
// let scattered_ray: Ray = Ray::default();
// let attenuation: Color = Color::default();

// if record
// .material
// .clone()
// .unwrap()
// .scatter(ray, record, attenuation, scattered_ray)
// {
// return (Self::ray_color(scattered_ray, depth - 1, world)) * attenuation;
// }
// return Color::new(0.0, 0.0, 0.0);

if let Some(hit) = world.hit(ray, Interval::new(0.001, std::f64::INFINITY)) {
if let Some(scatter) = hit.material.scatter(ray, &hit) {
Expand Down
48 changes: 24 additions & 24 deletions lib/src/utilities/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,30 @@ pub trait Hittable {
fn hit(&self, ray: Ray, ray_interval: Interval) -> Option<HitRecord>;
}

impl<T> Hittable for T
where
T: AsRef<[Box<dyn Hittable>]>,
{
fn hit(&self, ray: Ray, ray_interval: Interval) -> Option<HitRecord> {
let t_min: f64 = ray_interval.min;
let t_max: f64 = ray_interval.max;

let mut closest_so_far: Option<HitRecord> = None;

for object in self.as_ref().iter() {
let t_max_local = closest_so_far
.as_ref()
.map(|hit| hit.parameter)
.unwrap_or(t_max);
if let Some(record) = object.hit(ray, Interval::new(t_min, t_max_local)) {
closest_so_far = Some(record);
}
}

closest_so_far
}
}

pub struct Sphere {
center: Point3,
radius: f64,
Expand Down Expand Up @@ -67,27 +91,3 @@ impl Hittable for Sphere {
))
}
}

impl<T> Hittable for T
where
T: AsRef<[Box<dyn Hittable>]>,
{
fn hit(&self, ray: Ray, ray_interval: Interval) -> Option<HitRecord> {
let t_min: f64 = ray_interval.min;
let t_max: f64 = ray_interval.max;

let mut closest_so_far: Option<HitRecord> = None;

for object in self.as_ref().iter() {
let t_max_local = closest_so_far
.as_ref()
.map(|hit| hit.parameter)
.unwrap_or(t_max);
if let Some(record) = object.hit(ray, Interval::new(t_min, t_max_local)) {
closest_so_far = Some(record);
}
}

closest_so_far
}
}
78 changes: 71 additions & 7 deletions lib/src/utilities/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub trait Material {

#[derive(Clone)]
pub struct Lambertian {
pub albedo: Color,
albedo: Color,
}

impl Lambertian {
Expand Down Expand Up @@ -50,32 +50,96 @@ impl Material for Lambertian {
#[derive(Clone)]
pub struct Metal {
albedo: Color,
fuzz: f64,
}

impl Metal {
pub fn new(albedo: Color) -> Self {
Self { albedo: albedo }
pub fn new(albedo: Color, fuzz: f64) -> Self {
Self {
albedo,
fuzz: if fuzz < 1.0 { fuzz } else { 1.0 },
}
}
}

impl Default for Metal {
fn default() -> Self {
Self {
albedo: Color::new(0.8, 0.8, 0.8),
fuzz: 1.0,
}
}
}

impl Material for Metal {
fn scatter(&self, incoming_ray: Ray, record: &HitRecord) -> Option<Scatter> {
// Metal material with reflectance function
let reflect_direction: Vector3 = incoming_ray
let reflect_direction: Vector3 = (incoming_ray
.get_direction()
.unit_vector()
.reflection(&record.normal);
.reflection(&record.normal))
+ (Vector3::random_unit_vector() * self.fuzz);
let scattered_ray = Ray::new(record.point, reflect_direction);
let attenuation = self.albedo;
if scattered_ray.get_direction().dot_prod(record.normal) > 0.0 {
return Some(Scatter {
scattered_ray,
attenuation,
});
}
None
}
}

#[derive(Clone)]
pub struct Dielectric {
refractive_index: f64,
}

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

pub fn reflectance(cos_theta: f64, r_index: f64) -> f64 {
let mut r0: f64 = (1.0 - r_index) / (1.0 + r_index);
r0 = r0 * r0;
r0 + ((1.0 - r0) * ((1.0 - cos_theta).powi(5)))
}
}

impl Default for Dielectric {
fn default() -> Self {
Self {
refractive_index: 1.0,
}
}
}

impl Material for Dielectric {
fn scatter(&self, incoming_ray: Ray, record: &HitRecord) -> Option<Scatter> {
let attenuation: Color = Color::new(1.0, 1.0, 1.0);
let r_index: f64 = if record.is_face_front {
1.0 / self.refractive_index
} else {
self.refractive_index
};
let unit_direction: Vector3 = incoming_ray.get_direction().unit_vector();

let cos_theta: f64 = (-unit_direction.dot_prod(record.normal)).min(1.0); // std::fmin
let sin_theta: f64 = (1.0 - (cos_theta * cos_theta)).sqrt();
let can_refract: bool = r_index * sin_theta <= 1.0;

let ray_direction: Vector3 = if can_refract {
unit_direction.refraction(&record.normal, r_index)
} else {
unit_direction.reflection(&record.normal)
};
let scattered_ray: Ray = Ray::new(record.point, ray_direction);

Some(Scatter {
scattered_ray: Ray::new(record.point, reflect_direction),
attenuation: self.albedo,
scattered_ray,
attenuation,
})
}
}
9 changes: 9 additions & 0 deletions lib/src/utilities/vector3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ impl Vector3 {
pub fn reflection(&self, normal_vec: &Self) -> Self {
return *self - ((*normal_vec * (self.dot_prod(*normal_vec))) * 2.0);
}

pub fn refraction(&self, normal_vec: &Self, ratio_refractive_index: f64) -> Self {
let cos_theta: f64 = (-self.dot_prod(*normal_vec)).min(1.0); // std::fmin
let ray_out_perp: Vector3 = (*self + (*normal_vec * cos_theta)) * ratio_refractive_index;
let ray_out_par: Vector3 =
*normal_vec * (-(((1.0 - ray_out_perp.length_squared()).abs()).sqrt()));

ray_out_par + ray_out_perp
}
}

impl Default for Vector3 {
Expand Down
2 changes: 1 addition & 1 deletion project_bin/Cargo.toml → src/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "project_bin"
name = "bin"
version = "0.1.0"
edition = "2021"
license = "GNU GENERAL PUBLIC LICENSE"
Expand Down
14 changes: 10 additions & 4 deletions project_bin/src/main.rs → src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use lib::utilities::{
camera::Camera,
color::Color,
geometry::{Hittable, Sphere},
material::{Lambertian, Metal},
material::{Dielectric, Lambertian, Metal},
point::Point3,
};

Expand All @@ -15,12 +15,13 @@ fn main() {
// https://raytracing.github.io/books/RayTracingInOneWeekend.html

// World
let mut world: Vec<Box<dyn Hittable>> = Vec::with_capacity(11 * 11);
let mut world: Vec<Box<dyn Hittable>> = Vec::new();

let material_ground = Box::new(Lambertian::new(Color::new(0.8, 0.8, 0.0)));
let material_center = Box::new(Lambertian::new(Color::new(0.1, 0.2, 0.5)));
let material_left = Box::new(Metal::new(Color::new(0.8, 0.8, 0.8)));
let material_right = Box::new(Metal::new(Color::new(0.8, 0.6, 0.2)));
let material_left = Box::new(Dielectric::new(1.33));
let material_right = Box::new(Metal::new(Color::new(0.8, 0.6, 0.2), 1.0));
let material_bubble = Box::new(Dielectric::new(1.0 / 1.33));

world.push(Box::new(Sphere::new(
Point3::new(0.0, -100.5, -1.0),
Expand All @@ -42,6 +43,11 @@ fn main() {
0.5,
material_right,
)));
world.push(Box::new(Sphere::new(
Point3::new(-1.0, 0.0, -1.0),
0.4,
material_bubble,
)));

// Camera
let mut cam: Camera = Camera::new();
Expand Down

0 comments on commit 039f435

Please sign in to comment.