Added Dielectrics, Implemented Neg for Vec3
This commit is contained in:
parent
232d3350a2
commit
95eebf21b4
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
target/
|
target/
|
||||||
*.ppm
|
*.ppm
|
||||||
|
*.png
|
||||||
|
|
103
src/demos/dielectric_material.rs
Normal file
103
src/demos/dielectric_material.rs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
demos::{Chunk, Demo},
|
||||||
|
types::{
|
||||||
|
material::{Dielectric, Lambertian, Metal},
|
||||||
|
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||||
|
},
|
||||||
|
Camera,
|
||||||
|
},
|
||||||
|
rand::Rng,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct DielectricMaterial;
|
||||||
|
|
||||||
|
impl Demo for DielectricMaterial {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"dielectric-material"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||||
|
let x = chunk.x;
|
||||||
|
let y = chunk.y;
|
||||||
|
let nx = chunk.nx;
|
||||||
|
let ny = chunk.ny;
|
||||||
|
let start_x = chunk.start_x;
|
||||||
|
let start_y = chunk.start_y;
|
||||||
|
let buffer = &mut chunk.buffer;
|
||||||
|
|
||||||
|
let world = HitableList {
|
||||||
|
list: vec![
|
||||||
|
Box::new(Sphere::with_material(
|
||||||
|
Vec3::new(0.0, 0.0, -1.0),
|
||||||
|
0.5,
|
||||||
|
Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))),
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::with_material(
|
||||||
|
Vec3::new(0.0, -100.5, -1.0),
|
||||||
|
100.0,
|
||||||
|
Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.0))),
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::with_material(
|
||||||
|
Vec3::new(1.0, 0.0, -1.0),
|
||||||
|
0.5,
|
||||||
|
Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2))),
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::with_material(
|
||||||
|
Vec3::new(-1.0, 0.0, -1.0),
|
||||||
|
0.5,
|
||||||
|
Box::new(Dielectric::new(1.5)),
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::with_material(
|
||||||
|
Vec3::new(-1.0, 0.0, -1.0),
|
||||||
|
-0.45,
|
||||||
|
Box::new(Dielectric::new(1.5)),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let camera: Camera = Default::default();
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
for j in start_y..start_y + ny {
|
||||||
|
for i in start_x..start_x + nx {
|
||||||
|
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
for _s in 0..samples {
|
||||||
|
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||||
|
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||||
|
|
||||||
|
let ray = camera.get_ray(u, v);
|
||||||
|
color += calc_color(ray, &world, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
color /= samples as f64;
|
||||||
|
|
||||||
|
// gamma 2 corrected
|
||||||
|
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||||
|
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||||
|
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||||
|
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||||
|
if depth >= 50 {
|
||||||
|
Vec3::new(0.0, 0.0, 0.0)
|
||||||
|
} else {
|
||||||
|
let material = hit_rec.material.as_ref();
|
||||||
|
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||||
|
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||||
|
} else {
|
||||||
|
Vec3::new(0.0, 0.0, 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let unit_direction = ray.direction().unit_vector();
|
||||||
|
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||||
|
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,7 +67,7 @@ fn calc_color(ray: Ray, world: &HitableList, rng: &mut rand::rngs::ThreadRng) ->
|
||||||
// To combat this problem, We set a bias
|
// To combat this problem, We set a bias
|
||||||
// More information here, https://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/#shadow-acne
|
// More information here, https://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/#shadow-acne
|
||||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||||
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_space(rng);
|
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_sphere(rng);
|
||||||
calc_color(Ray::new(hit_rec.p, target - hit_rec.p), &world, rng) * 0.5
|
calc_color(Ray::new(hit_rec.p, target - hit_rec.p), &world, rng) * 0.5
|
||||||
} else {
|
} else {
|
||||||
let unit_direction = ray.direction().unit_vector();
|
let unit_direction = ray.direction().unit_vector();
|
||||||
|
@ -76,7 +76,7 @@ fn calc_color(ray: Ray, world: &HitableList, rng: &mut rand::rngs::ThreadRng) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_point_in_unit_space(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
fn random_point_in_unit_sphere(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||||
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||||
- Vec3::new(1.0, 1.0, 1.0);
|
- Vec3::new(1.0, 1.0, 1.0);
|
||||||
while point.sq_len() >= 1.0 {
|
while point.sq_len() >= 1.0 {
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
demos::{Chunk, Demo},
|
demos::{Chunk, Demo},
|
||||||
types::{material, Hitable, HitableList, Ray, Sphere, Vec3},
|
types::{
|
||||||
|
material::{Lambertian, Metal},
|
||||||
|
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||||
|
},
|
||||||
Camera,
|
Camera,
|
||||||
},
|
},
|
||||||
rand::Rng,
|
rand::Rng,
|
||||||
|
@ -11,7 +14,7 @@ pub struct Materials;
|
||||||
|
|
||||||
impl Demo for Materials {
|
impl Demo for Materials {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Metal Material"
|
"metal-material"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||||
|
@ -28,22 +31,22 @@ impl Demo for Materials {
|
||||||
Box::new(Sphere::with_material(
|
Box::new(Sphere::with_material(
|
||||||
Vec3::new(0.0, 0.0, -1.0),
|
Vec3::new(0.0, 0.0, -1.0),
|
||||||
0.5,
|
0.5,
|
||||||
Box::new(material::Lambertian::new(Vec3::new(0.8, 0.3, 0.3))),
|
Box::new(Lambertian::new(Vec3::new(0.8, 0.3, 0.3))),
|
||||||
)),
|
)),
|
||||||
Box::new(Sphere::with_material(
|
Box::new(Sphere::with_material(
|
||||||
Vec3::new(0.0, -100.5, -1.0),
|
Vec3::new(0.0, -100.5, -1.0),
|
||||||
100.0,
|
100.0,
|
||||||
Box::new(material::Lambertian::new(Vec3::new(0.8, 0.8, 0.0))),
|
Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.0))),
|
||||||
)),
|
)),
|
||||||
Box::new(Sphere::with_material(
|
Box::new(Sphere::with_material(
|
||||||
Vec3::new(1.0, 0.0, -1.0),
|
Vec3::new(1.0, 0.0, -1.0),
|
||||||
0.5,
|
0.5,
|
||||||
Box::new(material::Metal::new(Vec3::new(0.8, 0.6, 0.2))),
|
Box::new(Metal::with_fuzz(Vec3::new(0.8, 0.6, 0.2), 0.3)),
|
||||||
)),
|
)),
|
||||||
Box::new(Sphere::with_material(
|
Box::new(Sphere::with_material(
|
||||||
Vec3::new(-1.0, 0.0, -1.0),
|
Vec3::new(-1.0, 0.0, -1.0),
|
||||||
0.5,
|
0.5,
|
||||||
Box::new(material::Metal::new(Vec3::new(0.8, 0.8, 0.8))),
|
Box::new(Metal::with_fuzz(Vec3::new(0.8, 0.8, 0.8), 0.5)),
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod dielectric_material;
|
||||||
mod diffuse_materials;
|
mod diffuse_materials;
|
||||||
mod hitable_sphere;
|
mod hitable_sphere;
|
||||||
mod linear_gradient_rectangle;
|
mod linear_gradient_rectangle;
|
||||||
|
@ -7,6 +8,7 @@ mod simple_rectangle;
|
||||||
mod simple_sphere;
|
mod simple_sphere;
|
||||||
mod surface_normal_sphere;
|
mod surface_normal_sphere;
|
||||||
|
|
||||||
|
pub use dielectric_material::DielectricMaterial;
|
||||||
pub use diffuse_materials::DiffuseMaterials;
|
pub use diffuse_materials::DiffuseMaterials;
|
||||||
pub use hitable_sphere::HitableSphere;
|
pub use hitable_sphere::HitableSphere;
|
||||||
pub use linear_gradient_rectangle::LinearGradientRectangle;
|
pub use linear_gradient_rectangle::LinearGradientRectangle;
|
||||||
|
|
|
@ -78,6 +78,7 @@ fn main() -> Result<(), String> {
|
||||||
Some(Keycode::Num6) => active_demo = Box::new(demos::SimpleAntialiasing),
|
Some(Keycode::Num6) => active_demo = Box::new(demos::SimpleAntialiasing),
|
||||||
Some(Keycode::Num7) => active_demo = Box::new(demos::DiffuseMaterials),
|
Some(Keycode::Num7) => active_demo = Box::new(demos::DiffuseMaterials),
|
||||||
Some(Keycode::Num8) => active_demo = Box::new(demos::Materials),
|
Some(Keycode::Num8) => active_demo = Box::new(demos::Materials),
|
||||||
|
Some(Keycode::Num9) => active_demo = Box::new(demos::DielectricMaterial),
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,23 @@
|
||||||
use crate::types::{Material, Ray, Vec3};
|
use crate::types::{Material, Ray, Vec3};
|
||||||
|
|
||||||
pub struct HitRecord<'a> {
|
pub struct HitRecord<'a> {
|
||||||
|
/// Rays are represented by A + t * B
|
||||||
|
/// where A is the source point and B destination point
|
||||||
|
/// by adjusting t we can move forward/back on the ray
|
||||||
|
///
|
||||||
|
/// t is the point at which a ray intersected another object.
|
||||||
|
/// As in, If we put this value of t in A + t * B equation, We'll get the exact
|
||||||
|
/// point at which a ray intersects some other object
|
||||||
pub t: f64,
|
pub t: f64,
|
||||||
|
/// Ray object otherwise is represented by the Source/Destination points
|
||||||
|
/// p is what we get when we perform the operation, A + t * B
|
||||||
|
/// i.e. A vector from Ray source to the point t
|
||||||
pub p: Vec3,
|
pub p: Vec3,
|
||||||
|
|
||||||
|
/// unit outward facing normal
|
||||||
pub normal: Vec3,
|
pub normal: Vec3,
|
||||||
|
|
||||||
|
/// material if any of the surface
|
||||||
pub material: Option<&'a Box<dyn Material>>,
|
pub material: Option<&'a Box<dyn Material>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ use {
|
||||||
crate::types::{HitRecord, Ray, Vec3},
|
crate::types::{HitRecord, Ray, Vec3},
|
||||||
rand::Rng,
|
rand::Rng,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Material {
|
pub trait Material {
|
||||||
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>);
|
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>);
|
||||||
}
|
}
|
||||||
|
@ -10,46 +11,45 @@ pub struct Lambertian {
|
||||||
albedo: Vec3,
|
albedo: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material for Lambertian {
|
|
||||||
fn scatter(&self, _ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_space(&mut rng);
|
|
||||||
let scattered_ray = Ray::new(hit_rec.p, target - hit_rec.p);
|
|
||||||
|
|
||||||
(self.albedo, Some(scattered_ray))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Lambertian {
|
impl Lambertian {
|
||||||
pub fn new(a: Vec3) -> Self {
|
pub fn new(a: Vec3) -> Self {
|
||||||
Self { albedo: a }
|
Self { albedo: a }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_point_in_unit_space(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
impl Material for Lambertian {
|
||||||
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
fn scatter(&self, _ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
||||||
- Vec3::new(1.0, 1.0, 1.0);
|
let mut rng = rand::thread_rng();
|
||||||
while point.sq_len() >= 1.0 {
|
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_sphere(&mut rng);
|
||||||
point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
let scattered_ray = Ray::new(hit_rec.p, target - hit_rec.p);
|
||||||
- Vec3::new(1.0, 1.0, 1.0);
|
|
||||||
|
(self.albedo, Some(scattered_ray))
|
||||||
}
|
}
|
||||||
point
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Metal {
|
pub struct Metal {
|
||||||
albedo: Vec3,
|
albedo: Vec3,
|
||||||
|
fuzz: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Metal {
|
impl Metal {
|
||||||
pub fn new(albedo: Vec3) -> Self {
|
pub fn new(albedo: Vec3) -> Self {
|
||||||
Self { albedo }
|
Self { albedo, fuzz: 0.0 }
|
||||||
|
}
|
||||||
|
pub fn with_fuzz(albedo: Vec3, fuzz: f64) -> Self {
|
||||||
|
Self { albedo, fuzz }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material for Metal {
|
impl Material for Metal {
|
||||||
fn scatter(&self, ray_in: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
fn scatter(&self, ray_in: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
let reflected_ray = reflect(ray_in.direction().unit_vector(), hit_rec.normal);
|
let reflected_ray = reflect(ray_in.direction().unit_vector(), hit_rec.normal);
|
||||||
let scattered_ray = Ray::new(hit_rec.p, reflected_ray);
|
let scattered_ray = Ray::new(
|
||||||
|
hit_rec.p,
|
||||||
|
reflected_ray + random_point_in_unit_sphere(&mut rng) * self.fuzz,
|
||||||
|
);
|
||||||
|
|
||||||
if scattered_ray.direction().dot(&hit_rec.normal) > 0.0 {
|
if scattered_ray.direction().dot(&hit_rec.normal) > 0.0 {
|
||||||
(self.albedo, Some(scattered_ray))
|
(self.albedo, Some(scattered_ray))
|
||||||
|
@ -59,6 +59,82 @@ impl Material for Metal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Dielectric {
|
||||||
|
reflection_index: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dielectric {
|
||||||
|
pub fn new(reflection_index: f64) -> Self {
|
||||||
|
Self { reflection_index }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Material for Dielectric {
|
||||||
|
fn scatter(&self, ray_in: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
||||||
|
let reflected_ray = reflect(ray_in.direction(), hit_rec.normal);
|
||||||
|
// Glass absorbs nothing! So, Attenuation is always going to be 1.0 for this
|
||||||
|
let attenuation = Vec3::new(1.0, 1.0, 1.0);
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
let (outward_normal, ni_over_nt, cosine) = if ray_in.direction().dot(&hit_rec.normal) > 0.0
|
||||||
|
{
|
||||||
|
(
|
||||||
|
-hit_rec.normal,
|
||||||
|
self.reflection_index,
|
||||||
|
(ray_in.direction().dot(&hit_rec.normal) * self.reflection_index)
|
||||||
|
/ ray_in.direction().length(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
hit_rec.normal,
|
||||||
|
1.0 / self.reflection_index,
|
||||||
|
(-ray_in.direction().dot(&hit_rec.normal)) / ray_in.direction().length(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(refracted_ray) = refract(ray_in.direction(), outward_normal, ni_over_nt) {
|
||||||
|
let reflect_prob = schlick(cosine, self.reflection_index);
|
||||||
|
|
||||||
|
if rng.gen::<f64>() < reflect_prob {
|
||||||
|
(attenuation, Some(Ray::new(hit_rec.p, reflected_ray)))
|
||||||
|
} else {
|
||||||
|
(attenuation, Some(Ray::new(hit_rec.p, refracted_ray)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(attenuation, Some(Ray::new(hit_rec.p, reflected_ray)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polynomial approximation to figure out reflectivity as the angle changes
|
||||||
|
fn schlick(cosine: f64, reflection_index: f64) -> f64 {
|
||||||
|
let mut r0 = (1.0 - reflection_index) / (1.0 + reflection_index);
|
||||||
|
r0 = r0 * r0;
|
||||||
|
r0 + (1.0 - r0) * (1.0 - cosine).powf(5.0)
|
||||||
|
}
|
||||||
|
|
||||||
fn reflect(incident: Vec3, normal: Vec3) -> Vec3 {
|
fn reflect(incident: Vec3, normal: Vec3) -> Vec3 {
|
||||||
incident - normal * incident.dot(&normal) * 2.0
|
incident - normal * incident.dot(&normal) * 2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snell's Law
|
||||||
|
fn refract(incident: Vec3, normal: Vec3, ni_over_nt: f64) -> Option<Vec3> {
|
||||||
|
let uv = incident.unit_vector();
|
||||||
|
let dt = uv.dot(&normal);
|
||||||
|
let discriminant = 1.0 - ni_over_nt * ni_over_nt * (1.0 - dt * dt);
|
||||||
|
if discriminant > 0.0 {
|
||||||
|
Some((uv - normal * dt) * ni_over_nt - normal * discriminant.sqrt())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_point_in_unit_sphere(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||||
|
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||||
|
- Vec3::new(1.0, 1.0, 1.0);
|
||||||
|
while point.sq_len() >= 1.0 {
|
||||||
|
point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||||
|
- Vec3::new(1.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
point
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::types::{HitRecord, Hitable, Material, Ray, Vec3};
|
use crate::types::{HitRecord, Hitable, Material, Ray, Vec3};
|
||||||
|
|
||||||
pub struct Sphere {
|
pub struct Sphere {
|
||||||
center: Vec3,
|
center: Vec3,
|
||||||
radius: f64,
|
radius: f64,
|
||||||
|
@ -36,9 +37,10 @@ impl Hitable for Sphere {
|
||||||
// Check this for detailed proof
|
// Check this for detailed proof
|
||||||
// https://vchizhov.github.io/resources/ray%20tracing/ray%20tracing%20tutorial%20series%20vchizhov/ray_casting/part1/intersecting_a_sphere.md.html#appendix
|
// https://vchizhov.github.io/resources/ray%20tracing/ray%20tracing%20tutorial%20series%20vchizhov/ray_casting/part1/intersecting_a_sphere.md.html#appendix
|
||||||
let discriminant = b * b - a * c;
|
let discriminant = b * b - a * c;
|
||||||
|
let discriminant_root = discriminant.sqrt();
|
||||||
|
|
||||||
if discriminant > 0.0 {
|
if discriminant > 0.0 {
|
||||||
let root = (-b - discriminant.sqrt()) / a;
|
let root = (-b - discriminant_root) / a;
|
||||||
if root < t_max && root > t_min {
|
if root < t_max && root > t_min {
|
||||||
let p = ray.point_at_parameter(root);
|
let p = ray.point_at_parameter(root);
|
||||||
return Some(HitRecord {
|
return Some(HitRecord {
|
||||||
|
@ -49,7 +51,7 @@ impl Hitable for Sphere {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let root = (-b + discriminant.sqrt()) / a;
|
let root = (-b + discriminant_root) / a;
|
||||||
if root < t_max && root > t_min {
|
if root < t_max && root > t_min {
|
||||||
let p = ray.point_at_parameter(root);
|
let p = ray.point_at_parameter(root);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Display, Formatter, Result as FmtResult},
|
fmt::{Display, Formatter, Result as FmtResult},
|
||||||
ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
|
ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -107,6 +107,14 @@ impl SubAssign for Vec3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Neg for Vec3 {
|
||||||
|
type Output = Vec3;
|
||||||
|
|
||||||
|
fn neg(self) -> Vec3 {
|
||||||
|
Vec3([-self[0], -self[1], -self[2]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MulAssign<Vec3> for Vec3 {
|
impl MulAssign<Vec3> for Vec3 {
|
||||||
fn mul_assign(&mut self, o: Vec3) {
|
fn mul_assign(&mut self, o: Vec3) {
|
||||||
self[0] *= o[0];
|
self[0] *= o[0];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user