1
0

Completed the instances section

This commit is contained in:
Ishan Jain 2021-04-08 09:31:23 +05:30
parent 9d82129891
commit 73e7085818
7 changed files with 303 additions and 132 deletions

View File

@ -4,20 +4,23 @@ use rand::{prelude::SmallRng, SeedableRng};
use crate::{
demos::{Demo, ParallelHit},
hitable::shapes::{Cuboid, RectBuilder},
hitable::{
shapes::{Cuboid, RectBuilder},
Hitable,
},
materials::{DiffuseLight, Lambertian, MaterialBuilder},
texture::Solid,
types::Vec3,
BvhNode, Camera,
};
pub struct CornellBox {}
pub struct Instances {}
impl Demo for CornellBox {
impl Demo for Instances {
type DemoT = BvhNode<Arc<dyn ParallelHit>>;
fn name(&self) -> &'static str {
"cornell_box"
"instances"
}
fn world(&self) -> Self::DemoT {
@ -76,16 +79,20 @@ impl Demo for CornellBox {
));
// Add the two boxes
world.push(Arc::new(Cuboid::new(
Vec3::new(136.0, 0.0, 65.0),
Vec3::new(295.0, 165.0, 230.0),
white,
)));
world.push(Arc::new(Cuboid::new(
Vec3::new(265.0, 0.0, 295.0),
Vec3::new(430.0, 330.0, 460.0),
white,
)));
world.push(Arc::new(
Cuboid::new(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(165.0, 330.0, 165.0),
white,
)
.rotate_y(15.0)
.translate(Vec3::new(265.0, 0.0, 295.0)),
));
world.push(Arc::new(
Cuboid::new(Vec3::new(0.0, 0.0, 0.0), Vec3::splat(165.0), white)
.rotate_y(-18.0)
.translate(Vec3::new(130.0, 0.0, 65.0)),
));
BvhNode::new(&mut rng, &mut world, 0.0, 1.0)
}

View File

@ -13,15 +13,15 @@ use std::{
};
mod checkered_motion_blur;
mod cornell_box;
mod image_texture;
mod instances;
mod perlin_noise_ball;
mod simple_light;
mod two_spheres;
pub use checkered_motion_blur::CheckeredMotionBlur;
pub use cornell_box::CornellBox;
pub use image_texture::ImageTextureDemo;
pub use instances::Instances;
pub use perlin_noise_ball::PerlinNoiseBall;
pub use simple_light::SimpleLight;
pub use two_spheres::TwoSpheres;

View File

@ -1,112 +0,0 @@
use std::sync::Arc;
use crate::{
types::{Ray, Vec3},
Aabb, Material,
};
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,
/// 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,
/// unit outward facing normal
pub normal: Vec3,
/// material if any of the surface
pub material: &'a dyn Material,
/// texture coordinates for an object
pub u: f64,
pub v: f64,
pub front_face: bool,
}
impl<'a> HitRecord<'a> {
pub fn new(
t: f64,
p: Vec3,
normal: Vec3,
material: &'a dyn Material,
(u, v): (f64, f64),
) -> Self {
Self {
t,
p,
normal,
material,
u,
v,
front_face: false,
}
}
pub fn set_face_normal(&mut self, ray: &Ray) {
self.front_face = ray.direction.dot(&self.normal) < 0.0;
self.normal = if self.front_face {
self.normal
} else {
-self.normal
}
}
}
pub trait Hitable {
fn hit(&self, _ray: &Ray, _t_min: f64, _t_max: f64) -> Option<HitRecord>;
fn bounding_box(&self, _t0: f64, _t1: f64) -> Option<Aabb>;
}
impl<T: Hitable + ?Sized> Hitable for Arc<T> {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
self.as_ref().hit(ray, t_min, t_max)
}
fn bounding_box(&self, t0: f64, t1: f64) -> Option<Aabb> {
self.as_ref().bounding_box(t0, t1)
}
}
pub struct Translate<T> {
object: T,
offset: Vec3,
}
impl<T> Translate<T> {
pub fn new(object: T, offset: Vec3) -> Self {
Self { object, offset }
}
}
impl<T: Hitable> Hitable for Translate<T> {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
let moved_ray = Ray::new(ray.origin - self.offset, ray.direction, ray.time());
if let Some(mut hit) = self.object.hit(&moved_ray, t_min, t_max) {
hit.p += self.offset;
hit.set_face_normal(&moved_ray);
Some(hit)
} else {
None
}
}
fn bounding_box(&self, t0: f64, t1: f64) -> Option<Aabb> {
if let Some(bbox) = self.object.bounding_box(t0, t1) {
Some(Aabb::new(bbox.min + self.offset, bbox.max + self.offset))
} else {
None
}
}
}

View File

@ -1,7 +1,116 @@
pub mod bvh;
pub mod hitable;
pub mod hitable_list;
mod rotate;
pub mod shapes;
mod translate;
pub use bvh::*;
pub use hitable::*;
pub use translate::*;
use std::sync::Arc;
use crate::{
hitable::rotate::Rotate,
types::{Ray, Vec3},
Aabb, Material, X, Y, Z,
};
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,
/// 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,
/// unit outward facing normal
pub normal: Vec3,
/// material if any of the surface
pub material: &'a dyn Material,
/// texture coordinates for an object
pub u: f64,
pub v: f64,
pub front_face: bool,
}
impl<'a> HitRecord<'a> {
pub fn new(
t: f64,
p: Vec3,
normal: Vec3,
material: &'a dyn Material,
(u, v): (f64, f64),
) -> Self {
Self {
t,
p,
normal,
material,
u,
v,
front_face: false,
}
}
pub fn set_face_normal(&mut self, ray: &Ray) {
self.front_face = ray.direction.dot(&self.normal) < 0.0;
self.normal = if self.front_face {
self.normal
} else {
-self.normal
}
}
}
pub trait Hitable {
fn hit(&self, _ray: &Ray, _t_min: f64, _t_max: f64) -> Option<HitRecord>;
fn bounding_box(&self, _t0: f64, _t1: f64) -> Option<Aabb>;
fn translate(self, offset: impl Into<Vec3>) -> Translate<Self>
where
Self: Sized,
{
Translate::new(self, offset.into())
}
fn rotate_x(self, angle: f64) -> Rotate<X, Y, Z, Self>
where
Self: Sized,
{
Rotate::new(self, angle)
}
fn rotate_y(self, angle: f64) -> Rotate<Y, X, Z, Self>
where
Self: Sized,
{
Rotate::new(self, angle)
}
fn rotate_z(self, angle: f64) -> Rotate<Z, Y, X, Self>
where
Self: Sized,
{
Rotate::new(self, angle)
}
}
impl<T: Hitable + ?Sized> Hitable for Arc<T> {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
self.as_ref().hit(ray, t_min, t_max)
}
fn bounding_box(&self, t0: f64, t1: f64) -> Option<Aabb> {
self.as_ref().bounding_box(t0, t1)
}
}

130
src/hitable/rotate.rs Normal file
View File

