Add Pbrt scale texture and initial material stuff

This commit is contained in:
hal8174 2025-08-17 17:08:11 +02:00
parent 2476d2d49a
commit 0dfa2128dd
Signed by: hal8174
SSH key fingerprint: SHA256:NN98ZYwnrreQLSOV/g+amY7C3yL/mS1heD7bi5t6PPw
6 changed files with 176 additions and 8 deletions

View file

@ -1,5 +1,6 @@
use crate::tokenizer::Tokenizer; use crate::tokenizer::Tokenizer;
use error::SourceFile; use error::SourceFile;
use material::PbrtMaterial;
use miette::{Diagnostic, IntoDiagnostic, Result, SourceSpan, bail, miette}; use miette::{Diagnostic, IntoDiagnostic, Result, SourceSpan, bail, miette};
use ray_tracing_core::{ use ray_tracing_core::{
affine_transform::AffineTransform, affine_transform::AffineTransform,
@ -16,10 +17,10 @@ use thiserror::Error;
#[macro_use] #[macro_use]
mod tokenizer; mod tokenizer;
mod error; mod error;
mod material;
mod texture; mod texture;
struct Lexer { struct Lexer {
input: Tokenizer, input: Tokenizer,
} }
@ -70,6 +71,9 @@ enum Statement {
Unknown(String, Vec<String>), Unknown(String, Vec<String>),
Transform(AffineTransform), Transform(AffineTransform),
Texture(String, Arc<dyn PbrtTexture>), Texture(String, Arc<dyn PbrtTexture>),
Material(Arc<dyn PbrtMaterial>),
MakeNamedMaterial(String, Arc<dyn PbrtMaterial>),
NamedMaterial(String),
} }
fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> { fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> {
@ -399,6 +403,14 @@ impl Lexer {
texture::parse_texture(&mut self.input, textures) texture::parse_texture(&mut self.input, textures)
.map(|(name, texture)| Statement::Texture(name, texture)), .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" => { "ConcatTransform" => {
Some(parse_transform(&mut self.input).map(Statement::ConcatTransform)) Some(parse_transform(&mut self.input).map(Statement::ConcatTransform))
} }
@ -410,7 +422,6 @@ impl Lexer {
Ok(s) => Ok(Statement::CoordSysTransform(s)), Ok(s) => Ok(Statement::CoordSysTransform(s)),
Err(e) => Err(e), Err(e) => Err(e),
}), }),
"WorldBegin" => Some(Ok(Statement::WorldBegin)), "WorldBegin" => Some(Ok(Statement::WorldBegin)),
_ => { _ => {
if s.chars().any(|c| !c.is_ascii_alphabetic()) { if s.chars().any(|c| !c.is_ascii_alphabetic()) {

View file

@ -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<String, Arc<dyn PbrtTexture>>,
) -> Result<(String, Arc<dyn PbrtMaterial>)> {
let name = input.parse_next()?;
if input.parse_next::<String>()?.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<String, Arc<dyn PbrtTexture>>,
) -> Result<Arc<dyn PbrtMaterial>> {
let material: String = input.parse_parameter()?;
dbg!(material);
todo!()
}

View file

@ -1,14 +1,17 @@
use imagemap::{ImageMapEncoding, ImageMapWrap, SpectrumImageMapTexture}; use imagemap::{ImageMapEncoding, ImageMapWrap, SpectrumImageMapTexture};
use miette::{Result, miette}; use miette::{Result, miette};
use ray_tracing_core::{affine_transform::AffineTransform, color::Color, prelude::Float}; use ray_tracing_core::{affine_transform::AffineTransform, color::Color, prelude::Float};
use scale::SpectrumScaleTexture2d;
use std::{collections::HashMap, ops::Deref, sync::Arc}; use std::{collections::HashMap, ops::Deref, sync::Arc};
use crate::tokenizer::Tokenizer; use crate::tokenizer::Tokenizer;
mod checkerboard; mod checkerboard;
mod imagemap; mod imagemap;
mod scale;
pub trait PbrtTexture: std::fmt::Debug + Send + Sync { pub trait PbrtTexture: std::fmt::Debug + Send + Sync {
fn get_dimension(&self) -> TextureDimension;
fn get_2d_float_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_float_texture>>; 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>>; fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>>;
} }
@ -21,6 +24,22 @@ pub trait Pbrt_2d_spectrum_texture: std::fmt::Debug + Sync + Send {
fn get(&self, u: Float, v: Float) -> Color; fn get(&self, u: Float, v: Float) -> Color;
} }
#[derive(Debug)]
enum TextureDimension {
D2,
D3,
}
impl TextureDimension {
fn new(x: String) -> Result<Self> {
match x.as_str() {
"2" => Ok(TextureDimension::D2),
"3" => Ok(TextureDimension::D3),
_ => Err(miette!("Error parsing Texture dimension")),
}
}
}
#[derive(Debug)] #[derive(Debug)]
enum TextureMapping { enum TextureMapping {
UV, UV,
@ -46,6 +65,16 @@ fn parse_rgb(input: &mut Tokenizer) -> Result<Color> {
Ok(Color::new(t[0], t[1], t[2])) Ok(Color::new(t[0], t[1], t[2]))
} }
fn parse_float_texture(
input: &mut Tokenizer,
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
) -> Result<Arc<dyn PbrtTexture>> {
let texture_class: String = input.parse_next()?;
dbg!(texture_class);
todo!()
}
fn parse_spectrum_texture( fn parse_spectrum_texture(
input: &mut Tokenizer, input: &mut Tokenizer,
textures: &HashMap<String, Arc<dyn PbrtTexture>>, textures: &HashMap<String, Arc<dyn PbrtTexture>>,
@ -59,7 +88,7 @@ fn parse_spectrum_texture(
vscale, Float, 1.0; vscale, Float, 1.0;
udelta, Float, 0.0; udelta, Float, 0.0;
vdelta, Float, 0.0; vdelta, Float, 0.0;
dimension, u8, 2; dimension, TextureDimension, TextureDimension::D2;
tex1, ValueTexture<Color, String>, ValueTexture::Value(Color::white()); tex1, ValueTexture<Color, String>, ValueTexture::Value(Color::white());
tex2, ValueTexture<Color, String>, ValueTexture::Value(Color::black()) tex2, ValueTexture<Color, String>, ValueTexture::Value(Color::black())
=> =>
@ -68,7 +97,7 @@ fn parse_spectrum_texture(
vscale, "\"float vscale\"", input.parse_parameter()?; vscale, "\"float vscale\"", input.parse_parameter()?;
udelta, "\"float udelta\"", input.parse_parameter()?; udelta, "\"float udelta\"", input.parse_parameter()?;
vdelta, "\"float vdelta\"", 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, "\"rgb tex1\"", ValueTexture::Value(parse_rgb(input)?);
tex1, "\"spectrum tex1\"", ValueTexture::Value(parse_spectrum(input)?); tex1, "\"spectrum tex1\"", ValueTexture::Value(parse_spectrum(input)?);
tex1, "\"texture tex1\"", ValueTexture::Texture(input.parse_parameter()?); 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); let mapping = UVMapping::new(t.mapping, t.uscale, t.vscale, t.udelta, t.vdelta);
match t.dimension { match t.dimension {
2 => Ok(Arc::new(checkerboard::SpectrumCheckerboardTexture2d { TextureDimension::D2 => Ok(Arc::new(checkerboard::SpectrumCheckerboardTexture2d {
mapping, mapping,
tex: [ tex: [
match t.tex1 { match t.tex1 {
@ -108,7 +137,9 @@ fn parse_spectrum_texture(
}, },
], ],
})), })),
_ => Err(miette!("Only dimension 2 and 3 are supported")), TextureDimension::D3 => {
todo!()
}
} }
} }
"\"imagemap\"" => { "\"imagemap\"" => {
@ -149,6 +180,43 @@ fn parse_spectrum_texture(
dbg!(path), dbg!(path),
)?)) )?))
} }
"\"scale\"" => {
let t = parse_dict!(input =>
tex, ValueTexture<Color, String>, ValueTexture::Value(Color::white());
scale, ValueTexture<Float, String>, 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}")), _ => Err(miette!("unknown error {texture_class}")),
} }
} }
@ -162,6 +230,7 @@ pub fn parse_texture(
match texture_type.as_str() { match texture_type.as_str() {
"\"spectrum\"" => parse_spectrum_texture(input, textures).map(|t| (texture_name, t)), "\"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")), _ => Err(miette!("Texture type has to be spectrum or float")),
} }
} }

