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 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<String>),
Transform(AffineTransform),
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> {
@ -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()) {

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 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<Self>) -> Result<Arc<dyn Pbrt_2d_float_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;
}
#[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)]
enum TextureMapping {
UV,
@ -46,6 +65,16 @@ fn parse_rgb(input: &mut Tokenizer) -> Result<Color> {
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(
input: &mut Tokenizer,
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
@ -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<Color, String>, ValueTexture::Value(Color::white());
tex2, ValueTexture<Color, String>, 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<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}")),
}
}
@ -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")),
}
}

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>> {
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<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
Ok(self)
}
fn get_dimension(&self) -> TextureDimension {
TextureDimension::D2
}
}

View file

@ -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<Self>) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
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
}
}