@ -0,0 +1,130 @@
use std::marker::PhantomData;
use crate::{
hitable::{HitRecord, Hitable},
types::{Ray, Vec3},
Aabb, Dimension, X, Y, Z,
};
pub struct Rotate<D1, D2, D3, T: Hitable> {
hitable: T,
sin_theta: f64,
cos_theta: f64,
bbox: Option<Aabb>,
_tag: PhantomData<(D1, D2, D3)>,
}
impl<D1, D2, D3, T> Rotate<D1, D2, D3, T>
where
D1: Dimension,
D2: Dimension,
D3: Dimension,
T: Hitable,
{
pub fn new(object: T, angle: f64) -> Rotate<D1, D2, D3, T> {
let radians = angle.to_radians();
let sin_theta = radians.sin();
let cos_theta = radians.cos();
let mut min = Vec3::splat(f64::MAX);
let mut max = Vec3::splat(-f64::MAX);
let bbox = if let Some(bbox) = object.bounding_box(0.0, 1.0) {
for i in 0..2 {
let i = i as f64;
for j in 0..2 {
let j = j as f64;
for k in 0..2 {
let k = k as f64;
// D1 will be the axis about which we are rotating
let d1 = i * bbox.max.get::<D1>() + (1.0 - i) * bbox.min.get::<D1>();
let d2 = j * bbox.max.get::<D2>() + (1.0 - j) * bbox.min.get::<D2>();
let d3 = k * bbox.max.get::<D3>() + (1.0 - k) * bbox.min.get::<D3>();
let new_d2 = cos_theta * d2 + sin_theta * d3;
let new_d3 = -sin_theta * d2 + cos_theta * d3;
let tester = Vec3::splat(0.0)
.set::<D1>(d1)
.set::<D2>(new_d2)
.set::<D3>(new_d3);
min = Vec3::min(tester, min);
max = Vec3::max(tester, max);
}
}
}
Aabb::new(min, max)
} else {
Aabb::new(min, max)
};
Rotate {
hitable: object,
sin_theta,
cos_theta,
bbox: Some(bbox),
_tag: PhantomData,
}
}
}
impl<D1, D2, D3, T> Hitable for Rotate<D1, D2, D3, T>
where
D1: Dimension,
D2: Dimension,
D3: Dimension,
T: Hitable,
{
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
let origin = ray
.origin
.set::<D2>(
self.cos_theta * ray.origin.get::<D2>() - self.sin_theta * ray.origin.get::<D3>(),
)
.set::<D3>(
self.sin_theta * ray.origin.get::<D2>() + self.cos_theta * ray.origin.get::<D3>(),
);
let direction = ray
.direction
.set::<D2>(
self.cos_theta * ray.direction.get::<D2>()
- self.sin_theta * ray.direction.get::<D3>(),
)
.set::<D3>(
self.sin_theta * ray.direction.get::<D2>()
+ self.cos_theta * ray.direction.get::<D3>(),
);
let rotated_ray = Ray::new(origin, direction, ray.time());
let mut hit = self.hitable.hit(&rotated_ray, t_min, t_max)?;
hit.p = hit
.p
.set::<D2>(self.cos_theta * hit.p.get::<D2>() + self.sin_theta * hit.p.get::<D3>())
.set::<D3>(-self.sin_theta * hit.p.get::<D2>() + self.cos_theta * hit.p.get::<D3>());
hit.normal = hit
.normal
.set::<D2>(
self.cos_theta * hit.normal.get::<D2>() + self.sin_theta * hit.normal.get::<D3>(),
)
.set::<D3>(
-self.sin_theta * hit.normal.get::<D2>() + self.cos_theta * hit.normal.get::<D3>(),
);
hit.set_face_normal(&rotated_ray);
Some(hit)
}
fn bounding_box(&self, _t0: f64, _t1: f64) -> Option<Aabb> {
self.bbox
}
}

37
src/hitable/translate.rs Normal file
View File

@ -0,0 +1,37 @@
use crate::{
hitable::{HitRecord, Hitable},
types::{Ray, Vec3},
Aabb,
};
pub struct Translate<T> {
object: T,
offset: Vec3,
}
impl<T> Translate<T> {
pub const fn new(object: T, offset: Vec3) -> Self {
Self { object, offset }
}
}
impl<T: Hitable> Hitable for Translate<T> {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
let moved_ray = Ray::new(ray.origin - self.offset, ray.direction, ray.time());
if let Some(mut hit) = self.object.hit(&moved_ray, t_min, t_max) {
hit.p += self.offset;
hit.set_face_normal(&moved_ray);
Some(hit)
} else {
None
}
}
fn bounding_box(&self, t0: f64, t1: f64) -> Option<Aabb> {
self.object
.bounding_box(t0, t1)
.map(|bbox| Aabb::new(bbox.min + self.offset, bbox.max + self.offset))
}
}

View File

@ -66,7 +66,7 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
.create_texture_static(PixelFormatEnum::BGR888, width as u32, height as u32)
.map_err(|e| e.to_string())?;
let mut active_demo: &dyn Demo<DemoT = BvhNode<Arc<dyn ParallelHit>>> = &demos::CornellBox {};
let mut active_demo: &dyn Demo<DemoT = BvhNode<Arc<dyn ParallelHit>>> = &demos::Instances {};
let mut should_update = true;
loop {
@ -104,7 +104,7 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
should_update = true;
}
Some(Keycode::Num6) => {
active_demo = &demos::CornellBox {};
active_demo = &demos::Instances {};
should_update = true;
}
None => unreachable!(),