First pbrt textures approach

This commit is contained in:
hal8174 2025-08-14 20:18:46 +02:00
parent b4d34aa6ca
commit 1196cb7758
Signed by: hal8174
SSH key fingerprint: SHA256:JwuqS+eVfISfKr+DkDQ6NWAbGd1jFAHkPpCM1yCnlTs
2 changed files with 164 additions and 27 deletions

View file

@ -9,13 +9,17 @@ use ray_tracing_core::{
use std::{ use std::{
collections::HashMap, collections::HashMap,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc,
}; };
use texture::PbrtTexture;
use thiserror::Error; use thiserror::Error;
#[macro_use] #[macro_use]
mod tokenizer; mod tokenizer;
mod error; mod error;
mod texture;
struct Lexer { struct Lexer {
input: Tokenizer, input: Tokenizer,
} }
@ -65,6 +69,7 @@ enum Statement {
Shape(ShapeType, ShapeAlpha), Shape(ShapeType, ShapeAlpha),
Unknown(String, Vec<String>), Unknown(String, Vec<String>),
Transform(AffineTransform), Transform(AffineTransform),
Texture(String, Arc<dyn PbrtTexture>),
} }
fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> { fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> {
@ -363,7 +368,10 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> {
} }
impl Lexer { impl Lexer {
fn next(&mut self) -> Option<Result<Statement>> { fn next(
&mut self,
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
) -> Option<Result<Statement>> {
match self.input.next() { match self.input.next() {
Some(Ok(s)) => match s.as_str() { Some(Ok(s)) => match s.as_str() {
"AttributeBegin" => Some(Ok(Statement::AttributeBegin)), "AttributeBegin" => Some(Ok(Statement::AttributeBegin)),
@ -387,6 +395,10 @@ impl Lexer {
"Shape" => Some(parse_shape(&mut self.input)), "Shape" => Some(parse_shape(&mut self.input)),
"Rotate" => Some(parse_rotate(&mut self.input)), "Rotate" => Some(parse_rotate(&mut self.input)),
"Transform" => Some(parse_transform(&mut self.input).map(Statement::Transform)), "Transform" => Some(parse_transform(&mut self.input).map(Statement::Transform)),
"Texture" => Some(
texture::parse_texture(&mut self.input)
.map(|(name, texture)| Statement::Texture(name, texture)),
),
"ConcatTransform" => { "ConcatTransform" => {
Some(parse_transform(&mut self.input).map(Statement::ConcatTransform)) Some(parse_transform(&mut self.input).map(Statement::ConcatTransform))
} }
@ -550,20 +562,23 @@ impl<P: AsRef<Path> + std::fmt::Debug> Parser<P> {
} }
impl<P: AsRef<Path>> Parser<P> { impl<P: AsRef<Path>> Parser<P> {
fn next(&mut self) -> Option<Result<Statement>> { fn next(
&mut self,
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
) -> Option<Result<Statement>> {
if let Some(iter) = &mut self.inner { if let Some(iter) = &mut self.inner {
if let Some(statement) = iter.next() { if let Some(statement) = iter.next(textures) {
return Some(statement); return Some(statement);
} }
self.inner = None; self.inner = None;
} }
match self.iter.next() { match self.iter.next(textures) {
Some(Ok(Statement::Include(s))) => { Some(Ok(Statement::Include(s))) => {
let path = self.path.as_ref().parent().unwrap().join(s); let path = self.path.as_ref().parent().unwrap().join(s);
self.inner = Some(Box::new(Parser::new(path).unwrap())); self.inner = Some(Box::new(Parser::new(path).unwrap()));
self.next() self.next(textures)
} }
Some(s) => Some(s), Some(s) => Some(s),
None => None, None => None,
@ -653,7 +668,7 @@ struct PbrtScene {
fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> { fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
// unwrap on context.last() ok because context is never empty // unwrap on context.last() ok because context is never empty
let mut context = vec![AffineTransform::identity()]; let mut context_ctm = vec![AffineTransform::identity()];
let mut parser = Parser::new(path)?; let mut parser = Parser::new(path)?;
@ -663,23 +678,25 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
let mut named_transforms = HashMap::new(); let mut named_transforms = HashMap::new();
let mut textures = HashMap::new();
loop { loop {
let p = parser.next().ok_or_else(|| miette!(""))??; let p = parser.next(&textures).ok_or_else(|| miette!(""))??;
// dbg!(&p); // dbg!(&p);
match p { match p {
Statement::AttributeBegin => context.push(*context.last().unwrap()), Statement::AttributeBegin => context_ctm.push(*context_ctm.last().unwrap()),
Statement::AttributeEnd => { Statement::AttributeEnd => {
context.pop(); context_ctm.pop();
if context.is_empty() { if context_ctm.is_empty() {
return Err(miette!("Attribute end does not match.")); return Err(miette!("Attribute end does not match."));
} }
} }
Statement::Include(_) => unreachable!(), Statement::Include(_) => unreachable!(),
Statement::ConcatTransform(affine_transform) => { Statement::ConcatTransform(affine_transform) => {
*context.last_mut().unwrap() *= affine_transform *context_ctm.last_mut().unwrap() *= affine_transform
} }
Statement::Transform(affine_transform) => { Statement::Transform(affine_transform) => {
*context.last_mut().unwrap() = affine_transform *context_ctm.last_mut().unwrap() = affine_transform
} }
Statement::Unknown(s, _items) => { Statement::Unknown(s, _items) => {
eprintln!("Unknown statement: {s}") eprintln!("Unknown statement: {s}")
@ -688,14 +705,14 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
if camera.is_some() { if camera.is_some() {
return Err(miette!("The camera can only be set once.")); return Err(miette!("The camera can only be set once."));
} }
camera = Some((c, *context.last().unwrap())); camera = Some((c, *context_ctm.last().unwrap()));
named_transforms.insert(String::from("\"camera\""), *context.last().unwrap()); named_transforms.insert(String::from("\"camera\""), *context_ctm.last().unwrap());
} }
Statement::CoordinateSystem(s) => { Statement::CoordinateSystem(s) => {
named_transforms.insert(s, *context.last().unwrap()); named_transforms.insert(s, *context_ctm.last().unwrap());
} }
Statement::CoordSysTransform(s) => { Statement::CoordSysTransform(s) => {
*context.last_mut().unwrap() = *named_transforms *context_ctm.last_mut().unwrap() = *named_transforms
.get(&s) .get(&s)
.ok_or_else(|| miette!("unknown transform"))?; .ok_or_else(|| miette!("unknown transform"))?;
} }
@ -708,34 +725,36 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
let mut pbrt = Pbrt::new(PbrtWorldSettings { camera, camera_ctm }); let mut pbrt = Pbrt::new(PbrtWorldSettings { camera, camera_ctm });
let mut context = vec![AffineTransform::identity()]; let mut context_ctm = vec![AffineTransform::identity()];
while let Some(p) = parser.next().transpose()? { // let mut context_material = vec![];
while let Some(p) = parser.next(&textures).transpose()? {
match p { match p {
Statement::AttributeBegin => context.push(*context.last().unwrap()), Statement::AttributeBegin => context_ctm.push(*context_ctm.last().unwrap()),
Statement::AttributeEnd => { Statement::AttributeEnd => {
context.pop(); context_ctm.pop();
} }
Statement::Include(_) => unreachable!(), Statement::Include(_) => unreachable!(),
Statement::ConcatTransform(affine_transform) => { Statement::ConcatTransform(affine_transform) => {
*context.last_mut().unwrap() *= affine_transform *context_ctm.last_mut().unwrap() *= affine_transform
} }
Statement::Transform(affine_transform) => { Statement::Transform(affine_transform) => {
*context.last_mut().unwrap() = affine_transform *context_ctm.last_mut().unwrap() = affine_transform
} }
Statement::Shape(shape_type, shape_alpha) => { Statement::Shape(shape_type, shape_alpha) => {
pbrt.scene.shapes.push(Shape { pbrt.scene.shapes.push(Shape {
ctm: *context.last().unwrap(), ctm: *context_ctm.last().unwrap(),
material: 0, material: 0,
obj: shape_type, obj: shape_type,
alpha: shape_alpha, alpha: shape_alpha,
}); });
} }
Statement::CoordinateSystem(s) => { Statement::CoordinateSystem(s) => {
named_transforms.insert(s, *context.last().unwrap()); named_transforms.insert(s, *context_ctm.last().unwrap());
} }
Statement::CoordSysTransform(s) => { Statement::CoordSysTransform(s) => {
*context.last_mut().unwrap() = *named_transforms *context_ctm.last_mut().unwrap() = *named_transforms
.get(&s) .get(&s)
.ok_or_else(|| miette!("unknown transform"))?; .ok_or_else(|| miette!("unknown transform"))?;
} }
@ -746,8 +765,6 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
} }
} }
dbg!(named_transforms);
Ok(pbrt) Ok(pbrt)
} }

View file

@ -0,0 +1,120 @@
use miette::{Result, miette};
use ray_tracing_core::{color::Color, prelude::Float};
use std::sync::Arc;
use crate::tokenizer::Tokenizer;
pub trait PbrtTexture: std::fmt::Debug {
fn get_2d_float_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_float_texture>>;
fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>>;
}
pub trait Pbrt_2d_float_texture: std::fmt::Debug {
fn get(&self, u: Float, v: Float) -> Float;
}
pub trait Pbrt_2d_spectrum_texture: std::fmt::Debug {
fn get(&self, u: Float, v: Float) -> Color;
}
#[derive(Debug)]
enum TextureMapping {
UV,
Spherical,
}
impl TextureMapping {
fn new(x: String) -> Result<Self> {
match x.as_str() {
"\"uv\"" => Ok(TextureMapping::UV),
"\"spherical\"" => Ok(TextureMapping::Spherical),
_ => Err(miette!("Error")),
}
}
}
pub fn parse_texture(input: &mut Tokenizer) -> Result<(String, Arc<dyn PbrtTexture>)> {
let texture_name: String = input.parse_next()?;
let texture_type: String = input.parse_next()?;
let texture_class: String = input.parse_next()?;
match texture_class.as_str() {
"\"checkerboard\"" => {
let t = parse_dict!(input =>
mapping, TextureMapping, TextureMapping::UV;
uscale, Float, 1.0;
vscale, Float, 1.0;
udelta, Float, 0.0;
vdelta, Float, 0.0;
dimension, u8, 2
=>
mapping, "\"mapping\"", TextureMapping::new(input.parse_parameter()?)?;
uscale, "\"uscale\"", input.parse_parameter()?;
vscale, "\"vscale\"", input.parse_parameter()?;
udelta, "\"udelta\"", input.parse_parameter()?;
vdelta, "\"vdelta\"", input.parse_parameter()?;
dimension, "\"dimension\"", input.parse_parameter()?
);
dbg!(t);
todo!()
}
"\"checkerboard\"" => {
let t = parse_dict!(input =>
mapping, TextureMapping, TextureMapping::UV;
uscale, Float, 1.0;
vscale, Float, 1.0;
udelta, Float, 0.0;
vdelta, Float, 0.0
=>
mapping, "\"mapping\"", TextureMapping::new(input.parse_parameter()?)?;
uscale, "\"uscale\"", input.parse_parameter()?;
vscale, "\"vscale\"", input.parse_parameter()?;
udelta, "\"udelta\"", input.parse_parameter()?;
vdelta, "\"vdelta\"", input.parse_parameter()?
);
todo!()
}
_ => Err(miette!("unknown error")),
}
}
#[derive(Debug)]
enum FloatTexture2d {
Value(Float),
Texture {
float: Option<Arc<dyn Pbrt_2d_float_texture>>,
spectrum: Option<Arc<dyn Pbrt_2d_spectrum_texture>>,
},
}
#[derive(Debug)]
struct TextureD2<T> {
inner: T,
uscale: Float,
vscale: Float,
udelta: Float,
vdelta: Float,
mapping: TextureMapping,
}
impl<T: PbrtTexture> PbrtTexture for TextureD2<T> {
fn get_2d_float_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_float_texture>> {
todo!()
}
fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
todo!()
}
}
#[derive(Debug)]
struct CheckerboardTexture {
dimension: u8,
tex1: FloatTexture2d,
tex2: FloatTexture2d,
}