Implement initial area light
This commit is contained in:
		
							parent
							
								
									95092b1571
								
							
						
					
					
						commit
						333acab099
					
				
					 3 changed files with 102 additions and 22 deletions
				
			
		|  | @ -17,6 +17,20 @@ impl<A, B> Either<A, B> { | ||||||
|             Either::B(b) => Either::B(f(b)), |             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<A, B, E> Either<A, Result<B, E>> { | impl<A, B, E> Either<A, Result<B, E>> { | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| use crate::{ | use crate::{ | ||||||
|  |     either::Either, | ||||||
|     scene::PbrtScene, |     scene::PbrtScene, | ||||||
|     shape::{Shape, ShapeAlpha, ShapeType}, |     shape::{Shape, ShapeAlpha, ShapeType}, | ||||||
|     tokenizer::{Token, Tokenizer}, |     tokenizer::{Token, Tokenizer}, | ||||||
|  | @ -8,6 +9,7 @@ use miette::{IntoDiagnostic, Result, bail, miette}; | ||||||
| use ray_tracing_core::{ | use ray_tracing_core::{ | ||||||
|     affine_transform::AffineTransform, |     affine_transform::AffineTransform, | ||||||
|     color::Color, |     color::Color, | ||||||
|  |     light::Light, | ||||||
|     math::{Dir3, Pos3}, |     math::{Dir3, Pos3}, | ||||||
|     prelude::{Float, Rng}, |     prelude::{Float, Rng}, | ||||||
| }; | }; | ||||||
|  | @ -83,6 +85,22 @@ enum Statement<R> { | ||||||
|     Material(Arc<dyn PbrtMaterial<R>>), |     Material(Arc<dyn PbrtMaterial<R>>), | ||||||
|     MakeNamedMaterial(String, Arc<dyn PbrtMaterial<R>>), |     MakeNamedMaterial(String, Arc<dyn PbrtMaterial<R>>), | ||||||
|     NamedMaterial(String), |     NamedMaterial(String), | ||||||
|  |     AreaLight(AreaLight), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct AreaLight { | ||||||
|  |     pub color: 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() | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn parse_look_at<R>(iter: &mut Tokenizer) -> Result<Statement<R>> { | fn parse_look_at<R>(iter: &mut Tokenizer) -> Result<Statement<R>> { | ||||||
|  | @ -417,7 +435,9 @@ impl Lexer { | ||||||
|                     material::parse_make_named_material(&mut self.input, context) |                     material::parse_make_named_material(&mut self.input, context) | ||||||
|                         .map(|(name, material)| Statement::MakeNamedMaterial(name, material)), |                         .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" => { |                 "ConcatTransform" => { | ||||||
|                     Some(parse_transform(&mut self.input).map(Statement::ConcatTransform)) |                     Some(parse_transform(&mut self.input).map(Statement::ConcatTransform)) | ||||||
|                 } |                 } | ||||||
|  | @ -429,6 +449,8 @@ impl Lexer { | ||||||
|                     Ok(s) => Ok(Statement::CoordSysTransform(s)), |                     Ok(s) => Ok(Statement::CoordSysTransform(s)), | ||||||
|                     Err(e) => Err(e), |                     Err(e) => Err(e), | ||||||
|                 }), |                 }), | ||||||
|  | 
 | ||||||
|  |                 "AreaLightSource" => Some(parse_area_light(&mut self.input)), | ||||||
|                 "WorldBegin" => Some(Ok(Statement::WorldBegin)), |                 "WorldBegin" => Some(Ok(Statement::WorldBegin)), | ||||||
|                 _ => { |                 _ => { | ||||||
|                     if s.chars().any(|c| !c.is_ascii_alphabetic()) { |                     if s.chars().any(|c| !c.is_ascii_alphabetic()) { | ||||||
|  | @ -459,6 +481,22 @@ impl Lexer { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn parse_area_light<R>(input: &mut Tokenizer) -> Result<Statement<R>> { | ||||||
|  |     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<AffineTransform> { | fn parse_transform(input: &mut Tokenizer) -> Result<AffineTransform> { | ||||||
|     input.next_expect_bracket_open()?; |     input.next_expect_bracket_open()?; | ||||||
|     let mut v = [0.0; 16]; |     let mut v = [0.0; 16]; | ||||||
|  | @ -615,6 +653,7 @@ pub struct PbrtContext<R> { | ||||||
|     ctm: Vec<AffineTransform>, |     ctm: Vec<AffineTransform>, | ||||||
|     textures: HashMap<String, Arc<dyn PbrtTexture>>, |     textures: HashMap<String, Arc<dyn PbrtTexture>>, | ||||||
|     material: Vec<Arc<dyn PbrtMaterial<R>>>, |     material: Vec<Arc<dyn PbrtMaterial<R>>>, | ||||||
|  |     area_light: Vec<AreaLight>, | ||||||
|     materials: HashMap<String, Arc<dyn PbrtMaterial<R>>>, |     materials: HashMap<String, Arc<dyn PbrtMaterial<R>>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -623,6 +662,7 @@ impl<R> PbrtContext<R> { | ||||||
|         Self { |         Self { | ||||||
|             ctm: vec![AffineTransform::identity()], |             ctm: vec![AffineTransform::identity()], | ||||||
|             textures: HashMap::new(), |             textures: HashMap::new(), | ||||||
|  |             area_light: Vec::new(), | ||||||
|             material: Vec::new(), |             material: Vec::new(), | ||||||
|             materials: HashMap::new(), |             materials: HashMap::new(), | ||||||
|         } |         } | ||||||
|  | @ -651,6 +691,11 @@ impl<R> PbrtContext<R> { | ||||||
|             self.material |             self.material | ||||||
|                 .push(Arc::clone(self.material.last().unwrap())); |                 .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<()> { |     fn pop(&mut self) -> Result<()> { | ||||||
|  | @ -661,6 +706,7 @@ impl<R> PbrtContext<R> { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         self.material.pop(); |         self.material.pop(); | ||||||
|  |         self.area_light.pop(); | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  | @ -747,17 +793,26 @@ fn inner_parse_pbrt<R: Rng + std::fmt::Debug>( | ||||||
|             } |             } | ||||||
|             Statement::Shape(shape_type, shape_alpha) => { |             Statement::Shape(shape_type, shape_alpha) => { | ||||||
|                 dbg!(&context); |                 dbg!(&context); | ||||||
|                 pbrt.scene.shapes.push(Shape { |                 if context.area_light.is_empty() { | ||||||
|                     ctm: context.get_ctm(), |                     pbrt.scene.shapes.push(Shape { | ||||||
|                     material: Arc::clone( |                         ctm: context.get_ctm(), | ||||||
|                         context |                         material: Either::A(Arc::clone( | ||||||
|                             .material |                             context | ||||||
|                             .last() |                                 .material | ||||||
|                             .ok_or_else(|| miette!("No material specified"))?, |                                 .last() | ||||||
|                     ), |                                 .ok_or_else(|| miette!("No material specified"))?, | ||||||
|                     obj: shape_type, |                         )), | ||||||
|                     alpha: shape_alpha, |                         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) => { |             Statement::CoordinateSystem(s) => { | ||||||
|                 named_transforms.insert(s, context.get_ctm()); |                 named_transforms.insert(s, context.get_ctm()); | ||||||
|  | @ -774,6 +829,13 @@ fn inner_parse_pbrt<R: Rng + std::fmt::Debug>( | ||||||
|                     *context.material.last_mut().unwrap() = m; |                     *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) => { |             Statement::MakeNamedMaterial(n, m) => { | ||||||
|                 context.materials.insert(n, m); |                 context.materials.insert(n, m); | ||||||
|             } |             } | ||||||
|  | @ -801,7 +863,7 @@ fn inner_parse_pbrt<R: Rng + std::fmt::Debug>( | ||||||
| 
 | 
 | ||||||
|     // dbg!(context);
 |     // dbg!(context);
 | ||||||
| 
 | 
 | ||||||
|     Ok(pbrt) |     Ok(dbg!(pbrt)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn parse_pbrt_v4<R: Rng + std::fmt::Debug>( | pub fn parse_pbrt_v4<R: Rng + std::fmt::Debug>( | ||||||
|  |  | ||||||
|  | @ -2,13 +2,13 @@ use std::sync::Arc; | ||||||
| 
 | 
 | ||||||
| use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection}; | 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)] | #[derive(Debug)] | ||||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||||
| pub(crate) struct Shape<R: Rng> { | pub(crate) struct Shape<R: Rng> { | ||||||
|     pub(crate) ctm: AffineTransform, |     pub(crate) ctm: AffineTransform, | ||||||
|     pub(crate) material: Arc<dyn PbrtMaterial<R>>, |     pub(crate) material: Either<Arc<dyn PbrtMaterial<R>>, AreaLight>, | ||||||
|     pub(crate) obj: ShapeType, |     pub(crate) obj: ShapeType, | ||||||
|     pub(crate) alpha: ShapeAlpha, |     pub(crate) alpha: ShapeAlpha, | ||||||
| } | } | ||||||
|  | @ -21,7 +21,7 @@ pub(crate) enum ShapeAlpha { | ||||||
|     Texture(String), |     Texture(String), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | // #[derive(Debug)]
 | ||||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||||
| pub(crate) enum ShapeType { | pub(crate) enum ShapeType { | ||||||
|     Sphere { |     Sphere { | ||||||
|  | @ -219,12 +219,14 @@ impl<R: Rng + std::fmt::Debug> Shape<R> { | ||||||
|                             t, |                             t, | ||||||
|                             self.ctm |                             self.ctm | ||||||
|                                 .inverse_transform_normal((ray.at(t).as_dir()).normalize()), |                                 .inverse_transform_normal((ray.at(t).as_dir()).normalize()), | ||||||
|                             Some(UVMaterial { |                             self.material.get_a().map(|m| UVMaterial { | ||||||
|                                 u: phi, |                                 u: phi, | ||||||
|                                 v: Float::acos(p.z() / radius), |                                 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<R>), | ||||||
|                             0.0, |                             0.0, | ||||||
|                         )); |                         )); | ||||||
|                     } |                     } | ||||||
|  | @ -244,12 +246,14 @@ impl<R: Rng + std::fmt::Debug> Shape<R> { | ||||||
|                     return Some(Intersection::new( |                     return Some(Intersection::new( | ||||||
|                         t, |                         t, | ||||||
|                         Dir3::new(0.0, 0.0, 1.0), |                         Dir3::new(0.0, 0.0, 1.0), | ||||||
|                         Some(UVMaterial { |                         self.material.get_a().map(|m| UVMaterial { | ||||||
|                             u, |                             u, | ||||||
|                             v, |                             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<R>), | ||||||
|                         0.0, |                         0.0, | ||||||
|                     )); |                     )); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue