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::{
collections::HashMap,
path::{Path, PathBuf},
sync::Arc,
};
use texture::PbrtTexture;
use thiserror::Error;
#[macro_use]
mod tokenizer;
mod error;
mod texture;
struct Lexer {
input: Tokenizer,
}
@ -65,6 +69,7 @@ enum Statement {
Shape(ShapeType, ShapeAlpha),
Unknown(String, Vec<String>),
Transform(AffineTransform),
Texture(String, Arc<dyn PbrtTexture>),
}
fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> {
@ -363,7 +368,10 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> {
}
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() {
Some(Ok(s)) => match s.as_str() {
"AttributeBegin" => Some(Ok(Statement::AttributeBegin)),
@ -387,6 +395,10 @@ impl Lexer {
"Shape" => Some(parse_shape(&mut self.input)),
"Rotate" => Some(parse_rotate(&mut self.input)),
"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" => {
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> {
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(statement) = iter.next() {
if let Some(statement) = iter.next(textures) {
return Some(statement);
}
self.inner = None;
}
match self.iter.next() {
match self.iter.next(textures) {
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()
self.next(textures)
}
Some(s) => Some(s),
None => None,
@ -653,7 +668,7 @@ struct PbrtScene {
fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
// 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)?;
@ -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 textures = HashMap::new();
loop {
let p = parser.next().ok_or_else(|| miette!(""))??;
let p = parser.next(&textures).ok_or_else(|| miette!(""))??;
// dbg!(&p);
match p {
Statement::AttributeBegin => context.push(*context.last().unwrap()),
Statement::AttributeBegin => context_ctm.push(*context_ctm.last().unwrap()),
Statement::AttributeEnd => {
context.pop();
if context.is_empty() {
context_ctm.pop();
if context_ctm.is_empty() {
return Err(miette!("Attribute end does not match."));
}
}
Statement::Include(_) => unreachable!(),
Statement::ConcatTransform(affine_transform) => {
*context.last_mut().unwrap() *= affine_transform
*context_ctm.last_mut().unwrap() *= affine_transform
}
Statement::Transform(affine_transform) => {
*context.last_mut().unwrap() = affine_transform
*context_ctm.last_mut().unwrap() = affine_transform
}
Statement::Unknown(s, _items) => {
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() {
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());
camera = Some((c, *context_ctm.last().unwrap()));
named_transforms.insert(String::from("\"camera\""), *context_ctm.last().unwrap());
}
Statement::CoordinateSystem(s) => {
named_transforms.insert(s, *context.last().unwrap());
named_transforms.insert(s, *context_ctm.last().unwrap());
}
Statement::CoordSysTransform(s) => {
*context.last_mut().unwrap() = *named_transforms
*context_ctm.last_mut().unwrap() = *named_transforms
.get(&s)
.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 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 {
Statement::AttributeBegin => context.push(*context.last().unwrap()),
Statement::AttributeBegin => context_ctm.push(*context_ctm.last().unwrap()),
Statement::AttributeEnd => {
context.pop();
context_ctm.pop();
}
Statement::Include(_) => unreachable!(),
Statement::ConcatTransform(affine_transform) => {
*context.last_mut().unwrap() *= affine_transform
*context_ctm.last_mut().unwrap() *= 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) => {
pbrt.scene.shapes.push(Shape {
ctm: *context.last().unwrap(),
ctm: *context_ctm.last().unwrap(),
material: 0,
obj: shape_type,
alpha: shape_alpha,
});
}
Statement::CoordinateSystem(s) => {
named_transforms.insert(s, *context.last().unwrap());
named_transforms.insert(s, *context_ctm.last().unwrap());
}
Statement::CoordSysTransform(s) => {
*context.last_mut().unwrap() = *named_transforms
*context_ctm.last_mut().unwrap() = *named_transforms
.get(&s)
.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)
}

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,
}