First pbrt textures approach
This commit is contained in:
parent
b4d34aa6ca
commit
1196cb7758
2 changed files with 164 additions and 27 deletions
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
120
ray-tracing-pbrt-scene/src/texture.rs
Normal file
120
ray-tracing-pbrt-scene/src/texture.rs
Normal 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,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue