diff --git a/ray-tracing-pbrt-scene/examples/pbrt-test.rs b/ray-tracing-pbrt-scene/examples/pbrt-test.rs index d316b9e..a49cfc6 100644 --- a/ray-tracing-pbrt-scene/examples/pbrt-test.rs +++ b/ray-tracing-pbrt-scene/examples/pbrt-test.rs @@ -12,7 +12,7 @@ fn main() -> Result<(), miette::Error> { let t = parse_pbrt_v4(args.filename)?; - dbg!(t); + // dbg!(t); Ok(()) } diff --git a/ray-tracing-pbrt-scene/src/lib.rs b/ray-tracing-pbrt-scene/src/lib.rs index df2c516..9c95de1 100644 --- a/ray-tracing-pbrt-scene/src/lib.rs +++ b/ray-tracing-pbrt-scene/src/lib.rs @@ -6,7 +6,10 @@ use ray_tracing_core::{ math::{Dir3, Pos3}, prelude::Float, }; -use std::path::{Path, PathBuf}; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; use thiserror::Error; #[macro_use] @@ -25,13 +28,40 @@ impl Lexer { } } +#[derive(Debug)] +enum CameraType { + Orthographic { + frame_aspect_ratio: Option, + screen_window: Option, + lens_radius: Float, + focal_distance: Float, + }, + Perspective { + frame_aspect_ratio: Option, + screen_window: Option, + lens_radius: Float, + focal_distance: Float, + fov: Float, + }, +} + +#[derive(Debug)] +struct PbrtCamera { + camera_type: CameraType, + shutter_open: Float, + shutter_close: Float, +} + #[derive(Debug)] enum Statement { AttributeBegin, AttributeEnd, WorldBegin, + Camera(PbrtCamera), Include(String), ConcatTransform(AffineTransform), + CoordinateSystem(String), + CoordSysTransform(String), Shape(ShapeType, ShapeAlpha), Unknown(String, Vec), Transform(AffineTransform), @@ -90,7 +120,7 @@ fn parse_shape(iter: &mut Tokenizer) -> Result { n, "\"normal N\"", iter.parse_list_3(Dir3::new)?; s, "\"normal S\"", iter.parse_list_3(Dir3::new)?; uv, "\"point2 uv\"", iter.parse_list_2(|u, v| [u, v])?; - indices, "\"interger indices\"", iter.parse_list()?; + indices, "\"integer indices\"", iter.parse_list()?; alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) ); @@ -142,7 +172,7 @@ fn parse_shape(iter: &mut Tokenizer) -> Result { p, "\"point3 P\"", iter.parse_list_3(Pos3::new)?; n, "\"normal N\"", iter.parse_list_3(Dir3::new)?; uv, "\"point2 uv\"", iter.parse_list_2(|u, v| [u, v])?; - indices, "\"interger indices\"", iter.parse_list()?; + indices, "\"integer indices\"", iter.parse_list()?; alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) ); @@ -186,8 +216,8 @@ fn parse_shape(iter: &mut Tokenizer) -> Result { p, Vec, Vec::new(); alpha, ShapeAlpha, ShapeAlpha::None => - levels, "\"float levels\"", iter.parse_parameter()?; - indices, "\"interger indices\"", iter.parse_list()?; + levels, "\"integer levels\"", iter.parse_parameter()?; + indices, "\"integer indices\"", iter.parse_list()?; p, "\"point3 P\"", iter.parse_list_3(Pos3::new)?; alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) @@ -243,8 +273,8 @@ fn parse_shape(iter: &mut Tokenizer) -> Result { edgelength, Float, 1.0; alpha, ShapeAlpha, ShapeAlpha::None => - filename, "\"string filename\"", iter.parse_next()?; - displacement, "\"string displacement\"", Some(iter.parse_next()?); + filename, "\"string filename\"", iter.parse_parameter()?; + displacement, "\"string displacement\"", Some(iter.parse_parameter()?); edgelength, "\"float edgelength\"", iter.parse_parameter()?; alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) @@ -263,8 +293,77 @@ fn parse_shape(iter: &mut Tokenizer) -> Result { } } +fn parse_camera(tokenizer: &mut Tokenizer) -> Result { + let camera_type = tokenizer + .next() + .ok_or(miette!("unable to get shape type"))??; + + match camera_type.as_str() { + "\"orthographic\"" => { + let t = parse_dict!(tokenizer => + shutteropen, Float, 0.0; + shutterclose, Float, 1.0; + frame_aspect_ratio, Option, None; + screen_window, Option, None; + lens_radius, Float, 0.0; + focal_distance, Float, Float::powi(10.0, 30) + => + shutteropen, "\"float shutteropen\"", tokenizer.parse_parameter()?; + shutterclose, "\"float shutterclose\"", tokenizer.parse_parameter()?; + frame_aspect_ratio, "\"float frameaspectratio\"", Some(tokenizer.parse_parameter()?); + screen_window, "\"float screenwindow\"", Some(tokenizer.parse_parameter()?); + lens_radius, "\"float lensradius\"", tokenizer.parse_parameter()?; + focal_distance, "\"float focaldistance\"", tokenizer.parse_parameter()? + ); + + Ok(Statement::Camera(PbrtCamera { + camera_type: CameraType::Orthographic { + frame_aspect_ratio: t.frame_aspect_ratio, + screen_window: t.screen_window, + lens_radius: t.lens_radius, + focal_distance: t.focal_distance, + }, + shutter_open: t.shutteropen, + shutter_close: t.shutterclose, + })) + } + "\"perspective\"" => { + let t = parse_dict!(tokenizer => + shutteropen, Float, 0.0; + shutterclose, Float, 1.0; + frame_aspect_ratio, Option, None; + screen_window, Option, None; + lens_radius, Float, 0.0; + focal_distance, Float, Float::powi(10.0, 30); + fov, Float, 90.0 + => + shutteropen, "\"float shutteropen\"", tokenizer.parse_parameter()?; + shutterclose, "\"float shutterclose\"", tokenizer.parse_parameter()?; + frame_aspect_ratio, "\"float frameaspectratio\"", Some(tokenizer.parse_parameter()?); + screen_window, "\"float screenwindow\"", Some(tokenizer.parse_parameter()?); + lens_radius, "\"float lensradius\"", tokenizer.parse_parameter()?; + focal_distance, "\"float focaldistance\"", tokenizer.parse_parameter()?; + fov, "\"float fov\"", tokenizer.parse_parameter()? + ); + + Ok(Statement::Camera(PbrtCamera { + camera_type: CameraType::Perspective { + frame_aspect_ratio: t.frame_aspect_ratio, + screen_window: t.screen_window, + lens_radius: t.lens_radius, + focal_distance: t.focal_distance, + fov: t.fov, + }, + shutter_open: t.shutteropen, + shutter_close: t.shutterclose, + })) + } + _ => Err(miette!("Unknown camera_type {}", camera_type)), + } +} + impl Lexer { - fn next(&mut self, ctm: AffineTransform) -> Option> { + fn next(&mut self) -> Option> { match self.input.next() { Some(Ok(s)) => match s.as_str() { "AttributeBegin" => Some(Ok(Statement::AttributeBegin)), @@ -280,6 +379,7 @@ impl Lexer { Some(Ok(Statement::Include(s))) } + "Camera" => Some(parse_camera(&mut self.input)), "LookAt" => Some(parse_look_at(&mut self.input)), "Identity" => Some(Ok(Statement::ConcatTransform(AffineTransform::identity()))), "Translate" => Some(parse_translate(&mut self.input)), @@ -290,6 +390,15 @@ impl Lexer { "ConcatTransform" => { Some(parse_transform(&mut self.input).map(Statement::ConcatTransform)) } + "CoordinateSystem" => Some(match self.input.parse_parameter() { + Ok(s) => Ok(Statement::CoordinateSystem(s)), + Err(e) => Err(e), + }), + "CoordSysTransform" => Some(match self.input.parse_parameter() { + Ok(s) => Ok(Statement::CoordSysTransform(s)), + Err(e) => Err(e), + }), + "WorldBegin" => Some(Ok(Statement::WorldBegin)), _ => { if s.chars().any(|c| !c.is_ascii_alphabetic()) { @@ -441,20 +550,20 @@ impl + std::fmt::Debug> Parser

{ } impl> Parser

{ - fn next(&mut self, context: &PbrtContext) -> Option> { + fn next(&mut self) -> Option> { if let Some(iter) = &mut self.inner { - if let Some(statement) = iter.next(context) { + if let Some(statement) = iter.next() { return Some(statement); } self.inner = None; } - match self.iter.next(context.ctm) { + match self.iter.next() { Some(Ok(Statement::Include(s))) => { let path = self.path.as_ref().parent().unwrap().join(s); self.inner = Some(Box::new(Parser::new(path).unwrap())); - self.next(context) + self.next() } Some(s) => Some(s), None => None, @@ -523,104 +632,125 @@ pub struct Pbrt { } impl Pbrt { - fn new() -> Self { + fn new(settings: PbrtWorldSettings) -> Self { Self { - settings: PbrtWorldSettings {}, + settings, scene: PbrtScene { shapes: Vec::new() }, } } } #[derive(Debug)] -struct PbrtWorldSettings {} +struct PbrtWorldSettings { + camera: PbrtCamera, + camera_ctm: AffineTransform, +} #[derive(Debug)] struct PbrtScene { shapes: Vec, } -#[derive(Clone)] -struct PbrtContext { - ctm: AffineTransform, -} - -impl PbrtContext { - fn new() -> Self { - Self { - ctm: AffineTransform::identity(), - } - } -} - -fn inner_parse_pbrt( - path: impl AsRef + std::fmt::Debug, - context: Option, -) -> Result { +fn inner_parse_pbrt(path: impl AsRef + std::fmt::Debug) -> Result { // unwrap on context.last() ok because context is never empty - let mut context = vec![context.unwrap_or(PbrtContext::new())]; + let mut context = vec![AffineTransform::identity()]; let mut parser = Parser::new(path)?; - let mut pbrt = Pbrt::new(); - // parse global settings + let mut camera = None; + + let mut named_transforms = HashMap::new(); + loop { - let p = parser - .next(context.last().unwrap()) - .ok_or_else(|| miette!(""))??; + let p = parser.next().ok_or_else(|| miette!(""))??; // dbg!(&p); match p { - Statement::AttributeBegin => context.push(context.last().ok_or(miette!(""))?.clone()), + Statement::AttributeBegin => context.push(*context.last().unwrap()), Statement::AttributeEnd => { context.pop(); + if context.is_empty() { + return Err(miette!("Attribute end does not match.")); + } } Statement::Include(_) => unreachable!(), Statement::ConcatTransform(affine_transform) => { - context.last_mut().ok_or(miette!(""))?.ctm *= affine_transform + *context.last_mut().unwrap() *= affine_transform } Statement::Transform(affine_transform) => { - context.last_mut().ok_or(miette!(""))?.ctm = dbg!(affine_transform) + *context.last_mut().unwrap() = affine_transform } - Statement::Unknown(s, items) => { + Statement::Unknown(s, _items) => { eprintln!("Unknown statement: {s}") } + Statement::Camera(c) => { + if camera.is_some() { + return Err(miette!("The camera can only be set once.")); + } + camera = Some((c, *context.last().unwrap())); + named_transforms.insert(String::from("\"camera\""), *context.last().unwrap()); + } + Statement::CoordinateSystem(s) => { + named_transforms.insert(s, *context.last().unwrap()); + } + Statement::CoordSysTransform(s) => { + *context.last_mut().unwrap() = *named_transforms + .get(&s) + .ok_or_else(|| miette!("unknown transform"))?; + } Statement::WorldBegin => break, s => bail!("unexpected statemnet in global settings: {s:?}"), } } - while let Some(p) = parser.next(context.last().unwrap()).transpose()? { + let (camera, camera_ctm) = camera.ok_or(miette!("A camera has to be specified"))?; + + let mut pbrt = Pbrt::new(PbrtWorldSettings { camera, camera_ctm }); + + let mut context = vec![AffineTransform::identity()]; + + while let Some(p) = parser.next().transpose()? { match p { - Statement::AttributeBegin => context.push(context.last().ok_or(miette!(""))?.clone()), + Statement::AttributeBegin => context.push(*context.last().unwrap()), Statement::AttributeEnd => { context.pop(); } Statement::Include(_) => unreachable!(), Statement::ConcatTransform(affine_transform) => { - context.last_mut().ok_or(miette!(""))?.ctm *= affine_transform + *context.last_mut().unwrap() *= affine_transform } Statement::Transform(affine_transform) => { - context.last_mut().ok_or(miette!(""))?.ctm = dbg!(affine_transform) + *context.last_mut().unwrap() = affine_transform } Statement::Shape(shape_type, shape_alpha) => { pbrt.scene.shapes.push(Shape { - ctm: context.last().unwrap().ctm, + ctm: *context.last().unwrap(), material: 0, obj: shape_type, alpha: shape_alpha, }); } - Statement::Unknown(s, items) => { + Statement::CoordinateSystem(s) => { + named_transforms.insert(s, *context.last().unwrap()); + } + Statement::CoordSysTransform(s) => { + *context.last_mut().unwrap() = *named_transforms + .get(&s) + .ok_or_else(|| miette!("unknown transform"))?; + } + Statement::Unknown(s, _items) => { eprintln!("Unknown statement: {s}") } s => bail!("unexpected statemnet in world settings: {s:?}"), } } + dbg!(named_transforms); + Ok(pbrt) } pub fn parse_pbrt_v4(path: impl AsRef + std::fmt::Debug) -> Result { - inner_parse_pbrt(path, None) + inner_parse_pbrt(path) }