Add translated and rotated cuboids to cornell box scene.
Chose name 'cuboid' because 'box' is a module imported by the prelude in rust and makes things complicated.
This commit is contained in:
parent
f1fcbe7449
commit
7684bb2088
90
rtiow/src/cuboid.rs
Normal file
90
rtiow/src/cuboid.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use aabb::AABB;
|
||||
use flip_normals::FlipNormals;
|
||||
use hitable::Hit;
|
||||
use hitable::HitRecord;
|
||||
use hitable_list::HitableList;
|
||||
use material::Material;
|
||||
use ray::Ray;
|
||||
use rect::XYRect;
|
||||
use rect::XZRect;
|
||||
use rect::YZRect;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub struct Cuboid {
|
||||
p_min: Vec3,
|
||||
p_max: Vec3,
|
||||
walls: HitableList,
|
||||
}
|
||||
|
||||
impl Cuboid {
|
||||
pub fn new(p_min: Vec3, p_max: Vec3, material: Box<Material>) -> Cuboid {
|
||||
let material = Arc::new(material);
|
||||
|
||||
Cuboid {
|
||||
p_min,
|
||||
p_max,
|
||||
walls: HitableList::new(vec![
|
||||
Box::new(XYRect::new(
|
||||
p_min.x,
|
||||
p_max.x,
|
||||
p_min.y,
|
||||
p_max.y,
|
||||
p_max.z,
|
||||
Box::new(Arc::clone(&material)),
|
||||
)),
|
||||
Box::new(FlipNormals::new(Box::new(XYRect::new(
|
||||
p_min.x,
|
||||
p_max.x,
|
||||
p_min.y,
|
||||
p_max.y,
|
||||
p_min.z,
|
||||
Box::new(Arc::clone(&material)),
|
||||
)))),
|
||||
Box::new(XZRect::new(
|
||||
p_min.x,
|
||||
p_max.x,
|
||||
p_min.z,
|
||||
p_max.z,
|
||||
p_max.y,
|
||||
Box::new(Arc::clone(&material)),
|
||||
)),
|
||||
Box::new(FlipNormals::new(Box::new(XZRect::new(
|
||||
p_min.x,
|
||||
p_max.x,
|
||||
p_min.z,
|
||||
p_max.z,
|
||||
p_min.y,
|
||||
Box::new(Arc::clone(&material)),
|
||||
)))),
|
||||
Box::new(YZRect::new(
|
||||
p_min.y,
|
||||
p_max.y,
|
||||
p_min.z,
|
||||
p_max.z,
|
||||
p_max.x,
|
||||
Box::new(Arc::clone(&material)),
|
||||
)),
|
||||
Box::new(FlipNormals::new(Box::new(YZRect::new(
|
||||
p_min.y,
|
||||
p_max.y,
|
||||
p_min.z,
|
||||
p_max.z,
|
||||
p_min.x,
|
||||
Box::new(Arc::clone(&material)),
|
||||
)))),
|
||||
]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hit for Cuboid {
|
||||
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
self.walls.hit(r, t_min, t_max)
|
||||
}
|
||||
|
||||
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
|
||||
Some(AABB::new(self.p_min, self.p_max))
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
pub mod aabb;
|
||||
pub mod bvh;
|
||||
pub mod camera;
|
||||
pub mod cuboid;
|
||||
pub mod flip_normals;
|
||||
pub mod hitable;
|
||||
pub mod hitable_list;
|
||||
@ -11,9 +12,11 @@ pub mod perlin;
|
||||
pub mod ray;
|
||||
pub mod rect;
|
||||
pub mod renderer;
|
||||
pub mod rotate;
|
||||
pub mod scenes;
|
||||
pub mod sphere;
|
||||
pub mod texture;
|
||||
pub mod translate;
|
||||
pub mod vec3;
|
||||
|
||||
extern crate crossbeam_channel;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
extern crate rand;
|
||||
use self::rand::Rng;
|
||||
|
||||
@ -36,6 +38,15 @@ pub trait Material: Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
impl Material for Arc<Box<Material>> {
|
||||
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse {
|
||||
(**self).scatter(r_in, rec)
|
||||
}
|
||||
fn emitted(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
|
||||
(**self).emitted(u, v, p)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Lambertian {
|
||||
// TODO(wathiede): implement texture sharing via references
|
||||
albedo: Box<Texture>,
|
||||
|
||||
90
rtiow/src/rotate.rs
Normal file
90
rtiow/src/rotate.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use std::f32::consts::PI;
|
||||
use std::f32::MAX;
|
||||
use std::f32::MIN;
|
||||
|
||||
use aabb::AABB;
|
||||
use hitable::Hit;
|
||||
use hitable::HitRecord;
|
||||
use ray::Ray;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub struct RotateY {
|
||||
hitable: Box<Hit>,
|
||||
sin_theta: f32,
|
||||
cos_theta: f32,
|
||||
bbox: Option<AABB>,
|
||||
}
|
||||
|
||||
impl RotateY {
|
||||
pub fn new(hitable: Box<Hit>, angle: f32) -> RotateY {
|
||||
let radians = PI / 180. * angle;
|
||||
let sin_theta = radians.sin();
|
||||
let cos_theta = radians.cos();
|
||||
let mut min = vec![MAX, MAX, MAX];
|
||||
let mut max = vec![MIN, MIN, MIN];
|
||||
let bbox = hitable.bounding_box(0., 1.).unwrap();
|
||||
for i in 0..2 {
|
||||
for j in 0..2 {
|
||||
for k in 0..2 {
|
||||
let x = i as f32 * bbox.max().x + (1 - i) as f32 * bbox.min().x;
|
||||
let y = j as f32 * bbox.max().y + (1 - j) as f32 * bbox.min().y;
|
||||
let z = k as f32 * bbox.max().z + (1 - k) as f32 * bbox.min().z;
|
||||
let new_x = cos_theta * x + sin_theta * z;
|
||||
let new_z = -sin_theta * x + cos_theta * z;
|
||||
let tester = Vec3::new(new_x, y, new_z);
|
||||
for c in 0..3 {
|
||||
if tester[c] > max[c] {
|
||||
max[c] = tester[c];
|
||||
}
|
||||
if tester[c] < min[c] {
|
||||
min[c] = tester[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RotateY {
|
||||
hitable,
|
||||
sin_theta,
|
||||
cos_theta,
|
||||
bbox: Some(AABB::new(
|
||||
Vec3::new(min[0], min[1], min[2]),
|
||||
Vec3::new(max[0], max[1], max[2]),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hit for RotateY {
|
||||
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
let origin = Vec3::new(
|
||||
self.cos_theta * r.origin[0] - self.sin_theta * r.origin[2],
|
||||
r.origin.y,
|
||||
self.sin_theta * r.origin[0] + self.cos_theta * r.origin[2],
|
||||
);
|
||||
let direction = Vec3::new(
|
||||
self.cos_theta * r.direction[0] - self.sin_theta * r.direction[2],
|
||||
r.direction.y,
|
||||
self.sin_theta * r.direction[0] + self.cos_theta * r.direction[2],
|
||||
);
|
||||
let rotated_r = Ray::new(origin, direction, r.time);
|
||||
if let Some(rec) = self.hitable.hit(rotated_r, t_min, t_max) {
|
||||
let p = Vec3::new(
|
||||
self.cos_theta * rec.p[0] + self.sin_theta * rec.p[2],
|
||||
rec.p[1],
|
||||
-self.sin_theta * rec.p[0] + self.cos_theta * rec.p[2],
|
||||
);
|
||||
let normal = Vec3::new(
|
||||
self.cos_theta * rec.normal[0] + self.sin_theta * rec.normal[2],
|
||||
rec.normal[1],
|
||||
-self.sin_theta * rec.normal[0] + self.cos_theta * rec.normal[2],
|
||||
);
|
||||
return Some(HitRecord { p, normal, ..rec });
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
|
||||
self.bbox.clone()
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
use camera::Camera;
|
||||
use cuboid::Cuboid;
|
||||
use flip_normals::FlipNormals;
|
||||
use hitable::Hit;
|
||||
use hitable_list::HitableList;
|
||||
@ -10,7 +11,9 @@ use rect::XZRect;
|
||||
use rect::YZRect;
|
||||
use renderer::Opt;
|
||||
use renderer::Scene;
|
||||
use rotate::RotateY;
|
||||
use texture::ConstantTexture;
|
||||
use translate::Translate;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub fn new(opt: &Opt) -> Scene {
|
||||
@ -33,6 +36,34 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
);
|
||||
|
||||
let objects: Vec<Box<Hit>> = vec![
|
||||
// Box1
|
||||
Box::new(Translate::new(
|
||||
Box::new(RotateY::new(
|
||||
Box::new(Cuboid::new(
|
||||
Vec3::new(0., 0., 0.),
|
||||
Vec3::new(165., 165., 165.),
|
||||
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
|
||||
0.73, 0.73, 0.73,
|
||||
))))),
|
||||
)),
|
||||
-18.,
|
||||
)),
|
||||
Vec3::new(100., 0., 0.),
|
||||
)),
|
||||
// Box2
|
||||
Box::new(Translate::new(
|
||||
Box::new(RotateY::new(
|
||||
Box::new(Cuboid::new(
|
||||
Vec3::new(0., 0., 0.),
|
||||
Vec3::new(165., 330., 165.),
|
||||
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
|
||||
0.73, 0.73, 0.73,
|
||||
))))),
|
||||
)),
|
||||
15.,
|
||||
)),
|
||||
Vec3::new(265., 0., 295.),
|
||||
)),
|
||||
// Green wall left
|
||||
Box::new(FlipNormals::new(Box::new(YZRect::new(
|
||||
0.,
|
||||
|
||||
39
rtiow/src/translate.rs
Normal file
39
rtiow/src/translate.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use aabb::AABB;
|
||||
use hitable::Hit;
|
||||
use hitable::HitRecord;
|
||||
use ray::Ray;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub struct Translate {
|
||||
hitable: Box<Hit>,
|
||||
offset: Vec3,
|
||||
}
|
||||
|
||||
impl Translate {
|
||||
pub fn new(hitable: Box<Hit>, offset: Vec3) -> Translate {
|
||||
Translate { hitable, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hit for Translate {
|
||||
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
let moved_r = Ray::new(r.origin - self.offset, r.direction, r.time);
|
||||
if let Some(rec) = self.hitable.hit(moved_r, t_min, t_max) {
|
||||
return Some(HitRecord {
|
||||
p: rec.p + self.offset,
|
||||
..rec
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
|
||||
if let Some(bbox) = self.hitable.bounding_box(t_min, t_max) {
|
||||
return Some(AABB::new(
|
||||
bbox.min() + self.offset,
|
||||
bbox.max() + self.offset,
|
||||
));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user