diff --git a/ray-tracing-core/src/affine_transform.rs b/ray-tracing-core/src/affine_transform.rs index 8277e46..859f10f 100644 --- a/ray-tracing-core/src/affine_transform.rs +++ b/ray-tracing-core/src/affine_transform.rs @@ -77,6 +77,27 @@ impl AffineTransform { } } + pub fn look_at(pos: Pos3, look: Pos3, up: Dir3) -> Self { + let dir = (look - pos).normalize(); + let right = Dir3::cross(up.normalize(), dir).normalize(); + let new_up = Dir3::cross(dir, right); + + let mat = [ + [right.x(), new_up.x(), dir.x(), pos.x()], + [right.y(), new_up.y(), dir.y(), pos.y()], + [right.z(), new_up.z(), dir.z(), pos.z()], + ]; + + let inv = Self::invert(mat); + + Self { mat, inv } + } + + fn invert(mat: [[Float; 4]; 3]) -> [[Float; 3]; 3] { + eprintln!("Matrix inversion not implemented"); + [[0.0; 3]; 3] + } + pub fn transform_pos(&self, pos: Pos3) -> Pos3 { Pos3::new( self.mat[0][0] * pos.x() @@ -93,6 +114,13 @@ impl AffineTransform { + self.mat[2][3], ) } + pub fn transform_dir(&self, dir: Dir3) -> Dir3 { + Dir3::new( + self.mat[0][0] * dir.x() + self.mat[0][1] * dir.y() + self.mat[0][2] * dir.z(), + self.mat[1][0] * dir.x() + self.mat[1][1] * dir.y() + self.mat[1][2] * dir.z(), + self.mat[2][0] * dir.x() + self.mat[2][1] * dir.y() + self.mat[2][2] * dir.z(), + ) + } pub fn transform_normal(&self, pos: Pos3) -> Pos3 { Pos3::new( self.inv[0][0] * pos.x() + self.inv[0][1] * pos.y() + self.inv[0][2] * pos.z(), diff --git a/ray-tracing-pbrt-scene/src/lib.rs b/ray-tracing-pbrt-scene/src/lib.rs index 3c2b772..37e4470 100644 --- a/ray-tracing-pbrt-scene/src/lib.rs +++ b/ray-tracing-pbrt-scene/src/lib.rs @@ -7,7 +7,11 @@ use std::{ use miette::{Diagnostic, Error, IntoDiagnostic, Result, bail, miette}; use nom::IResult; -use ray_tracing_core::math::{Dir3, Pos3}; +use ray_tracing_core::{ + affine_transform::AffineTransform, + math::{Dir3, Pos3}, + prelude::Float, +}; struct Tokenizer>> { input_iterator: Peekable, @@ -109,10 +113,10 @@ impl>> Lexer { #[derive(Debug)] enum Statement { - AttributeStart, + AttributeBegin, AttributeEnd, Include(String), - LookAt { eye: Pos3, look_at: Pos3, up: Dir3 }, + ConcatTransform(AffineTransform), Unknown(String, Vec), } @@ -160,16 +164,27 @@ fn parse_look_at(iter: &mut impl Iterator>) -> Result>> Iterator for Lexer { - type Item = Result; +fn parse_shape>>( + iter: &mut Peekable>, +) -> std::result::Result { + let shape_type = iter.next().ok_or(miette!(""))??; - fn next(&mut self) -> Option { + match shape_type.as_str() { + "sphere" => {} + _ => Err(miette!("")), + } +} + +impl>> Lexer { + fn next(&mut self, ctm: AffineTransform) -> Option> { match self.input.next() { Some(Ok(s)) => match s.as_str() { - "AttributeStart" => Some(Ok(Statement::AttributeStart)), + "AttributeBegin" => Some(Ok(Statement::AttributeBegin)), "AttributeEnd" => Some(Ok(Statement::AttributeEnd)), "Include" => { let s = self @@ -183,6 +198,7 @@ impl>> Iterator for Lexer { Some(Ok(Statement::Include(s))) } "LookAt" => Some(parse_look_at(&mut self.input)), + "Identity" => Some(Ok(Statement::ConcatTransform(AffineTransform::identity()))), _ => { if s.chars().any(|c| !c.is_ascii_alphabetic()) { Some(Err(miette!("malformed identifier"))) @@ -202,6 +218,7 @@ impl>> Iterator for Lexer { Some(Ok(Statement::Unknown(s, v))) } } + "Shape" => Some(parse_shape(&mut self.input)), }, Some(Err(e)) => Some(Err(e)), None => None, @@ -234,6 +251,7 @@ struct Parser

{ path: P, inner: Option>>, iter: Lexer>>>, + ctm: AffineTransform, } impl + std::fmt::Debug> Parser

{ @@ -242,12 +260,21 @@ impl + std::fmt::Debug> Parser

{ let bufreader = BufReader::new(std::fs::File::open(&path).into_diagnostic()?); Ok(Self { path, + ctm: AffineTransform::identity(), inner: None, iter: Lexer::new(BytesToChar { iter: bufreader.bytes(), }), }) } + + fn apply_transform(&mut self, transform: AffineTransform) { + self.ctm *= transform; + } + + fn set_transform(&mut self, transform: AffineTransform) { + self.ctm = transform; + } } impl> Iterator for Parser

{ @@ -261,7 +288,7 @@ impl> Iterator for Parser

{ self.inner = None; } - match self.iter.next() { + match self.iter.next(self.ctm) { Some(Ok(Statement::Include(s))) => { let path = self.path.as_ref().parent().unwrap().join(s); self.inner = Some(Box::new(Parser::new(path).unwrap())); @@ -274,6 +301,80 @@ impl> Iterator for Parser

{ } } +enum ShapeType { + Sphere { + radius: Float, + zmin: Float, + zmax: Float, + phimax: Float, + }, +} + +struct Shape { + ctm: AffineTransform, + material: usize, + obj: ShapeType, +} + +struct Pbrt { + settings: PbrtWorldSettings, + scene: PbrtScene, +} +impl Pbrt { + fn new() -> Self { + Self { + settings: todo!(), + scene: todo!(), + } + } +} + +struct PbrtWorldSettings {} + +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 { + let mut context = vec![context.unwrap_or(PbrtContext::new())]; + + let mut parser = Parser::new(path)?; + + let mut pbrt = Pbrt::new(); + + while let Some(p) = parser.next().transpose()? { + match p { + Statement::AttributeBegin => context.push(context.last().ok_or(miette!(""))?.clone()), + Statement::AttributeEnd => { + context.pop(); + } + Statement::Include(_) => unreachable!(), + Statement::ConcatTransform(affine_transform) => { + context.last_mut().ok_or(miette!(""))?.ctm *= affine_transform + } + Statement::Unknown(_, items) => todo!(), + } + } + + todo!() +} + pub fn parse_pbrt_v4(path: impl AsRef + std::fmt::Debug) -> Result<()> { let mut tokens = 0; for token in Parser::new(path).unwrap() {