View file

@ -35,6 +35,10 @@ impl PbrtTexture for FloatCheckerboardTexture2d {
fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> { fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
Err(miette!("Unable to use this texture as a spectrum texture")) Err(miette!("Unable to use this texture as a spectrum texture"))
} }
fn get_dimension(&self) -> TextureDimension {
TextureDimension::D2
}
} }
#[derive(Debug)] #[derive(Debug)]
pub(super) struct SpectrumCheckerboardTexture2d { pub(super) struct SpectrumCheckerboardTexture2d {
@ -71,4 +75,8 @@ impl PbrtTexture for SpectrumCheckerboardTexture2d {
fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> { fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
Ok(self) Ok(self)
} }
fn get_dimension(&self) -> TextureDimension {
TextureDimension::D2
}
} }

View file

@ -46,7 +46,6 @@ impl ImageMapEncoding {
} }
} }
#[derive(Debug)]
pub(super) struct SpectrumImageMapTexture { pub(super) struct SpectrumImageMapTexture {
mapping: UVMapping, mapping: UVMapping,
scale: Float, scale: Float,
@ -55,6 +54,18 @@ pub(super) struct SpectrumImageMapTexture {
image: image::Rgb32FImage, 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 { fn srgb_nonlinear(x: f32) -> f32 {
if x <= 0.04045 { if x <= 0.04045 {
x / 12.92 x / 12.92
@ -125,4 +136,8 @@ impl PbrtTexture for SpectrumImageMapTexture {
fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> { fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
Ok(self) Ok(self)
} }
fn get_dimension(&self) -> TextureDimension {
TextureDimension::D2
}
} }

View file

@ -0,0 +1,37 @@
use super::*;
#[derive(Debug)]
pub(super) struct SpectrumScaleTexture2d {
pub(super) tex: ValueTexture<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
pub(super) scale: ValueTexture<Float, Arc<dyn Pbrt_2d_float_texture>>,
}
impl PbrtTexture for SpectrumScaleTexture2d {
fn get_dimension(&self) -> TextureDimension {
TextureDimension::D2
}
fn get_2d_float_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_float_texture>> {
Err(miette!("Unable to convert to float texture"))
}
fn get_2d_spectrum_texture(self: Arc<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
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
}
}