Add light as associated type for scene and get something to draw with pbrt materials.

This commit is contained in:
hal8174 2025-08-26 20:27:24 +02:00
parent b54a2b16fe
commit bb2089477e
Signed by: hal8174
SSH key fingerprint: SHA256:NN98ZYwnrreQLSOV/g+amY7C3yL/mS1heD7bi5t6PPw
13 changed files with 286 additions and 87 deletions

View file

@ -7,8 +7,9 @@ use material::PbrtMaterial;
use miette::{IntoDiagnostic, Result, bail, miette};
use ray_tracing_core::{
affine_transform::AffineTransform,
color::Color,
math::{Dir3, Pos3},
prelude::Float,
prelude::{Float, Rng},
};
use std::{
collections::HashMap,
@ -66,7 +67,7 @@ struct PbrtCamera {
}
#[derive(Debug)]
enum Statement {
enum Statement<R> {
AttributeBegin,
AttributeEnd,
WorldBegin,
@ -79,12 +80,12 @@ enum Statement {
Unknown(String, Vec<Token>),
Transform(AffineTransform),
Texture(String, Arc<dyn PbrtTexture>),
Material(Arc<dyn PbrtMaterial>),
MakeNamedMaterial(String, Arc<dyn PbrtMaterial>),
Material(Arc<dyn PbrtMaterial<R>>),
MakeNamedMaterial(String, Arc<dyn PbrtMaterial<R>>),
NamedMaterial(String),
}
fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> {
fn parse_look_at<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
let eye = Pos3::new(iter.parse_next()?, iter.parse_next()?, iter.parse_next()?);
let look_at = Pos3::new(iter.parse_next()?, iter.parse_next()?, iter.parse_next()?);
let up = Dir3::new(iter.parse_next()?, iter.parse_next()?, iter.parse_next()?);
@ -95,7 +96,7 @@ fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> {
))
}
fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> {
fn parse_shape<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
let shape_type = iter
.next_if_string_value()
.ok_or(miette!("unable to get shape type"))??;
@ -312,7 +313,7 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> {
}
}
fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> {
fn parse_camera<R>(tokenizer: &mut Tokenizer) -> Result<Statement<R>> {
let camera_type = tokenizer
.next_if_string_value()
.ok_or(miette!("unable to get shape type"))??;
@ -382,7 +383,7 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> {
}
impl Lexer {
fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> {
fn next<R: Rng>(&mut self, context: &PbrtContext<R>) -> Option<Result<Statement<R>>> {
match self.input.next() {
Some(Ok(Token::Identifier(s))) => match s.as_str() {
"AttributeBegin" => Some(Ok(Statement::AttributeBegin)),
@ -481,7 +482,7 @@ fn parse_transform(input: &mut Tokenizer) -> Result<AffineTransform> {
.ok_or(miette!("Unable to invert transformation"))
}
fn parse_translate(iter: &mut Tokenizer) -> Result<Statement> {
fn parse_translate<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
let pos = Pos3::new(iter.parse_next()?, iter.parse_next()?, iter.parse_next()?);
Ok(Statement::ConcatTransform(AffineTransform::translation(
@ -489,7 +490,7 @@ fn parse_translate(iter: &mut Tokenizer) -> Result<Statement> {
)))
}
fn parse_scale(iter: &mut Tokenizer) -> Result<Statement> {
fn parse_scale<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
Ok(Statement::ConcatTransform(AffineTransform::scale(
iter.parse_next()?,
iter.parse_next()?,
@ -497,7 +498,7 @@ fn parse_scale(iter: &mut Tokenizer) -> Result<Statement> {
)))
}
fn parse_rotate(iter: &mut Tokenizer) -> Result<Statement> {
fn parse_rotate<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
let angle = iter.parse_parameter()?;
let dir = Dir3::new(
iter.parse_parameter()?,
@ -557,7 +558,7 @@ impl Parser {
}
impl Parser {
fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> {
fn next<R: Rng>(&mut self, context: &PbrtContext<R>) -> Option<Result<Statement<R>>> {
if let Some(iter) = &mut self.inner {
if let Some(statement) = iter.next(context) {
return Some(statement);
@ -579,16 +580,21 @@ impl Parser {
}
#[derive(Debug)]
pub struct Pbrt {
pub struct Pbrt<R: Rng> {
pub settings: PbrtWorldSettings,
pub scene: PbrtScene,
pub scene: PbrtScene<R>,
}
impl Pbrt {
impl<R: Rng> Pbrt<R> {
fn new(settings: PbrtWorldSettings) -> Self {
Self {
settings,
scene: PbrtScene { shapes: Vec::new() },
scene: PbrtScene {
shapes: Vec::new(),
infinite_light: Some(scene::PbrtInfiniteLight {
color: Color::white(),
}),
},
}
}
}
@ -601,14 +607,14 @@ pub struct PbrtWorldSettings {
}
#[derive(Debug)]
pub struct PbrtContext {
pub struct PbrtContext<R> {
ctm: Vec<AffineTransform>,
textures: HashMap<String, Arc<dyn PbrtTexture>>,
material: Vec<Arc<dyn PbrtMaterial>>,
materials: HashMap<String, Arc<dyn PbrtMaterial>>,
material: Vec<Arc<dyn PbrtMaterial<R>>>,
materials: HashMap<String, Arc<dyn PbrtMaterial<R>>>,
}
impl PbrtContext {
impl<R> PbrtContext<R> {
fn new() -> Self {
Self {
ctm: vec![AffineTransform::identity()],
@ -626,11 +632,11 @@ impl PbrtContext {
self.textures.get(name)
}
pub fn get_named_material(&self, name: &String) -> Option<&Arc<dyn PbrtMaterial>> {
pub fn get_named_material(&self, name: &String) -> Option<&Arc<dyn PbrtMaterial<R>>> {
self.materials.get(name)
}
pub fn get_material(&self) -> Option<&Arc<dyn PbrtMaterial>> {
pub fn get_material(&self) -> Option<&Arc<dyn PbrtMaterial<R>>> {
self.material.last()
}
@ -656,7 +662,9 @@ impl PbrtContext {
}
}
fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
fn inner_parse_pbrt<R: Rng + std::fmt::Debug>(
path: impl AsRef<Path> + std::fmt::Debug,
) -> Result<Pbrt<R>> {
// unwrap on context.last() ok because context is never empty
let mut context = PbrtContext::new();
@ -792,6 +800,8 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
Ok(pbrt)
}
pub fn parse_pbrt_v4(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
pub fn parse_pbrt_v4<R: Rng + std::fmt::Debug>(
path: impl AsRef<Path> + std::fmt::Debug,
) -> Result<Pbrt<R>> {
inner_parse_pbrt(path)
}