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",
|
"image 0.25.6",
|
||||||
"miette",
|
"miette",
|
||||||
"nom 8.0.0",
|
"nom 8.0.0",
|
||||||
|
"rand",
|
||||||
"ray-tracing-core",
|
"ray-tracing-core",
|
||||||
"thiserror 2.0.12",
|
"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;
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AreaLight {
|
pub struct AreaLight {
|
||||||
pub(crate) color: Color,
|
pub(crate) color: Color,
|
||||||
|
|
|
||||||
|
|
@ -8,37 +8,43 @@ pub trait Scene<R: Rng> {
|
||||||
Self: 'a,
|
Self: 'a,
|
||||||
R: 'a;
|
R: 'a;
|
||||||
|
|
||||||
|
type Light<'b>: Light<R>
|
||||||
|
where
|
||||||
|
Self: 'b,
|
||||||
|
R: 'b;
|
||||||
|
|
||||||
fn intersect(
|
fn intersect(
|
||||||
&self,
|
&self,
|
||||||
ray: Ray,
|
ray: Ray,
|
||||||
min: Float,
|
min: Float,
|
||||||
max: Float,
|
max: Float,
|
||||||
) -> Option<Intersection<'_, R, Self::Mat<'_>>>;
|
) -> Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>>;
|
||||||
|
|
||||||
fn sample_light<'b>(
|
fn sample_light<'b>(
|
||||||
&self,
|
&self,
|
||||||
w_in: Dir3,
|
w_in: Dir3,
|
||||||
intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Option<LightSample<'_, R>>
|
) -> Option<LightSample<'_, R>>
|
||||||
where
|
where
|
||||||
Self: 'b;
|
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,
|
t: Float,
|
||||||
normal: Dir3,
|
normal: Dir3,
|
||||||
material: Option<M>,
|
material: Option<M>,
|
||||||
light: Option<&'sc dyn Light<R>>,
|
light: Option<L>,
|
||||||
light_pdf: Float,
|
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(
|
pub fn new(
|
||||||
t: Float,
|
t: Float,
|
||||||
normal: Dir3,
|
normal: Dir3,
|
||||||
material: Option<M>,
|
material: Option<M>,
|
||||||
light: Option<&'sc dyn Light<R>>,
|
light: Option<L>,
|
||||||
light_pdf: Float,
|
light_pdf: Float,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -47,6 +53,7 @@ impl<'sc, R: Rng, M: Material<R>> Intersection<'sc, R, M> {
|
||||||
material,
|
material,
|
||||||
light,
|
light,
|
||||||
light_pdf,
|
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()
|
self.material.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn light(&self) -> Option<&'sc dyn Light<R>> {
|
pub fn light(&self) -> Option<&L> {
|
||||||
self.light
|
self.light.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn light_pdf(&self) -> Float {
|
pub fn light_pdf(&self) -> Float {
|
||||||
|
|
@ -120,19 +127,25 @@ impl<T: Scene<R> + ?Sized, R: Rng> Scene<R> for Box<T> {
|
||||||
T: 'a,
|
T: 'a,
|
||||||
R: 'a;
|
R: 'a;
|
||||||
|
|
||||||
|
type Light<'b>
|
||||||
|
= T::Light<'b>
|
||||||
|
where
|
||||||
|
T: 'b,
|
||||||
|
R: 'b;
|
||||||
|
|
||||||
fn intersect(
|
fn intersect(
|
||||||
&self,
|
&self,
|
||||||
ray: Ray,
|
ray: Ray,
|
||||||
min: Float,
|
min: Float,
|
||||||
max: Float,
|
max: Float,
|
||||||
) -> Option<Intersection<'_, R, Self::Mat<'_>>> {
|
) -> Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>> {
|
||||||
self.deref().intersect(ray, min, max)
|
self.deref().intersect(ray, min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sample_light<'b>(
|
fn sample_light<'b>(
|
||||||
&self,
|
&self,
|
||||||
w_in: Dir3,
|
w_in: Dir3,
|
||||||
intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Option<LightSample<'_, R>>
|
) -> Option<LightSample<'_, R>>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,4 @@ nom = "8.0.0"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
const_format = "0.2.34"
|
const_format = "0.2.34"
|
||||||
|
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use rand::rngs::SmallRng;
|
||||||
use ray_tracing_pbrt_scene::parse_pbrt_v4;
|
use ray_tracing_pbrt_scene::parse_pbrt_v4;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
|
@ -10,7 +11,7 @@ struct Args {
|
||||||
fn main() -> Result<(), miette::Error> {
|
fn main() -> Result<(), miette::Error> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let _t = parse_pbrt_v4(args.filename)?;
|
let _t = parse_pbrt_v4::<SmallRng>(args.filename)?;
|
||||||
|
|
||||||
// dbg!(t);
|
// dbg!(t);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ use material::PbrtMaterial;
|
||||||
use miette::{IntoDiagnostic, Result, bail, miette};
|
use miette::{IntoDiagnostic, Result, bail, miette};
|
||||||
use ray_tracing_core::{
|
use ray_tracing_core::{
|
||||||
affine_transform::AffineTransform,
|
affine_transform::AffineTransform,
|
||||||
|
color::Color,
|
||||||
math::{Dir3, Pos3},
|
math::{Dir3, Pos3},
|
||||||
prelude::Float,
|
prelude::{Float, Rng},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
|
@ -66,7 +67,7 @@ struct PbrtCamera {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Statement {
|
enum Statement<R> {
|
||||||
AttributeBegin,
|
AttributeBegin,
|
||||||
AttributeEnd,
|
AttributeEnd,
|
||||||
WorldBegin,
|
WorldBegin,
|
||||||
|
|
@ -79,12 +80,12 @@ enum Statement {
|
||||||
Unknown(String, Vec<Token>),
|
Unknown(String, Vec<Token>),
|
||||||
Transform(AffineTransform),
|
Transform(AffineTransform),
|
||||||
Texture(String, Arc<dyn PbrtTexture>),
|
Texture(String, Arc<dyn PbrtTexture>),
|
||||||
Material(Arc<dyn PbrtMaterial>),
|
Material(Arc<dyn PbrtMaterial<R>>),
|
||||||
MakeNamedMaterial(String, Arc<dyn PbrtMaterial>),
|
MakeNamedMaterial(String, Arc<dyn PbrtMaterial<R>>),
|
||||||
NamedMaterial(String),
|
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 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 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()?);
|
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
|
let shape_type = iter
|
||||||
.next_if_string_value()
|
.next_if_string_value()
|
||||||
.ok_or(miette!("unable to get shape type"))??;
|
.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
|
let camera_type = tokenizer
|
||||||
.next_if_string_value()
|
.next_if_string_value()
|
||||||
.ok_or(miette!("unable to get shape type"))??;
|
.ok_or(miette!("unable to get shape type"))??;
|
||||||
|
|
@ -382,7 +383,7 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lexer {
|
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() {
|
match self.input.next() {
|
||||||
Some(Ok(Token::Identifier(s))) => match s.as_str() {
|
Some(Ok(Token::Identifier(s))) => match s.as_str() {
|
||||||
"AttributeBegin" => Some(Ok(Statement::AttributeBegin)),
|
"AttributeBegin" => Some(Ok(Statement::AttributeBegin)),
|
||||||
|
|
@ -481,7 +482,7 @@ fn parse_transform(input: &mut Tokenizer) -> Result<AffineTransform> {
|
||||||
.ok_or(miette!("Unable to invert transformation"))
|
.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()?);
|
let pos = Pos3::new(iter.parse_next()?, iter.parse_next()?, iter.parse_next()?);
|
||||||
|
|
||||||
Ok(Statement::ConcatTransform(AffineTransform::translation(
|
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(
|
Ok(Statement::ConcatTransform(AffineTransform::scale(
|
||||||
iter.parse_next()?,
|
iter.parse_next()?,
|
||||||
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 angle = iter.parse_parameter()?;
|
||||||
let dir = Dir3::new(
|
let dir = Dir3::new(
|
||||||
iter.parse_parameter()?,
|
iter.parse_parameter()?,
|
||||||
|
|
@ -557,7 +558,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
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(iter) = &mut self.inner {
|
||||||
if let Some(statement) = iter.next(context) {
|
if let Some(statement) = iter.next(context) {
|
||||||
return Some(statement);
|
return Some(statement);
|
||||||
|
|
@ -579,16 +580,21 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pbrt {
|
pub struct Pbrt<R: Rng> {
|
||||||
pub settings: PbrtWorldSettings,
|
pub settings: PbrtWorldSettings,
|
||||||
pub scene: PbrtScene,
|
pub scene: PbrtScene<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pbrt {
|
impl<R: Rng> Pbrt<R> {
|
||||||
fn new(settings: PbrtWorldSettings) -> Self {
|
fn new(settings: PbrtWorldSettings) -> Self {
|
||||||
Self {
|
Self {
|
||||||
settings,
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct PbrtContext {
|
pub struct PbrtContext<R> {
|
||||||
ctm: Vec<AffineTransform>,
|
ctm: Vec<AffineTransform>,
|
||||||
textures: HashMap<String, Arc<dyn PbrtTexture>>,
|
textures: HashMap<String, Arc<dyn PbrtTexture>>,
|
||||||
material: Vec<Arc<dyn PbrtMaterial>>,
|
material: Vec<Arc<dyn PbrtMaterial<R>>>,
|
||||||
materials: HashMap<String, Arc<dyn PbrtMaterial>>,
|
materials: HashMap<String, Arc<dyn PbrtMaterial<R>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PbrtContext {
|
impl<R> PbrtContext<R> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ctm: vec![AffineTransform::identity()],
|
ctm: vec![AffineTransform::identity()],
|
||||||
|
|
@ -626,11 +632,11 @@ impl PbrtContext {
|
||||||
self.textures.get(name)
|
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)
|
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()
|
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
|
// unwrap on context.last() ok because context is never empty
|
||||||
let mut context = PbrtContext::new();
|
let mut context = PbrtContext::new();
|
||||||
|
|
||||||
|
|
@ -792,6 +800,8 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
|
||||||
Ok(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)
|
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::{
|
use crate::{
|
||||||
either::Either,
|
either::Either,
|
||||||
|
|
@ -7,12 +7,35 @@ use crate::{
|
||||||
|
|
||||||
use super::*;
|
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,
|
input: &mut Tokenizer,
|
||||||
context: &PbrtContext,
|
context: &PbrtContext<R>,
|
||||||
) -> Result<(String, Arc<dyn PbrtMaterial>)> {
|
) -> Result<(String, Arc<dyn PbrtMaterial<R>>)> {
|
||||||
let name = input.next_string_value()?;
|
let name = input.next_string_value()?;
|
||||||
|
|
||||||
if input.next_string_value()?.as_str() != "string type" {
|
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)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -57,7 +89,16 @@ struct PbrtDielectricMaterial {
|
||||||
vroughness: Either<Float, Arc<dyn Pbrt2dFloatTexture>>,
|
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)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -65,11 +106,24 @@ struct PbrtDiffuseMaterial {
|
||||||
reflectance: Either<Color, Arc<dyn Pbrt2dSpectrumTexture>>,
|
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,
|
input: &mut Tokenizer,
|
||||||
context: &PbrtContext,
|
context: &PbrtContext<R>,
|
||||||
) -> Result<Arc<dyn Pbrt2dFloatTexture>> {
|
) -> Result<Arc<dyn Pbrt2dFloatTexture>> {
|
||||||
let n = input.next_string_value()?;
|
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())
|
.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,
|
input: &mut Tokenizer,
|
||||||
context: &PbrtContext,
|
context: &PbrtContext<R>,
|
||||||
) -> Result<Arc<dyn Pbrt2dSpectrumTexture>> {
|
) -> Result<Arc<dyn Pbrt2dSpectrumTexture>> {
|
||||||
let n = input.next_string_value()?;
|
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())
|
.and_then(|t| Arc::clone(t).get_2d_spectrum_texture())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_material(
|
pub fn parse_material<R: Rng>(
|
||||||
input: &mut Tokenizer,
|
input: &mut Tokenizer,
|
||||||
context: &PbrtContext,
|
context: &PbrtContext<R>,
|
||||||
) -> Result<Arc<dyn PbrtMaterial>> {
|
) -> Result<Arc<dyn PbrtMaterial<R>>> {
|
||||||
let material: String = input.next_string_value()?;
|
let material: String = input.next_string_value()?;
|
||||||
|
|
||||||
match material.as_str() {
|
match material.as_str() {
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,114 @@
|
||||||
use ray_tracing_core::{
|
use ray_tracing_core::{
|
||||||
prelude::{Material, Rng},
|
color::Color,
|
||||||
scene::Scene,
|
light::Light,
|
||||||
|
prelude::{Float, Material, Rng},
|
||||||
|
scene::{Intersection, Scene},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::shape::Shape;
|
use crate::{material::PbrtMaterial, shape::Shape};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PbrtScene {
|
pub struct PbrtScene<R: Rng> {
|
||||||
pub(crate) shapes: Vec<Shape>,
|
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>
|
type Mat<'a>
|
||||||
= &'a dyn Material<R>
|
= UVMaterial<'a, R>
|
||||||
where
|
where
|
||||||
R: 'a;
|
R: 'a;
|
||||||
|
|
||||||
|
type Light<'b>
|
||||||
|
= &'b dyn Light<R>
|
||||||
|
where
|
||||||
|
R: 'b;
|
||||||
|
|
||||||
fn intersect(
|
fn intersect(
|
||||||
&'_ self,
|
&'_ self,
|
||||||
ray: ray_tracing_core::prelude::Ray,
|
ray: ray_tracing_core::prelude::Ray,
|
||||||
min: ray_tracing_core::prelude::Float,
|
min: ray_tracing_core::prelude::Float,
|
||||||
max: 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;
|
let mut i = None;
|
||||||
for s in &self.shapes {
|
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.as_ref().is_none_or(
|
||||||
|i: &ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>| {
|
|i: &ray_tracing_core::scene::Intersection<
|
||||||
i.t() > new_i.t()
|
R,
|
||||||
},
|
Self::Mat<'_>,
|
||||||
|
Self::Light<'_>,
|
||||||
|
>| { i.t() > new_i.t() },
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
i = Some(new_i);
|
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>(
|
fn sample_light<'b>(
|
||||||
&self,
|
&self,
|
||||||
_w_in: ray_tracing_core::prelude::Dir3,
|
_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,
|
_rng: &mut R,
|
||||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection};
|
use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection};
|
||||||
|
|
||||||
use crate::material::PbrtMaterial;
|
use crate::{material::PbrtMaterial, scene::UVMaterial};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) struct Shape {
|
pub(crate) struct Shape<R: Rng> {
|
||||||
pub(crate) ctm: AffineTransform,
|
pub(crate) ctm: AffineTransform,
|
||||||
pub(crate) material: Arc<dyn PbrtMaterial>,
|
pub(crate) material: Arc<dyn PbrtMaterial<R>>,
|
||||||
pub(crate) obj: ShapeType,
|
pub(crate) obj: ShapeType,
|
||||||
pub(crate) alpha: ShapeAlpha,
|
pub(crate) alpha: ShapeAlpha,
|
||||||
}
|
}
|
||||||
|
|
@ -158,13 +158,13 @@ fn bilinear_intersection(
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shape {
|
impl<R: Rng + std::fmt::Debug> Shape<R> {
|
||||||
pub(crate) fn intersect<R: Rng>(
|
pub(crate) fn intersect(
|
||||||
&'_ self,
|
&'_ self,
|
||||||
ray: Ray,
|
ray: Ray,
|
||||||
min: Float,
|
min: Float,
|
||||||
max: Float,
|
max: Float,
|
||||||
) -> Option<Intersection<'_, R, &'_ dyn Material<R>>> {
|
) -> Option<Intersection<R, UVMaterial<'_, R>, &'_ dyn Light<R>>> {
|
||||||
let ray = self.ctm.transform_ray(ray);
|
let ray = self.ctm.transform_ray(ray);
|
||||||
|
|
||||||
match &self.obj {
|
match &self.obj {
|
||||||
|
|
@ -213,10 +213,19 @@ impl Shape {
|
||||||
}
|
}
|
||||||
false
|
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(
|
return Some(Intersection::new(
|
||||||
t,
|
t,
|
||||||
(ray.at(t) - Pos3::zero()).normalize(),
|
(ray.at(t) - Pos3::zero()).normalize(),
|
||||||
None,
|
Some(UVMaterial {
|
||||||
|
u: phi,
|
||||||
|
v: Float::acos(p.z() / radius),
|
||||||
|
material: self.material.as_ref(),
|
||||||
|
}),
|
||||||
None,
|
None,
|
||||||
0.0,
|
0.0,
|
||||||
));
|
));
|
||||||
|
|
@ -231,10 +240,20 @@ impl Shape {
|
||||||
uv: _,
|
uv: _,
|
||||||
} => {
|
} => {
|
||||||
if indices.is_empty()
|
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]])
|
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!(),
|
ShapeType::LoopSubDiv { .. } => todo!(),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
use crate::{PbrtContext, either::Either, tokenizer::Tokenizer};
|
use crate::{PbrtContext, either::Either, tokenizer::Tokenizer};
|
||||||
use imagemap::{ImageMapEncoding, ImageMapWrap, SpectrumImageMapTexture};
|
use imagemap::{ImageMapEncoding, ImageMapWrap, SpectrumImageMapTexture};
|
||||||
use miette::{Result, miette};
|
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 scale::SpectrumScaleTexture2d;
|
||||||
use std::sync::Arc;
|
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]))
|
Ok(Color::new(t[0], t[1], t[2]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_float_texture(
|
fn parse_float_texture<R: Rng>(
|
||||||
input: &mut Tokenizer,
|
input: &mut Tokenizer,
|
||||||
context: &PbrtContext,
|
context: &PbrtContext<R>,
|
||||||
) -> Result<Arc<dyn PbrtTexture>> {
|
) -> Result<Arc<dyn PbrtTexture>> {
|
||||||
let texture_class = input.next_string_value()?;
|
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,
|
input: &mut Tokenizer,
|
||||||
context: &PbrtContext,
|
context: &PbrtContext<R>,
|
||||||
) -> Result<Arc<dyn PbrtTexture>> {
|
) -> Result<Arc<dyn PbrtTexture>> {
|
||||||
let texture_class = input.next_string_value()?;
|
let texture_class = input.next_string_value()?;
|
||||||
match texture_class.as_str() {
|
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,
|
input: &mut Tokenizer,
|
||||||
context: &PbrtContext,
|
context: &PbrtContext<R>,
|
||||||
) -> Result<(String, Arc<dyn PbrtTexture>)> {
|
) -> Result<(String, Arc<dyn PbrtTexture>)> {
|
||||||
let texture_name: String = input.next_string_value()?;
|
let texture_name: String = input.next_string_value()?;
|
||||||
let texture_type: 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
|
where
|
||||||
A: 'a,
|
A: 'a,
|
||||||
R: 'a;
|
R: 'a;
|
||||||
|
|
||||||
|
type Light<'b>
|
||||||
|
= &'b dyn Light<R>
|
||||||
|
where
|
||||||
|
A: 'b,
|
||||||
|
R: 'b;
|
||||||
|
|
||||||
fn intersect(
|
fn intersect(
|
||||||
&self,
|
&self,
|
||||||
ray: Ray,
|
ray: Ray,
|
||||||
min: Float,
|
min: Float,
|
||||||
max: 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 (t, n, i) = self.acceleration_structure.intersect(ray, min, max)?;
|
||||||
|
|
||||||
let material = &self.materials[i as usize];
|
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>(
|
fn sample_light<'b>(
|
||||||
&self,
|
&self,
|
||||||
_w_in: Dir3,
|
_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,
|
rng: &mut R,
|
||||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,19 @@ where
|
||||||
M: 'a,
|
M: 'a,
|
||||||
R: 'a;
|
R: 'a;
|
||||||
|
|
||||||
|
type Light<'b>
|
||||||
|
= &'b dyn Light<R>
|
||||||
|
where
|
||||||
|
M: 'b,
|
||||||
|
R: 'b;
|
||||||
|
|
||||||
fn intersect(
|
fn intersect(
|
||||||
&self,
|
&self,
|
||||||
ray: Ray,
|
ray: Ray,
|
||||||
min: Float,
|
min: Float,
|
||||||
max: Float,
|
max: Float,
|
||||||
) -> Option<Intersection<'_, R, Self::Mat<'_>>> {
|
) -> Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>> {
|
||||||
let mut intersection: Option<Intersection<'_, R, Self::Mat<'_>>> = None;
|
let mut intersection: Option<Intersection<R, Self::Mat<'_>, Self::Light<'_>>> = None;
|
||||||
|
|
||||||
for &(c, r) in &self.spheres {
|
for &(c, r) in &self.spheres {
|
||||||
let offset = ray.start() - c;
|
let offset = ray.start() - c;
|
||||||
|
|
@ -84,7 +90,7 @@ where
|
||||||
fn sample_light<'b>(
|
fn sample_light<'b>(
|
||||||
&self,
|
&self,
|
||||||
_w_in: Dir3,
|
_w_in: Dir3,
|
||||||
_intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
_intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||||
_rng: &mut R,
|
_rng: &mut R,
|
||||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -323,12 +323,17 @@ impl<R: Rng> Scene<R> for TriangleBVH<R> {
|
||||||
where
|
where
|
||||||
R: 'a;
|
R: 'a;
|
||||||
|
|
||||||
|
type Light<'b>
|
||||||
|
= &'b dyn Light<R>
|
||||||
|
where
|
||||||
|
R: 'b;
|
||||||
|
|
||||||
fn intersect(
|
fn intersect(
|
||||||
&self,
|
&self,
|
||||||
ray: Ray,
|
ray: Ray,
|
||||||
min: Float,
|
min: Float,
|
||||||
max: 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 (i, t) = self.intersect_bvh(0, ray, min, max)?;
|
||||||
|
|
||||||
let triangle = self.triangles[i as usize];
|
let triangle = self.triangles[i as usize];
|
||||||
|
|
@ -350,7 +355,7 @@ impl<R: Rng> Scene<R> for TriangleBVH<R> {
|
||||||
fn sample_light<'b>(
|
fn sample_light<'b>(
|
||||||
&self,
|
&self,
|
||||||
_w_in: Dir3,
|
_w_in: Dir3,
|
||||||
_intersection: &Intersection<'_, R, Self::Mat<'b>>,
|
_intersection: &Intersection<R, Self::Mat<'b>, Self::Light<'b>>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue