Move Material to new module && TriangleBVH intersect && Seperate light and material
This commit is contained in:
parent
50d3874467
commit
b3fdef8837
18 changed files with 180 additions and 90 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -731,12 +731,21 @@ dependencies = [
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ray-tracing-material"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
"ray-tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ray-tracing-scene"
|
name = "ray-tracing-scene"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"ray-tracing-core",
|
"ray-tracing-core",
|
||||||
|
"ray-tracing-material",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [ "ray-tracing-core", "ray-tracing-image", "ray-tracing-scene"]
|
members = [ "ray-tracing-core", "ray-tracing-image", "ray-tracing-material", "ray-tracing-scene"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ impl AABB {
|
||||||
&& pos.z <= self.max.z
|
&& pos.z <= self.max.z
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intersect_ray(self, ray: Ray) -> Option<Float> {
|
pub fn intersect_ray(self, ray: Ray, min: Float, max: Float) -> Option<Float> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod aabb;
|
pub mod aabb;
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
pub mod light;
|
||||||
pub mod material;
|
pub mod material;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod ray;
|
pub mod ray;
|
||||||
|
|
@ -11,6 +12,7 @@ pub mod prelude {
|
||||||
pub type Float = f32;
|
pub type Float = f32;
|
||||||
pub use crate::aabb::AABB;
|
pub use crate::aabb::AABB;
|
||||||
pub use crate::color::Color;
|
pub use crate::color::Color;
|
||||||
|
pub use crate::light::Light;
|
||||||
pub use crate::material::Material;
|
pub use crate::material::Material;
|
||||||
pub use crate::math::*;
|
pub use crate::math::*;
|
||||||
pub use crate::ray::Ray;
|
pub use crate::ray::Ray;
|
||||||
|
|
|
||||||
26
ray-tracing-core/src/light.rs
Normal file
26
ray-tracing-core/src/light.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
pub trait Light<R: Rng>: Sync {
|
||||||
|
fn emit(&self, w_in: Dir3, rng: &mut R) -> Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AreaLight {
|
||||||
|
pub(crate) color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AreaLight {
|
||||||
|
pub fn new(color: Color) -> Self {
|
||||||
|
Self { color }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Rng> Light<R> for AreaLight {
|
||||||
|
fn emit(&self, w_in: Dir3, _rng: &mut R) -> Color {
|
||||||
|
if w_in.y() > 0.0 {
|
||||||
|
self.color
|
||||||
|
} else {
|
||||||
|
Color::black()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,52 +3,5 @@ use rand::Rng;
|
||||||
|
|
||||||
/// All calculations for the material are done a tangent space of the intersection.
|
/// All calculations for the material are done a tangent space of the intersection.
|
||||||
pub trait Material<R: Rng>: Sync {
|
pub trait Material<R: Rng>: Sync {
|
||||||
fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Option<Color> {
|
fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color;
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit(&self, w_in: Dir3, rng: &mut R) -> Option<Color> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DefaultMaterial {}
|
|
||||||
|
|
||||||
impl<R: Rng> Material<R> for DefaultMaterial {
|
|
||||||
// evaluates the bsdf
|
|
||||||
fn eval(&self, _w_in: Dir3, _w_out: Dir3, _rng: &mut R) -> Option<Color> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DiffuseMaterial {
|
|
||||||
color: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DiffuseMaterial {
|
|
||||||
pub fn new(color: Color) -> Self {
|
|
||||||
Self { color }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Rng> Material<R> for DiffuseMaterial {
|
|
||||||
fn eval(&self, _w_in: Dir3, _w_out: Dir3, _rng: &mut R) -> Option<Color> {
|
|
||||||
Some(self.color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AreaLight {
|
|
||||||
color: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AreaLight {
|
|
||||||
pub fn new(color: Color) -> Self {
|
|
||||||
Self { color }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Rng> Material<R> for AreaLight {
|
|
||||||
fn emit(&self, _w_in: Dir3, _rng: &mut R) -> Option<Color> {
|
|
||||||
Some(self.color)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,9 @@ mod test {
|
||||||
|
|
||||||
dbg!(f);
|
dbg!(f);
|
||||||
|
|
||||||
dbg!(f.to_world(Dir3::new(0.0, 1.0, 0.0)));
|
let t = dbg!(f.to_world(Dir3::new(1.0, 1.0, 1.0)));
|
||||||
|
|
||||||
|
dbg!(f.to_frame(t));
|
||||||
|
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,27 +50,25 @@ where
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
while let Some(i) = self.scene.intersect(r, 0.001, Float::INFINITY) {
|
while let Some(i) = self.scene.intersect(r, 0.001, Float::INFINITY) {
|
||||||
if count > 4 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let frame = i.tangent_frame();
|
let frame = i.tangent_frame();
|
||||||
let w_in = frame.to_frame(-r.dir());
|
let w_in = frame.to_frame(-r.dir());
|
||||||
let w_out = Dir3::generate_uniform_hemisphere(rng);
|
let w_out = Dir3::generate_uniform_hemisphere(rng);
|
||||||
|
|
||||||
let mat = i.material();
|
if let Some(light) = i.light() {
|
||||||
|
sum += alpha * light.emit(w_in, rng) * w_out.y();
|
||||||
if let Some(c) = mat.emit(w_in, rng) {
|
|
||||||
sum += alpha * c * w_out.y();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(c) = mat.eval(w_in, w_out, rng) {
|
if let Some(material) = i.material() {
|
||||||
alpha *= c;
|
alpha *= material.eval(w_in, w_out, rng) * w_out.y();
|
||||||
} else {
|
} else {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = Ray::new(r.at(i.t()), frame.to_world(w_out), r.time());
|
r = Ray::new(r.at(i.t()), frame.to_world(w_out), r.time());
|
||||||
count += 1;
|
count += 1;
|
||||||
|
if count > 4 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sum
|
sum
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,22 @@ pub trait Scene<R: Rng> {
|
||||||
pub struct Intersection<'sc, R: Rng> {
|
pub struct Intersection<'sc, R: Rng> {
|
||||||
t: Float,
|
t: Float,
|
||||||
normal: Dir3,
|
normal: Dir3,
|
||||||
material: &'sc dyn Material<R>,
|
material: Option<&'sc dyn Material<R>>,
|
||||||
|
light: Option<&'sc dyn Light<R>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'sc, R: Rng> Intersection<'sc, R> {
|
impl<'sc, R: Rng> Intersection<'sc, R> {
|
||||||
pub fn new(t: Float, normal: Dir3, material: &'sc dyn Material<R>) -> Self {
|
pub fn new(
|
||||||
|
t: Float,
|
||||||
|
normal: Dir3,
|
||||||
|
material: Option<&'sc dyn Material<R>>,
|
||||||
|
light: Option<&'sc dyn Light<R>>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
t,
|
t,
|
||||||
normal,
|
normal,
|
||||||
material,
|
material,
|
||||||
|
light,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,10 +35,14 @@ impl<'sc, R: Rng> Intersection<'sc, R> {
|
||||||
self.normal
|
self.normal
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn material(&self) -> &'sc dyn Material<R> {
|
pub fn material(&self) -> Option<&'sc dyn Material<R>> {
|
||||||
self.material
|
self.material
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn light(&self) -> Option<&'sc dyn Light<R>> {
|
||||||
|
self.light
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tangent_frame(&self) -> Frame {
|
pub fn tangent_frame(&self) -> Frame {
|
||||||
Frame::from_normal(self.normal)
|
Frame::from_normal(self.normal)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,9 @@ fn main() -> ImageResult<()> {
|
||||||
let s = cornel();
|
let s = cornel();
|
||||||
|
|
||||||
let c = BasicCamera::new(
|
let c = BasicCamera::new(
|
||||||
640,
|
|
||||||
400,
|
400,
|
||||||
Pos3::new(-10.0, 0.0, 0.0),
|
400,
|
||||||
|
Pos3::new(-6.0, 0.0, 0.0),
|
||||||
Dir3::new(1.0, 0.0, 0.0),
|
Dir3::new(1.0, 0.0, 0.0),
|
||||||
Dir3::up(),
|
Dir3::up(),
|
||||||
Float::to_radians(90.0),
|
Float::to_radians(90.0),
|
||||||
|
|
@ -49,5 +49,5 @@ fn main() -> ImageResult<()> {
|
||||||
|
|
||||||
let r = PathTracer::new(s, c);
|
let r = PathTracer::new(s, c);
|
||||||
|
|
||||||
render_image(r, "test.exr", 1024)
|
render_image(r, "test.exr", 1048)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
ray-tracing-material/Cargo.toml
Normal file
8
ray-tracing-material/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "ray-tracing-material"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.8.5"
|
||||||
|
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||||
11
ray-tracing-material/src/default.rs
Normal file
11
ray-tracing-material/src/default.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use rand::Rng;
|
||||||
|
use ray_tracing_core::prelude::*;
|
||||||
|
|
||||||
|
pub struct DefaultMaterial {}
|
||||||
|
|
||||||
|
impl<R: Rng> Material<R> for DefaultMaterial {
|
||||||
|
// evaluates the bsdf
|
||||||
|
fn eval(&self, _w_in: Dir3, _w_out: Dir3, _rng: &mut R) -> Color {
|
||||||
|
Color::black()
|
||||||
|
}
|
||||||
|
}
|
||||||
20
ray-tracing-material/src/diffuse.rs
Normal file
20
ray-tracing-material/src/diffuse.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use rand::Rng;
|
||||||
|
use ray_tracing_core::prelude::*;
|
||||||
|
|
||||||
|
pub struct DiffuseMaterial {
|
||||||
|
pub(crate) albedo: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiffuseMaterial {
|
||||||
|
pub fn new(color: Color) -> Self {
|
||||||
|
Self {
|
||||||
|
albedo: color * FloatConsts::FRAC_1_PI,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Rng> Material<R> for DiffuseMaterial {
|
||||||
|
fn eval(&self, _w_in: Dir3, _w_out: Dir3, _rng: &mut R) -> Color {
|
||||||
|
self.albedo
|
||||||
|
}
|
||||||
|
}
|
||||||
2
ray-tracing-material/src/lib.rs
Normal file
2
ray-tracing-material/src/lib.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod default;
|
||||||
|
pub mod diffuse;
|
||||||
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
ray-tracing-core = { path = "../ray-tracing-core" }
|
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||||
|
ray-tracing-material = { path = "../ray-tracing-material" }
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use ray_tracing_core::material::DefaultMaterial;
|
|
||||||
use ray_tracing_core::prelude::*;
|
use ray_tracing_core::prelude::*;
|
||||||
use ray_tracing_core::scene::{Intersection, Scene};
|
use ray_tracing_core::scene::{Intersection, Scene};
|
||||||
|
use ray_tracing_material::default::DefaultMaterial;
|
||||||
|
|
||||||
pub struct BasicScene {
|
pub struct BasicScene {
|
||||||
pub(crate) spheres: Vec<(Pos3, Float)>,
|
pub(crate) spheres: Vec<(Pos3, Float)>,
|
||||||
|
|
@ -30,7 +30,8 @@ impl<R: Rng> Scene<R> for BasicScene {
|
||||||
let int = Intersection::new(
|
let int = Intersection::new(
|
||||||
d,
|
d,
|
||||||
((ray.start() + d * ray.dir()) - c).normalize(),
|
((ray.start() + d * ray.dir()) - c).normalize(),
|
||||||
&DefaultMaterial {},
|
Some(&DefaultMaterial {}),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
if d >= min && d <= max {
|
if d >= min && d <= max {
|
||||||
if let Some(i) = intersection.as_ref() {
|
if let Some(i) = intersection.as_ref() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,2 @@
|
||||||
use rand::Rng;
|
|
||||||
use ray_tracing_core::material::DefaultMaterial;
|
|
||||||
use ray_tracing_core::prelude::*;
|
|
||||||
|
|
||||||
pub mod basic_scene;
|
pub mod basic_scene;
|
||||||
|
|
||||||
pub mod triangle_bvh;
|
pub mod triangle_bvh;
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,15 @@ type Index = u32;
|
||||||
pub struct TriangleBVH<R: Rng> {
|
pub struct TriangleBVH<R: Rng> {
|
||||||
vertices: Vec<Pos3>,
|
vertices: Vec<Pos3>,
|
||||||
triangles: Vec<Triangle>,
|
triangles: Vec<Triangle>,
|
||||||
materials: Vec<Box<dyn Material<R>>>,
|
materials: Vec<BVHMaterial<R>>,
|
||||||
bvh: Vec<Node>,
|
bvh: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BVHMaterial<R: Rng> {
|
||||||
|
material: Option<Box<dyn Material<R>>>,
|
||||||
|
light: Option<Box<dyn Light<R>>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum Node {
|
enum Node {
|
||||||
Inner {
|
Inner {
|
||||||
|
|
@ -53,7 +58,7 @@ fn triangle_intersection(ray: Ray, v: [Pos3; 3]) -> Option<Float> {
|
||||||
let inv_det = 1.0 / det;
|
let inv_det = 1.0 / det;
|
||||||
let s = ray.start() - v[0];
|
let s = ray.start() - v[0];
|
||||||
let u = inv_det * s.dot(ray_cross_e2);
|
let u = inv_det * s.dot(ray_cross_e2);
|
||||||
if u < 0.0 || u > 1.0 {
|
if !(0.0..=1.0).contains(&u) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,11 +87,7 @@ fn triangle_normal(v: [Pos3; 3]) -> Dir3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Rng> TriangleBVH<R> {
|
impl<R: Rng> TriangleBVH<R> {
|
||||||
fn new(
|
fn new(vertices: Vec<Pos3>, triangles: Vec<Triangle>, materials: Vec<BVHMaterial<R>>) -> Self {
|
||||||
vertices: Vec<Pos3>,
|
|
||||||
triangles: Vec<Triangle>,
|
|
||||||
materials: Vec<Box<dyn Material<R>>>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
vertices,
|
vertices,
|
||||||
bvh: vec![Node::Leaf {
|
bvh: vec![Node::Leaf {
|
||||||
|
|
@ -120,7 +121,40 @@ impl<R: Rng> TriangleBVH<R> {
|
||||||
left_aabb,
|
left_aabb,
|
||||||
right,
|
right,
|
||||||
right_aabb,
|
right_aabb,
|
||||||
} => todo!(),
|
} => {
|
||||||
|
let left_intersect = left_aabb.intersect_ray(ray, min, max);
|
||||||
|
let right_intersect = right_aabb.intersect_ray(ray, min, max);
|
||||||
|
|
||||||
|
match (left_intersect, right_intersect) {
|
||||||
|
(None, None) => None,
|
||||||
|
(None, Some(_)) => self.intersect_bvh(right, ray, min, max),
|
||||||
|
(Some(_), None) => self.intersect_bvh(left, ray, min, max),
|
||||||
|
(Some(l), Some(r)) => {
|
||||||
|
let close;
|
||||||
|
let far;
|
||||||
|
if l < r {
|
||||||
|
close = left;
|
||||||
|
far = right;
|
||||||
|
} else {
|
||||||
|
close = right;
|
||||||
|
far = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(close_intersect) = self.intersect_bvh(close, ray, min, max) {
|
||||||
|
if let Some(far_intersect) = self
|
||||||
|
.intersect_bvh(far, ray, min, Float::min(min, close_intersect.1))
|
||||||
|
.filter(|far_intersect| far_intersect.1 < close_intersect.1)
|
||||||
|
{
|
||||||
|
Some(far_intersect)
|
||||||
|
} else {
|
||||||
|
Some(close_intersect)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.intersect_bvh(far, ray, min, max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Node::Leaf { start, count } => {
|
Node::Leaf { start, count } => {
|
||||||
let mut intersection = None;
|
let mut intersection = None;
|
||||||
for i in start..(start + count) {
|
for i in start..(start + count) {
|
||||||
|
|
@ -148,19 +182,24 @@ impl<R: Rng> Scene<R> for TriangleBVH<R> {
|
||||||
let (i, t) = self.intersect_bvh(0, ray, min, max)?;
|
let (i, t) = self.intersect_bvh(0, ray, min, max)?;
|
||||||
|
|
||||||
let triangle = self.triangles[i as usize];
|
let triangle = self.triangles[i as usize];
|
||||||
let material = self.materials[triangle.material as usize].as_ref();
|
let material = &self.materials[triangle.material as usize];
|
||||||
|
|
||||||
let n = triangle_normal(self.get_vertices(i)).normalize();
|
let n = triangle_normal(self.get_vertices(i)).normalize();
|
||||||
|
|
||||||
Some(Intersection::new(t, n, material))
|
Some(Intersection::new(
|
||||||
|
t,
|
||||||
|
n,
|
||||||
|
material.material.as_deref(),
|
||||||
|
material.light.as_deref(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod examples {
|
pub mod examples {
|
||||||
use super::{Triangle, TriangleBVH};
|
use super::{BVHMaterial, Triangle, TriangleBVH};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use ray_tracing_core::material::{AreaLight, DiffuseMaterial};
|
use ray_tracing_core::{light::AreaLight, prelude::*};
|
||||||
use ray_tracing_core::prelude::*;
|
use ray_tracing_material::diffuse::DiffuseMaterial;
|
||||||
|
|
||||||
pub fn cornel<R: Rng>() -> TriangleBVH<R> {
|
pub fn cornel<R: Rng>() -> TriangleBVH<R> {
|
||||||
let side_length = 1.5;
|
let side_length = 1.5;
|
||||||
|
|
@ -196,10 +235,22 @@ pub mod examples {
|
||||||
Triangle::new([11, 9, 10], 3),
|
Triangle::new([11, 9, 10], 3),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Box::new(DiffuseMaterial::new(Color::new(0.8, 0.8, 0.8))),
|
BVHMaterial {
|
||||||
Box::new(DiffuseMaterial::new(Color::new(0.9, 0.0, 0.0))),
|
material: Some(Box::new(DiffuseMaterial::new(Color::new(0.8, 0.8, 0.8)))),
|
||||||
Box::new(DiffuseMaterial::new(Color::new(0.0, 0.9, 0.0))),
|
light: None,
|
||||||
Box::new(AreaLight::new(Color::new(5.0, 5.0, 5.0))),
|
},
|
||||||
|
BVHMaterial {
|
||||||
|
material: Some(Box::new(DiffuseMaterial::new(Color::new(0.9, 0.0, 0.0)))),
|
||||||
|
light: None,
|
||||||
|
},
|
||||||
|
BVHMaterial {
|
||||||
|
material: Some(Box::new(DiffuseMaterial::new(Color::new(0.0, 0.9, 0.0)))),
|
||||||
|
light: None,
|
||||||
|
},
|
||||||
|
BVHMaterial {
|
||||||
|
material: None,
|
||||||
|
light: Some(Box::new(AreaLight::new(Color::white() * 30.0))),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue