Implement DiffuseLight material.
Allow Scenes to define global_illumination so scenes without lighting can continue to work.
This commit is contained in:
parent
34ce373269
commit
9c5233e057
@ -8,6 +8,7 @@ pub mod material;
|
||||
pub mod moving_sphere;
|
||||
pub mod perlin;
|
||||
pub mod ray;
|
||||
pub mod rect;
|
||||
pub mod renderer;
|
||||
pub mod scenes;
|
||||
pub mod sphere;
|
||||
|
||||
@ -31,6 +31,9 @@ pub struct ScatterResponse {
|
||||
|
||||
pub trait Material: Send + Sync {
|
||||
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse;
|
||||
fn emitted(&self, _u: f32, _v: f32, _p: Vec3) -> Vec3 {
|
||||
Vec3::new(0., 0., 0.)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Lambertian {
|
||||
@ -149,3 +152,27 @@ impl Material for Dielectric {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiffuseLight {
|
||||
emit: Box<Texture>,
|
||||
}
|
||||
|
||||
impl DiffuseLight {
|
||||
pub fn new(emit: Box<Texture>) -> DiffuseLight {
|
||||
DiffuseLight { emit }
|
||||
}
|
||||
}
|
||||
|
||||
impl Material for DiffuseLight {
|
||||
fn scatter(&self, _r_in: &Ray, _rec: &HitRecord) -> ScatterResponse {
|
||||
ScatterResponse {
|
||||
scattered: Default::default(),
|
||||
attenutation: Default::default(),
|
||||
reflected: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn emitted(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
|
||||
self.emit.value(u, v, p)
|
||||
}
|
||||
}
|
||||
|
||||
58
rtiow/src/rect.rs
Normal file
58
rtiow/src/rect.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use aabb::AABB;
|
||||
use hitable::Hit;
|
||||
use hitable::HitRecord;
|
||||
use material::Material;
|
||||
use ray::Ray;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub struct XYRect {
|
||||
x0: f32,
|
||||
x1: f32,
|
||||
y0: f32,
|
||||
y1: f32,
|
||||
k: f32,
|
||||
material: Box<Material>,
|
||||
}
|
||||
|
||||
impl XYRect {
|
||||
pub fn new(x0: f32, x1: f32, y0: f32, y1: f32, k: f32, material: Box<Material>) -> XYRect {
|
||||
XYRect {
|
||||
x0,
|
||||
x1,
|
||||
y0,
|
||||
y1,
|
||||
k,
|
||||
material,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hit for XYRect {
|
||||
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
let t = (self.k - r.origin.z) / r.direction.z;
|
||||
if t < t_min || t > t_max {
|
||||
return None;
|
||||
}
|
||||
let x = r.origin.x + t * r.direction.x;
|
||||
let y = r.origin.y + t * r.direction.y;
|
||||
if x < self.x0 || x > self.x1 || y < self.y0 || y > self.y1 {
|
||||
return None;
|
||||
}
|
||||
let u = (x - self.x0) / (self.x1 - self.x0);
|
||||
let v = (y - self.y0) / (self.y1 - self.y0);
|
||||
Some(HitRecord {
|
||||
t,
|
||||
uv: (u, v),
|
||||
p: r.point_at_parameter(t),
|
||||
normal: Vec3::new(0., 0., 1.),
|
||||
material: &*self.material,
|
||||
})
|
||||
}
|
||||
|
||||
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
|
||||
Some(AABB::new(
|
||||
Vec3::new(self.x0, self.y0, self.k - 0.0001),
|
||||
Vec3::new(self.x1, self.y1, self.k + 0.0001),
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -96,21 +96,36 @@ pub struct Scene {
|
||||
pub subsamples: usize,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub global_illumination: bool,
|
||||
}
|
||||
|
||||
fn color(r: Ray, world: &Hit, depth: usize) -> Vec3 {
|
||||
// color will trace ray up to 50 bounces deep accumulating color as it goes. If
|
||||
// global_illumination is true, a default light background color is assumed and will light the
|
||||
// world. If false, it is expected the scene has emissive light sources.
|
||||
fn color(r: Ray, world: &Hit, depth: usize, global_illumination: bool) -> Vec3 {
|
||||
if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) {
|
||||
let (u, v) = rec.uv;
|
||||
let emitted = rec.material.emitted(u, v, rec.p);
|
||||
let scatter_response = rec.material.scatter(&r, &rec);
|
||||
if depth < 50 && scatter_response.reflected {
|
||||
return scatter_response.attenutation
|
||||
* color(scatter_response.scattered, world, depth + 1);
|
||||
return emitted + scatter_response.attenutation * color(
|
||||
scatter_response.scattered,
|
||||
world,
|
||||
depth + 1,
|
||||
global_illumination,
|
||||
);
|
||||
} else {
|
||||
return emitted;
|
||||
}
|
||||
return Default::default();
|
||||
}
|
||||
if global_illumination {
|
||||
// No hit, choose color from background.
|
||||
let unit_direction = r.direction.unit_vector();
|
||||
let t = 0.5 * (unit_direction.y + 1.);
|
||||
Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t
|
||||
return Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t;
|
||||
}
|
||||
// No global illumination, so background is black.
|
||||
Vec3::new(0., 0., 0.)
|
||||
}
|
||||
|
||||
fn trace_pixel(x: usize, y: usize, scene: &Scene) -> Vec3 {
|
||||
@ -118,7 +133,7 @@ fn trace_pixel(x: usize, y: usize, scene: &Scene) -> Vec3 {
|
||||
let u = (rng.gen_range::<f32>(0., 1.) + x as f32) / scene.width as f32;
|
||||
let v = (rng.gen_range::<f32>(0., 1.) + y as f32) / scene.height as f32;
|
||||
let ray = scene.camera.get_ray(u, v);
|
||||
color(ray, scene.world.as_ref(), 0)
|
||||
color(ray, scene.world.as_ref(), 0, scene.global_illumination)
|
||||
}
|
||||
|
||||
fn render_worker(
|
||||
|
||||
@ -73,5 +73,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
subsamples: opt.subsamples,
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
subsamples: opt.subsamples,
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -71,5 +71,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
subsamples: opt.subsamples,
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,9 @@ use camera::Camera;
|
||||
use hitable::Hit;
|
||||
use hitable_list::HitableList;
|
||||
use kdtree::KDTree;
|
||||
use material::DiffuseLight;
|
||||
use material::Lambertian;
|
||||
use rect::XYRect;
|
||||
use renderer::Opt;
|
||||
use renderer::Scene;
|
||||
use sphere::Sphere;
|
||||
@ -14,7 +16,7 @@ use texture::NoiseTexture;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub fn new(opt: &Opt) -> Scene {
|
||||
let lookfrom = Vec3::new(0., 5., 20.);
|
||||
let lookfrom = Vec3::new(30., 2., 0.);
|
||||
let lookat = Vec3::new(0., 1., 0.);
|
||||
let dist_to_focus = 10.0;
|
||||
let aperture = 0.0;
|
||||
@ -53,6 +55,26 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
// Box::new(Lambertian::new(ground_color)),
|
||||
Box::new(Lambertian::new(Box::new(NoiseTexture::with_scale(10.)))),
|
||||
)),
|
||||
Box::new(XYRect::new(
|
||||
0.,
|
||||
4.,
|
||||
0.,
|
||||
4.,
|
||||
-4.,
|
||||
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
|
||||
Vec3::new(4., 4., 4.),
|
||||
)))),
|
||||
)),
|
||||
Box::new(XYRect::new(
|
||||
0.,
|
||||
4.,
|
||||
0.,
|
||||
4.,
|
||||
4.,
|
||||
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
|
||||
Vec3::new(0., 4., 4.),
|
||||
)))),
|
||||
)),
|
||||
/*
|
||||
Box::new(Sphere::new(
|
||||
Vec3::new(0., 0., 0.),
|
||||
@ -90,5 +112,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
subsamples: opt.subsamples,
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,5 +76,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
subsamples: opt.subsamples,
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use image::RgbImage;
|
||||
|
||||
use perlin::turb;
|
||||
use perlin::GENERATOR;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub trait Texture: Send + Sync {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user