From 0dfa2128dd58a2d07fdea261eb8bc187c78a7719 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sun, 17 Aug 2025 17:08:11 +0200 Subject: [PATCH] Add Pbrt scale texture and initial material stuff --- ray-tracing-pbrt-scene/src/lib.rs | 17 +++- ray-tracing-pbrt-scene/src/material.rs | 28 +++++++ ray-tracing-pbrt-scene/src/texture.rs | 77 ++++++++++++++++++- .../src/texture/checkerboard.rs | 8 ++ .../src/texture/imagemap.rs | 17 +++- ray-tracing-pbrt-scene/src/texture/scale.rs | 37 +++++++++ 6 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 ray-tracing-pbrt-scene/src/material.rs create mode 100644 ray-tracing-pbrt-scene/src/texture/scale.rs diff --git a/ray-tracing-pbrt-scene/src/lib.rs b/ray-tracing-pbrt-scene/src/lib.rs index e3b4e4e..efab7b8 100644 --- a/ray-tracing-pbrt-scene/src/lib.rs +++ b/ray-tracing-pbrt-scene/src/lib.rs @@ -1,5 +1,6 @@ use crate::tokenizer::Tokenizer; use error::SourceFile; +use material::PbrtMaterial; use miette::{Diagnostic, IntoDiagnostic, Result, SourceSpan, bail, miette}; use ray_tracing_core::{ affine_transform::AffineTransform, @@ -16,10 +17,10 @@ use thiserror::Error; #[macro_use] mod tokenizer; - mod error; - +mod material; mod texture; + struct Lexer { input: Tokenizer, } @@ -70,6 +71,9 @@ enum Statement { Unknown(String, Vec), Transform(AffineTransform), Texture(String, Arc), + Material(Arc), + MakeNamedMaterial(String, Arc), + NamedMaterial(String), } fn parse_look_at(iter: &mut Tokenizer) -> Result { @@ -399,6 +403,14 @@ impl Lexer { texture::parse_texture(&mut self.input, textures) .map(|(name, texture)| Statement::Texture(name, texture)), ), + "Material" => Some( + material::parse_material(&mut self.input, textures).map(Statement::Material), + ), + "MakeNamedMaterial" => Some( + material::parse_make_named_material(&mut self.input, textures) + .map(|(name, material)| Statement::MakeNamedMaterial(name, material)), + ), + "NamedMaterial" => Some(self.input.parse_parameter().map(Statement::NamedMaterial)), "ConcatTransform" => { Some(parse_transform(&mut self.input).map(Statement::ConcatTransform)) } @@ -410,7 +422,6 @@ impl Lexer { Ok(s) => Ok(Statement::CoordSysTransform(s)), Err(e) => Err(e), }), - "WorldBegin" => Some(Ok(Statement::WorldBegin)), _ => { if s.chars().any(|c| !c.is_ascii_alphabetic()) { diff --git a/ray-tracing-pbrt-scene/src/material.rs b/ray-tracing-pbrt-scene/src/material.rs new file mode 100644 index 0000000..1c71cac --- /dev/null +++ b/ray-tracing-pbrt-scene/src/material.rs @@ -0,0 +1,28 @@ +use super::*; + +pub trait PbrtMaterial: std::fmt::Debug + Send + Sync {} + +pub fn parse_make_named_material( + input: &mut Tokenizer, + textures: &HashMap>, +) -> Result<(String, Arc)> { + let name = input.parse_next()?; + + if input.parse_next::()?.as_str() != "\"string type\"" { + return Err(miette!( + "first element of make named material dict has to be type" + )); + } + Ok((name, parse_material(input, textures)?)) +} + +pub fn parse_material( + input: &mut Tokenizer, + textures: &HashMap>, +) -> Result> { + let material: String = input.parse_parameter()?; + + dbg!(material); + + todo!() +} diff --git a/ray-tracing-pbrt-scene/src/texture.rs b/ray-tracing-pbrt-scene/src/texture.rs index 3e7559b..2991344 100644 --- a/ray-tracing-pbrt-scene/src/texture.rs +++ b/ray-tracing-pbrt-scene/src/texture.rs @@ -1,14 +1,17 @@ use imagemap::{ImageMapEncoding, ImageMapWrap, SpectrumImageMapTexture}; use miette::{Result, miette}; use ray_tracing_core::{affine_transform::AffineTransform, color::Color, prelude::Float}; +use scale::SpectrumScaleTexture2d; use std::{collections::HashMap, ops::Deref, sync::Arc}; use crate::tokenizer::Tokenizer; mod checkerboard; mod imagemap; +mod scale; pub trait PbrtTexture: std::fmt::Debug + Send + Sync { + fn get_dimension(&self) -> TextureDimension; fn get_2d_float_texture(self: Arc) -> Result>; fn get_2d_spectrum_texture(self: Arc) -> Result>; } @@ -21,6 +24,22 @@ pub trait Pbrt_2d_spectrum_texture: std::fmt::Debug + Sync + Send { fn get(&self, u: Float, v: Float) -> Color; } +#[derive(Debug)] +enum TextureDimension { + D2, + D3, +} + +impl TextureDimension { + fn new(x: String) -> Result { + match x.as_str() { + "2" => Ok(TextureDimension::D2), + "3" => Ok(TextureDimension::D3), + _ => Err(miette!("Error parsing Texture dimension")), + } + } +} + #[derive(Debug)] enum TextureMapping { UV, @@ -46,6 +65,16 @@ fn parse_rgb(input: &mut Tokenizer) -> Result { Ok(Color::new(t[0], t[1], t[2])) } +fn parse_float_texture( + input: &mut Tokenizer, + textures: &HashMap>, +) -> Result> { + let texture_class: String = input.parse_next()?; + + dbg!(texture_class); + todo!() +} + fn parse_spectrum_texture( input: &mut Tokenizer, textures: &HashMap>, @@ -59,7 +88,7 @@ fn parse_spectrum_texture( vscale, Float, 1.0; udelta, Float, 0.0; vdelta, Float, 0.0; - dimension, u8, 2; + dimension, TextureDimension, TextureDimension::D2; tex1, ValueTexture, ValueTexture::Value(Color::white()); tex2, ValueTexture, ValueTexture::Value(Color::black()) => @@ -68,7 +97,7 @@ fn parse_spectrum_texture( vscale, "\"float vscale\"", input.parse_parameter()?; udelta, "\"float udelta\"", input.parse_parameter()?; vdelta, "\"float vdelta\"", input.parse_parameter()?; - dimension, "\"integer dimension\"", input.parse_parameter()?; + dimension, "\"integer dimension\"", TextureDimension::new(input.parse_parameter()?)?; tex1, "\"rgb tex1\"", ValueTexture::Value(parse_rgb(input)?); tex1, "\"spectrum tex1\"", ValueTexture::Value(parse_spectrum(input)?); tex1, "\"texture tex1\"", ValueTexture::Texture(input.parse_parameter()?); @@ -81,7 +110,7 @@ fn parse_spectrum_texture( let mapping = UVMapping::new(t.mapping, t.uscale, t.vscale, t.udelta, t.vdelta); match t.dimension { - 2 => Ok(Arc::new(checkerboard::SpectrumCheckerboardTexture2d { + TextureDimension::D2 => Ok(Arc::new(checkerboard::SpectrumCheckerboardTexture2d { mapping, tex: [ match t.tex1 { @@ -108,7 +137,9 @@ fn parse_spectrum_texture( }, ], })), - _ => Err(miette!("Only dimension 2 and 3 are supported")), + TextureDimension::D3 => { + todo!() + } } } "\"imagemap\"" => { @@ -149,6 +180,43 @@ fn parse_spectrum_texture( dbg!(path), )?)) } + "\"scale\"" => { + let t = parse_dict!(input => + tex, ValueTexture, ValueTexture::Value(Color::white()); + scale, ValueTexture, ValueTexture::Value(1.0) + => + tex, "\"rgb tex\"", ValueTexture::Value(parse_rgb(input)?); + tex, "\"spectrum tex\"", ValueTexture::Value(parse_spectrum(input)?); + tex, "\"texture tex\"", ValueTexture::Texture(input.parse_parameter()?); + scale, "\"float scale\"", ValueTexture::Value(input.parse_parameter()?); + scale, "\"texture scale\"", ValueTexture::Texture(input.parse_parameter()?) + ); + + Ok(Arc::new(SpectrumScaleTexture2d { + tex: match t.tex { + ValueTexture::Value(v) => ValueTexture::Value(v), + ValueTexture::Texture(t) => ValueTexture::Texture( + Arc::clone( + textures + .get(&t) + .ok_or_else(|| miette!("Unable to find texture scale"))?, + ) + .get_2d_spectrum_texture()?, + ), + }, + scale: match t.scale { + ValueTexture::Value(v) => ValueTexture::Value(v), + ValueTexture::Texture(t) => ValueTexture::Texture( + Arc::clone( + textures + .get(&t) + .ok_or_else(|| miette!("Unable to find texture scale"))?, + ) + .get_2d_float_texture()?, + ), + }, + })) + } _ => Err(miette!("unknown error {texture_class}")), } } @@ -162,6 +230,7 @@ pub fn parse_texture( match texture_type.as_str() { "\"spectrum\"" => parse_spectrum_texture(input, textures).map(|t| (texture_name, t)), + "\"float\"" => parse_float_texture(input, textures).map(|t| (texture_name, t)), _ => Err(miette!("Texture type has to be spectrum or float")), } } diff --git a/ray-tracing-pbrt-scene/src/texture/checkerboard.rs b/ray-tracing-pbrt-scene/src/texture/checkerboard.rs index f918d83..13f988a 100644 --- a/ray-tracing-pbrt-scene/src/texture/checkerboard.rs +++ b/ray-tracing-pbrt-scene/src/texture/checkerboard.rs @@ -35,6 +35,10 @@ impl PbrtTexture for FloatCheckerboardTexture2d { fn get_2d_spectrum_texture(self: Arc) -> Result> { Err(miette!("Unable to use this texture as a spectrum texture")) } + + fn get_dimension(&self) -> TextureDimension { + TextureDimension::D2 + } } #[derive(Debug)] pub(super) struct SpectrumCheckerboardTexture2d { @@ -71,4 +75,8 @@ impl PbrtTexture for SpectrumCheckerboardTexture2d { fn get_2d_spectrum_texture(self: Arc) -> Result> { Ok(self) } + + fn get_dimension(&self) -> TextureDimension { + TextureDimension::D2 + } } diff --git a/ray-tracing-pbrt-scene/src/texture/imagemap.rs b/ray-tracing-pbrt-scene/src/texture/imagemap.rs index a11b3a4..9a50c2d 100644 --- a/ray-tracing-pbrt-scene/src/texture/imagemap.rs +++ b/ray-tracing-pbrt-scene/src/texture/imagemap.rs @@ -46,7 +46,6 @@ impl ImageMapEncoding { } } -#[derive(Debug)] pub(super) struct SpectrumImageMapTexture { mapping: UVMapping, scale: Float, @@ -55,6 +54,18 @@ pub(super) struct SpectrumImageMapTexture { image: image::Rgb32FImage, } +impl std::fmt::Debug for SpectrumImageMapTexture { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SpectrumImageMapTexture") + .field("mapping", &self.mapping) + .field("scale", &self.scale) + .field("wrap", &self.wrap) + .field("invert", &self.invert) + .field("image", &"image data") + .finish() + } +} + fn srgb_nonlinear(x: f32) -> f32 { if x <= 0.04045 { x / 12.92 @@ -125,4 +136,8 @@ impl PbrtTexture for SpectrumImageMapTexture { fn get_2d_spectrum_texture(self: Arc) -> Result> { Ok(self) } + + fn get_dimension(&self) -> TextureDimension { + TextureDimension::D2 + } } diff --git a/ray-tracing-pbrt-scene/src/texture/scale.rs b/ray-tracing-pbrt-scene/src/texture/scale.rs new file mode 100644 index 0000000..88ac284 --- /dev/null +++ b/ray-tracing-pbrt-scene/src/texture/scale.rs @@ -0,0 +1,37 @@ +use super::*; + +#[derive(Debug)] +pub(super) struct SpectrumScaleTexture2d { + pub(super) tex: ValueTexture>, + pub(super) scale: ValueTexture>, +} + +impl PbrtTexture for SpectrumScaleTexture2d { + fn get_dimension(&self) -> TextureDimension { + TextureDimension::D2 + } + + fn get_2d_float_texture(self: Arc) -> Result> { + Err(miette!("Unable to convert to float texture")) + } + + fn get_2d_spectrum_texture(self: Arc) -> Result> { + Ok(self) + } +} + +impl Pbrt_2d_spectrum_texture for SpectrumScaleTexture2d { + fn get(&self, u: Float, v: Float) -> Color { + let x = match &self.tex { + ValueTexture::Value(x) => *x, + ValueTexture::Texture(t) => t.get(u, v), + }; + + let s = match &self.scale { + ValueTexture::Value(s) => *s, + ValueTexture::Texture(t) => t.get(u, v), + }; + + x * s + } +}