Add light as associated type for scene and get something to draw with pbrt materials.
This commit is contained in:
parent
b54a2b16fe
commit
bb2089477e
13 changed files with 286 additions and 87 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -2315,6 +2315,7 @@ dependencies = [
|
|||
"image 0.25.6",
|
||||
"miette",
|
||||
"nom 8.0.0",
|
||||
"rand",
|
||||
"ray-tracing-core",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,18 @@ pub trait Light<R: Rng>: Send + Sync + Debug {
|
|||
fn emit(&self, w_in: Dir3, rng: &mut R) -> Color;
|
||||
}
|
||||
|
||||
impl<R: Rng> Light<R> for &'_ dyn Light<R> {
|
||||
fn emit(&self, w_in: Dir3, rng: &mut R) -> Color {
|
||||
(*self).emit(w_in, rng)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng, L: Light<R>> Light<R> for &L {
|
||||
fn emit(&self, w_in: Dir3, rng: &mut R) -> Color {
|
||||
(*self).emit(w_in, rng)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AreaLight {
|
||||
pub(crate) color: Color,
|
||||
|
|
|
|||
|
|
@ -8,37 +8,43 @@ pub trait Scene<R: Rng> {
|
|||
Self: 'a,
|
||||
R: 'a;
|
||||
|
||||
type Light<'b>: Light<R>
|
||||
where
|
||||
Self: 'b,
|
||||
R: 'b;
|
||||
|
||||
fn intersect(
|
||||
&self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<Intersection<'_, R, Self::Mat<'_>>>;
|
||||
) -> Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>>;
|
||||
|
||||
fn sample_light<'b>(
|
||||
&self,
|
||||
w_in: Dir3,
|
||||
intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
||||
intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||
rng: &mut R,
|
||||
) -> Option<LightSample<'_, R>>
|
||||
where
|
||||
Self: 'b;
|
||||
}
|
||||
|
||||
pub struct Intersection<'sc, R: Rng, M: Material<R> + 'sc> {
|
||||
pub struct Intersection<R: Rng, M: Material<R>, L: Light<R>> {
|
||||
t: Float,
|
||||
normal: Dir3,
|
||||
material: Option<M>,
|
||||
light: Option<&'sc dyn Light<R>>,
|
||||
light: Option<L>,
|
||||
light_pdf: Float,
|
||||
r: std::marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<'sc, R: Rng, M: Material<R>> Intersection<'sc, R, M> {
|
||||
impl<R: Rng, M: Material<R>, L: Light<R>> Intersection<R, M, L> {
|
||||
pub fn new(
|
||||
t: Float,
|
||||
normal: Dir3,
|
||||
material: Option<M>,
|
||||
light: Option<&'sc dyn Light<R>>,
|
||||
light: Option<L>,
|
||||
light_pdf: Float,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
|
@ -47,6 +53,7 @@ impl<'sc, R: Rng, M: Material<R>> Intersection<'sc, R, M> {
|
|||
material,
|
||||
light,
|
||||
light_pdf,
|
||||
r: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,8 +69,8 @@ impl<'sc, R: Rng, M: Material<R>> Intersection<'sc, R, M> {
|
|||
self.material.as_ref()
|
||||
}
|
||||
|
||||
pub fn light(&self) -> Option<&'sc dyn Light<R>> {
|
||||
self.light
|
||||
pub fn light(&self) -> Option<&L> {
|
||||
self.light.as_ref()
|
||||
}
|
||||
|
||||
pub fn light_pdf(&self) -> Float {
|
||||
|
|
@ -120,19 +127,25 @@ impl<T: Scene<R> + ?Sized, R: Rng> Scene<R> for Box<T> {
|
|||
T: 'a,
|
||||
R: 'a;
|
||||
|
||||
type Light<'b>
|
||||
= T::Light<'b>
|
||||
where
|
||||
T: 'b,
|
||||
R: 'b;
|
||||
|
||||
fn intersect(
|
||||
&self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<Intersection<'_, R, Self::Mat<'_>>> {
|
||||
) -> Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>> {
|
||||
self.deref().intersect(ray, min, max)
|
||||
}
|
||||
|
||||
fn sample_light<'b>(
|
||||
&self,
|
||||
w_in: Dir3,
|
||||
intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
||||
intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||
rng: &mut R,
|
||||
) -> Option<LightSample<'_, R>>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@ nom = "8.0.0"
|
|||
thiserror = "2.0.12"
|
||||
image = "0.25.6"
|
||||
const_format = "0.2.34"
|
||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use clap::Parser;
|
||||
use rand::rngs::SmallRng;
|
||||
use ray_tracing_pbrt_scene::parse_pbrt_v4;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ struct Args {
|
|||
fn main() -> Result<(), miette::Error> {
|
||||
let args = Args::parse();
|
||||
|
||||
let _t = parse_pbrt_v4(args.filename)?;
|
||||
let _t = parse_pbrt_v4::<SmallRng>(args.filename)?;
|
||||
|
||||
// dbg!(t);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use ray_tracing_core::color::Color;
|
||||
use ray_tracing_core::{color::Color, material::SampleResult, prelude::*};
|
||||
|
||||
use crate::{
|
||||
either::Either,
|
||||
|
|
@ -7,12 +7,35 @@ use crate::{
|
|||
|
||||
use super::*;
|
||||
|
||||
pub trait PbrtMaterial: std::fmt::Debug + Send + Sync {}
|
||||
pub trait PbrtMaterial<R: Rng>: std::fmt::Debug + Send + Sync {
|
||||
/// evaluate f(w_in, w_out)
|
||||
fn eval(&self, u: Float, v: Float, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color;
|
||||
|
||||
pub fn parse_make_named_material(
|
||||
/// sample w_out and return:
|
||||
/// f(w_in, w_out) * cos(theta) / pdf
|
||||
fn sample(&self, u: Float, v: Float, w_in: Dir3, rng: &mut R) -> SampleResult {
|
||||
let w_out = Dir3::sample_cosine_hemisphere(rng);
|
||||
|
||||
SampleResult::new(
|
||||
w_out,
|
||||
self.eval(u, v, w_in, w_out, rng) * FloatConsts::PI,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
/// returns the pdf for (w_in, w_out)
|
||||
fn pdf(&self, u: Float, v: Float, w_in: Dir3, w_out: Dir3) -> Float {
|
||||
let _ = v;
|
||||
let _ = u;
|
||||
let _ = w_out;
|
||||
FloatConsts::FRAC_1_PI * Float::max(w_in.y(), 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_make_named_material<R: Rng>(
|
||||
input: &mut Tokenizer,
|
||||
context: &PbrtContext,
|
||||
) -> Result<(String, Arc<dyn PbrtMaterial>)> {
|
||||
context: &PbrtContext<R>,
|
||||
) -> Result<(String, Arc<dyn PbrtMaterial<R>>)> {
|
||||
let name = input.next_string_value()?;
|
||||
|
||||
if input.next_string_value()?.as_str() != "string type" {
|
||||
|
|
@ -42,7 +65,16 @@ struct PbrtCoatedDiffuseMaterial {
|
|||
>,
|
||||
}
|
||||
|
||||
impl PbrtMaterial for PbrtCoatedDiffuseMaterial {}
|
||||
impl<R: Rng> PbrtMaterial<R> for PbrtCoatedDiffuseMaterial {
|
||||
fn eval(&self, u: Float, v: Float, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color {
|
||||
let _ = rng;
|
||||
let _ = w_out;
|
||||
let _ = w_in;
|
||||
let _ = u;
|
||||
let _ = v;
|
||||
Color::black()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -57,7 +89,16 @@ struct PbrtDielectricMaterial {
|
|||
vroughness: Either<Float, Arc<dyn Pbrt2dFloatTexture>>,
|
||||
}
|
||||
|
||||
impl PbrtMaterial for PbrtDielectricMaterial {}
|
||||
impl<R: Rng> PbrtMaterial<R> for PbrtDielectricMaterial {
|
||||
fn eval(&self, u: Float, v: Float, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color {
|
||||
let _ = rng;
|
||||
let _ = w_out;
|
||||
let _ = w_in;
|
||||
let _ = v;
|
||||
let _ = u;
|
||||
Color::black()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -65,11 +106,24 @@ struct PbrtDiffuseMaterial {
|
|||
reflectance: Either<Color, Arc<dyn Pbrt2dSpectrumTexture>>,
|
||||
}
|
||||
|
||||
impl PbrtMaterial for PbrtDiffuseMaterial {}
|
||||
impl<R: Rng> PbrtMaterial<R> for PbrtDiffuseMaterial {
|
||||
fn eval(&self, u: Float, v: Float, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color {
|
||||
let _ = rng;
|
||||
let _ = w_in;
|
||||
if w_out.y() >= 0.0 {
|
||||
match &self.reflectance {
|
||||
Either::A(v) => *v,
|
||||
Either::B(t) => t.get(u, v),
|
||||
}
|
||||
} else {
|
||||
Color::black()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_2d_float_texture(
|
||||
fn parse_2d_float_texture<R: Rng>(
|
||||
input: &mut Tokenizer,
|
||||
context: &PbrtContext,
|
||||
context: &PbrtContext<R>,
|
||||
) -> Result<Arc<dyn Pbrt2dFloatTexture>> {
|
||||
let n = input.next_string_value()?;
|
||||
|
||||
|
|
@ -79,9 +133,9 @@ fn parse_2d_float_texture(
|
|||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
}
|
||||
|
||||
fn parse_2d_spectrum_texture(
|
||||
fn parse_2d_spectrum_texture<R: Rng>(
|
||||
input: &mut Tokenizer,
|
||||
context: &PbrtContext,
|
||||
context: &PbrtContext<R>,
|
||||
) -> Result<Arc<dyn Pbrt2dSpectrumTexture>> {
|
||||
let n = input.next_string_value()?;
|
||||
|
||||
|
|
@ -91,10 +145,10 @@ fn parse_2d_spectrum_texture(
|
|||
.and_then(|t| Arc::clone(t).get_2d_spectrum_texture())
|
||||
}
|
||||
|
||||
pub fn parse_material(
|
||||
pub fn parse_material<R: Rng>(
|
||||
input: &mut Tokenizer,
|
||||
context: &PbrtContext,
|
||||
) -> Result<Arc<dyn PbrtMaterial>> {
|
||||
context: &PbrtContext<R>,
|
||||
) -> Result<Arc<dyn PbrtMaterial<R>>> {
|
||||
let material: String = input.next_string_value()?;
|
||||
|
||||
match material.as_str() {
|
||||
|
|
|
|||
|
|
@ -1,47 +1,114 @@
|
|||
use ray_tracing_core::{
|
||||
prelude::{Material, Rng},
|
||||
scene::Scene,
|
||||
color::Color,
|
||||
light::Light,
|
||||
prelude::{Float, Material, Rng},
|
||||
scene::{Intersection, Scene},
|
||||
};
|
||||
|
||||
use crate::shape::Shape;
|
||||
use crate::{material::PbrtMaterial, shape::Shape};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PbrtScene {
|
||||
pub(crate) shapes: Vec<Shape>,
|
||||
pub struct PbrtScene<R: Rng> {
|
||||
pub(crate) shapes: Vec<Shape<R>>,
|
||||
pub(crate) infinite_light: Option<PbrtInfiniteLight>,
|
||||
}
|
||||
|
||||
impl<R: Rng> Scene<R> for PbrtScene {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PbrtInfiniteLight {
|
||||
pub(crate) color: Color,
|
||||
}
|
||||
|
||||
impl<R: Rng> Light<R> for PbrtInfiniteLight {
|
||||
fn emit(&self, w_in: ray_tracing_core::prelude::Dir3, rng: &mut R) -> Color {
|
||||
let _ = rng;
|
||||
let _ = w_in;
|
||||
self.color
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UVMaterial<'a, R: Rng + std::fmt::Debug> {
|
||||
pub(crate) u: Float,
|
||||
pub(crate) v: Float,
|
||||
pub(crate) material: &'a dyn PbrtMaterial<R>,
|
||||
}
|
||||
|
||||
impl<R: Rng + std::fmt::Debug> Material<R> for UVMaterial<'_, R> {
|
||||
fn eval(
|
||||
&self,
|
||||
w_in: ray_tracing_core::prelude::Dir3,
|
||||
w_out: ray_tracing_core::prelude::Dir3,
|
||||
rng: &mut R,
|
||||
) -> Color {
|
||||
self.material.eval(self.u, self.v, w_in, w_out, rng)
|
||||
}
|
||||
|
||||
fn sample(
|
||||
&self,
|
||||
w_in: ray_tracing_core::prelude::Dir3,
|
||||
rng: &mut R,
|
||||
) -> ray_tracing_core::material::SampleResult {
|
||||
self.material.sample(self.u, self.v, w_in, rng)
|
||||
}
|
||||
|
||||
fn pdf(
|
||||
&self,
|
||||
w_in: ray_tracing_core::prelude::Dir3,
|
||||
w_out: ray_tracing_core::prelude::Dir3,
|
||||
) -> Float {
|
||||
self.material.pdf(self.u, self.v, w_in, w_out)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng + std::fmt::Debug> Scene<R> for PbrtScene<R> {
|
||||
type Mat<'a>
|
||||
= &'a dyn Material<R>
|
||||
= UVMaterial<'a, R>
|
||||
where
|
||||
R: 'a;
|
||||
|
||||
type Light<'b>
|
||||
= &'b dyn Light<R>
|
||||
where
|
||||
R: 'b;
|
||||
|
||||
fn intersect(
|
||||
&'_ self,
|
||||
ray: ray_tracing_core::prelude::Ray,
|
||||
min: ray_tracing_core::prelude::Float,
|
||||
max: ray_tracing_core::prelude::Float,
|
||||
) -> Option<ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>> {
|
||||
) -> Option<ray_tracing_core::scene::Intersection<R, Self::Mat<'_>, Self::Light<'_>>> {
|
||||
let mut i = None;
|
||||
for s in &self.shapes {
|
||||
if let Some(new_i) = s.intersect::<R>(ray, min, max)
|
||||
if let Some(new_i) = s.intersect(ray, min, max)
|
||||
&& i.as_ref().is_none_or(
|
||||
|i: &ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>| {
|
||||
i.t() > new_i.t()
|
||||
},
|
||||
|i: &ray_tracing_core::scene::Intersection<
|
||||
R,
|
||||
Self::Mat<'_>,
|
||||
Self::Light<'_>,
|
||||
>| { i.t() > new_i.t() },
|
||||
)
|
||||
{
|
||||
i = Some(new_i);
|
||||
}
|
||||
}
|
||||
|
||||
i
|
||||
i.or_else(|| {
|
||||
self.infinite_light.as_ref().map(|l| {
|
||||
Intersection::new(
|
||||
Float::INFINITY,
|
||||
-ray.dir(),
|
||||
None,
|
||||
Some(l as &dyn Light<R>),
|
||||
0.0,
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn sample_light<'b>(
|
||||
&self,
|
||||
_w_in: ray_tracing_core::prelude::Dir3,
|
||||
_intersection: &ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'b>>,
|
||||
_intersection: &ray_tracing_core::scene::Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||
_rng: &mut R,
|
||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ use std::sync::Arc;
|
|||
|
||||
use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection};
|
||||
|
||||
use crate::material::PbrtMaterial;
|
||||
use crate::{material::PbrtMaterial, scene::UVMaterial};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct Shape {
|
||||
pub(crate) struct Shape<R: Rng> {
|
||||
pub(crate) ctm: AffineTransform,
|
||||
pub(crate) material: Arc<dyn PbrtMaterial>,
|
||||
pub(crate) material: Arc<dyn PbrtMaterial<R>>,
|
||||
pub(crate) obj: ShapeType,
|
||||
pub(crate) alpha: ShapeAlpha,
|
||||
}
|
||||
|
|
@ -158,13 +158,13 @@ fn bilinear_intersection(
|
|||
.next()
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
pub(crate) fn intersect<R: Rng>(
|
||||
impl<R: Rng + std::fmt::Debug> Shape<R> {
|
||||
pub(crate) fn intersect(
|
||||
&'_ self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<Intersection<'_, R, &'_ dyn Material<R>>> {
|
||||
) -> Option<Intersection<R, UVMaterial<'_, R>, &'_ dyn Light<R>>> {
|
||||
let ray = self.ctm.transform_ray(ray);
|
||||
|
||||
match &self.obj {
|
||||
|
|
@ -213,10 +213,19 @@ impl Shape {
|
|||
}
|
||||
false
|
||||
}) {
|
||||
let p = ray.at(t0);
|
||||
let mut phi = Float::atan2(p.y(), p.x());
|
||||
if phi < 0.0 {
|
||||
phi += 2.0 * FloatConsts::PI;
|
||||
}
|
||||
return Some(Intersection::new(
|
||||
t,
|
||||
(ray.at(t) - Pos3::zero()).normalize(),
|
||||
None,
|
||||
Some(UVMaterial {
|
||||
u: phi,
|
||||
v: Float::acos(p.z() / radius),
|
||||
material: self.material.as_ref(),
|
||||
}),
|
||||
None,
|
||||
0.0,
|
||||
));
|
||||
|
|
@ -231,10 +240,20 @@ impl Shape {
|
|||
uv: _,
|
||||
} => {
|
||||
if indices.is_empty()
|
||||
&& let Some((t, _u, _v)) =
|
||||
&& let Some((t, u, v)) =
|
||||
bilinear_intersection(ray, min, max, [p[0], p[1], p[2], p[3]])
|
||||
{
|
||||
return Some(Intersection::new(t, Dir3::up(), None, None, 0.0));
|
||||
return Some(Intersection::new(
|
||||
t,
|
||||
Dir3::up(),
|
||||
Some(UVMaterial {
|
||||
u,
|
||||
v,
|
||||
material: self.material.as_ref(),
|
||||
}),
|
||||
None,
|
||||
0.0,
|
||||
));
|
||||
}
|
||||
}
|
||||
ShapeType::LoopSubDiv { .. } => todo!(),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use crate::{PbrtContext, either::Either, tokenizer::Tokenizer};
|
||||
use imagemap::{ImageMapEncoding, ImageMapWrap, SpectrumImageMapTexture};
|
||||
use miette::{Result, miette};
|
||||
use ray_tracing_core::{color::Color, prelude::Float};
|
||||
use ray_tracing_core::{
|
||||
color::Color,
|
||||
prelude::{Float, Rng},
|
||||
};
|
||||
use scale::SpectrumScaleTexture2d;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -65,9 +68,9 @@ pub fn parse_rgb(input: &mut Tokenizer) -> Result<Color> {
|
|||
Ok(Color::new(t[0], t[1], t[2]))
|
||||
}
|
||||
|
||||
fn parse_float_texture(
|
||||
fn parse_float_texture<R: Rng>(
|
||||
input: &mut Tokenizer,
|
||||
context: &PbrtContext,
|
||||
context: &PbrtContext<R>,
|
||||
) -> Result<Arc<dyn PbrtTexture>> {
|
||||
let texture_class = input.next_string_value()?;
|
||||
|
||||
|
|
@ -138,9 +141,9 @@ fn parse_float_texture(
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_spectrum_texture(
|
||||
fn parse_spectrum_texture<R: Rng>(
|
||||
input: &mut Tokenizer,
|
||||
context: &PbrtContext,
|
||||
context: &PbrtContext<R>,
|
||||
) -> Result<Arc<dyn PbrtTexture>> {
|
||||
let texture_class = input.next_string_value()?;
|
||||
match texture_class.as_str() {
|
||||
|
|
@ -284,9 +287,9 @@ fn parse_spectrum_texture(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_texture(
|
||||
pub fn parse_texture<R: Rng>(
|
||||
input: &mut Tokenizer,
|
||||
context: &PbrtContext,
|
||||
context: &PbrtContext<R>,
|
||||
) -> Result<(String, Arc<dyn PbrtTexture>)> {
|
||||
let texture_name: String = input.next_string_value()?;
|
||||
let texture_type: String = input.next_string_value()?;
|
||||
|
|
|
|||
|
|
@ -78,12 +78,19 @@ impl<A: AccelerationStructure<u32>, R: Rng> Scene<R> for AccelerationStructureSc
|
|||
where
|
||||
A: 'a,
|
||||
R: 'a;
|
||||
|
||||
type Light<'b>
|
||||
= &'b dyn Light<R>
|
||||
where
|
||||
A: 'b,
|
||||
R: 'b;
|
||||
|
||||
fn intersect(
|
||||
&self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>> {
|
||||
) -> Option<ray_tracing_core::scene::Intersection<R, Self::Mat<'_>, Self::Light<'_>>> {
|
||||
let (t, n, i) = self.acceleration_structure.intersect(ray, min, max)?;
|
||||
|
||||
let material = &self.materials[i as usize];
|
||||
|
|
@ -106,7 +113,7 @@ impl<A: AccelerationStructure<u32>, R: Rng> Scene<R> for AccelerationStructureSc
|
|||
fn sample_light<'b>(
|
||||
&self,
|
||||
_w_in: Dir3,
|
||||
_intersection: &ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'b>>,
|
||||
_intersection: &ray_tracing_core::scene::Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||
rng: &mut R,
|
||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -37,13 +37,19 @@ where
|
|||
M: 'a,
|
||||
R: 'a;
|
||||
|
||||
type Light<'b>
|
||||
= &'b dyn Light<R>
|
||||
where
|
||||
M: 'b,
|
||||
R: 'b;
|
||||
|
||||
fn intersect(
|
||||
&self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<Intersection<'_, R, Self::Mat<'_>>> {
|
||||
let mut intersection: Option<Intersection<'_, R, Self::Mat<'_>>> = None;
|
||||
) -> Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>> {
|
||||
let mut intersection: Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>> = None;
|
||||
|
||||
for &(c, r) in &self.spheres {
|
||||
let offset = ray.start() - c;
|
||||
|
|
@ -84,7 +90,7 @@ where
|
|||
fn sample_light<'b>(
|
||||
&self,
|
||||
_w_in: Dir3,
|
||||
_intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
||||
_intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||
_rng: &mut R,
|
||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -323,12 +323,17 @@ impl<R: Rng> Scene<R> for TriangleBVH<R> {
|
|||
where
|
||||
R: 'a;
|
||||
|
||||
type Light<'b>
|
||||
= &'b dyn Light<R>
|
||||
where
|
||||
R: 'b;
|
||||
|
||||
fn intersect(
|
||||
&self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>> {
|
||||
) -> Option<ray_tracing_core::scene::Intersection<R, Self::Mat<'_>, Self::Light<'_>>> {
|
||||
let (i, t) = self.intersect_bvh(0, ray, min, max)?;
|
||||
|
||||
let triangle = self.triangles[i as usize];
|
||||
|
|
@ -350,7 +355,7 @@ impl<R: Rng> Scene<R> for TriangleBVH<R> {
|
|||
fn sample_light<'b>(
|
||||
&self,
|
||||
_w_in: Dir3,
|
||||
_intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
||||
_intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||
rng: &mut R,
|
||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||
where
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue