Added new scene, added pdf in lambertian material
This commit is contained in:
parent
96e103ee61
commit
f645eb4f00
|
@ -1,19 +1,16 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rand::{prelude::SmallRng, Rng, SeedableRng};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
demos::Demo,
|
demos::Demo,
|
||||||
hitable::{
|
hitable::{
|
||||||
hitable_list::HitableList,
|
hitable_list::HitableList,
|
||||||
shapes::{Cuboid, MovingSphere, RectBuilder, Sphere},
|
shapes::{Cuboid, RectBuilder, Sphere},
|
||||||
volume::ConstantMedium,
|
|
||||||
Hitable,
|
Hitable,
|
||||||
},
|
},
|
||||||
materials::{Dielectric, DiffuseLight, Isotropic, Lambertian, MaterialBuilder, Metal},
|
materials::{DiffuseLight, Lambertian, MaterialBuilder, Metal},
|
||||||
texture::{ImageTexture, PerlinNoise, Solid},
|
texture::Solid,
|
||||||
types::Vec3,
|
types::Vec3,
|
||||||
BvhNode, Camera,
|
Camera,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CornellBox {}
|
pub struct CornellBox {}
|
||||||
|
@ -26,125 +23,79 @@ impl Demo for CornellBox {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn world(&self) -> Self::DemoT {
|
fn world(&self) -> Self::DemoT {
|
||||||
let mut rng = rand::thread_rng();
|
let red = Lambertian::new(Solid::new(Vec3::new(0.65, 0.05, 0.05)));
|
||||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
let white = Lambertian::new(Solid::new(Vec3::new(0.73, 0.73, 0.73)));
|
||||||
|
let green = Lambertian::new(Solid::new(Vec3::new(0.12, 0.45, 0.15)));
|
||||||
let mut ground_boxes = HitableList { list: Vec::new() };
|
let light = DiffuseLight::new(Solid::new(Vec3::splat(15)));
|
||||||
let ground = Lambertian::new(Solid::new(Vec3::new(0.48, 0.83, 0.53)));
|
|
||||||
|
|
||||||
for i in 0..20 {
|
|
||||||
let i = i as f64;
|
|
||||||
for j in 0..20 {
|
|
||||||
let j = j as f64;
|
|
||||||
|
|
||||||
let w = 100.0;
|
|
||||||
let x0 = -1000.0 + i * w;
|
|
||||||
let z0 = -1000.0 + j * w;
|
|
||||||
let y0 = 0.0;
|
|
||||||
|
|
||||||
let x1 = x0 + w;
|
|
||||||
let y1 = rng.gen_range(1.0..=101.0);
|
|
||||||
let z1 = z0 + w;
|
|
||||||
|
|
||||||
ground_boxes.push(Arc::new(Cuboid::new(
|
|
||||||
Vec3::new(x0, y0, z0),
|
|
||||||
Vec3::new(x1, y1, z1),
|
|
||||||
ground.clone(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut objects = HitableList { list: Vec::new() };
|
let mut objects = HitableList { list: Vec::new() };
|
||||||
objects.push(Arc::new(BvhNode::new(
|
|
||||||
&mut rng,
|
|
||||||
&mut ground_boxes.list,
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
)));
|
|
||||||
|
|
||||||
let light = DiffuseLight::new(Solid::new(Vec3::splat(7.0)));
|
|
||||||
objects.push(Arc::new(
|
objects.push(Arc::new(
|
||||||
RectBuilder
|
RectBuilder
|
||||||
.x(123.0..=423.0)
|
.y(0.0..=555.0)
|
||||||
.z(147.0..=412.0)
|
.z(0.0..=555.0)
|
||||||
|
.x(555.0)
|
||||||
|
.material(green),
|
||||||
|
));
|
||||||
|
objects.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.y(0.0..=555.0)
|
||||||
|
.z(0.0..=555.0)
|
||||||
|
.x(0.0)
|
||||||
|
.material(red),
|
||||||
|
));
|
||||||
|
objects.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.x(213.0..=343.0)
|
||||||
|
.z(227.0..=332.0)
|
||||||
.y(554.0)
|
.y(554.0)
|
||||||
.material(light),
|
.material(light),
|
||||||
));
|
));
|
||||||
|
objects.push(Arc::new(
|
||||||
let center1 = Vec3::new(400.0, 400.0, 200.0);
|
RectBuilder
|
||||||
let center2 = center1 + Vec3::new(30.0, 0.0, 0.0);
|
.x(0.0..=555.0)
|
||||||
objects.push(Arc::new(MovingSphere::new(
|
.z(0.0..=555.0)
|
||||||
center1,
|
.y(555.0)
|
||||||
center2,
|
.material(white.clone()),
|
||||||
0.0,
|
));
|
||||||
1.0,
|
objects.push(Arc::new(
|
||||||
50.0,
|
RectBuilder
|
||||||
Lambertian::new(Solid::new(Vec3::new(0.7, 0.3, 0.1))),
|
.x(0.0..=555.0)
|
||||||
)));
|
.z(0.0..=555.0)
|
||||||
|
.y(0.0)
|
||||||
objects.push(Arc::new(Sphere::new(
|
.material(white.clone()),
|
||||||
Vec3::new(260.0, 150.0, 45.0),
|
));
|
||||||
50.0,
|
objects.push(Arc::new(
|
||||||
Dielectric::new(1.5),
|
RectBuilder
|
||||||
)));
|
.x(0.0..=555.0)
|
||||||
|
.y(0.0..=555.0)
|
||||||
objects.push(Arc::new(Sphere::new(
|
.z(555.0)
|
||||||
Vec3::new(0.0, 150.0, 145.0),
|
.material(white.clone()),
|
||||||
50.0,
|
));
|
||||||
Metal::with_fuzz(Vec3::new(0.8, 0.8, 0.9), 1.0),
|
|
||||||
)));
|
|
||||||
|
|
||||||
let boundary = Sphere::new(Vec3::new(360.0, 150.0, 145.0), 70.0, Dielectric::new(1.5));
|
|
||||||
objects.push(Arc::new(boundary.clone()));
|
|
||||||
objects.push(Arc::new(ConstantMedium::new(
|
|
||||||
boundary,
|
|
||||||
Isotropic::new(Solid::new(Vec3::new(0.2, 0.4, 0.9))),
|
|
||||||
0.2,
|
|
||||||
)));
|
|
||||||
|
|
||||||
objects.push(Arc::new(ConstantMedium::new(
|
|
||||||
Sphere::new(Vec3::splat(0.0), 5000.0, Dielectric::new(1.5)),
|
|
||||||
Isotropic::new(Solid::new(Vec3::splat(1.0))),
|
|
||||||
0.0001,
|
|
||||||
)));
|
|
||||||
|
|
||||||
let earthmap = ImageTexture::from_filename("assets/earthmap.jpg")
|
|
||||||
.expect("error in reading assets/earthmap.jpg");
|
|
||||||
objects.push(Arc::new(Sphere::new(
|
|
||||||
Vec3::new(400.0, 200.0, 400.0),
|
|
||||||
100.0,
|
|
||||||
Lambertian::new(earthmap),
|
|
||||||
)));
|
|
||||||
|
|
||||||
objects.push(Arc::new(Sphere::new(
|
|
||||||
Vec3::new(220.0, 280.0, 300.0),
|
|
||||||
80.0,
|
|
||||||
Lambertian::new(PerlinNoise::with_scale(&mut rng, 0.1)),
|
|
||||||
)));
|
|
||||||
|
|
||||||
let mut boxes2 = HitableList { list: Vec::new() };
|
|
||||||
let white = Lambertian::new(Solid::new(Vec3::splat(0.73)));
|
|
||||||
for _ in 0..1000 {
|
|
||||||
boxes2.push(Arc::new(Sphere::new(
|
|
||||||
Vec3::random_in_range(&mut rng, 0.0..=165.0),
|
|
||||||
10.0,
|
|
||||||
white.clone(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
objects.push(Arc::new(
|
objects.push(Arc::new(
|
||||||
BvhNode::new(&mut rng, &mut boxes2.list, 0.0, 1.0)
|
Cuboid::new(
|
||||||
|
Vec3::splat(0.0),
|
||||||
|
Vec3::new(165.0, 330.0, 165.0),
|
||||||
|
white.clone(),
|
||||||
|
)
|
||||||
.rotate_y(15.0)
|
.rotate_y(15.0)
|
||||||
.translate(Vec3::new(-100.0, 270.0, 395.0)),
|
.translate(Vec3::new(265.0, 0.0, 295.0)),
|
||||||
|
));
|
||||||
|
|
||||||
|
objects.push(Arc::new(
|
||||||
|
Cuboid::new(Vec3::splat(0.0), Vec3::splat(165.0), white)
|
||||||
|
.rotate_y(-18.0)
|
||||||
|
.translate(Vec3::new(130.0, 0.0, 65.0)),
|
||||||
));
|
));
|
||||||
|
|
||||||
objects
|
objects
|
||||||
}
|
}
|
||||||
|
|
||||||
fn camera(&self, aspect_ratio: f64) -> Camera {
|
fn camera(&self, aspect_ratio: f64) -> Camera {
|
||||||
let lookfrom = Vec3::new(478.0, 278.0, -600.0);
|
let lookfrom = Vec3::new(278.0, 278.0, -800.0);
|
||||||
let lookat = Vec3::new(278.0, 278.0, 0.0);
|
let lookat = Vec3::new(278.0, 278.0, 0.0);
|
||||||
let aperture = 0.1;
|
let aperture = 0.0;
|
||||||
let focus_distance = 40.0;
|
let focus_distance = 40.0;
|
||||||
Camera::new(
|
Camera::new(
|
||||||
lookfrom,
|
lookfrom,
|
||||||
|
|
|
@ -137,6 +137,8 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
||||||
}
|
}
|
||||||
if should_update {
|
if should_update {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
// TODO(ishan): Update it to only re-render if height/width has changed
|
||||||
|
// this block should run if the app was sent to background
|
||||||
active_demo.render(&mut buffer, width, height, NUM_SAMPLES);
|
active_demo.render(&mut buffer, width, height, NUM_SAMPLES);
|
||||||
println!(
|
println!(
|
||||||
"Demo {} Time Taken(s) = {}",
|
"Demo {} Time Taken(s) = {}",
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl Material for Dielectric {
|
||||||
ray_in: &Ray,
|
ray_in: &Ray,
|
||||||
hit_rec: &HitRecord,
|
hit_rec: &HitRecord,
|
||||||
rng: &mut SmallRng,
|
rng: &mut SmallRng,
|
||||||
) -> (Vec3, Option<Ray>) {
|
) -> (Vec3, f64, Option<Ray>) {
|
||||||
// Glass absorbs nothing! So, Attenuation is always going to be 1.0 for this
|
// Glass absorbs nothing! So, Attenuation is always going to be 1.0 for this
|
||||||
let attenuation = Vec3::splat(1.0);
|
let attenuation = Vec3::splat(1.0);
|
||||||
|
|
||||||
|
@ -44,17 +44,20 @@ impl Material for Dielectric {
|
||||||
let direction = reflect(unit_direction, hit_rec.normal);
|
let direction = reflect(unit_direction, hit_rec.normal);
|
||||||
(
|
(
|
||||||
attenuation,
|
attenuation,
|
||||||
|
0.0,
|
||||||
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
||||||
)
|
)
|
||||||
} else if let Some(direction) = refract(unit_direction, hit_rec.normal, refraction_ratio) {
|
} else if let Some(direction) = refract(unit_direction, hit_rec.normal, refraction_ratio) {
|
||||||
(
|
(
|
||||||
attenuation,
|
attenuation,
|
||||||
|
0.0,
|
||||||
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let direction = reflect(unit_direction, hit_rec.normal);
|
let direction = reflect(unit_direction, hit_rec.normal);
|
||||||
(
|
(
|
||||||
attenuation,
|
attenuation,
|
||||||
|
0.0,
|
||||||
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,15 @@ impl<T: Texture> Isotropic<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Texture + Send + Sync> Material for Isotropic<T> {
|
impl<T: Texture + Send + Sync> Material for Isotropic<T> {
|
||||||
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord, rng: &mut SmallRng) -> (Vec3, Option<Ray>) {
|
fn scatter(
|
||||||
|
&self,
|
||||||
|
ray: &Ray,
|
||||||
|
hit_rec: &HitRecord,
|
||||||
|
rng: &mut SmallRng,
|
||||||
|
) -> (Vec3, f64, Option<Ray>) {
|
||||||
(
|
(
|
||||||
self.texture.value(hit_rec.u, hit_rec.v, hit_rec.p),
|
self.texture.value(hit_rec.u, hit_rec.v, hit_rec.p),
|
||||||
|
0.0,
|
||||||
Some(Ray::new(
|
Some(Ray::new(
|
||||||
hit_rec.p,
|
hit_rec.p,
|
||||||
random_point_in_unit_sphere(rng),
|
random_point_in_unit_sphere(rng),
|
||||||
|
|
|
@ -2,7 +2,7 @@ use rand::prelude::SmallRng;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hitable::HitRecord,
|
hitable::HitRecord,
|
||||||
materials::random_point_in_unit_sphere,
|
materials::{random_point_in_unit_hemisphere, random_point_in_unit_sphere},
|
||||||
types::{Ray, Vec3},
|
types::{Ray, Vec3},
|
||||||
Material, Texture,
|
Material, Texture,
|
||||||
};
|
};
|
||||||
|
@ -19,13 +19,29 @@ impl<T: Texture> Lambertian<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Texture + Send + Sync> Material for Lambertian<T> {
|
impl<T: Texture + Send + Sync> Material for Lambertian<T> {
|
||||||
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord, rng: &mut SmallRng) -> (Vec3, Option<Ray>) {
|
fn scatter(
|
||||||
let scatter_direction = hit_rec.normal + random_point_in_unit_sphere(rng);
|
&self,
|
||||||
let scattered_ray = Ray::new(hit_rec.p, scatter_direction, ray.time());
|
ray: &Ray,
|
||||||
|
hit_rec: &HitRecord,
|
||||||
|
rng: &mut SmallRng,
|
||||||
|
) -> (Vec3, f64, Option<Ray>) {
|
||||||
|
let direction = random_point_in_unit_hemisphere(rng, &hit_rec.normal);
|
||||||
|
|
||||||
|
let scattered_ray = Ray::new(hit_rec.p, direction.unit_vector(), ray.time());
|
||||||
(
|
(
|
||||||
self.albedo.value(hit_rec.u, hit_rec.v, hit_rec.p),
|
self.albedo.value(hit_rec.u, hit_rec.v, hit_rec.p),
|
||||||
|
0.5 / std::f64::consts::PI,
|
||||||
Some(scattered_ray),
|
Some(scattered_ray),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scatter_pdf(&self, _ray: &Ray, hit_rec: &HitRecord, scatterd: &Ray) -> f64 {
|
||||||
|
let cosine: f64 = hit_rec.normal.dot(&scatterd.direction.unit_vector());
|
||||||
|
|
||||||
|
if cosine < 0.0 {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
cosine / std::f64::consts::PI
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl Material for Metal {
|
||||||
ray_in: &Ray,
|
ray_in: &Ray,
|
||||||
hit_rec: &HitRecord,
|
hit_rec: &HitRecord,
|
||||||
rng: &mut SmallRng,
|
rng: &mut SmallRng,
|
||||||
) -> (Vec3, Option<Ray>) {
|
) -> (Vec3, f64, Option<Ray>) {
|
||||||
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(
|
let scattered_ray = Ray::new(
|
||||||
hit_rec.p,
|
hit_rec.p,
|
||||||
|
@ -38,9 +38,9 @@ impl Material for Metal {
|
||||||
);
|
);
|
||||||
|
|
||||||
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, 0.0, Some(scattered_ray))
|
||||||
} else {
|
} else {
|
||||||
(self.albedo, None)
|
(self.albedo, 0.0, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,12 @@ pub trait Material: Send + Sync {
|
||||||
_ray: &Ray,
|
_ray: &Ray,
|
||||||
_hit_rec: &HitRecord,
|
_hit_rec: &HitRecord,
|
||||||
_rng: &mut SmallRng,
|
_rng: &mut SmallRng,
|
||||||
) -> (Vec3, Option<Ray>) {
|
) -> (Vec3, f64, Option<Ray>) {
|
||||||
(Vec3::splat(0.0), None)
|
(Vec3::splat(0.0), 0.0, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scatter_pdf(&self, _ray: &Ray, _hit_rec: &HitRecord, _scattered: &Ray) -> f64 {
|
||||||
|
0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit(&self, _u: f64, _v: f64, _p: Vec3) -> Vec3 {
|
fn emit(&self, _u: f64, _v: f64, _p: Vec3) -> Vec3 {
|
||||||
|
@ -58,11 +62,41 @@ fn refract(incident: Vec3, normal: Vec3, ni_over_nt: f64) -> Option<Vec3> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_point_in_unit_sphere<R: Rng + ?Sized>(rng: &mut R) -> Vec3 {
|
fn random_point_in_unit_sphere<R: Rng + ?Sized>(rng: &mut R) -> Vec3 {
|
||||||
let mut point = Vec3::random(rng) * 2.0 - Vec3::splat(1.0);
|
let u: f64 = rng.gen();
|
||||||
while point.sq_len() >= 1.0 {
|
let v: f64 = rng.gen();
|
||||||
point = Vec3::random(rng) * 2.0 - Vec3::splat(1.0);
|
|
||||||
|
let theta = u * 2.0 * std::f64::consts::PI;
|
||||||
|
let phi = (2.0 * v - 1.0).acos();
|
||||||
|
|
||||||
|
let radius = rng.gen::<f64>().cbrt();
|
||||||
|
|
||||||
|
let x = radius * phi.sin() * theta.cos();
|
||||||
|
let y = radius * phi.sin() * theta.sin();
|
||||||
|
let z = radius * phi.cos();
|
||||||
|
|
||||||
|
Vec3::new(x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_point_in_unit_hemisphere<R: Rng + ?Sized>(rng: &mut R, normal: &Vec3) -> Vec3 {
|
||||||
|
let u: f64 = rng.gen();
|
||||||
|
let v: f64 = rng.gen();
|
||||||
|
|
||||||
|
let theta = u * 2.0 * std::f64::consts::PI;
|
||||||
|
let phi = (v.sqrt()).acos();
|
||||||
|
|
||||||
|
let radius = rng.gen::<f64>().cbrt();
|
||||||
|
|
||||||
|
let x = radius * phi.sin() * theta.cos();
|
||||||
|
let y = radius * phi.sin() * theta.sin();
|
||||||
|
let z = radius * phi.cos();
|
||||||
|
|
||||||
|
let point = Vec3::new(x, y, z);
|
||||||
|
|
||||||
|
if point.dot(normal) >= 0.0 {
|
||||||
point
|
point
|
||||||
|
} else {
|
||||||
|
-point
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MaterialBuilder<T> {
|
pub trait MaterialBuilder<T> {
|
||||||
|
|
|
@ -40,9 +40,14 @@ impl Ray {
|
||||||
let material = hit_rec.material;
|
let material = hit_rec.material;
|
||||||
let emitted_color = hit_rec.material.emit(hit_rec.u, hit_rec.v, hit_rec.p);
|
let emitted_color = hit_rec.material.emit(hit_rec.u, hit_rec.v, hit_rec.p);
|
||||||
|
|
||||||
if let (attenuation, Some(scattered_ray)) = material.scatter(self, &hit_rec, rng) {
|
if let (attenuation, pdf, Some(scattered_ray)) =
|
||||||
|
material.scatter(self, &hit_rec, rng)
|
||||||
|
{
|
||||||
emitted_color
|
emitted_color
|
||||||
+ attenuation * scattered_ray.color(world, rng, background, depth + 1)
|
+ attenuation
|
||||||
|
* material.scatter_pdf(self, &hit_rec, &scattered_ray)
|
||||||
|
* scattered_ray.color(world, rng, background, depth + 1)
|
||||||
|
/ pdf
|
||||||
} else {
|
} else {
|
||||||
emitted_color
|
emitted_color
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,11 @@ impl Vec3 {
|
||||||
self.get::<Z>()
|
self.get::<Z>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn abs(&self) -> Self {
|
||||||
|
Vec3::new(self.x().abs(), self.y().abs(), self.z().abs())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get<D: Dimension>(&self) -> f64 {
|
pub fn get<D: Dimension>(&self) -> f64 {
|
||||||
unsafe { self.0.extract_unchecked(D::INDEX) }
|
unsafe { self.0.extract_unchecked(D::INDEX) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user