diff --git a/ray-tracing-pbrt-scene/src/either.rs b/ray-tracing-pbrt-scene/src/either.rs
index 1ee8cfa..a950439 100644
--- a/ray-tracing-pbrt-scene/src/either.rs
+++ b/ray-tracing-pbrt-scene/src/either.rs
@@ -17,6 +17,20 @@ impl Either {
Either::B(b) => Either::B(f(b)),
}
}
+
+ pub fn get_a(&self) -> Option<&A> {
+ match self {
+ Either::A(a) => Some(a),
+ Either::B(_) => None,
+ }
+ }
+
+ pub fn get_b(&self) -> Option<&B> {
+ match self {
+ Either::A(_) => None,
+ Either::B(b) => Some(b),
+ }
+ }
}
impl Either> {
diff --git a/ray-tracing-pbrt-scene/src/lib.rs b/ray-tracing-pbrt-scene/src/lib.rs
index 95d6e8b..a3b3f69 100644
--- a/ray-tracing-pbrt-scene/src/lib.rs
+++ b/ray-tracing-pbrt-scene/src/lib.rs
@@ -1,4 +1,5 @@
use crate::{
+ either::Either,
scene::PbrtScene,
shape::{Shape, ShapeAlpha, ShapeType},
tokenizer::{Token, Tokenizer},
@@ -8,6 +9,7 @@ use miette::{IntoDiagnostic, Result, bail, miette};
use ray_tracing_core::{
affine_transform::AffineTransform,
color::Color,
+ light::Light,
math::{Dir3, Pos3},
prelude::{Float, Rng},
};
@@ -83,6 +85,22 @@ enum Statement {
Material(Arc>),
MakeNamedMaterial(String, Arc>),
NamedMaterial(String),
+ AreaLight(AreaLight),
+}
+
+#[derive(Debug, Clone)]
+pub struct AreaLight {
+ pub color: Color,
+}
+
+impl Light for AreaLight {
+ fn emit(&self, w_in: Dir3, _rng: &mut R) -> Color {
+ if w_in.y() > 0.0 {
+ self.color
+ } else {
+ Color::black()
+ }
+ }
}
fn parse_look_at(iter: &mut Tokenizer) -> Result> {
@@ -417,7 +435,9 @@ impl Lexer {
material::parse_make_named_material(&mut self.input, context)
.map(|(name, material)| Statement::MakeNamedMaterial(name, material)),
),
- "NamedMaterial" => Some(self.input.parse_parameter().map(Statement::NamedMaterial)),
+ "NamedMaterial" => {
+ Some(self.input.next_string_value().map(Statement::NamedMaterial))
+ }
"ConcatTransform" => {
Some(parse_transform(&mut self.input).map(Statement::ConcatTransform))
}
@@ -429,6 +449,8 @@ impl Lexer {
Ok(s) => Ok(Statement::CoordSysTransform(s)),
Err(e) => Err(e),
}),
+
+ "AreaLightSource" => Some(parse_area_light(&mut self.input)),
"WorldBegin" => Some(Ok(Statement::WorldBegin)),
_ => {
if s.chars().any(|c| !c.is_ascii_alphabetic()) {
@@ -459,6 +481,22 @@ impl Lexer {
}
}
+fn parse_area_light(input: &mut Tokenizer) -> Result> {
+ let s = input.next_string_value()?;
+
+ if s.as_str() != "diffuse" {
+ return Err(miette!(
+ labels = vec![input.last_span_labeled(Some("here"))],
+ "Only diffuse area light supported."
+ )
+ .with_source_code(input.get_src()));
+ }
+
+ Ok(Statement::AreaLight(parse_dict2!(input, AreaLight;
+ color, Color::white(), ["rgb L", texture::parse_rgb(input)?]
+ )))
+}
+
fn parse_transform(input: &mut Tokenizer) -> Result {
input.next_expect_bracket_open()?;
let mut v = [0.0; 16];
@@ -615,6 +653,7 @@ pub struct PbrtContext {
ctm: Vec,
textures: HashMap>,
material: Vec>>,
+ area_light: Vec,
materials: HashMap>>,
}
@@ -623,6 +662,7 @@ impl PbrtContext {
Self {
ctm: vec![AffineTransform::identity()],
textures: HashMap::new(),
+ area_light: Vec::new(),
material: Vec::new(),
materials: HashMap::new(),
}
@@ -651,6 +691,11 @@ impl PbrtContext {
self.material
.push(Arc::clone(self.material.last().unwrap()));
}
+
+ if !self.area_light.is_empty() {
+ self.area_light
+ .push(self.area_light.last().unwrap().clone());
+ }
}
fn pop(&mut self) -> Result<()> {
@@ -661,6 +706,7 @@ impl PbrtContext {
}
self.material.pop();
+ self.area_light.pop();
Ok(())
}
@@ -747,17 +793,26 @@ fn inner_parse_pbrt(
}
Statement::Shape(shape_type, shape_alpha) => {
dbg!(&context);
- pbrt.scene.shapes.push(Shape {
- ctm: context.get_ctm(),
- material: Arc::clone(
- context
- .material
- .last()
- .ok_or_else(|| miette!("No material specified"))?,
- ),
- obj: shape_type,
- alpha: shape_alpha,
- });
+ if context.area_light.is_empty() {
+ pbrt.scene.shapes.push(Shape {
+ ctm: context.get_ctm(),
+ material: Either::A(Arc::clone(
+ context
+ .material
+ .last()
+ .ok_or_else(|| miette!("No material specified"))?,
+ )),
+ obj: shape_type,
+ alpha: shape_alpha,
+ });
+ } else {
+ pbrt.scene.shapes.push(Shape {
+ ctm: context.get_ctm(),
+ material: Either::B(context.area_light.last().unwrap().clone()),
+ obj: shape_type,
+ alpha: shape_alpha,
+ });
+ }
}
Statement::CoordinateSystem(s) => {
named_transforms.insert(s, context.get_ctm());
@@ -774,6 +829,13 @@ fn inner_parse_pbrt(
*context.material.last_mut().unwrap() = m;
}
}
+ Statement::AreaLight(l) => {
+ if context.area_light.is_empty() {
+ context.area_light.push(l);
+ } else {
+ *context.area_light.last_mut().unwrap() = l;
+ }
+ }
Statement::MakeNamedMaterial(n, m) => {
context.materials.insert(n, m);
}
@@ -801,7 +863,7 @@ fn inner_parse_pbrt(
// dbg!(context);
- Ok(pbrt)
+ Ok(dbg!(pbrt))
}
pub fn parse_pbrt_v4(
diff --git a/ray-tracing-pbrt-scene/src/shape.rs b/ray-tracing-pbrt-scene/src/shape.rs
index 8fc787f..ab69922 100644
--- a/ray-tracing-pbrt-scene/src/shape.rs
+++ b/ray-tracing-pbrt-scene/src/shape.rs
@@ -2,13 +2,13 @@ use std::sync::Arc;
use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection};
-use crate::{material::PbrtMaterial, scene::UVMaterial};
+use crate::{AreaLight, either::Either, material::PbrtMaterial, scene::UVMaterial};
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct Shape {
pub(crate) ctm: AffineTransform,
- pub(crate) material: Arc>,
+ pub(crate) material: Either>, AreaLight>,
pub(crate) obj: ShapeType,
pub(crate) alpha: ShapeAlpha,
}
@@ -21,7 +21,7 @@ pub(crate) enum ShapeAlpha {
Texture(String),
}
-#[derive(Debug)]
+// #[derive(Debug)]
#[allow(dead_code)]
pub(crate) enum ShapeType {
Sphere {
@@ -219,12 +219,14 @@ impl Shape {
t,
self.ctm
.inverse_transform_normal((ray.at(t).as_dir()).normalize()),
- Some(UVMaterial {
+ self.material.get_a().map(|m| UVMaterial {
u: phi,
v: Float::acos(p.z() / radius),
- material: self.material.as_ref(),
+ material: m.as_ref(),
}),
- None,
+ self.material
+ .get_b()
+ .map(|l| l as &dyn ray_tracing_core::light::Light),
0.0,
));
}
@@ -244,12 +246,14 @@ impl Shape {
return Some(Intersection::new(
t,
Dir3::new(0.0, 0.0, 1.0),
- Some(UVMaterial {
+ self.material.get_a().map(|m| UVMaterial {
u,
v,
- material: self.material.as_ref(),
+ material: m.as_ref(),
}),
- None,
+ self.material
+ .get_b()
+ .map(|l| l as &dyn ray_tracing_core::light::Light),
0.0,
));
}