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 rand::{prelude::SmallRng, Rng, SeedableRng};
|
||||
|
||||
use crate::{
|
||||
demos::Demo,
|
||||
hitable::{
|
||||
hitable_list::HitableList,
|
||||
shapes::{Cuboid, MovingSphere, RectBuilder, Sphere},
|
||||
volume::ConstantMedium,
|
||||
shapes::{Cuboid, RectBuilder, Sphere},
|
||||
Hitable,
|
||||
},
|
||||
materials::{Dielectric, DiffuseLight, Isotropic, Lambertian, MaterialBuilder, Metal},
|
||||
texture::{ImageTexture, PerlinNoise, Solid},
|
||||
materials::{DiffuseLight, Lambertian, MaterialBuilder, Metal},
|
||||
texture::Solid,
|
||||
types::Vec3,
|
||||
BvhNode, Camera,
|
||||
Camera,
|
||||
};
|
||||
|
||||
pub struct CornellBox {}
|
||||
|
@ -26,125 +23,79 @@ impl Demo for CornellBox {
|
|||
}
|
||||
|
||||
fn world(&self) -> Self::DemoT {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
|
||||
let mut ground_boxes = HitableList { list: Vec::new() };
|
||||
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 red = Lambertian::new(Solid::new(Vec3::new(0.65, 0.05, 0.05)));
|
||||
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 light = DiffuseLight::new(Solid::new(Vec3::splat(15)));
|
||||
|
||||
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(
|
||||
RectBuilder
|
||||
.x(123.0..=423.0)
|
||||
.z(147.0..=412.0)
|
||||
.y(0.0..=555.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)
|
||||
.material(light),
|
||||
));
|
||||
|
||||
let center1 = Vec3::new(400.0, 400.0, 200.0);
|
||||
let center2 = center1 + Vec3::new(30.0, 0.0, 0.0);
|
||||
objects.push(Arc::new(MovingSphere::new(
|
||||
center1,
|
||||
center2,
|
||||
0.0,
|
||||
1.0,
|
||||
50.0,
|
||||
Lambertian::new(Solid::new(Vec3::new(0.7, 0.3, 0.1))),
|
||||
)));
|
||||
|
||||
objects.push(Arc::new(Sphere::new(
|
||||
Vec3::new(260.0, 150.0, 45.0),
|
||||
50.0,
|
||||
Dielectric::new(1.5),
|
||||
)));
|
||||
|
||||
objects.push(Arc::new(Sphere::new(
|
||||
Vec3::new(0.0, 150.0, 145.0),
|
||||
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(
|
||||
RectBuilder
|
||||
.x(0.0..=555.0)
|
||||
.z(0.0..=555.0)
|
||||
.y(555.0)
|
||||
.material(white.clone()),
|
||||
));
|
||||
objects.push(Arc::new(
|
||||
RectBuilder
|
||||
.x(0.0..=555.0)
|
||||
.z(0.0..=555.0)
|
||||
.y(0.0)
|
||||
.material(white.clone()),
|
||||
));
|
||||
objects.push(Arc::new(
|
||||
RectBuilder
|
||||
.x(0.0..=555.0)
|
||||
.y(0.0..=555.0)
|
||||
.z(555.0)
|
||||
.material(white.clone()),
|
||||
));
|
||||
|
||||
objects.push(Arc::new(
|
||||
BvhNode::new(&mut rng, &mut boxes2.list, 0.0, 1.0)
|
||||
.rotate_y(15.0)
|
||||
.translate(Vec3::new(-100.0, 270.0, 395.0)),
|
||||
Cuboid::new(
|
||||
Vec3::splat(0.0),
|
||||
Vec3::new(165.0, 330.0, 165.0),
|
||||
white.clone(),
|
||||
)
|
||||
.rotate_y(15.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
|
||||
}
|
||||
|
||||
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 aperture = 0.1;
|
||||
let aperture = 0.0;
|
||||
let focus_distance = 40.0;
|
||||
Camera::new(
|
||||
lookfrom,
|
||||
|
|
|
@ -137,6 +137,8 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
|||
}
|
||||
if should_update {
|
||||
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);
|
||||
println!(
|
||||
"Demo {} Time Taken(s) = {}",
|
||||
|
|
|
@ -24,7 +24,7 @@ impl Material for Dielectric {
|
|||
ray_in: &Ray,
|
||||
hit_rec: &HitRecord,
|
||||
rng: &mut SmallRng,
|
||||
) -> (Vec3, Option<Ray>) {
|
||||
) -> (Vec3, f64, Option<Ray>) {
|
||||
// Glass absorbs nothing! So, Attenuation is always going to be 1.0 for this
|
||||
let attenuation = Vec3::splat(1.0);
|
||||
|
||||
|
@ -44,17 +44,20 @@ impl Material for Dielectric {
|
|||
let direction = reflect(unit_direction, hit_rec.normal);
|
||||
(
|
||||
attenuation,
|
||||
0.0,
|
||||
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
||||
)
|
||||
} else if let Some(direction) = refract(unit_direction, hit_rec.normal, refraction_ratio) {
|
||||
(
|
||||
attenuation,
|
||||
0.0,
|
||||
Some(Ray::new(hit_rec.p, direction, ray_in.time())),
|
||||
)
|
||||
} else {
|
||||
let direction = reflect(unit_direction, hit_rec.normal);
|
||||
(
|
||||
attenuation,
|
||||
0.0,
|
||||
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> {
|
||||
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),
|
||||
0.0,
|
||||
Some(Ray::new(
|
||||
hit_rec.p,
|
||||
random_point_in_unit_sphere(rng),
|
||||
|
|
|
@ -2,7 +2,7 @@ use rand::prelude::SmallRng;
|
|||
|
||||
use crate::{
|
||||
hitable::HitRecord,
|
||||
materials::random_point_in_unit_sphere,
|
||||
materials::{random_point_in_unit_hemisphere, random_point_in_unit_sphere},
|
||||
types::{Ray, Vec3},
|
||||
Material, Texture,
|
||||
};
|
||||
|
@ -19,13 +19,29 @@ impl<T: Texture> 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>) {
|
||||
let scatter_direction = hit_rec.normal + random_point_in_unit_sphere(rng);
|
||||
let scattered_ray = Ray::new(hit_rec.p, scatter_direction, ray.time());
|
||||
fn scatter(
|
||||
&self,
|
||||
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),
|
||||
0.5 / std::f64::consts::PI,
|
||||
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,
|
||||
hit_rec: &HitRecord,
|
||||
rng: &mut SmallRng,
|
||||
) -> (Vec3, Option<Ray>) {
|
||||
) -> (Vec3, f64, Option<Ray>) {
|
||||
let reflected_ray = reflect(ray_in.direction.unit_vector(), hit_rec.normal);
|
||||
let scattered_ray = Ray::new(
|
||||
hit_rec.p,
|
||||
|
@ -38,9 +38,9 @@ impl Material for Metal {
|
|||
);
|
||||
|
||||
if scattered_ray.direction.dot(&hit_rec.normal) > 0.0 {
|
||||
(self.albedo, Some(scattered_ray))
|
||||
(self.albedo, 0.0, Some(scattered_ray))
|
||||
} else {
|
||||
(self.albedo, None)
|
||||
(self.albedo, 0.0, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,12 @@ pub trait Material: Send + Sync {
|
|||
_ray: &Ray,
|
||||
_hit_rec: &HitRecord,
|
||||
_rng: &mut SmallRng,
|
||||
) -> (Vec3, Option<Ray>) {
|
||||
(Vec3::splat(0.0), None)
|
||||
) -> (Vec3, f64, Option<Ray>) {
|
||||
(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 {
|
||||
|
@ -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 {
|
||||
let mut point = Vec3::random(rng) * 2.0 - Vec3::splat(1.0);
|
||||
while point.sq_len() >= 1.0 {
|
||||
point = Vec3::random(rng) * 2.0 - Vec3::splat(1.0);
|
||||
let u: f64 = rng.gen();
|
||||
let v: f64 = rng.gen();
|
||||
|
||||
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
|
||||
} else {
|
||||
-point
|
||||
}
|
||||
point
|
||||
}
|
||||
|
||||
pub trait MaterialBuilder<T> {
|
||||
|
|
|
@ -40,9 +40,14 @@ impl Ray {
|
|||
let material = hit_rec.material;
|
||||
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
|
||||
+ 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 {
|
||||
emitted_color
|
||||
}
|
||||
|
|
|
@ -47,6 +47,11 @@ impl Vec3 {
|
|||
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 {
|
||||
unsafe { self.0.extract_unchecked(D::INDEX) }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user