Compare commits
3 commits
853e980e83
...
7db434535b
| Author | SHA1 | Date | |
|---|---|---|---|
| 7db434535b | |||
| dac5d2c28f | |||
| 4e1b3619f4 |
42 changed files with 887 additions and 757 deletions
|
|
@ -6,8 +6,8 @@ use crate::core::shape::Shape;
|
||||||
use crate::spectra::{SampledSpectrum, N_SPECTRUM_SAMPLES};
|
use crate::spectra::{SampledSpectrum, N_SPECTRUM_SAMPLES};
|
||||||
use crate::utils::math::{catmull_rom_weights, square};
|
use crate::utils::math::{catmull_rom_weights, square};
|
||||||
use crate::utils::sampling::sample_catmull_rom_2d;
|
use crate::utils::sampling::sample_catmull_rom_2d;
|
||||||
use crate::utils::Ptr;
|
use crate::core::{LightIdx, MaterialIdx};
|
||||||
use crate::{gvec_with_capacity, Float, GVec, PI};
|
use crate::{gvec_with_capacity, Float, GVec, PI, Ptr};
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use num_traits::Float as NumFloat;
|
use num_traits::Float as NumFloat;
|
||||||
|
|
||||||
|
|
@ -78,8 +78,8 @@ impl From<&SubsurfaceInteraction> for SurfaceInteraction {
|
||||||
dndv: Normal3f::zero(),
|
dndv: Normal3f::zero(),
|
||||||
},
|
},
|
||||||
face_index: 0,
|
face_index: 0,
|
||||||
area_light: Ptr::null(),
|
area_light: LightIdx::default(),
|
||||||
material: Ptr::null(),
|
material: MaterialIdx::default(),
|
||||||
dpdx: Vector3f::zero(),
|
dpdx: Vector3f::zero(),
|
||||||
dpdy: Vector3f::zero(),
|
dpdy: Vector3f::zero(),
|
||||||
dudx: 0.,
|
dudx: 0.,
|
||||||
|
|
|
||||||
34
shared/src/core/handle.rs
Normal file
34
shared/src/core/handle.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
use crate::core::light::Light;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct LightIdx(pub u32);
|
||||||
|
|
||||||
|
impl LightIdx {
|
||||||
|
pub const NONE: Self = LightIdx(u32::MAX);
|
||||||
|
pub fn is_none(self) -> bool { self.0 == u32::MAX }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LightIdx {
|
||||||
|
fn default() -> Self { Self::NONE }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LightIdx {
|
||||||
|
#[inline]
|
||||||
|
pub fn get(self, lights: &[Light]) -> &Light {
|
||||||
|
&lights[self.0 as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct MaterialIdx(pub u32);
|
||||||
|
|
||||||
|
impl MaterialIdx {
|
||||||
|
pub const NONE: Self = MaterialIdx(u32::MAX);
|
||||||
|
pub fn is_none(self) -> bool { self.0 == u32::MAX }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MaterialIdx {
|
||||||
|
fn default() -> Self { Self::NONE }
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::core::color::{ColorEncoding, ColorEncodingTrait, LINEAR};
|
use crate::core::color::{ColorEncoding, ColorEncodingTrait, LINEAR};
|
||||||
use crate::core::geometry::{Bounds2f, Point2f, Point2fi, Point2i};
|
use crate::core::geometry::{Bounds2f, Point2f, Point2fi, Point2i};
|
||||||
use crate::utils::math::{f16_to_f32_software, lerp, square};
|
use crate::utils::math::{f16_to_f32_software, lerp, square};
|
||||||
use crate::{gvec_with_capacity, Float, GVec};
|
use crate::{gvec_with_capacity, Float, GVec, Ptr};
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{bail, Result};
|
||||||
use core::hash;
|
use core::hash;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use num_traits::Float as NumFloat;
|
use num_traits::Float as NumFloat;
|
||||||
|
|
@ -23,7 +23,7 @@ impl WrapMode {
|
||||||
"black" => Ok(WrapMode::Black),
|
"black" => Ok(WrapMode::Black),
|
||||||
"repeat" => Ok(WrapMode::Repeat),
|
"repeat" => Ok(WrapMode::Repeat),
|
||||||
"octahedralsphere" => Ok(WrapMode::OctahedralSphere),
|
"octahedralsphere" => Ok(WrapMode::OctahedralSphere),
|
||||||
_ => bail!("{:?}: wrap mode unknown", name)
|
_ => bail!("{:?}: wrap mode unknown", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -236,6 +236,17 @@ pub struct Image {
|
||||||
pub pixels: Pixels,
|
pub pixels: Pixels,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct ImageView {
|
||||||
|
pub pixels: *const u8,
|
||||||
|
pub byte_len: usize,
|
||||||
|
pub resolution: Point2i,
|
||||||
|
pub n_channels: i32,
|
||||||
|
pub format: PixelFormat,
|
||||||
|
pub encoding: ColorEncoding,
|
||||||
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
format: PixelFormat,
|
format: PixelFormat,
|
||||||
|
|
@ -472,3 +483,34 @@ impl Image {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum FilterFunction {
|
||||||
|
Point,
|
||||||
|
Bilinear,
|
||||||
|
Trilinear,
|
||||||
|
Ewa,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilterFunction {
|
||||||
|
pub fn parse(name: &str) -> Result<FilterFunction> {
|
||||||
|
match name {
|
||||||
|
"ewa" | "EWA" => Ok(FilterFunction::Ewa),
|
||||||
|
"trilinear" => Ok(FilterFunction::Trilinear),
|
||||||
|
"bilinear" => Ok(FilterFunction::Bilinear),
|
||||||
|
"point" => Ok(FilterFunction::Point),
|
||||||
|
_ => bail!("Filter function unknown"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct ImagePyramid {
|
||||||
|
pub levels: *const Ptr<Image>,
|
||||||
|
pub level_count: u32,
|
||||||
|
pub wrap_mode: WrapMode,
|
||||||
|
pub filter: FilterFunction,
|
||||||
|
pub max_aniso: f32,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::Float;
|
|
||||||
use crate::bxdfs::DiffuseBxDF;
|
use crate::bxdfs::DiffuseBxDF;
|
||||||
use crate::core::bsdf::BSDF;
|
use crate::core::bsdf::BSDF;
|
||||||
use crate::core::bssrdf::BSSRDF;
|
use crate::core::bssrdf::BSSRDF;
|
||||||
|
|
@ -10,15 +9,16 @@ use crate::core::geometry::{
|
||||||
use crate::core::image::Image;
|
use crate::core::image::Image;
|
||||||
use crate::core::light::{Light, LightTrait};
|
use crate::core::light::{Light, LightTrait};
|
||||||
use crate::core::material::{
|
use crate::core::material::{
|
||||||
Material, MaterialEvalContext, MaterialTrait, NormalBumpEvalContext, bump_map, normal_map,
|
bump_map, normal_map, Material, MaterialEvalContext, MaterialTrait, NormalBumpEvalContext,
|
||||||
};
|
};
|
||||||
use crate::core::medium::{Medium, MediumInterface, PhaseFunction};
|
use crate::core::medium::{Medium, MediumInterface, PhaseFunction};
|
||||||
use crate::core::sampler::{Sampler, SamplerTrait};
|
use crate::core::sampler::{Sampler, SamplerTrait};
|
||||||
use crate::core::shape::Shape;
|
use crate::core::shape::Shape;
|
||||||
use crate::core::texture::{GPUFloatTexture, UniversalTextureEvaluator};
|
use crate::core::texture::{FloatTexture, UniversalTextureEvaluator};
|
||||||
|
use crate::core::{LightIdx, MaterialIdx};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::Ptr;
|
|
||||||
use crate::utils::math::{clamp, difference_of_products, square};
|
use crate::utils::math::{clamp, difference_of_products, square};
|
||||||
|
use crate::{GVec, Ptr, Float};
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
@ -217,8 +217,8 @@ pub struct ShadingGeom {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
pub struct SurfaceInteraction {
|
pub struct SurfaceInteraction {
|
||||||
pub area_light: Ptr<Light>,
|
pub area_light: LightIdx,
|
||||||
pub material: Ptr<Material>,
|
pub material: MaterialIdx,
|
||||||
pub shape: Ptr<Shape>,
|
pub shape: Ptr<Shape>,
|
||||||
pub common: InteractionBase,
|
pub common: InteractionBase,
|
||||||
pub shading: ShadingGeom,
|
pub shading: ShadingGeom,
|
||||||
|
|
@ -239,13 +239,17 @@ unsafe impl Send for SurfaceInteraction {}
|
||||||
unsafe impl Sync for SurfaceInteraction {}
|
unsafe impl Sync for SurfaceInteraction {}
|
||||||
|
|
||||||
impl SurfaceInteraction {
|
impl SurfaceInteraction {
|
||||||
pub fn le(&self, w: Vector3f, lambda: &SampledWavelengths) -> SampledSpectrum {
|
pub fn le(
|
||||||
if !self.area_light.is_null() {
|
&self,
|
||||||
self.area_light
|
w: Vector3f,
|
||||||
.l(self.p(), self.n(), self.common.uv, w, lambda)
|
lambda: &SampledWavelengths,
|
||||||
} else {
|
lights: &GVec<Light>,
|
||||||
SampledSpectrum::new(0.)
|
) -> SampledSpectrum {
|
||||||
|
if self.area_light.is_none() {
|
||||||
|
return SampledSpectrum::new(0.);
|
||||||
}
|
}
|
||||||
|
let light = self.area_light.get(lights);
|
||||||
|
light.l(self.p(), self.n(), self.common.uv, w, lambda)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_differentials(&mut self, r: &Ray, camera: &Camera, samples_per_pixel: i32) {
|
pub fn compute_differentials(&mut self, r: &Ray, camera: &Camera, samples_per_pixel: i32) {
|
||||||
|
|
@ -347,7 +351,7 @@ impl SurfaceInteraction {
|
||||||
pub fn compute_bump_geom(
|
pub fn compute_bump_geom(
|
||||||
&mut self,
|
&mut self,
|
||||||
tex_eval: &UniversalTextureEvaluator,
|
tex_eval: &UniversalTextureEvaluator,
|
||||||
displacement: Ptr<GPUFloatTexture>,
|
displacement: Ptr<FloatTexture>,
|
||||||
normal_image: Ptr<Image>,
|
normal_image: Ptr<Image>,
|
||||||
) {
|
) {
|
||||||
let ctx = NormalBumpEvalContext::from(&*self);
|
let ctx = NormalBumpEvalContext::from(&*self);
|
||||||
|
|
@ -519,9 +523,9 @@ impl SurfaceInteraction {
|
||||||
dndu,
|
dndu,
|
||||||
dndv,
|
dndv,
|
||||||
},
|
},
|
||||||
material: Ptr::null(),
|
material: MaterialIdx::default(),
|
||||||
face_index: 0,
|
face_index: 0,
|
||||||
area_light: Ptr::null(),
|
area_light: LightIdx::default(),
|
||||||
dpdx: Vector3f::zero(),
|
dpdx: Vector3f::zero(),
|
||||||
dpdy: Vector3f::zero(),
|
dpdy: Vector3f::zero(),
|
||||||
dudx: 0.0,
|
dudx: 0.0,
|
||||||
|
|
@ -591,8 +595,8 @@ impl SurfaceInteraction {
|
||||||
#[cfg(not(target_os = "cuda"))]
|
#[cfg(not(target_os = "cuda"))]
|
||||||
pub fn set_intersection_properties(
|
pub fn set_intersection_properties(
|
||||||
&mut self,
|
&mut self,
|
||||||
mtl: Ptr<Material>,
|
mtl: MaterialIdx,
|
||||||
area: Ptr<Light>,
|
area: LightIdx,
|
||||||
ray_medium: Ptr<Medium>,
|
ray_medium: Ptr<Medium>,
|
||||||
prim_medium_interface: MediumInterface,
|
prim_medium_interface: MediumInterface,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::core::interaction::{Interaction, InteractionTrait, ShadingGeom, Surfa
|
||||||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{
|
use crate::core::texture::{
|
||||||
GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext, TextureEvaluator,
|
FloatTexture, SpectrumTexture, TextureEvalContext, TextureEvaluator,
|
||||||
};
|
};
|
||||||
use crate::materials::*;
|
use crate::materials::*;
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
|
|
@ -122,7 +122,7 @@ pub fn normal_map(normal_map: &Image, ctx: &NormalBumpEvalContext) -> (Vector3f,
|
||||||
|
|
||||||
pub fn bump_map<T: TextureEvaluator>(
|
pub fn bump_map<T: TextureEvaluator>(
|
||||||
tex_eval: &T,
|
tex_eval: &T,
|
||||||
displacement: &GPUFloatTexture,
|
displacement: &FloatTexture,
|
||||||
ctx: &NormalBumpEvalContext,
|
ctx: &NormalBumpEvalContext,
|
||||||
) -> (Vector3f, Vector3f) {
|
) -> (Vector3f, Vector3f) {
|
||||||
debug_assert!(tex_eval.can_evaluate(&[Ptr::from(displacement)], &[]));
|
debug_assert!(tex_eval.can_evaluate(&[Ptr::from(displacement)], &[]));
|
||||||
|
|
@ -174,7 +174,7 @@ pub trait MaterialTrait {
|
||||||
|
|
||||||
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool;
|
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool;
|
||||||
fn get_normal_map(&self) -> Option<&Image>;
|
fn get_normal_map(&self) -> Option<&Image>;
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture>;
|
fn get_displacement(&self) -> Ptr<FloatTexture>;
|
||||||
fn has_subsurface_scattering(&self) -> bool;
|
fn has_subsurface_scattering(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ pub mod color;
|
||||||
pub mod film;
|
pub mod film;
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
pub mod handle;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod interaction;
|
pub mod interaction;
|
||||||
pub mod light;
|
pub mod light;
|
||||||
|
|
@ -19,3 +20,5 @@ pub mod scattering;
|
||||||
pub mod shape;
|
pub mod shape;
|
||||||
pub mod spectrum;
|
pub mod spectrum;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
|
|
||||||
|
pub use handle::{LightIdx, MaterialIdx};
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use num_traits::{Float as NumFloat, Num, NumCast, PrimInt};
|
||||||
|
|
||||||
use crate::core::light::LightTrait;
|
use crate::core::light::LightTrait;
|
||||||
use crate::core::shape::Shape;
|
use crate::core::shape::Shape;
|
||||||
use crate::core::texture::GPUFloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::lights::*;
|
use crate::lights::*;
|
||||||
use crate::spectra::{DenselySampledSpectrum, RGBColorSpace};
|
use crate::spectra::{DenselySampledSpectrum, RGBColorSpace};
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ use crate::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction
|
||||||
use crate::core::light::Light;
|
use crate::core::light::Light;
|
||||||
use crate::core::material::Material;
|
use crate::core::material::Material;
|
||||||
use crate::core::medium::{Medium, MediumInterface};
|
use crate::core::medium::{Medium, MediumInterface};
|
||||||
use crate::core::pbrt::Float;
|
|
||||||
use crate::core::shape::{Shape, ShapeIntersection, ShapeTrait};
|
use crate::core::shape::{Shape, ShapeIntersection, ShapeTrait};
|
||||||
use crate::core::texture::{GPUFloatTexture, TextureEvalContext};
|
use crate::core::texture::{FloatTexture, TextureEvalContext};
|
||||||
|
use crate::core::{LightIdx, MaterialIdx};
|
||||||
use crate::utils::hash::hash_float;
|
use crate::utils::hash::hash_float;
|
||||||
use crate::utils::transform::{AnimatedTransform, Transform};
|
use crate::utils::transform::{AnimatedTransform, Transform};
|
||||||
use crate::utils::Ptr;
|
use crate::{Float, Ptr};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -26,10 +26,10 @@ pub trait PrimitiveTrait: Send + Sync {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct GeometricPrimitive {
|
pub struct GeometricPrimitive {
|
||||||
pub shape: Ptr<Shape>,
|
pub shape: Ptr<Shape>,
|
||||||
pub material: Ptr<Material>,
|
pub material: MaterialIdx,
|
||||||
pub area_light: Ptr<Light>,
|
pub area_light: LightIdx,
|
||||||
pub medium_interface: MediumInterface,
|
pub medium_interface: MediumInterface,
|
||||||
pub alpha: Ptr<GPUFloatTexture>,
|
pub alpha: Ptr<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for GeometricPrimitive {}
|
unsafe impl Send for GeometricPrimitive {}
|
||||||
|
|
@ -91,7 +91,7 @@ impl PrimitiveTrait for GeometricPrimitive {
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct SimplePrimitive {
|
pub struct SimplePrimitive {
|
||||||
pub shape: Ptr<Shape>,
|
pub shape: Ptr<Shape>,
|
||||||
pub material: Ptr<Material>,
|
pub material: MaterialIdx,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrimitiveTrait for SimplePrimitive {
|
impl PrimitiveTrait for SimplePrimitive {
|
||||||
|
|
@ -103,7 +103,7 @@ impl PrimitiveTrait for SimplePrimitive {
|
||||||
let mut si = self.shape.intersect(r, t_max)?;
|
let mut si = self.shape.intersect(r, t_max)?;
|
||||||
si.set_intersection_properties(
|
si.set_intersection_properties(
|
||||||
self.material,
|
self.material,
|
||||||
Ptr::null(),
|
LightIdx::default(),
|
||||||
MediumInterface::default(),
|
MediumInterface::default(),
|
||||||
r.medium,
|
r.medium,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use crate::core::geometry::{
|
||||||
use crate::core::interaction::{
|
use crate::core::interaction::{
|
||||||
Interaction, InteractionTrait, MediumInteraction, SurfaceInteraction,
|
Interaction, InteractionTrait, MediumInteraction, SurfaceInteraction,
|
||||||
};
|
};
|
||||||
|
use crate::core::{MaterialIdx, LightIdx};
|
||||||
use crate::core::light::Light;
|
use crate::core::light::Light;
|
||||||
use crate::core::material::Material;
|
use crate::core::material::Material;
|
||||||
use crate::core::medium::{Medium, MediumInterface};
|
use crate::core::medium::{Medium, MediumInterface};
|
||||||
|
|
@ -37,8 +38,8 @@ impl ShapeIntersection {
|
||||||
|
|
||||||
pub fn set_intersection_properties(
|
pub fn set_intersection_properties(
|
||||||
&mut self,
|
&mut self,
|
||||||
mtl: Ptr<Material>,
|
mtl: MaterialIdx,
|
||||||
area: Ptr<Light>,
|
area: LightIdx,
|
||||||
prim_medium_interface: MediumInterface,
|
prim_medium_interface: MediumInterface,
|
||||||
ray_medium: Ptr<Medium>,
|
ray_medium: Ptr<Medium>,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ impl UVMapping {
|
||||||
let dsdy = self.su * ctx.dudy;
|
let dsdy = self.su * ctx.dudy;
|
||||||
let dtdx = self.sv * ctx.dvdx;
|
let dtdx = self.sv * ctx.dvdx;
|
||||||
let dtdy = self.sv * ctx.dvdy;
|
let dtdy = self.sv * ctx.dvdy;
|
||||||
let st = Point2f::new(self.su * ctx.uv[0] + self.du, self.sv * ctx.uv[1] * self.dv);
|
let st = Point2f::new(self.su * ctx.uv[0] + self.du, self.sv * ctx.uv[1] + self.dv);
|
||||||
TexCoord2D {
|
TexCoord2D {
|
||||||
st,
|
st,
|
||||||
dsdx,
|
dsdx,
|
||||||
|
|
@ -107,7 +107,7 @@ impl SphericalMapping {
|
||||||
let x2y2 = square(pt.x()) + square(pt.y());
|
let x2y2 = square(pt.x()) + square(pt.y());
|
||||||
let sqrtx2y2 = x2y2.sqrt();
|
let sqrtx2y2 = x2y2.sqrt();
|
||||||
let dsdp = Vector3f::new(-pt.y(), pt.x(), 0.) / (2. * PI * x2y2);
|
let dsdp = Vector3f::new(-pt.y(), pt.x(), 0.) / (2. * PI * x2y2);
|
||||||
let dtdp = 1. / (PI * (x2y2 * square(pt.z())))
|
let dtdp = 1. / (PI * (x2y2 + square(pt.z())))
|
||||||
* Vector3f::new(
|
* Vector3f::new(
|
||||||
pt.x() * pt.z() / sqrtx2y2,
|
pt.x() * pt.z() / sqrtx2y2,
|
||||||
pt.y() * pt.z() / sqrtx2y2,
|
pt.y() * pt.z() / sqrtx2y2,
|
||||||
|
|
@ -148,7 +148,7 @@ impl CylindricalMapping {
|
||||||
let pt = self.texture_from_render.apply_to_point(ctx.p);
|
let pt = self.texture_from_render.apply_to_point(ctx.p);
|
||||||
let x2y2 = square(pt.x()) + square(pt.y());
|
let x2y2 = square(pt.x()) + square(pt.y());
|
||||||
let dsdp = Vector3f::new(-pt.y(), pt.x(), 0.) / (2. * PI * x2y2);
|
let dsdp = Vector3f::new(-pt.y(), pt.x(), 0.) / (2. * PI * x2y2);
|
||||||
let dtdp = Vector3f::new(1., 0., 0.);
|
let dtdp = Vector3f::new(0., 0., 1.);
|
||||||
let dpdx = self.texture_from_render.apply_to_vector(ctx.dpdx);
|
let dpdx = self.texture_from_render.apply_to_vector(ctx.dpdx);
|
||||||
let dpdy = self.texture_from_render.apply_to_vector(ctx.dpdy);
|
let dpdy = self.texture_from_render.apply_to_vector(ctx.dpdy);
|
||||||
let dsdx = dsdp.dot(dpdx);
|
let dsdx = dsdp.dot(dpdx);
|
||||||
|
|
@ -341,34 +341,34 @@ impl From<&Interaction> for TextureEvalContext {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum GPUFloatTexture {
|
pub enum FloatTexture {
|
||||||
Constant(FloatConstantTexture),
|
Constant(FloatConstantTexture),
|
||||||
DirectionMix(GPUFloatDirectionMixTexture),
|
DirectionMix(FloatDirectionMixTexture),
|
||||||
Scaled(GPUFloatScaledTexture),
|
Scaled(FloatScaledTexture),
|
||||||
Bilerp(FloatBilerpTexture),
|
Bilerp(FloatBilerpTexture),
|
||||||
Checkerboard(FloatCheckerboardTexture),
|
Checkerboard(FloatCheckerboardTexture),
|
||||||
Dots(FloatDotsTexture),
|
Dots(FloatDotsTexture),
|
||||||
FBm(FBmTexture),
|
FBm(FBmTexture),
|
||||||
Windy(WindyTexture),
|
Windy(WindyTexture),
|
||||||
Wrinkled(WrinkledTexture),
|
Wrinkled(WrinkledTexture),
|
||||||
Image(GPUFloatImageTexture),
|
Image(FloatImageTexture),
|
||||||
Mix(GPUFloatMixTexture),
|
Mix(FloatMixTexture),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUFloatTexture {
|
impl FloatTexture {
|
||||||
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
||||||
match self {
|
match self {
|
||||||
GPUFloatTexture::Constant(t) => t.evaluate(ctx),
|
FloatTexture::Constant(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::DirectionMix(t) => t.evaluate(ctx),
|
FloatTexture::DirectionMix(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Scaled(t) => t.evaluate(ctx),
|
FloatTexture::Scaled(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Bilerp(t) => t.evaluate(ctx),
|
FloatTexture::Bilerp(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Checkerboard(t) => t.evaluate(ctx),
|
FloatTexture::Checkerboard(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Dots(t) => t.evaluate(ctx),
|
FloatTexture::Dots(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::FBm(t) => t.evaluate(ctx),
|
FloatTexture::FBm(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Windy(t) => t.evaluate(ctx),
|
FloatTexture::Windy(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Wrinkled(t) => t.evaluate(ctx),
|
FloatTexture::Wrinkled(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Image(t) => t.evaluate(ctx),
|
FloatTexture::Image(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Mix(t) => t.evaluate(ctx),
|
FloatTexture::Mix(t) => t.evaluate(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -384,51 +384,51 @@ pub enum SpectrumType {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum GPUSpectrumTexture {
|
pub enum SpectrumTexture {
|
||||||
Constant(SpectrumConstantTexture),
|
Constant(SpectrumConstantTexture),
|
||||||
Bilerp(SpectrumBilerpTexture),
|
Bilerp(SpectrumBilerpTexture),
|
||||||
Checkerboard(SpectrumCheckerboardTexture),
|
Checkerboard(SpectrumCheckerboardTexture),
|
||||||
Marble(MarbleTexture),
|
Marble(MarbleTexture),
|
||||||
DirectionMix(GPUSpectrumDirectionMixTexture),
|
DirectionMix(SpectrumDirectionMixTexture),
|
||||||
Dots(SpectrumDotsTexture),
|
Dots(SpectrumDotsTexture),
|
||||||
Scaled(GPUSpectrumScaledTexture),
|
Scaled(SpectrumScaledTexture),
|
||||||
Image(GPUSpectrumImageTexture),
|
Image(SpectrumImageTexture),
|
||||||
Mix(GPUSpectrumMixTexture),
|
Mix(SpectrumMixTexture),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUSpectrumTexture {
|
impl SpectrumTexture {
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
&self,
|
&self,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
) -> SampledSpectrum {
|
) -> SampledSpectrum {
|
||||||
match self {
|
match self {
|
||||||
GPUSpectrumTexture::Constant(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Constant(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Bilerp(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Bilerp(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Checkerboard(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Checkerboard(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Marble(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Marble(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::DirectionMix(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::DirectionMix(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Dots(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Dots(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Scaled(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Scaled(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Image(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Image(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Mix(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Mix(t) => t.evaluate(ctx, lambda),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TextureEvaluator: Send + Sync {
|
pub trait TextureEvaluator: Send + Sync {
|
||||||
fn evaluate_float(&self, tex: &GPUFloatTexture, ctx: &TextureEvalContext) -> Float;
|
fn evaluate_float(&self, tex: &FloatTexture, ctx: &TextureEvalContext) -> Float;
|
||||||
fn evaluate_spectrum(
|
fn evaluate_spectrum(
|
||||||
&self,
|
&self,
|
||||||
tex: &GPUSpectrumTexture,
|
tex: &SpectrumTexture,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
) -> SampledSpectrum;
|
) -> SampledSpectrum;
|
||||||
|
|
||||||
fn can_evaluate(
|
fn can_evaluate(
|
||||||
&self,
|
&self,
|
||||||
_ftex: &[Ptr<GPUFloatTexture>],
|
_ftex: &[Ptr<FloatTexture>],
|
||||||
_stex: &[Ptr<GPUSpectrumTexture>],
|
_stex: &[Ptr<SpectrumTexture>],
|
||||||
) -> bool;
|
) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,13 +437,13 @@ pub trait TextureEvaluator: Send + Sync {
|
||||||
pub struct UniversalTextureEvaluator;
|
pub struct UniversalTextureEvaluator;
|
||||||
|
|
||||||
impl TextureEvaluator for UniversalTextureEvaluator {
|
impl TextureEvaluator for UniversalTextureEvaluator {
|
||||||
fn evaluate_float(&self, tex: &GPUFloatTexture, ctx: &TextureEvalContext) -> Float {
|
fn evaluate_float(&self, tex: &FloatTexture, ctx: &TextureEvalContext) -> Float {
|
||||||
tex.evaluate(ctx)
|
tex.evaluate(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_spectrum(
|
fn evaluate_spectrum(
|
||||||
&self,
|
&self,
|
||||||
tex: &GPUSpectrumTexture,
|
tex: &SpectrumTexture,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
) -> SampledSpectrum {
|
) -> SampledSpectrum {
|
||||||
|
|
@ -452,8 +452,8 @@ impl TextureEvaluator for UniversalTextureEvaluator {
|
||||||
|
|
||||||
fn can_evaluate(
|
fn can_evaluate(
|
||||||
&self,
|
&self,
|
||||||
_float_textures: &[Ptr<GPUFloatTexture>],
|
_float_textures: &[Ptr<FloatTexture>],
|
||||||
_spectrum_textures: &[Ptr<GPUSpectrumTexture>],
|
_spectrum_textures: &[Ptr<SpectrumTexture>],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
@ -464,39 +464,39 @@ impl TextureEvaluator for UniversalTextureEvaluator {
|
||||||
pub struct BasicTextureEvaluator;
|
pub struct BasicTextureEvaluator;
|
||||||
|
|
||||||
impl TextureEvaluator for BasicTextureEvaluator {
|
impl TextureEvaluator for BasicTextureEvaluator {
|
||||||
fn evaluate_float(&self, tex: &GPUFloatTexture, ctx: &TextureEvalContext) -> Float {
|
fn evaluate_float(&self, tex: &FloatTexture, ctx: &TextureEvalContext) -> Float {
|
||||||
match tex {
|
match tex {
|
||||||
GPUFloatTexture::Constant(t) => t.evaluate(ctx),
|
FloatTexture::Constant(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Image(t) => t.evaluate(ctx),
|
FloatTexture::Image(t) => t.evaluate(ctx),
|
||||||
_ => 0.0,
|
_ => 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_spectrum(
|
fn evaluate_spectrum(
|
||||||
&self,
|
&self,
|
||||||
tex: &GPUSpectrumTexture,
|
tex: &SpectrumTexture,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
) -> SampledSpectrum {
|
) -> SampledSpectrum {
|
||||||
match tex {
|
match tex {
|
||||||
GPUSpectrumTexture::Constant(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Constant(t) => t.evaluate(ctx, lambda),
|
||||||
GPUSpectrumTexture::Image(t) => t.evaluate(ctx, lambda),
|
SpectrumTexture::Image(t) => t.evaluate(ctx, lambda),
|
||||||
_ => SampledSpectrum::new(0.0),
|
_ => SampledSpectrum::new(0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_evaluate(
|
fn can_evaluate(
|
||||||
&self,
|
&self,
|
||||||
ftex: &[Ptr<GPUFloatTexture>],
|
ftex: &[Ptr<FloatTexture>],
|
||||||
stex: &[Ptr<GPUSpectrumTexture>],
|
stex: &[Ptr<SpectrumTexture>],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
for t in ftex {
|
for t in ftex {
|
||||||
if t.is_null() {
|
if t.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match t.get().unwrap() {
|
match t.get().unwrap() {
|
||||||
GPUFloatTexture::Constant(_)
|
FloatTexture::Constant(_)
|
||||||
| GPUFloatTexture::Image(_) => {}
|
| FloatTexture::Image(_) => {}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -505,8 +505,8 @@ impl TextureEvaluator for BasicTextureEvaluator {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match t.get().unwrap() {
|
match t.get().unwrap() {
|
||||||
GPUSpectrumTexture::Constant(_)
|
SpectrumTexture::Constant(_)
|
||||||
| GPUSpectrumTexture::Image(_) => {}
|
| SpectrumTexture::Image(_) => {}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::core::medium::MediumInterface;
|
||||||
use crate::core::shape::{Shape, ShapeSampleContext, ShapeTrait};
|
use crate::core::shape::{Shape, ShapeSampleContext, ShapeTrait};
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{
|
use crate::core::texture::{
|
||||||
GPUFloatTexture, TextureEvalContext, TextureEvaluator, UniversalTextureEvaluator,
|
FloatTexture, TextureEvalContext, TextureEvaluator, UniversalTextureEvaluator,
|
||||||
};
|
};
|
||||||
use crate::spectra::*;
|
use crate::spectra::*;
|
||||||
use crate::utils::hash::hash_float;
|
use crate::utils::hash::hash_float;
|
||||||
|
|
@ -24,7 +24,7 @@ use num_traits::Float as NumFloat;
|
||||||
pub struct DiffuseAreaLight {
|
pub struct DiffuseAreaLight {
|
||||||
pub base: LightBase,
|
pub base: LightBase,
|
||||||
pub shape: Ptr<Shape>,
|
pub shape: Ptr<Shape>,
|
||||||
pub alpha: Ptr<GPUFloatTexture>,
|
pub alpha: Ptr<FloatTexture>,
|
||||||
pub colorspace: Ptr<RGBColorSpace>,
|
pub colorspace: Ptr<RGBColorSpace>,
|
||||||
pub lemit: Ptr<DenselySampledSpectrum>,
|
pub lemit: Ptr<DenselySampledSpectrum>,
|
||||||
pub image: Ptr<Image>,
|
pub image: Ptr<Image>,
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ use crate::core::interaction::{Interaction, InteractionBase, SimpleInteraction};
|
||||||
use crate::core::light::{LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait};
|
use crate::core::light::{LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait};
|
||||||
use crate::core::spectrum::SpectrumTrait;
|
use crate::core::spectrum::SpectrumTrait;
|
||||||
use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::Ptr;
|
use crate::utils::math::square;
|
||||||
use crate::{Float, PI};
|
use crate::{Float, Ptr, PI};
|
||||||
use num_traits::Float as NumFloat;
|
use num_traits::Float as NumFloat;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
@ -42,7 +42,7 @@ impl LightTrait for DistantLight {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||||
self.scale * self.lemit.sample(&lambda) * PI * self.scene_radius.sqrt()
|
self.scale * self.lemit.sample(&lambda) * PI * square(self.scene_radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sample_li(
|
fn sample_li(
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
use crate::core::geometry::primitives::OctahedralVector;
|
use crate::core::geometry::primitives::OctahedralVector;
|
||||||
use crate::core::geometry::{Bounds3f, Normal3f, Point3f, Vector3f, VectorLike};
|
use crate::core::geometry::{Bounds3f, DirectionCone, Normal3f, Point3f, Vector3f, VectorLike};
|
||||||
use crate::core::geometry::{DirectionCone, Normal};
|
use crate::core::light::{Light, LightBounds, LightSampleContext};
|
||||||
use crate::core::light::Light;
|
use crate::core::LightIdx;
|
||||||
use crate::core::light::{LightBounds, LightSampleContext};
|
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::math::{clamp, lerp, sample_discrete};
|
use crate::utils::math::{clamp, lerp, sample_discrete};
|
||||||
use crate::utils::math::{safe_sqrt, square};
|
use crate::utils::math::{safe_sqrt, square};
|
||||||
|
|
@ -167,25 +166,25 @@ impl CompactLightBounds {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SampledLight {
|
pub struct SampledLight {
|
||||||
pub light: Ptr<Light>,
|
pub light: LightIdx,
|
||||||
pub p: Float,
|
pub p: Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SampledLight {
|
// impl SampledLight {
|
||||||
pub fn new(light: Light, p: Float) -> Self {
|
// pub fn new(light: Light, p: Float) -> Self {
|
||||||
Self {
|
// Self {
|
||||||
light: Ptr::from(&light),
|
// light: Ptr::from(&light),
|
||||||
p,
|
// p,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait LightSamplerTrait {
|
pub trait LightSamplerTrait {
|
||||||
fn sample_with_context(&self, ctx: &LightSampleContext, u: Float) -> Option<SampledLight>;
|
fn sample_with_context(&self, ctx: &LightSampleContext, u: Float) -> Option<SampledLight>;
|
||||||
fn pmf_with_context(&self, ctx: &LightSampleContext, light: &Light) -> Float;
|
fn pmf_with_context(&self, ctx: &LightSampleContext, idx: LightIdx) -> Float;
|
||||||
fn sample(&self, u: Float) -> Option<SampledLight>;
|
fn sample(&self, u: Float) -> Option<SampledLight>;
|
||||||
fn pmf(&self, light: &Light) -> Float;
|
fn pmf(&self, idx: LightIdx) -> Float;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -198,18 +197,12 @@ pub enum LightSampler {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct UniformLightSampler {
|
pub struct UniformLightSampler {
|
||||||
lights: Ptr<Light>,
|
|
||||||
lights_len: u32,
|
lights_len: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UniformLightSampler {
|
impl UniformLightSampler {
|
||||||
pub fn new(lights: Ptr<Light>, lights_len: u32) -> Self {
|
pub fn new(lights_len: u32) -> Self {
|
||||||
Self { lights, lights_len }
|
Self { lights_len }
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn light(&self, idx: usize) -> Light {
|
|
||||||
unsafe { *self.lights.add(idx) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,39 +210,33 @@ impl LightSamplerTrait for UniformLightSampler {
|
||||||
fn sample_with_context(&self, _ctx: &LightSampleContext, u: Float) -> Option<SampledLight> {
|
fn sample_with_context(&self, _ctx: &LightSampleContext, u: Float) -> Option<SampledLight> {
|
||||||
self.sample(u)
|
self.sample(u)
|
||||||
}
|
}
|
||||||
fn pmf_with_context(&self, _ctx: &LightSampleContext, light: &Light) -> Float {
|
|
||||||
self.pmf(light)
|
|
||||||
}
|
|
||||||
fn sample(&self, u: Float) -> Option<SampledLight> {
|
fn sample(&self, u: Float) -> Option<SampledLight> {
|
||||||
if self.lights_len == 0 {
|
if self.lights_len == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let light_index = ((u * self.lights_len as Float) as u32).min(self.lights_len - 1);
|
||||||
let light_index = (u as u32 * self.lights_len).min(self.lights_len - 1) as usize;
|
|
||||||
Some(SampledLight {
|
Some(SampledLight {
|
||||||
light: Ptr::from(&self.light(light_index)),
|
light: LightIdx(light_index),
|
||||||
p: 1. / self.lights_len as Float,
|
p: 1.0 / self.lights_len as Float,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn pmf(&self, _light: &Light) -> Float {
|
|
||||||
if self.lights_len == 0 {
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
1. / self.lights_len as Float
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
fn pmf_with_context(&self, _ctx: &LightSampleContext, _idx: LightIdx) -> Float {
|
||||||
#[derive(Clone, Copy, Debug)]
|
self.pmf(_idx)
|
||||||
pub struct Alias {
|
}
|
||||||
pub q: Float,
|
|
||||||
pub alias: u32,
|
fn pmf(&self, _idx: LightIdx) -> Float {
|
||||||
|
if self.lights_len == 0 {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
1.0 / self.lights_len as Float
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Debug, Copy)]
|
#[derive(Clone, Debug, Copy)]
|
||||||
pub struct PowerLightSampler {
|
pub struct PowerLightSampler {
|
||||||
pub lights: Ptr<Light>,
|
|
||||||
pub lights_len: u32,
|
pub lights_len: u32,
|
||||||
pub alias_table: Ptr<AliasTable>,
|
pub alias_table: Ptr<AliasTable>,
|
||||||
}
|
}
|
||||||
|
|
@ -262,32 +249,23 @@ impl LightSamplerTrait for PowerLightSampler {
|
||||||
self.sample(u)
|
self.sample(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pmf_with_context(&self, _ctx: &LightSampleContext, light: &Light) -> Float {
|
fn pmf_with_context(&self, _ctx: &LightSampleContext, idx: LightIdx) -> Float {
|
||||||
self.pmf(light)
|
self.pmf(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sample(&self, u: Float) -> Option<SampledLight> {
|
fn sample(&self, u: Float) -> Option<SampledLight> {
|
||||||
if self.alias_table.size() == 0 {
|
if self.alias_table.size() == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (light_index, pmf, _) = self.alias_table.sample(u);
|
let (light_index, pmf, _) = self.alias_table.sample(u);
|
||||||
|
|
||||||
let light_ref = unsafe { self.lights.add(light_index as usize) };
|
|
||||||
Some(SampledLight {
|
Some(SampledLight {
|
||||||
light: light_ref,
|
light: LightIdx(light_index),
|
||||||
p: pmf,
|
p: pmf,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pmf(&self, light: &Light) -> Float {
|
fn pmf(&self, idx: LightIdx) -> Float {
|
||||||
let target = light as *const Light;
|
self.alias_table.pmf(idx.0)
|
||||||
for i in 0..self.lights_len as usize {
|
|
||||||
if unsafe { self.lights.add(i) }.as_raw() == target {
|
|
||||||
return self.alias_table.pmf(i as u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -426,15 +404,17 @@ impl LightSamplerTrait for BVHLightSampler {
|
||||||
fn sample_with_context(&self, ctx: &LightSampleContext, mut u: Float) -> Option<SampledLight> {
|
fn sample_with_context(&self, ctx: &LightSampleContext, mut u: Float) -> Option<SampledLight> {
|
||||||
let empty_nodes = if self.nodes_len == 0 { 0. } else { 1. };
|
let empty_nodes = if self.nodes_len == 0 { 0. } else { 1. };
|
||||||
let inf_size = self.infinite_lights_len as Float;
|
let inf_size = self.infinite_lights_len as Float;
|
||||||
let light_size = self.lights_len as Float;
|
|
||||||
|
|
||||||
let p_inf = inf_size / (inf_size + empty_nodes);
|
let p_inf = inf_size / (inf_size + empty_nodes);
|
||||||
|
|
||||||
if u < p_inf {
|
if u < p_inf {
|
||||||
u /= p_inf;
|
u /= p_inf;
|
||||||
let ind = (u * light_size).min(light_size - 1.) as usize;
|
// sample uniformly from infinite lights; their global index equals their
|
||||||
|
// position in the infinite_lights array (infinite lights are at 0..n_inf
|
||||||
|
// in the scene lights array by construction)
|
||||||
|
let ind = (u * inf_size).min(inf_size - 1.) as u32;
|
||||||
let pmf = p_inf / inf_size;
|
let pmf = p_inf / inf_size;
|
||||||
return Some(SampledLight::new(self.infinite_light(ind), pmf));
|
return Some(SampledLight { light: LightIdx(ind), p: pmf });
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.nodes_len == 0 {
|
if self.nodes_len == 0 {
|
||||||
|
|
@ -469,28 +449,32 @@ impl LightSamplerTrait for BVHLightSampler {
|
||||||
node_ind = if child == 0 { child0_idx } else { child1_idx };
|
node_ind = if child == 0 { child0_idx } else { child1_idx };
|
||||||
} else {
|
} else {
|
||||||
if node_ind > 0 || node.light_bounds.importance(p, n, &self.all_light_bounds) > 0. {
|
if node_ind > 0 || node.light_bounds.importance(p, n, &self.all_light_bounds) > 0. {
|
||||||
let light_idx = node.child_or_light_index() as usize;
|
// child_or_light_index() is the global index into the scene lights array
|
||||||
return Some(SampledLight::new(self.light(light_idx), pmf));
|
return Some(SampledLight {
|
||||||
|
light: LightIdx(node.child_or_light_index()),
|
||||||
|
p: pmf,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pmf_with_context(&self, ctx: &LightSampleContext, light: &Light) -> Float {
|
fn pmf_with_context(&self, ctx: &LightSampleContext, idx: LightIdx) -> Float {
|
||||||
let empty_nodes = if self.nodes_len == 0 { 0. } else { 1. };
|
let empty_nodes = if self.nodes_len == 0 { 0. } else { 1. };
|
||||||
let n_infinite = self.infinite_lights_len as Float;
|
let n_infinite = self.infinite_lights_len as Float;
|
||||||
if self
|
|
||||||
.light_index_in(self.infinite_lights, self.infinite_lights_len, light)
|
// Infinite lights occupy indices 0..infinite_lights_len in the global array
|
||||||
.is_some()
|
if idx.0 < self.infinite_lights_len {
|
||||||
{
|
|
||||||
return 1.0 / (n_infinite + empty_nodes);
|
return 1.0 / (n_infinite + empty_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(light_index) = self.light_index_in(self.lights, self.lights_len, light) else {
|
let light_index = idx.0 as usize;
|
||||||
|
if light_index >= self.lights_len as usize {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// bit_trail[light_index] encodes the path from root to the leaf for this light
|
||||||
let mut bit_trail = self.bit_trail(light_index);
|
let mut bit_trail = self.bit_trail(light_index);
|
||||||
let p_inf = n_infinite / (n_infinite + empty_nodes);
|
let p_inf = n_infinite / (n_infinite + empty_nodes);
|
||||||
let mut pmf = 1.0 - p_inf;
|
let mut pmf = 1.0 - p_inf;
|
||||||
|
|
@ -516,17 +500,12 @@ impl LightSamplerTrait for BVHLightSampler {
|
||||||
}
|
}
|
||||||
|
|
||||||
let which_child = (bit_trail & 1) as usize;
|
let which_child = (bit_trail & 1) as usize;
|
||||||
|
|
||||||
// Update probability: prob of picking the correct child
|
|
||||||
pmf *= ci[which_child] / sum_importance;
|
pmf *= ci[which_child] / sum_importance;
|
||||||
|
|
||||||
// Advance
|
|
||||||
node_ind = if which_child == 1 {
|
node_ind = if which_child == 1 {
|
||||||
node.child_or_light_index() as usize
|
node.child_or_light_index() as usize
|
||||||
} else {
|
} else {
|
||||||
node_ind + 1
|
node_ind + 1
|
||||||
};
|
};
|
||||||
|
|
||||||
bit_trail >>= 1;
|
bit_trail >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -535,20 +514,17 @@ impl LightSamplerTrait for BVHLightSampler {
|
||||||
if self.lights_len == 0 {
|
if self.lights_len == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let light_ind = (u * self.lights_len as Float).min(self.lights_len as Float - 1.) as u32;
|
||||||
let light_ind = (u * self.lights_len as Float).min(self.lights_len as Float - 1.) as usize;
|
Some(SampledLight {
|
||||||
|
light: LightIdx(light_ind),
|
||||||
Some(SampledLight::new(
|
p: 1. / self.lights_len as Float,
|
||||||
self.light(light_ind),
|
})
|
||||||
1. / self.lights_len as Float,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pmf(&self, _light: &Light) -> Float {
|
fn pmf(&self, _idx: LightIdx) -> Float {
|
||||||
if self.lights_len == 0 {
|
if self.lights_len == 0 {
|
||||||
return 0.;
|
return 0.;
|
||||||
}
|
}
|
||||||
|
|
||||||
1. / self.lights_len as Float
|
1. / self.lights_len as Float
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::core::image::Image;
|
||||||
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
||||||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
use crate::utils::math::clamp;
|
use crate::utils::math::clamp;
|
||||||
|
|
@ -17,13 +17,13 @@ use crate::utils::math::clamp;
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct CoatedDiffuseMaterial {
|
pub struct CoatedDiffuseMaterial {
|
||||||
pub normal_map: Ptr<Image>,
|
pub normal_map: Ptr<Image>,
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub reflectance: Ptr<GPUSpectrumTexture>,
|
pub reflectance: Ptr<SpectrumTexture>,
|
||||||
pub albedo: Ptr<GPUSpectrumTexture>,
|
pub albedo: Ptr<SpectrumTexture>,
|
||||||
pub u_roughness: Ptr<GPUFloatTexture>,
|
pub u_roughness: Ptr<FloatTexture>,
|
||||||
pub v_roughness: Ptr<GPUFloatTexture>,
|
pub v_roughness: Ptr<FloatTexture>,
|
||||||
pub thickness: Ptr<GPUFloatTexture>,
|
pub thickness: Ptr<FloatTexture>,
|
||||||
pub g: Ptr<GPUFloatTexture>,
|
pub g: Ptr<FloatTexture>,
|
||||||
pub eta: Ptr<Spectrum>,
|
pub eta: Ptr<Spectrum>,
|
||||||
pub max_depth: u32,
|
pub max_depth: u32,
|
||||||
pub n_samples: u32,
|
pub n_samples: u32,
|
||||||
|
|
@ -34,13 +34,13 @@ pub struct CoatedDiffuseMaterial {
|
||||||
impl CoatedDiffuseMaterial {
|
impl CoatedDiffuseMaterial {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
reflectance: Ptr<GPUSpectrumTexture>,
|
reflectance: Ptr<SpectrumTexture>,
|
||||||
u_roughness: Ptr<GPUFloatTexture>,
|
u_roughness: Ptr<FloatTexture>,
|
||||||
v_roughness: Ptr<GPUFloatTexture>,
|
v_roughness: Ptr<FloatTexture>,
|
||||||
thickness: Ptr<GPUFloatTexture>,
|
thickness: Ptr<FloatTexture>,
|
||||||
albedo: Ptr<GPUSpectrumTexture>,
|
albedo: Ptr<SpectrumTexture>,
|
||||||
g: Ptr<GPUFloatTexture>,
|
g: Ptr<FloatTexture>,
|
||||||
displacement: Ptr<GPUFloatTexture>,
|
displacement: Ptr<FloatTexture>,
|
||||||
eta: Ptr<Spectrum>,
|
eta: Ptr<Spectrum>,
|
||||||
normal_map: Ptr<Image>,
|
normal_map: Ptr<Image>,
|
||||||
remap_roughness: bool,
|
remap_roughness: bool,
|
||||||
|
|
@ -141,7 +141,7 @@ impl MaterialTrait for CoatedDiffuseMaterial {
|
||||||
Some(&*self.normal_map)
|
Some(&*self.normal_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,18 +153,18 @@ impl MaterialTrait for CoatedDiffuseMaterial {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct CoatedConductorMaterial {
|
pub struct CoatedConductorMaterial {
|
||||||
displacement: Ptr<GPUFloatTexture>,
|
displacement: Ptr<FloatTexture>,
|
||||||
interface_uroughness: Ptr<GPUFloatTexture>,
|
interface_uroughness: Ptr<FloatTexture>,
|
||||||
interface_vroughness: Ptr<GPUFloatTexture>,
|
interface_vroughness: Ptr<FloatTexture>,
|
||||||
thickness: Ptr<GPUFloatTexture>,
|
thickness: Ptr<FloatTexture>,
|
||||||
interface_eta: Ptr<Spectrum>,
|
interface_eta: Ptr<Spectrum>,
|
||||||
g: Ptr<GPUFloatTexture>,
|
g: Ptr<FloatTexture>,
|
||||||
albedo: Ptr<GPUSpectrumTexture>,
|
albedo: Ptr<SpectrumTexture>,
|
||||||
conductor_uroughness: Ptr<GPUFloatTexture>,
|
conductor_uroughness: Ptr<FloatTexture>,
|
||||||
conductor_vroughness: Ptr<GPUFloatTexture>,
|
conductor_vroughness: Ptr<FloatTexture>,
|
||||||
conductor_eta: Ptr<GPUSpectrumTexture>,
|
conductor_eta: Ptr<SpectrumTexture>,
|
||||||
k: Ptr<GPUSpectrumTexture>,
|
k: Ptr<SpectrumTexture>,
|
||||||
reflectance: Ptr<GPUSpectrumTexture>,
|
reflectance: Ptr<SpectrumTexture>,
|
||||||
normal_map: Ptr<Image>,
|
normal_map: Ptr<Image>,
|
||||||
max_depth: u32,
|
max_depth: u32,
|
||||||
n_samples: u32,
|
n_samples: u32,
|
||||||
|
|
@ -175,17 +175,17 @@ pub struct CoatedConductorMaterial {
|
||||||
impl CoatedConductorMaterial {
|
impl CoatedConductorMaterial {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
displacement: Ptr<GPUFloatTexture>,
|
displacement: Ptr<FloatTexture>,
|
||||||
interface_uroughness: Ptr<GPUFloatTexture>,
|
interface_uroughness: Ptr<FloatTexture>,
|
||||||
interface_vroughness: Ptr<GPUFloatTexture>,
|
interface_vroughness: Ptr<FloatTexture>,
|
||||||
thickness: Ptr<GPUFloatTexture>,
|
thickness: Ptr<FloatTexture>,
|
||||||
g: Ptr<GPUFloatTexture>,
|
g: Ptr<FloatTexture>,
|
||||||
albedo: Ptr<GPUSpectrumTexture>,
|
albedo: Ptr<SpectrumTexture>,
|
||||||
conductor_uroughness: Ptr<GPUFloatTexture>,
|
conductor_uroughness: Ptr<FloatTexture>,
|
||||||
conductor_vroughness: Ptr<GPUFloatTexture>,
|
conductor_vroughness: Ptr<FloatTexture>,
|
||||||
conductor_eta: Ptr<GPUSpectrumTexture>,
|
conductor_eta: Ptr<SpectrumTexture>,
|
||||||
k: Ptr<GPUSpectrumTexture>,
|
k: Ptr<SpectrumTexture>,
|
||||||
reflectance: Ptr<GPUSpectrumTexture>,
|
reflectance: Ptr<SpectrumTexture>,
|
||||||
normal_map: Ptr<Image>,
|
normal_map: Ptr<Image>,
|
||||||
interface_eta: Ptr<Spectrum>,
|
interface_eta: Ptr<Spectrum>,
|
||||||
max_depth: u32,
|
max_depth: u32,
|
||||||
|
|
@ -337,7 +337,7 @@ impl MaterialTrait for CoatedConductorMaterial {
|
||||||
self.normal_map.get()
|
self.normal_map.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,37 +10,37 @@ use crate::core::image::Image;
|
||||||
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
||||||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::textures::GPUSpectrumMixTexture;
|
use crate::textures::SpectrumMixTexture;
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
use crate::utils::math::clamp;
|
use crate::utils::math::clamp;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct HairMaterial {
|
pub struct HairMaterial {
|
||||||
pub sigma_a: Ptr<GPUSpectrumTexture>,
|
pub sigma_a: Ptr<SpectrumTexture>,
|
||||||
pub color: Ptr<GPUSpectrumTexture>,
|
pub color: Ptr<SpectrumTexture>,
|
||||||
pub eumelanin: Ptr<GPUFloatTexture>,
|
pub eumelanin: Ptr<FloatTexture>,
|
||||||
pub pheomelanin: Ptr<GPUFloatTexture>,
|
pub pheomelanin: Ptr<FloatTexture>,
|
||||||
pub eta: Ptr<GPUFloatTexture>,
|
pub eta: Ptr<FloatTexture>,
|
||||||
pub beta_m: Ptr<GPUFloatTexture>,
|
pub beta_m: Ptr<FloatTexture>,
|
||||||
pub beta_n: Ptr<GPUFloatTexture>,
|
pub beta_n: Ptr<FloatTexture>,
|
||||||
pub alpha: Ptr<GPUFloatTexture>,
|
pub alpha: Ptr<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HairMaterial {
|
impl HairMaterial {
|
||||||
#[cfg(not(target_os = "cuda"))]
|
#[cfg(not(target_os = "cuda"))]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sigma_a: Ptr<GPUSpectrumTexture>,
|
sigma_a: Ptr<SpectrumTexture>,
|
||||||
color: Ptr<GPUSpectrumTexture>,
|
color: Ptr<SpectrumTexture>,
|
||||||
eumelanin: Ptr<GPUFloatTexture>,
|
eumelanin: Ptr<FloatTexture>,
|
||||||
pheomelanin: Ptr<GPUFloatTexture>,
|
pheomelanin: Ptr<FloatTexture>,
|
||||||
eta: Ptr<GPUFloatTexture>,
|
eta: Ptr<FloatTexture>,
|
||||||
beta_m: Ptr<GPUFloatTexture>,
|
beta_m: Ptr<FloatTexture>,
|
||||||
beta_n: Ptr<GPUFloatTexture>,
|
beta_n: Ptr<FloatTexture>,
|
||||||
alpha: Ptr<GPUFloatTexture>,
|
alpha: Ptr<FloatTexture>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sigma_a,
|
sigma_a,
|
||||||
|
|
@ -81,7 +81,7 @@ impl MaterialTrait for HairMaterial {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
Ptr::null()
|
Ptr::null()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ impl MaterialTrait for HairMaterial {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct MeasuredMaterial {
|
pub struct MeasuredMaterial {
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub normal_map: Ptr<Image>,
|
pub normal_map: Ptr<Image>,
|
||||||
pub brdf: Ptr<MeasuredBxDFData>,
|
pub brdf: Ptr<MeasuredBxDFData>,
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +126,7 @@ impl MaterialTrait for MeasuredMaterial {
|
||||||
Some(&*self.normal_map)
|
Some(&*self.normal_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,15 +139,15 @@ impl MaterialTrait for MeasuredMaterial {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct SubsurfaceMaterial {
|
pub struct SubsurfaceMaterial {
|
||||||
pub normal_map: Ptr<Image>,
|
pub normal_map: Ptr<Image>,
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub sigma_a: Ptr<GPUSpectrumTexture>,
|
pub sigma_a: Ptr<SpectrumTexture>,
|
||||||
pub sigma_s: Ptr<GPUSpectrumMixTexture>,
|
pub sigma_s: Ptr<SpectrumMixTexture>,
|
||||||
pub reflectance: Ptr<GPUSpectrumMixTexture>,
|
pub reflectance: Ptr<SpectrumMixTexture>,
|
||||||
pub mfp: Ptr<GPUSpectrumMixTexture>,
|
pub mfp: Ptr<SpectrumMixTexture>,
|
||||||
pub eta: Float,
|
pub eta: Float,
|
||||||
pub scale: Float,
|
pub scale: Float,
|
||||||
pub u_roughness: Ptr<GPUFloatTexture>,
|
pub u_roughness: Ptr<FloatTexture>,
|
||||||
pub v_roughness: Ptr<GPUFloatTexture>,
|
pub v_roughness: Ptr<FloatTexture>,
|
||||||
pub remap_roughness: bool,
|
pub remap_roughness: bool,
|
||||||
pub table: Ptr<BSSRDFTable>,
|
pub table: Ptr<BSSRDFTable>,
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +178,7 @@ impl MaterialTrait for SubsurfaceMaterial {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::core::image::Image;
|
||||||
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
||||||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::math::clamp;
|
use crate::utils::math::clamp;
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
|
|
@ -17,24 +17,24 @@ use crate::utils::Ptr;
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct ConductorMaterial {
|
pub struct ConductorMaterial {
|
||||||
pub normal_map: Ptr<Image>,
|
pub normal_map: Ptr<Image>,
|
||||||
pub reflectance: Ptr<GPUSpectrumTexture>,
|
pub reflectance: Ptr<SpectrumTexture>,
|
||||||
pub eta: Ptr<GPUSpectrumTexture>,
|
pub eta: Ptr<SpectrumTexture>,
|
||||||
pub k: Ptr<GPUSpectrumTexture>,
|
pub k: Ptr<SpectrumTexture>,
|
||||||
pub u_roughness: Ptr<GPUFloatTexture>,
|
pub u_roughness: Ptr<FloatTexture>,
|
||||||
pub v_roughness: Ptr<GPUFloatTexture>,
|
pub v_roughness: Ptr<FloatTexture>,
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub remap_roughness: bool,
|
pub remap_roughness: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConductorMaterial {
|
impl ConductorMaterial {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
normal_map: Ptr<Image>,
|
normal_map: Ptr<Image>,
|
||||||
reflectance: Ptr<GPUSpectrumTexture>,
|
reflectance: Ptr<SpectrumTexture>,
|
||||||
eta: Ptr<GPUSpectrumTexture>,
|
eta: Ptr<SpectrumTexture>,
|
||||||
k: Ptr<GPUSpectrumTexture>,
|
k: Ptr<SpectrumTexture>,
|
||||||
u_roughness: Ptr<GPUFloatTexture>,
|
u_roughness: Ptr<FloatTexture>,
|
||||||
v_roughness: Ptr<GPUFloatTexture>,
|
v_roughness: Ptr<FloatTexture>,
|
||||||
displacement: Ptr<GPUFloatTexture>,
|
displacement: Ptr<FloatTexture>,
|
||||||
remap_roughness: bool,
|
remap_roughness: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -105,7 +105,7 @@ impl MaterialTrait for ConductorMaterial {
|
||||||
self.normal_map.get()
|
self.normal_map.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::core::image::Image;
|
||||||
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
||||||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::math::clamp;
|
use crate::utils::math::clamp;
|
||||||
use crate::Ptr;
|
use crate::Ptr;
|
||||||
|
|
@ -17,9 +17,9 @@ use crate::Ptr;
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct DielectricMaterial {
|
pub struct DielectricMaterial {
|
||||||
pub normal_map: Ptr<Image>,
|
pub normal_map: Ptr<Image>,
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub u_roughness: Ptr<GPUFloatTexture>,
|
pub u_roughness: Ptr<FloatTexture>,
|
||||||
pub v_roughness: Ptr<GPUFloatTexture>,
|
pub v_roughness: Ptr<FloatTexture>,
|
||||||
pub eta: Ptr<Spectrum>,
|
pub eta: Ptr<Spectrum>,
|
||||||
pub remap_roughness: bool,
|
pub remap_roughness: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +71,7 @@ impl MaterialTrait for DielectricMaterial {
|
||||||
Some(&*self.normal_map)
|
Some(&*self.normal_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +83,7 @@ impl MaterialTrait for DielectricMaterial {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct ThinDielectricMaterial {
|
pub struct ThinDielectricMaterial {
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub normal_map: Ptr<Image>,
|
pub normal_map: Ptr<Image>,
|
||||||
pub eta: Ptr<Spectrum>,
|
pub eta: Ptr<Spectrum>,
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +114,7 @@ impl MaterialTrait for ThinDielectricMaterial {
|
||||||
Some(&*self.normal_map)
|
Some(&*self.normal_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::Float;
|
|
||||||
use crate::bxdfs::{
|
use crate::bxdfs::{
|
||||||
CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, HairBxDF,
|
CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, HairBxDF,
|
||||||
};
|
};
|
||||||
|
|
@ -9,17 +8,18 @@ use crate::core::image::Image;
|
||||||
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
||||||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::Ptr;
|
|
||||||
use crate::utils::math::clamp;
|
use crate::utils::math::clamp;
|
||||||
|
use crate::Float;
|
||||||
|
use crate::Ptr;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct DiffuseMaterial {
|
pub struct DiffuseMaterial {
|
||||||
pub normal_map: Ptr<Image>,
|
pub normal_map: Ptr<Image>,
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub reflectance: Ptr<GPUSpectrumTexture>,
|
pub reflectance: Ptr<SpectrumTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialTrait for DiffuseMaterial {
|
impl MaterialTrait for DiffuseMaterial {
|
||||||
|
|
@ -29,7 +29,8 @@ impl MaterialTrait for DiffuseMaterial {
|
||||||
ctx: &MaterialEvalContext,
|
ctx: &MaterialEvalContext,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
) -> BSDF {
|
) -> BSDF {
|
||||||
let r = tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda);
|
let spec = tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda);
|
||||||
|
let r = SampledSpectrum::clamp(&spec, 0., 1.);
|
||||||
let bxdf = BxDF::Diffuse(DiffuseBxDF::new(r));
|
let bxdf = BxDF::Diffuse(DiffuseBxDF::new(r));
|
||||||
BSDF::new(ctx.ns, ctx.dpdus, bxdf)
|
BSDF::new(ctx.ns, ctx.dpdus, bxdf)
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +52,7 @@ impl MaterialTrait for DiffuseMaterial {
|
||||||
self.normal_map.get()
|
self.normal_map.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,9 +65,9 @@ impl MaterialTrait for DiffuseMaterial {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct DiffuseTransmissionMaterial {
|
pub struct DiffuseTransmissionMaterial {
|
||||||
pub image: Ptr<Image>,
|
pub image: Ptr<Image>,
|
||||||
pub displacement: Ptr<GPUFloatTexture>,
|
pub displacement: Ptr<FloatTexture>,
|
||||||
pub reflectance: Ptr<GPUFloatTexture>,
|
pub reflectance: Ptr<FloatTexture>,
|
||||||
pub transmittance: Ptr<GPUFloatTexture>,
|
pub transmittance: Ptr<FloatTexture>,
|
||||||
pub scale: Float,
|
pub scale: Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,7 +97,7 @@ impl MaterialTrait for DiffuseTransmissionMaterial {
|
||||||
self.image.get()
|
self.image.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
self.displacement
|
self.displacement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::core::image::Image;
|
||||||
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
||||||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
use crate::utils::hash::hash_float;
|
use crate::utils::hash::hash_float;
|
||||||
|
|
@ -17,7 +17,7 @@ use crate::utils::math::clamp;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct MixMaterial {
|
pub struct MixMaterial {
|
||||||
pub amount: Ptr<GPUFloatTexture>,
|
pub amount: Ptr<FloatTexture>,
|
||||||
pub materials: [Ptr<Material>; 2],
|
pub materials: [Ptr<Material>; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +73,7 @@ impl MaterialTrait for MixMaterial {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
fn get_displacement(&self) -> Ptr<FloatTexture> {
|
||||||
panic!(
|
panic!(
|
||||||
"MixMaterial::get_displacement() shouldn't be called. \
|
"MixMaterial::get_displacement() shouldn't be called. \
|
||||||
Displacement is not supported on Mix materials directly."
|
Displacement is not supported on Mix materials directly."
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::Float;
|
use crate::Float;
|
||||||
use crate::core::texture::{
|
use crate::core::texture::{
|
||||||
GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext, TextureMapping2D, TextureMapping3D,
|
FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D, TextureMapping3D,
|
||||||
TextureMapping3DTrait,
|
TextureMapping3DTrait,
|
||||||
};
|
};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
|
|
@ -46,7 +46,7 @@ fn checkerboard(
|
||||||
pub struct FloatCheckerboardTexture {
|
pub struct FloatCheckerboardTexture {
|
||||||
pub map2d: Ptr<TextureMapping2D>,
|
pub map2d: Ptr<TextureMapping2D>,
|
||||||
pub map3d: Ptr<TextureMapping3D>,
|
pub map3d: Ptr<TextureMapping3D>,
|
||||||
pub tex: [Ptr<GPUFloatTexture>; 2],
|
pub tex: [Ptr<FloatTexture>; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatCheckerboardTexture {
|
impl FloatCheckerboardTexture {
|
||||||
|
|
@ -77,7 +77,7 @@ impl FloatCheckerboardTexture {
|
||||||
pub struct SpectrumCheckerboardTexture {
|
pub struct SpectrumCheckerboardTexture {
|
||||||
pub map2d: Ptr<TextureMapping2D>,
|
pub map2d: Ptr<TextureMapping2D>,
|
||||||
pub map3d: Ptr<TextureMapping3D>,
|
pub map3d: Ptr<TextureMapping3D>,
|
||||||
pub tex: [Ptr<GPUSpectrumTexture>; 2],
|
pub tex: [Ptr<SpectrumTexture>; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpectrumCheckerboardTexture {
|
impl SpectrumCheckerboardTexture {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::Float;
|
use crate::Float;
|
||||||
use crate::core::geometry::{Point2f, VectorLike};
|
use crate::core::geometry::{Point2f, VectorLike};
|
||||||
use crate::core::texture::{
|
use crate::core::texture::{
|
||||||
GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext, TextureMapping2D,
|
FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D,
|
||||||
};
|
};
|
||||||
use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
|
|
@ -29,8 +29,8 @@ fn inside_polka_dot(st: Point2f) -> bool {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct FloatDotsTexture {
|
pub struct FloatDotsTexture {
|
||||||
pub mapping: TextureMapping2D,
|
pub mapping: TextureMapping2D,
|
||||||
pub outside_dot: Ptr<GPUFloatTexture>,
|
pub outside_dot: Ptr<FloatTexture>,
|
||||||
pub inside_dot: Ptr<GPUFloatTexture>,
|
pub inside_dot: Ptr<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatDotsTexture {
|
impl FloatDotsTexture {
|
||||||
|
|
@ -54,8 +54,8 @@ impl FloatDotsTexture {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct SpectrumDotsTexture {
|
pub struct SpectrumDotsTexture {
|
||||||
pub mapping: TextureMapping2D,
|
pub mapping: TextureMapping2D,
|
||||||
pub outside_dot: Ptr<GPUSpectrumTexture>,
|
pub outside_dot: Ptr<SpectrumTexture>,
|
||||||
pub inside_dot: Ptr<GPUSpectrumTexture>,
|
pub inside_dot: Ptr<SpectrumTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpectrumDotsTexture {
|
impl SpectrumDotsTexture {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::core::color::{RGB, XYZ};
|
use crate::core::color::{RGB, XYZ};
|
||||||
use crate::core::image::Image;
|
use crate::core::image::{Image, WrapMode, WrapMode2D};
|
||||||
use crate::core::spectrum::SpectrumTrait;
|
use crate::core::spectrum::SpectrumTrait;
|
||||||
use crate::core::texture::{SpectrumType, TextureEvalContext, TextureMapping2D};
|
use crate::core::texture::{SpectrumType, TextureEvalContext, TextureMapping2D};
|
||||||
use crate::spectra::{
|
use crate::spectra::{
|
||||||
|
|
@ -13,104 +13,119 @@ use crate::Float;
|
||||||
* Leaving it here isolated, for careful handling */
|
* Leaving it here isolated, for careful handling */
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Debug, Copy)]
|
#[derive(Clone, Debug, Copy)]
|
||||||
pub struct GPUSpectrumImageTexture {
|
pub struct SpectrumImageTexture {
|
||||||
pub mapping: TextureMapping2D,
|
pub wrap_mode: WrapMode,
|
||||||
pub tex_obj: u64,
|
pub tex_obj: u64,
|
||||||
pub image: Ptr<Image>,
|
|
||||||
pub scale: Float,
|
pub scale: Float,
|
||||||
pub invert: bool,
|
|
||||||
pub is_single_channel: bool,
|
|
||||||
pub color_space: Ptr<RGBColorSpace>,
|
|
||||||
pub spectrum_type: SpectrumType,
|
pub spectrum_type: SpectrumType,
|
||||||
|
pub image: Ptr<Image>,
|
||||||
|
pub color_space: Ptr<RGBColorSpace>,
|
||||||
|
pub mapping: TextureMapping2D,
|
||||||
|
pub is_single_channel: bool,
|
||||||
|
pub invert: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUSpectrumImageTexture {
|
impl SpectrumImageTexture {
|
||||||
#[allow(unused)]
|
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
&self,
|
&self,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
) -> SampledSpectrum {
|
) -> SampledSpectrum {
|
||||||
#[cfg(not(feature = "cuda"))]
|
#[cfg(feature = "cuda")]
|
||||||
{
|
if self.tex_obj != 0 {
|
||||||
return SampledSpectrum::zero();
|
// FUTURE: hardware sampling path.
|
||||||
|
// let c = self.mapping.map(ctx);
|
||||||
|
// let rgb = tex2d_grad(self.tex_obj, c.st, [c.dsdx,c.dtdx], [c.dsdy,c.dtdy]);
|
||||||
|
// return spectrum_from_rgb(rgb * self.scale, self.invert, self.spectrum_type, ...);
|
||||||
|
// Until then, fall through to software path below.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cuda")]
|
let Some(image) = self.image.get() else {
|
||||||
{
|
return SampledSpectrum::zero();
|
||||||
use cuda_std::intrinsics;
|
};
|
||||||
let c = self.mapping.map(ctx);
|
let mut c = self.mapping.map(ctx);
|
||||||
let u = c.st.x();
|
c.st[1] = 1.0 - c.st[1]; // flip V to match pbrt convention
|
||||||
let v = 1.0 - c.st.y();
|
|
||||||
|
|
||||||
let d_p_dx = [c.dsdx, c.dtdx];
|
let wrap = WrapMode2D {
|
||||||
let d_p_dy = [c.dsdy, c.dtdy];
|
uv: [self.wrap_mode; 2],
|
||||||
|
};
|
||||||
let tex_color = if self.is_single_channel {
|
let rgb = if image.n_channels == 1 {
|
||||||
let val = 0.;
|
let v = image.bilerp_channel_with_wrap(c.st, 0, wrap);
|
||||||
// let val: Float =
|
RGB::new(v, v, v)
|
||||||
// unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
|
} else {
|
||||||
RGB::new(val, val, val)
|
RGB::new(
|
||||||
} else {
|
image.bilerp_channel_with_wrap(c.st, 0, wrap),
|
||||||
let val = [0., 0., 0., 0.];
|
image.bilerp_channel_with_wrap(c.st, 1, wrap),
|
||||||
// let val: [Float; 4] =
|
image.bilerp_channel_with_wrap(c.st, 2, wrap),
|
||||||
// unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
|
)
|
||||||
RGB::new(val[0], val[1], val[2])
|
};
|
||||||
};
|
let mut rgb = rgb * self.scale;
|
||||||
|
if self.invert {
|
||||||
let mut rgb = tex_color * self.scale;
|
rgb = (RGB::new(1.0, 1.0, 1.0) - rgb);
|
||||||
if self.invert {
|
}
|
||||||
rgb = (RGB::new(1.0, 1.0, 1.0) - rgb).clamp_zero();
|
rgb = rgb.clamp_zero();
|
||||||
}
|
let cs = self
|
||||||
|
.color_space
|
||||||
match self.spectrum_type {
|
.get()
|
||||||
SpectrumType::Unbounded => {
|
.expect("color_space must not be null");
|
||||||
RGBUnboundedSpectrum::new(&self.color_space, rgb).sample(lambda)
|
match self.spectrum_type {
|
||||||
}
|
SpectrumType::Unbounded => RGBUnboundedSpectrum::new(cs, rgb).sample(lambda),
|
||||||
SpectrumType::Albedo => {
|
SpectrumType::Albedo => RGBAlbedoSpectrum::new(cs, rgb.clamp(0.0, 1.0)).sample(lambda),
|
||||||
RGBAlbedoSpectrum::new(&self.color_space, rgb.clamp(0.0, 1.0)).sample(lambda)
|
_ => RGBIlluminantSpectrum::new(cs, rgb).sample(lambda),
|
||||||
}
|
|
||||||
_ => RGBIlluminantSpectrum::new(&self.color_space, rgb).sample(lambda),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct GPUFloatImageTexture {
|
pub struct FloatImageTexture {
|
||||||
|
pub image: Ptr<Image>,
|
||||||
pub mapping: TextureMapping2D,
|
pub mapping: TextureMapping2D,
|
||||||
|
pub wrap_mode: WrapMode,
|
||||||
pub tex_obj: u64,
|
pub tex_obj: u64,
|
||||||
pub scale: Float,
|
pub scale: Float,
|
||||||
pub invert: bool,
|
pub invert: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUFloatImageTexture {
|
impl FloatImageTexture {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
||||||
#[cfg(not(feature = "cuda"))]
|
#[cfg(not(feature = "cuda"))]
|
||||||
{
|
{
|
||||||
return 0.;
|
let wrap = WrapMode2D {
|
||||||
|
uv: [self.wrap_mode; 2],
|
||||||
|
};
|
||||||
|
let mut c = self.mapping.map(ctx);
|
||||||
|
c.st[1] = 1.0 - c.st[1];
|
||||||
|
let Some(image) = self.image.get() else { return 0. };
|
||||||
|
|
||||||
|
let v = image.bilerp_channel_with_wrap(c.st, 0, wrap);
|
||||||
|
let v = if self.invert { (1.0 - v).max(0.0) } else { v };
|
||||||
|
return v * self.scale;
|
||||||
}
|
}
|
||||||
#[cfg(feature = "cuda")]
|
#[cfg(feature = "cuda")]
|
||||||
#[allow(unused)]
|
|
||||||
{
|
{
|
||||||
use cuda_std::intrinsics;
|
if self.tex_obj != 0 {
|
||||||
let c = self.mapping.map(ctx);
|
use cuda_std::intrinsics;
|
||||||
let u = c.st.x();
|
let c = self.mapping.map(ctx);
|
||||||
let v = 1.0 - c.st.y();
|
let u = c.st.x();
|
||||||
let d_p_dx = [c.dsdx, c.dtdx];
|
let v = 1.0 - c.st.y();
|
||||||
let d_p_dy = [c.dsdy, c.dtdy];
|
let d_p_dx = [c.dsdx, c.dtdx];
|
||||||
// let val: Float = unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
|
let d_p_dy = [c.dsdy, c.dtdy];
|
||||||
let val: Float = 0.;
|
// let val: Float = unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
|
||||||
|
let _ = (u, v, d_p_dx, d_p_dy);
|
||||||
let result = if self.invert {
|
let val: Float = 0.;
|
||||||
// Invert the pixel intensity
|
let result = if self.invert { (1.0 - val).max(0.0) } else { val };
|
||||||
(1.0 - val).max(0.0)
|
return result * self.scale;
|
||||||
} else {
|
}
|
||||||
val
|
// software path (no hardware texture object)
|
||||||
};
|
let wrap = WrapMode2D { uv: [self.wrap_mode; 2] };
|
||||||
|
let mut c = self.mapping.map(ctx);
|
||||||
return result * self.scale;
|
c.st[1] = 1.0 - c.st[1];
|
||||||
|
let Some(image) = self.image.get() else { return 0. };
|
||||||
|
let v = image.bilerp_channel_with_wrap(c.st, 0, wrap);
|
||||||
|
let v = if self.invert { (1.0 - v).max(0.0) } else { v };
|
||||||
|
return v * self.scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
use crate::Float;
|
use crate::Float;
|
||||||
use crate::core::geometry::{Vector3f, VectorLike};
|
use crate::core::geometry::{Vector3f, VectorLike};
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvalContext};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct GPUFloatMixTexture {
|
pub struct FloatMixTexture {
|
||||||
pub tex1: Ptr<GPUFloatTexture>,
|
pub tex1: Ptr<FloatTexture>,
|
||||||
pub tex2: Ptr<GPUFloatTexture>,
|
pub tex2: Ptr<FloatTexture>,
|
||||||
pub amount: Ptr<GPUFloatTexture>,
|
pub amount: Ptr<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUFloatMixTexture {
|
impl FloatMixTexture {
|
||||||
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
||||||
let amt = self.amount.get().map(|t| t.evaluate(ctx)).unwrap_or(0.0);
|
let amt = self.amount.get().map(|t| t.evaluate(ctx)).unwrap_or(0.0);
|
||||||
let t1 = if amt != 1.0 {
|
let t1 = if amt != 1.0 {
|
||||||
|
|
@ -33,13 +33,13 @@ impl GPUFloatMixTexture {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct GPUFloatDirectionMixTexture {
|
pub struct FloatDirectionMixTexture {
|
||||||
pub tex1: Ptr<GPUFloatTexture>,
|
pub tex1: Ptr<FloatTexture>,
|
||||||
pub tex2: Ptr<GPUFloatTexture>,
|
pub tex2: Ptr<FloatTexture>,
|
||||||
pub dir: Vector3f,
|
pub dir: Vector3f,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUFloatDirectionMixTexture {
|
impl FloatDirectionMixTexture {
|
||||||
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
||||||
let amt = self.dir.abs_dot(ctx.n.into());
|
let amt = self.dir.abs_dot(ctx.n.into());
|
||||||
let t1 = if amt != 1.0 {
|
let t1 = if amt != 1.0 {
|
||||||
|
|
@ -60,13 +60,13 @@ impl GPUFloatDirectionMixTexture {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct GPUSpectrumMixTexture {
|
pub struct SpectrumMixTexture {
|
||||||
pub tex1: Ptr<GPUSpectrumTexture>,
|
pub tex1: Ptr<SpectrumTexture>,
|
||||||
pub tex2: Ptr<GPUSpectrumTexture>,
|
pub tex2: Ptr<SpectrumTexture>,
|
||||||
pub amount: Ptr<GPUFloatTexture>,
|
pub amount: Ptr<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUSpectrumMixTexture {
|
impl SpectrumMixTexture {
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
&self,
|
&self,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
|
|
@ -97,13 +97,13 @@ impl GPUSpectrumMixTexture {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct GPUSpectrumDirectionMixTexture {
|
pub struct SpectrumDirectionMixTexture {
|
||||||
pub tex1: Ptr<GPUSpectrumTexture>,
|
pub tex1: Ptr<SpectrumTexture>,
|
||||||
pub tex2: Ptr<GPUSpectrumTexture>,
|
pub tex2: Ptr<SpectrumTexture>,
|
||||||
pub dir: Vector3f,
|
pub dir: Vector3f,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUSpectrumDirectionMixTexture {
|
impl SpectrumDirectionMixTexture {
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
&self,
|
&self,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::Float;
|
use crate::Float;
|
||||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext};
|
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvalContext};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use crate::utils::Ptr;
|
use crate::utils::Ptr;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct GPUFloatScaledTexture {
|
pub struct FloatScaledTexture {
|
||||||
pub tex: Ptr<GPUFloatTexture>,
|
pub tex: Ptr<FloatTexture>,
|
||||||
pub scale: Ptr<GPUFloatTexture>,
|
pub scale: Ptr<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUFloatScaledTexture {
|
impl FloatScaledTexture {
|
||||||
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
||||||
let sc = self.scale.get().map(|t| t.evaluate(ctx)).unwrap();
|
let sc = self.scale.get().map(|t| t.evaluate(ctx)).unwrap();
|
||||||
if sc == 0. {
|
if sc == 0. {
|
||||||
|
|
@ -22,12 +22,12 @@ impl GPUFloatScaledTexture {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct GPUSpectrumScaledTexture {
|
pub struct SpectrumScaledTexture {
|
||||||
pub tex: Ptr<GPUSpectrumTexture>,
|
pub tex: Ptr<SpectrumTexture>,
|
||||||
pub scale: Ptr<GPUFloatTexture>,
|
pub scale: Ptr<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUSpectrumScaledTexture {
|
impl SpectrumScaledTexture {
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
&self,
|
&self,
|
||||||
ctx: &TextureEvalContext,
|
ctx: &TextureEvalContext,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ use crate::core::film::Film;
|
||||||
use crate::core::filter::Filter;
|
use crate::core::filter::Filter;
|
||||||
use crate::core::light::Light;
|
use crate::core::light::Light;
|
||||||
use crate::core::sampler::Sampler;
|
use crate::core::sampler::Sampler;
|
||||||
|
use crate::core::material::Material;
|
||||||
|
use crate::core::LightIdx;
|
||||||
use crate::lights::sampler::LightSampler;
|
use crate::lights::sampler::LightSampler;
|
||||||
use crate::wavefront::aggregate::WavefrontAggregate;
|
use crate::wavefront::aggregate::WavefrontAggregate;
|
||||||
use crate::wavefront::workitems::*;
|
use crate::wavefront::workitems::*;
|
||||||
|
|
@ -15,7 +17,9 @@ pub struct WavefrontPathIntegrator<A: WavefrontAggregate> {
|
||||||
pub max_depth: u32,
|
pub max_depth: u32,
|
||||||
pub samples_per_pixel: u32,
|
pub samples_per_pixel: u32,
|
||||||
pub regularize: bool,
|
pub regularize: bool,
|
||||||
pub infinite_lights: GVec<Ptr<Light>>,
|
pub lights: GVec<Light>,
|
||||||
|
pub materials: GVec<Material>,
|
||||||
|
pub infinite_lights: GVec<LightIdx>,
|
||||||
pub max_queue_size: u32,
|
pub max_queue_size: u32,
|
||||||
pub scanlines_per_pass: u32,
|
pub scanlines_per_pass: u32,
|
||||||
pub light_sampler: LightSampler,
|
pub light_sampler: LightSampler,
|
||||||
|
|
@ -33,4 +37,3 @@ pub struct WavefrontPathIntegrator<A: WavefrontAggregate> {
|
||||||
pub trait WavefrontRenderer {
|
pub trait WavefrontRenderer {
|
||||||
fn render(&mut self);
|
fn render(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ use crate::core::film::VisibleSurface;
|
||||||
use crate::core::geometry::{
|
use crate::core::geometry::{
|
||||||
Normal3f, Point2f, Point2i, Point3f, Point3fi, Ray, RayDifferential, Vector3f,
|
Normal3f, Point2f, Point2i, Point3f, Point3fi, Ray, RayDifferential, Vector3f,
|
||||||
};
|
};
|
||||||
use crate::core::light::Light;
|
use crate::core::light::{Light, LightSampleContext};
|
||||||
use crate::core::light::LightSampleContext;
|
use crate::core::{MaterialIdx, LightIdx};
|
||||||
use crate::core::material::Material;
|
use crate::core::material::Material;
|
||||||
use crate::core::medium::{Medium, MediumInterface};
|
use crate::core::medium::{Medium, MediumInterface};
|
||||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
|
|
@ -207,7 +207,7 @@ impl SoA for EscapedRayWorkItemSoA {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct HitAreaLightWorkItem {
|
pub struct HitAreaLightWorkItem {
|
||||||
pub area_light: Ptr<Light>,
|
pub area_light: LightIdx,
|
||||||
pub p: Point3f,
|
pub p: Point3f,
|
||||||
pub n: Normal3f,
|
pub n: Normal3f,
|
||||||
pub uv: Point2f,
|
pub uv: Point2f,
|
||||||
|
|
@ -225,7 +225,7 @@ pub struct HitAreaLightWorkItem {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct HitAreaLightWorkItemSoA {
|
pub struct HitAreaLightWorkItemSoA {
|
||||||
pub area_light: SoABuffer<Ptr<Light>>,
|
pub area_light: SoABuffer<LightIdx>,
|
||||||
pub p: SoABuffer<Point3f>,
|
pub p: SoABuffer<Point3f>,
|
||||||
pub n: SoABuffer<Normal3f>,
|
pub n: SoABuffer<Normal3f>,
|
||||||
pub uv: SoABuffer<Point2f>,
|
pub uv: SoABuffer<Point2f>,
|
||||||
|
|
@ -308,8 +308,8 @@ pub struct MaterialEvalWorkItem {
|
||||||
pub wo: Vector3f,
|
pub wo: Vector3f,
|
||||||
pub time: Float,
|
pub time: Float,
|
||||||
pub face_index: i32,
|
pub face_index: i32,
|
||||||
pub material: Ptr<Material>,
|
pub material: MaterialIdx,
|
||||||
pub area_light: Ptr<Light>,
|
pub area_light: LightIdx,
|
||||||
pub medium_interface: MediumInterface,
|
pub medium_interface: MediumInterface,
|
||||||
pub pixel_index: u32,
|
pub pixel_index: u32,
|
||||||
pub lambda: SampledWavelengths,
|
pub lambda: SampledWavelengths,
|
||||||
|
|
@ -336,8 +336,8 @@ pub struct MaterialEvalWorkItemSoA {
|
||||||
pub wo: SoABuffer<Vector3f>,
|
pub wo: SoABuffer<Vector3f>,
|
||||||
pub time: SoABuffer<Float>,
|
pub time: SoABuffer<Float>,
|
||||||
pub face_index: SoABuffer<i32>,
|
pub face_index: SoABuffer<i32>,
|
||||||
pub material: SoABuffer<Ptr<Material>>,
|
pub material: SoABuffer<MaterialIdx>,
|
||||||
pub area_light: SoABuffer<Ptr<Light>>,
|
pub area_light: SoABuffer<LightIdx>,
|
||||||
pub medium_interface: SoABuffer<MediumInterface>,
|
pub medium_interface: SoABuffer<MediumInterface>,
|
||||||
pub pixel_index: SoABuffer<u32>,
|
pub pixel_index: SoABuffer<u32>,
|
||||||
pub lambda: SoABuffer<SampledWavelengths>,
|
pub lambda: SoABuffer<SampledWavelengths>,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ pub trait InteractionGetter {
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
camera: &Camera,
|
camera: &Camera,
|
||||||
sampler: &mut Sampler,
|
sampler: &mut Sampler,
|
||||||
|
materials: &[Material],
|
||||||
) -> Option<BSDF>;
|
) -> Option<BSDF>;
|
||||||
|
|
||||||
fn get_bssrdf(
|
fn get_bssrdf(
|
||||||
|
|
@ -26,6 +27,7 @@ pub trait InteractionGetter {
|
||||||
_ray: &Ray,
|
_ray: &Ray,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
_camera: &Camera,
|
_camera: &Camera,
|
||||||
|
materials: &[Material],
|
||||||
) -> Option<BSSRDF>;
|
) -> Option<BSSRDF>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,18 +38,20 @@ impl InteractionGetter for SurfaceInteraction {
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
camera: &Camera,
|
camera: &Camera,
|
||||||
sampler: &mut Sampler,
|
sampler: &mut Sampler,
|
||||||
|
materials: &[Material],
|
||||||
) -> Option<BSDF> {
|
) -> Option<BSDF> {
|
||||||
self.compute_differentials(r, camera, sampler.samples_per_pixel());
|
self.compute_differentials(r, camera, sampler.samples_per_pixel());
|
||||||
|
if self.material.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut active_mat: &Material = &materials[self.material.0 as usize];
|
||||||
let material = {
|
let material = {
|
||||||
let Some(mut active_mat) = self.material.get() else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let tex_eval = UniversalTextureEvaluator;
|
let tex_eval = UniversalTextureEvaluator;
|
||||||
while let Material::Mix(mix) = active_mat {
|
while let Material::Mix(mix) = active_mat {
|
||||||
let ctx = MaterialEvalContext::from(&*self);
|
let ctx = MaterialEvalContext::from(&*self);
|
||||||
active_mat = mix.choose_material(&tex_eval, &ctx)?;
|
active_mat = mix.choose_material(&tex_eval, &ctx)?;
|
||||||
}
|
}
|
||||||
*active_mat
|
active_mat
|
||||||
};
|
};
|
||||||
let ctx = MaterialEvalContext::from(&*self);
|
let ctx = MaterialEvalContext::from(&*self);
|
||||||
let tex_eval = UniversalTextureEvaluator;
|
let tex_eval = UniversalTextureEvaluator;
|
||||||
|
|
@ -73,10 +77,12 @@ impl InteractionGetter for SurfaceInteraction {
|
||||||
_ray: &Ray,
|
_ray: &Ray,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
_camera: &Camera,
|
_camera: &Camera,
|
||||||
|
materials: &[Material],
|
||||||
) -> Option<BSSRDF> {
|
) -> Option<BSSRDF> {
|
||||||
let Some(mut active_mat) = self.material.get() else {
|
if self.material.is_none() {
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
|
let mut active_mat: &Material = &materials[self.material.0 as usize];
|
||||||
let tex_eval = UniversalTextureEvaluator;
|
let tex_eval = UniversalTextureEvaluator;
|
||||||
while let Material::Mix(mix) = active_mat {
|
while let Material::Mix(mix) = active_mat {
|
||||||
let ctx = MaterialEvalContext::from(self);
|
let ctx = MaterialEvalContext::from(self);
|
||||||
|
|
@ -95,6 +101,7 @@ impl InteractionGetter for MediumInteraction {
|
||||||
_lambda: &SampledWavelengths,
|
_lambda: &SampledWavelengths,
|
||||||
_camera: &Camera,
|
_camera: &Camera,
|
||||||
_sampler: &mut Sampler,
|
_sampler: &mut Sampler,
|
||||||
|
_materials: &[Material],
|
||||||
) -> Option<BSDF> {
|
) -> Option<BSDF> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +111,7 @@ impl InteractionGetter for MediumInteraction {
|
||||||
_ray: &Ray,
|
_ray: &Ray,
|
||||||
_lambda: &SampledWavelengths,
|
_lambda: &SampledWavelengths,
|
||||||
_camera: &Camera,
|
_camera: &Camera,
|
||||||
|
_materials: &[Material],
|
||||||
) -> Option<BSSRDF> {
|
) -> Option<BSSRDF> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +124,7 @@ impl InteractionGetter for SimpleInteraction {
|
||||||
_lambda: &SampledWavelengths,
|
_lambda: &SampledWavelengths,
|
||||||
_camera: &Camera,
|
_camera: &Camera,
|
||||||
_sampler: &mut Sampler,
|
_sampler: &mut Sampler,
|
||||||
|
_materials: &[Material],
|
||||||
) -> Option<BSDF> {
|
) -> Option<BSDF> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -125,6 +134,7 @@ impl InteractionGetter for SimpleInteraction {
|
||||||
_ray: &Ray,
|
_ray: &Ray,
|
||||||
_lambda: &SampledWavelengths,
|
_lambda: &SampledWavelengths,
|
||||||
_camera: &Camera,
|
_camera: &Camera,
|
||||||
|
_materials: &[Material],
|
||||||
) -> Option<BSSRDF> {
|
) -> Option<BSSRDF> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,14 +88,14 @@ impl MaterialFactory for Material {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_diffuse_material(arena: &Arena) -> Material {
|
pub fn default_diffuse_material(arena: &Arena) -> Material {
|
||||||
use shared::core::texture::GPUSpectrumTexture;
|
use shared::core::texture::SpectrumTexture;
|
||||||
use shared::core::texture::SpectrumConstantTexture;
|
use shared::core::texture::SpectrumConstantTexture;
|
||||||
use shared::core::spectrum::{ConstantSpectrum, Spectrum};
|
use shared::core::spectrum::{ConstantSpectrum, Spectrum};
|
||||||
use shared::materials::DiffuseMaterial;
|
use shared::materials::DiffuseMaterial;
|
||||||
use shared::utils::Ptr;
|
use shared::utils::Ptr;
|
||||||
|
|
||||||
let grey = Spectrum::Constant(ConstantSpectrum { c: 0.5 });
|
let grey = Spectrum::Constant(ConstantSpectrum { c: 0.5 });
|
||||||
let tex = GPUSpectrumTexture::Constant(SpectrumConstantTexture::new(grey));
|
let tex = SpectrumTexture::Constant(SpectrumConstantTexture::new(grey));
|
||||||
let tex_ptr = arena.alloc(tex);
|
let tex_ptr = arena.alloc(tex);
|
||||||
|
|
||||||
Material::Diffuse(DiffuseMaterial {
|
Material::Diffuse(DiffuseMaterial {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use shared::core::{
|
use shared::core::{
|
||||||
|
LightIdx, MaterialIdx,
|
||||||
light::Light,
|
light::Light,
|
||||||
material::Material,
|
material::Material,
|
||||||
medium::MediumInterface,
|
medium::MediumInterface,
|
||||||
primitive::{GeometricPrimitive, SimplePrimitive},
|
primitive::{GeometricPrimitive, SimplePrimitive},
|
||||||
shape::Shape,
|
shape::Shape,
|
||||||
texture::GPUFloatTexture,
|
texture::FloatTexture,
|
||||||
};
|
};
|
||||||
|
use shared::Ptr;
|
||||||
use shared::utils::Ptr;
|
|
||||||
|
|
||||||
pub trait CreateSimplePrimitive {
|
pub trait CreateSimplePrimitive {
|
||||||
fn new(shape: Ptr<Shape>, material: Ptr<Material>) -> SimplePrimitive {
|
fn new(shape: Ptr<Shape>, material: MaterialIdx) -> SimplePrimitive {
|
||||||
SimplePrimitive { shape, material }
|
SimplePrimitive { shape, material }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,10 +20,10 @@ impl CreateSimplePrimitive for SimplePrimitive {}
|
||||||
pub trait CreateGeometricPrimitive {
|
pub trait CreateGeometricPrimitive {
|
||||||
fn new(
|
fn new(
|
||||||
shape: Ptr<Shape>,
|
shape: Ptr<Shape>,
|
||||||
material: Ptr<Material>,
|
material: MaterialIdx,
|
||||||
area_light: Ptr<Light>,
|
area_light: LightIdx,
|
||||||
medium_interface: MediumInterface,
|
medium_interface: MediumInterface,
|
||||||
alpha: Ptr<GPUFloatTexture>,
|
alpha: Ptr<FloatTexture>,
|
||||||
) -> GeometricPrimitive {
|
) -> GeometricPrimitive {
|
||||||
GeometricPrimitive {
|
GeometricPrimitive {
|
||||||
shape,
|
shape,
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
||||||
let media = scene.create_media();
|
let media = scene.create_media();
|
||||||
let textures = scene.create_textures(arena);
|
let textures = scene.create_textures(arena);
|
||||||
let (named_materials, materials) = scene.create_materials(&textures, arena)?;
|
let (named_materials, materials) = scene.create_materials(&textures, arena)?;
|
||||||
let lights = scene.create_lights(&textures, arena);
|
let (lights, al_map) = scene.create_lights(&textures, &media, arena);
|
||||||
|
|
||||||
let _have_scattering = {
|
let _have_scattering = {
|
||||||
let shapes = scene.shapes.lock();
|
let shapes = scene.shapes.lock();
|
||||||
|
|
@ -30,8 +30,7 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
||||||
.any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty())
|
.any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty())
|
||||||
};
|
};
|
||||||
|
|
||||||
let (aggregate, area_lights) =
|
let aggregate = scene.create_aggregate(&textures, &named_materials, &materials, al_map, &media, arena);
|
||||||
scene.create_aggregate(&textures, &named_materials, &materials, &media, arena);
|
|
||||||
|
|
||||||
let mut all_lights = lights;
|
let mut all_lights = lights;
|
||||||
all_lights.extend(area_lights);
|
all_lights.extend(area_lights);
|
||||||
|
|
@ -60,7 +59,7 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
||||||
loop {
|
loop {
|
||||||
if let Some(isect) = aggregate.intersect(&ray, Some(Float::INFINITY)) {
|
if let Some(isect) = aggregate.intersect(&ray, Some(Float::INFINITY)) {
|
||||||
let intr = isect.intr;
|
let intr = isect.intr;
|
||||||
if intr.material.is_null() {
|
if intr.material.is_none() {
|
||||||
log::warn!("Ignoring material")
|
log::warn!("Ignoring material")
|
||||||
} else {
|
} else {
|
||||||
let world_from_render = camera.base().camera_transform.world_from_render;
|
let world_from_render = camera.base().camera_transform.world_from_render;
|
||||||
|
|
@ -80,7 +79,7 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
||||||
log::debug!("Distance from camera: {}\n", intr.p().distance(cr.ray.o));
|
log::debug!("Distance from camera: {}\n", intr.p().distance(cr.ray.o));
|
||||||
|
|
||||||
for (name, mtl) in &named_materials {
|
for (name, mtl) in &named_materials {
|
||||||
if *mtl == *intr.material.get().unwrap() {
|
if *mtl == intr.material {
|
||||||
log::debug!("Named material: {}\n\n", name);
|
log::debug!("Named material: {}\n\n", name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +103,7 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
||||||
sampler.clone(),
|
sampler.clone(),
|
||||||
aggregate.clone(),
|
aggregate.clone(),
|
||||||
all_lights,
|
all_lights,
|
||||||
|
materials,
|
||||||
arena,
|
arena,
|
||||||
);
|
);
|
||||||
wf.render();
|
wf.render();
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use crate::lights::sampler::create_light_sampler;
|
||||||
use crate::utils::parallel::{run_async, AsyncJob};
|
use crate::utils::parallel::{run_async, AsyncJob};
|
||||||
use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary};
|
use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary};
|
||||||
use crate::utils::resolve_filename;
|
use crate::utils::resolve_filename;
|
||||||
use crate::wavefront::{CreateWavefront, CpuAggregate, CpuWavefrontRenderer};
|
use crate::wavefront::{CpuAggregate, CpuWavefrontRenderer, CreateWavefront};
|
||||||
use crate::{Arena, ArenaUpload, FileLoc};
|
use crate::{Arena, ArenaUpload, FileLoc};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
@ -32,6 +32,7 @@ use shared::core::primitive::{AnimatedPrimitive, GeometricPrimitive, Primitive,
|
||||||
use shared::core::sampler::{Sampler, SamplerTrait};
|
use shared::core::sampler::{Sampler, SamplerTrait};
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::core::texture::SpectrumType;
|
use shared::core::texture::SpectrumType;
|
||||||
|
use shared::core::{LightIdx, MaterialIdx};
|
||||||
use shared::spectra::RGBColorSpace;
|
use shared::spectra::RGBColorSpace;
|
||||||
use shared::textures::FloatConstantTexture;
|
use shared::textures::FloatConstantTexture;
|
||||||
use shared::utils::soa::SoA;
|
use shared::utils::soa::SoA;
|
||||||
|
|
@ -77,28 +78,30 @@ fn resolve_medium_interface(
|
||||||
|
|
||||||
fn resolve_material(
|
fn resolve_material(
|
||||||
mat_ref: &MaterialRef,
|
mat_ref: &MaterialRef,
|
||||||
named_materials: &HashMap<String, Material>,
|
named_materials: &HashMap<String, MaterialIdx>,
|
||||||
materials: &[Material],
|
materials: &[Material],
|
||||||
loc: &FileLoc,
|
loc: &FileLoc,
|
||||||
arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Material {
|
) -> MaterialIdx {
|
||||||
match mat_ref {
|
match mat_ref {
|
||||||
MaterialRef::Name(name) => match named_materials.get(name) {
|
MaterialRef::Name(name) => match named_materials.get(name) {
|
||||||
Some(m) => *m,
|
Some(m) => *m,
|
||||||
None => {
|
None => {
|
||||||
log::error!("{}: named material '{}' not found", loc, name);
|
MaterialIdx::default()
|
||||||
crate::core::material::default_diffuse_material(arena)
|
// log::error!("{}: named material '{}' not found", loc, name);
|
||||||
|
// crate::core::material::default_diffuse_material(arena)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MaterialRef::Index(idx) => {
|
MaterialRef::Index(idx) => {
|
||||||
if *idx < materials.len() {
|
if *idx < materials.len() {
|
||||||
materials[*idx]
|
MaterialIdx(*idx as u32)
|
||||||
} else {
|
} else {
|
||||||
log::error!("{}: material index {} out of bounds", loc, idx);
|
MaterialIdx::default()
|
||||||
crate::core::material::default_diffuse_material(arena)
|
// log::error!("{}: material index {} out of bounds", loc, idx);
|
||||||
|
// crate::core::material::default_diffuse_material(arena)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MaterialRef::None => crate::core::material::default_diffuse_material(arena),
|
MaterialRef::None => MaterialIdx::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +158,8 @@ impl Default for BasicScene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type AreaLightMap = HashMap<(usize, usize), LightIdx>;
|
||||||
|
|
||||||
impl BasicScene {
|
impl BasicScene {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -295,26 +300,53 @@ impl BasicScene {
|
||||||
arena: Arc<Arena>,
|
arena: Arc<Arena>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut state = self.texture_state.lock();
|
let mut state = self.texture_state.lock();
|
||||||
self.add_texture_generic(
|
|
||||||
name,
|
if texture.render_from_object.is_animated() {
|
||||||
texture,
|
log::info!(
|
||||||
&mut state,
|
"{}: animated world-to-texture not supported, using start transform",
|
||||||
|s| &mut s.serial_spectrum_textures,
|
texture.base.loc
|
||||||
|s| &mut s.spectrum_texture_jobs,
|
);
|
||||||
move |tex| {
|
}
|
||||||
let render_from_texture = tex.render_from_object.start_transform;
|
|
||||||
let tex_dict = TextureParameterDictionary::new(tex.base.parameters.into(), None);
|
if texture.base.name != "imagemap" && texture.base.name != "ptex" {
|
||||||
|
state.serial_spectrum_textures.push((name, texture));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let filename = resolve_filename(&texture.base.parameters.get_one_string("filename", "")?);
|
||||||
|
if !self.validate_texture_file(&filename, &texture.base.loc, &mut state.n_missing_textures)
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid duplicate work if the same file is already being loaded
|
||||||
|
if state.loading_texture_filenames.contains(&filename) {
|
||||||
|
state.serial_spectrum_textures.push((name, texture));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.loading_texture_filenames.insert(filename.clone());
|
||||||
|
state
|
||||||
|
.async_spectrum_textures
|
||||||
|
.push((name.clone(), texture.clone()));
|
||||||
|
|
||||||
|
let job = run_async(move || {
|
||||||
|
let render_from_texture = texture.render_from_object.start_transform;
|
||||||
|
let tex_dict = TextureParameterDictionary::new(texture.base.parameters.into(), None);
|
||||||
|
Arc::new(
|
||||||
SpectrumTexture::create(
|
SpectrumTexture::create(
|
||||||
&tex.base.name,
|
&texture.base.name,
|
||||||
render_from_texture,
|
render_from_texture,
|
||||||
tex_dict,
|
tex_dict,
|
||||||
SpectrumType::Albedo,
|
SpectrumType::Albedo,
|
||||||
tex.base.loc,
|
texture.base.loc,
|
||||||
&arena,
|
&arena,
|
||||||
)
|
)
|
||||||
.expect("Could not create spectrum texture")
|
.expect("Could not create spectrum texture"),
|
||||||
},
|
)
|
||||||
)
|
});
|
||||||
|
state.spectrum_texture_jobs.insert(name, job);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_area_light(&self, light: SceneEntity) -> usize {
|
pub fn add_area_light(&self, light: SceneEntity) -> usize {
|
||||||
|
|
@ -367,10 +399,39 @@ impl BasicScene {
|
||||||
let mut named = NamedTextures {
|
let mut named = NamedTextures {
|
||||||
float_textures: Arc::new(float_textures.clone()),
|
float_textures: Arc::new(float_textures.clone()),
|
||||||
albedo_spectrum_textures: Arc::new(spectrum_textures.clone()),
|
albedo_spectrum_textures: Arc::new(spectrum_textures.clone()),
|
||||||
illuminant_spectrum_textures: Arc::new(spectrum_textures.clone()),
|
illuminant_spectrum_textures: Arc::new(HashMap::new()),
|
||||||
unbounded_spectrum_textures: Arc::new(spectrum_textures.clone()),
|
unbounded_spectrum_textures: Arc::new(HashMap::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (name, entity) in state.async_spectrum_textures.drain(..) {
|
||||||
|
let render_from_texture = entity.render_from_object.start_transform;
|
||||||
|
let params = entity.base.parameters.clone();
|
||||||
|
|
||||||
|
let unbounded = SpectrumTexture::create(
|
||||||
|
&entity.base.name,
|
||||||
|
render_from_texture,
|
||||||
|
TextureParameterDictionary::new(params.clone().into(), None),
|
||||||
|
SpectrumType::Unbounded,
|
||||||
|
entity.base.loc.clone(),
|
||||||
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create unbounded spectrum texture");
|
||||||
|
|
||||||
|
let illum = SpectrumTexture::create(
|
||||||
|
&entity.base.name,
|
||||||
|
render_from_texture,
|
||||||
|
TextureParameterDictionary::new(params.into(), None),
|
||||||
|
SpectrumType::Illuminant,
|
||||||
|
entity.base.loc,
|
||||||
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create illuminant spectrum texture");
|
||||||
|
|
||||||
|
Arc::make_mut(&mut named.unbounded_spectrum_textures)
|
||||||
|
.insert(name.clone(), Arc::new(unbounded));
|
||||||
|
Arc::make_mut(&mut named.illuminant_spectrum_textures).insert(name, Arc::new(illum));
|
||||||
|
}
|
||||||
|
|
||||||
// Serial float textures may reference already-loaded textures
|
// Serial float textures may reference already-loaded textures
|
||||||
for (name, entity) in state.serial_float_textures.drain(..) {
|
for (name, entity) in state.serial_float_textures.drain(..) {
|
||||||
let render_from_texture = entity.render_from_object.start_transform;
|
let render_from_texture = entity.render_from_object.start_transform;
|
||||||
|
|
@ -389,18 +450,30 @@ impl BasicScene {
|
||||||
|
|
||||||
for (name, entity) in state.serial_spectrum_textures.drain(..) {
|
for (name, entity) in state.serial_spectrum_textures.drain(..) {
|
||||||
let render_from_texture = entity.render_from_object.start_transform;
|
let render_from_texture = entity.render_from_object.start_transform;
|
||||||
let tex_dict =
|
let make = |st: SpectrumType, named: &NamedTextures, loc| {
|
||||||
TextureParameterDictionary::new(entity.base.parameters.into(), Some(&named));
|
let tex_dict = TextureParameterDictionary::new(
|
||||||
let tex = SpectrumTexture::create(
|
entity.base.parameters.clone().into(),
|
||||||
&entity.base.name,
|
Some(named),
|
||||||
render_from_texture,
|
);
|
||||||
tex_dict,
|
SpectrumTexture::create(
|
||||||
SpectrumType::Albedo,
|
&entity.base.name,
|
||||||
entity.base.loc,
|
render_from_texture,
|
||||||
arena,
|
tex_dict,
|
||||||
)
|
st,
|
||||||
.expect("Could not create spectrum texture");
|
loc,
|
||||||
Arc::make_mut(&mut named.albedo_spectrum_textures).insert(name, Arc::new(tex));
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create spectrum texture")
|
||||||
|
};
|
||||||
|
|
||||||
|
let albedo = make(SpectrumType::Albedo, &named, entity.base.loc.clone());
|
||||||
|
let unbounded = make(SpectrumType::Unbounded, &named, entity.base.loc.clone());
|
||||||
|
let illum = make(SpectrumType::Illuminant, &named, entity.base.loc);
|
||||||
|
Arc::make_mut(&mut named.albedo_spectrum_textures)
|
||||||
|
.insert(name.clone(), Arc::new(albedo));
|
||||||
|
Arc::make_mut(&mut named.unbounded_spectrum_textures)
|
||||||
|
.insert(name.clone(), Arc::new(unbounded));
|
||||||
|
Arc::make_mut(&mut named.illuminant_spectrum_textures).insert(name, Arc::new(illum));
|
||||||
}
|
}
|
||||||
|
|
||||||
named
|
named
|
||||||
|
|
@ -517,25 +590,31 @@ impl BasicScene {
|
||||||
state.map.clone()
|
state.map.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_lights(&self, _textures: &NamedTextures, arena: &Arena) -> Vec<Arc<Light>> {
|
pub fn create_lights(
|
||||||
|
&self,
|
||||||
|
textures: &NamedTextures,
|
||||||
|
media: &HashMap<String, Arc<Medium>>,
|
||||||
|
arena: &Arena,
|
||||||
|
) -> (Vec<Light>, AreaLightMap) {
|
||||||
let light_state = self.light_state.lock();
|
let light_state = self.light_state.lock();
|
||||||
|
let shapes = self.shapes.lock();
|
||||||
|
let film_cs = self.film_colorspace.lock();
|
||||||
|
let film_cs_ref = film_cs.as_deref();
|
||||||
let camera = self
|
let camera = self
|
||||||
.get_camera()
|
.get_camera()
|
||||||
.expect("Camera must be initialized before lights");
|
.expect("Camera must be initialized before lights");
|
||||||
let camera_transform = camera.base().camera_transform;
|
let camera_transform = camera.base().camera_transform;
|
||||||
let mut lights: Vec<Arc<Light>> = Vec::new();
|
|
||||||
|
|
||||||
// Non-area lights created from stored entities
|
let mut lights: Vec<Light> = Vec::new();
|
||||||
|
|
||||||
for entity in &light_state.lights {
|
for entity in &light_state.lights {
|
||||||
let medium = self.get_medium(&entity.medium, &entity.transformed_base.base.loc);
|
let medium = self.get_medium(&entity.medium, &entity.transformed_base.base.loc);
|
||||||
|
|
||||||
if entity.transformed_base.render_from_object.is_animated() {
|
if entity.transformed_base.render_from_object.is_animated() {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"{}: animated lights aren't supported, using start transform.",
|
"{}: animated lights aren't supported, using start transform.",
|
||||||
entity.transformed_base.base.loc
|
entity.transformed_base.base.loc
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
match crate::core::light::create_light(
|
match crate::core::light::create_light(
|
||||||
&entity.transformed_base.base.name,
|
&entity.transformed_base.base.name,
|
||||||
entity.transformed_base.render_from_object.start_transform,
|
entity.transformed_base.render_from_object.start_transform,
|
||||||
|
|
@ -545,28 +624,78 @@ impl BasicScene {
|
||||||
camera_transform,
|
camera_transform,
|
||||||
arena,
|
arena,
|
||||||
) {
|
) {
|
||||||
Ok(light) => lights.push(Arc::new(light)),
|
Ok(light) => lights.push(light), // bare Light, no Arc
|
||||||
Err(e) => {
|
Err(e) => log::error!(
|
||||||
log::error!(
|
"{}: failed to create light: {}",
|
||||||
"{}: failed to create light: {}",
|
entity.transformed_base.base.loc,
|
||||||
entity.transformed_base.base.loc,
|
e
|
||||||
e
|
),
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut area_map: AreaLightMap = HashMap::new();
|
||||||
|
for (entity_idx, entity) in shapes.iter().enumerate() {
|
||||||
|
let Some(al_idx) = entity.light_index else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let al = &light_state.area_lights[al_idx];
|
||||||
|
|
||||||
|
let created_shapes = match Shape::create(
|
||||||
|
&entity.base.name,
|
||||||
|
*entity.render_from_object,
|
||||||
|
*entity.object_from_render,
|
||||||
|
entity.reverse_orientation,
|
||||||
|
entity.base.parameters.clone(),
|
||||||
|
&textures.float_textures,
|
||||||
|
entity.base.loc.clone(),
|
||||||
|
arena,
|
||||||
|
) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let alpha_tex = get_alpha_texture(
|
||||||
|
&entity.base.parameters,
|
||||||
|
&entity.base.loc,
|
||||||
|
&textures.float_textures,
|
||||||
|
);
|
||||||
|
let cs = al.parameters.color_space.as_deref().or(film_cs_ref);
|
||||||
|
|
||||||
|
for (sub_idx, shape) in created_shapes.iter().enumerate() {
|
||||||
|
let default_alpha = Arc::new(FloatTexture::default());
|
||||||
|
let alpha_ref = alpha_tex.as_ref().unwrap_or(&default_alpha);
|
||||||
|
match crate::core::light::create_area_light(
|
||||||
|
*entity.render_from_object,
|
||||||
|
None,
|
||||||
|
&al.parameters,
|
||||||
|
&al.loc,
|
||||||
|
shape,
|
||||||
|
alpha_ref,
|
||||||
|
cs,
|
||||||
|
arena,
|
||||||
|
) {
|
||||||
|
Ok(light) => {
|
||||||
|
let idx = LightIdx(lights.len() as u32);
|
||||||
|
lights.push(light);
|
||||||
|
area_map.insert((entity_idx, sub_idx), idx);
|
||||||
|
}
|
||||||
|
Err(e) => log::error!("{}: area light creation failed: {}", al.loc, e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lights
|
(lights, area_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_aggregate(
|
pub fn create_aggregate(
|
||||||
&self,
|
&self,
|
||||||
textures: &NamedTextures,
|
textures: &NamedTextures,
|
||||||
named_materials: &HashMap<String, Material>,
|
named_materials: &HashMap<String, MaterialIdx>,
|
||||||
materials: &[Material],
|
materials: &[Material],
|
||||||
|
area_map: &AreaLightMap,
|
||||||
media: &HashMap<String, Arc<Medium>>,
|
media: &HashMap<String, Arc<Medium>>,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> (Arc<Primitive>, Vec<Arc<Light>>) {
|
) -> Arc<Primitive> {
|
||||||
let mut shapes = self.shapes.lock();
|
let mut shapes = self.shapes.lock();
|
||||||
let mut animated_shapes = self.animated_shapes.lock();
|
let mut animated_shapes = self.animated_shapes.lock();
|
||||||
let mut instance_defs = self.instance_definitions.lock();
|
let mut instance_defs = self.instance_definitions.lock();
|
||||||
|
|
@ -575,21 +704,16 @@ impl BasicScene {
|
||||||
let film_cs = self.film_colorspace.lock();
|
let film_cs = self.film_colorspace.lock();
|
||||||
let film_cs_ref = film_cs.as_deref();
|
let film_cs_ref = film_cs.as_deref();
|
||||||
|
|
||||||
let mut all_lights: Vec<Arc<Light>> = Vec::new();
|
|
||||||
|
|
||||||
log::info!("Starting shapes");
|
log::info!("Starting shapes");
|
||||||
let mut primitives = Self::create_primitives_for_shapes(
|
let mut primitives = Self::create_primitives_for_shapes(
|
||||||
&shapes,
|
&shapes,
|
||||||
textures,
|
textures,
|
||||||
named_materials,
|
named_materials,
|
||||||
materials,
|
materials,
|
||||||
&light_state,
|
area_map,
|
||||||
media,
|
media,
|
||||||
film_cs_ref,
|
|
||||||
arena,
|
arena,
|
||||||
&mut all_lights,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
shapes.clear();
|
shapes.clear();
|
||||||
shapes.shrink_to_fit();
|
shapes.shrink_to_fit();
|
||||||
|
|
||||||
|
|
@ -598,72 +722,62 @@ impl BasicScene {
|
||||||
textures,
|
textures,
|
||||||
named_materials,
|
named_materials,
|
||||||
materials,
|
materials,
|
||||||
&light_state,
|
area_map,
|
||||||
media,
|
media,
|
||||||
film_cs_ref,
|
|
||||||
arena,
|
arena,
|
||||||
&mut all_lights,
|
|
||||||
);
|
);
|
||||||
primitives.extend(animated_primitives);
|
primitives.extend(animated_primitives);
|
||||||
|
|
||||||
animated_shapes.clear();
|
animated_shapes.clear();
|
||||||
animated_shapes.shrink_to_fit();
|
animated_shapes.shrink_to_fit();
|
||||||
log::info!("Finished shapes");
|
log::info!("Finished shapes");
|
||||||
|
|
||||||
log::info!("Starting instances");
|
log::info!("Starting instances");
|
||||||
let mut resolved_defs: HashMap<String, Option<Primitive>> = HashMap::new();
|
let mut resolved_defs: HashMap<String, Option<Primitive>> = HashMap::new();
|
||||||
|
|
||||||
for (name, def) in instance_defs.drain() {
|
for (name, def) in instance_defs.drain() {
|
||||||
let mut inst_prims = Self::create_primitives_for_shapes(
|
let mut inst_prims = Self::create_primitives_for_shapes(
|
||||||
&def.shapes,
|
&def.shapes,
|
||||||
textures,
|
textures,
|
||||||
named_materials,
|
named_materials,
|
||||||
materials,
|
materials,
|
||||||
&light_state,
|
area_map,
|
||||||
media,
|
media,
|
||||||
film_cs_ref,
|
|
||||||
arena,
|
arena,
|
||||||
&mut all_lights,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let animated_inst_prims = Self::create_primitives_for_animated_shapes(
|
let animated_inst_prims = Self::create_primitives_for_animated_shapes(
|
||||||
&def.animated_shapes,
|
&def.animated_shapes,
|
||||||
textures,
|
textures,
|
||||||
named_materials,
|
named_materials,
|
||||||
materials,
|
materials,
|
||||||
&light_state,
|
area_map,
|
||||||
media,
|
media,
|
||||||
film_cs_ref,
|
|
||||||
arena,
|
arena,
|
||||||
&mut all_lights,
|
|
||||||
);
|
);
|
||||||
inst_prims.extend(animated_inst_prims);
|
inst_prims.extend(animated_inst_prims);
|
||||||
|
|
||||||
let aggregate = if inst_prims.len() > 1 {
|
let aggregate = if inst_prims.len() > 1 {
|
||||||
let bvh = BVHAggregate::new(inst_prims, 4, SplitMethod::SAH);
|
Some(Primitive::BVH(arena.alloc(BVHAggregate::new(
|
||||||
Some(Primitive::BVH(arena.alloc(bvh)))
|
inst_prims,
|
||||||
|
4,
|
||||||
|
SplitMethod::SAH,
|
||||||
|
))))
|
||||||
} else if inst_prims.len() == 1 {
|
} else if inst_prims.len() == 1 {
|
||||||
Some(inst_prims.into_iter().next().unwrap())
|
Some(inst_prims.into_iter().next().unwrap())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
resolved_defs.insert(name, aggregate);
|
resolved_defs.insert(name, aggregate);
|
||||||
}
|
}
|
||||||
|
|
||||||
for inst in instances.drain(..) {
|
for inst in instances.drain(..) {
|
||||||
let def = match resolved_defs.get(&inst.name) {
|
let def = match resolved_defs.get(&inst.name) {
|
||||||
Some(Some(prim)) => prim,
|
Some(Some(prim)) => prim,
|
||||||
Some(None) => continue, // empty instance
|
Some(None) => continue,
|
||||||
None => {
|
None => {
|
||||||
log::error!("{}: object instance '{}' not defined", inst.loc, inst.name);
|
log::error!("{}: object instance '{}' not defined", inst.loc, inst.name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let prim = match &inst.transform {
|
let prim = match &inst.transform {
|
||||||
InstanceTransform::Static(xform) => {
|
InstanceTransform::Static(xform) => {
|
||||||
// TransformedPrimitive wraps a primitive with a static transform
|
|
||||||
Primitive::Transformed(shared::core::primitive::TransformedPrimitive {
|
Primitive::Transformed(shared::core::primitive::TransformedPrimitive {
|
||||||
primitive: arena.alloc(*def),
|
primitive: arena.alloc(*def),
|
||||||
render_from_primitive: arena.alloc(**xform),
|
render_from_primitive: arena.alloc(**xform),
|
||||||
|
|
@ -676,7 +790,6 @@ impl BasicScene {
|
||||||
};
|
};
|
||||||
primitives.push(prim);
|
primitives.push(prim);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Finished instances");
|
log::info!("Finished instances");
|
||||||
|
|
||||||
log::info!("Starting top-level accelerator");
|
log::info!("Starting top-level accelerator");
|
||||||
|
|
@ -688,7 +801,7 @@ impl BasicScene {
|
||||||
let agg_ptr = arena.alloc(aggregate);
|
let agg_ptr = arena.alloc(aggregate);
|
||||||
log::info!("Finished top-level accelerator");
|
log::info!("Finished top-level accelerator");
|
||||||
|
|
||||||
(Arc::new(Primitive::BVH(agg_ptr)), all_lights)
|
Arc::new(Primitive::BVH(agg_ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Integrator
|
// Integrator
|
||||||
|
|
@ -723,12 +836,21 @@ impl BasicScene {
|
||||||
camera: Arc<Camera>,
|
camera: Arc<Camera>,
|
||||||
sampler: Arc<Sampler>,
|
sampler: Arc<Sampler>,
|
||||||
aggregate: Arc<Primitive>,
|
aggregate: Arc<Primitive>,
|
||||||
lights: Vec<Arc<Light>>,
|
lights: Vec<Light>,
|
||||||
|
materials: Vec<Material>,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> CpuWavefrontRenderer {
|
) -> CpuWavefrontRenderer {
|
||||||
let integrator_entity = self.integrator.lock().clone().unwrap();
|
let integrator_entity = self.integrator.lock().clone().unwrap();
|
||||||
let params = &integrator_entity.parameters;
|
let params = &integrator_entity.parameters;
|
||||||
CpuWavefrontRenderer::create(params.clone(), camera, sampler, aggregate, lights, arena)
|
CpuWavefrontRenderer::create(
|
||||||
|
params.clone(),
|
||||||
|
camera,
|
||||||
|
sampler,
|
||||||
|
aggregate,
|
||||||
|
lights,
|
||||||
|
materials,
|
||||||
|
arena,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
|
|
@ -769,17 +891,15 @@ impl BasicScene {
|
||||||
fn create_primitives_for_shapes(
|
fn create_primitives_for_shapes(
|
||||||
shapes: &[ShapeSceneEntity],
|
shapes: &[ShapeSceneEntity],
|
||||||
textures: &NamedTextures,
|
textures: &NamedTextures,
|
||||||
named_materials: &HashMap<String, Material>,
|
named_materials: &HashMap<String, MaterialIdx>,
|
||||||
materials: &[Material],
|
materials: &[Material],
|
||||||
light_state: &LightState,
|
area_map: &AreaLightMap,
|
||||||
media: &HashMap<String, Arc<Medium>>,
|
media: &HashMap<String, Arc<Medium>>,
|
||||||
film_cs: Option<&RGBColorSpace>,
|
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
area_lights: &mut Vec<Arc<Light>>,
|
|
||||||
) -> Vec<Primitive> {
|
) -> Vec<Primitive> {
|
||||||
let mut primitives = Vec::new();
|
let mut primitives = Vec::new();
|
||||||
|
|
||||||
for entity in shapes {
|
for (entity_idx, entity) in shapes.iter().enumerate() {
|
||||||
let created_shapes = match Shape::create(
|
let created_shapes = match Shape::create(
|
||||||
&entity.base.name,
|
&entity.base.name,
|
||||||
*entity.render_from_object,
|
*entity.render_from_object,
|
||||||
|
|
@ -801,22 +921,18 @@ impl BasicScene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
eprintln!("shape '{}' n={}", entity.base.name, created_shapes.len());
|
let mtl: MaterialIdx = resolve_material(
|
||||||
|
|
||||||
let mtl = resolve_material(
|
|
||||||
&entity.material,
|
&entity.material,
|
||||||
named_materials,
|
named_materials,
|
||||||
materials,
|
materials,
|
||||||
&entity.base.loc,
|
&entity.base.loc,
|
||||||
arena,
|
arena,
|
||||||
);
|
);
|
||||||
|
|
||||||
let alpha_tex = get_alpha_texture(
|
let alpha_tex = get_alpha_texture(
|
||||||
&entity.base.parameters,
|
&entity.base.parameters,
|
||||||
&entity.base.loc,
|
&entity.base.loc,
|
||||||
&textures.float_textures,
|
&textures.float_textures,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mi = resolve_medium_interface(
|
let mi = resolve_medium_interface(
|
||||||
media,
|
media,
|
||||||
&entity.inside_medium,
|
&entity.inside_medium,
|
||||||
|
|
@ -824,73 +940,39 @@ impl BasicScene {
|
||||||
&entity.base.loc,
|
&entity.base.loc,
|
||||||
);
|
);
|
||||||
|
|
||||||
let al_entity = entity.light_index.map(|idx| &light_state.area_lights[idx]);
|
for (sub_idx, shape) in created_shapes.into_iter().enumerate() {
|
||||||
|
// look up the pre-created light index instead of creating one
|
||||||
|
let light_idx = area_map
|
||||||
|
.get(&(entity_idx, sub_idx))
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(LightIdx::NONE);
|
||||||
|
|
||||||
for shape in created_shapes {
|
|
||||||
// Create area light for this shape if the entity has one
|
|
||||||
let light_ptr = al_entity
|
|
||||||
.and_then(|al| {
|
|
||||||
let cs = al.parameters.color_space.as_deref().or(film_cs);
|
|
||||||
let default_alpha = Arc::new(FloatTexture::default());
|
|
||||||
let alpha_ref = alpha_tex.as_ref().unwrap_or(&default_alpha);
|
|
||||||
match crate::core::light::create_area_light(
|
|
||||||
*entity.render_from_object,
|
|
||||||
None,
|
|
||||||
&al.parameters,
|
|
||||||
&al.loc,
|
|
||||||
&shape,
|
|
||||||
alpha_ref,
|
|
||||||
cs,
|
|
||||||
arena,
|
|
||||||
) {
|
|
||||||
Ok(light) => {
|
|
||||||
area_lights.push(Arc::new(light));
|
|
||||||
Some(arena.alloc(light))
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{}: area light creation failed: {}", al.loc, e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(Ptr::null());
|
|
||||||
|
|
||||||
// Pick SimplePrimitive when no extras are needed
|
|
||||||
let prim =
|
let prim =
|
||||||
if light_ptr.is_null() && !mi.is_medium_transition() && alpha_tex.is_none() {
|
if light_idx.is_none() && !mi.is_medium_transition() && alpha_tex.is_none() {
|
||||||
Primitive::Simple(SimplePrimitive::new(shape, arena.alloc(mtl)))
|
Primitive::Simple(SimplePrimitive::new(shape, mtl)) // mtl is MaterialIdx now
|
||||||
} else {
|
} else {
|
||||||
let alpha_ptr = alpha_tex
|
let alpha_ptr = alpha_tex
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| arena.upload(t.as_ref()))
|
.map(|t| arena.upload(t.as_ref()))
|
||||||
.unwrap_or(Ptr::null());
|
.unwrap_or(Ptr::null());
|
||||||
|
|
||||||
Primitive::Geometric(GeometricPrimitive::new(
|
Primitive::Geometric(GeometricPrimitive::new(
|
||||||
shape,
|
shape, mtl, light_idx, mi, alpha_ptr,
|
||||||
arena.alloc(mtl),
|
|
||||||
light_ptr,
|
|
||||||
mi,
|
|
||||||
alpha_ptr,
|
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
primitives.push(prim);
|
primitives.push(prim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
primitives
|
primitives
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_primitives_for_animated_shapes(
|
fn create_primitives_for_animated_shapes(
|
||||||
shapes: &[AnimatedShapeSceneEntity],
|
shapes: &[AnimatedShapeSceneEntity],
|
||||||
textures: &NamedTextures,
|
textures: &NamedTextures,
|
||||||
named_materials: &HashMap<String, Material>,
|
named_materials: &HashMap<String, MaterialIdx>,
|
||||||
materials: &[Material],
|
materials: &[Material],
|
||||||
light_state: &LightState,
|
area_map: &AreaLightMap,
|
||||||
media: &HashMap<String, Arc<Medium>>,
|
media: &HashMap<String, Arc<Medium>>,
|
||||||
_film_cs: Option<&RGBColorSpace>,
|
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
_area_lights: &mut Vec<Arc<Light>>,
|
|
||||||
) -> Vec<Primitive> {
|
) -> Vec<Primitive> {
|
||||||
let mut primitives = Vec::new();
|
let mut primitives = Vec::new();
|
||||||
|
|
||||||
|
|
@ -943,9 +1025,7 @@ impl BasicScene {
|
||||||
&entity.transformed_base.base.loc,
|
&entity.transformed_base.base.loc,
|
||||||
);
|
);
|
||||||
|
|
||||||
let al_entity = entity.light_index.map(|idx| &light_state.area_lights[idx]);
|
if entity.light_index.is_some() {
|
||||||
|
|
||||||
if al_entity.is_some() {
|
|
||||||
log::error!(
|
log::error!(
|
||||||
"{}: animated area lights are not supported.",
|
"{}: animated area lights are not supported.",
|
||||||
entity.transformed_base.base.loc
|
entity.transformed_base.base.loc
|
||||||
|
|
@ -956,7 +1036,7 @@ impl BasicScene {
|
||||||
let mut base_prims = Vec::new();
|
let mut base_prims = Vec::new();
|
||||||
for shape in created_shapes {
|
for shape in created_shapes {
|
||||||
let base = if !mi.is_medium_transition() && alpha_tex.is_none() {
|
let base = if !mi.is_medium_transition() && alpha_tex.is_none() {
|
||||||
Primitive::Simple(SimplePrimitive::new(shape, arena.alloc(mtl)))
|
Primitive::Simple(SimplePrimitive::new(shape, mtl))
|
||||||
} else {
|
} else {
|
||||||
let alpha_ptr = alpha_tex
|
let alpha_ptr = alpha_tex
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -965,8 +1045,8 @@ impl BasicScene {
|
||||||
|
|
||||||
Primitive::Geometric(GeometricPrimitive::new(
|
Primitive::Geometric(GeometricPrimitive::new(
|
||||||
shape,
|
shape,
|
||||||
arena.alloc(mtl),
|
mtl,
|
||||||
Ptr::null(), // no area light on animated shapes
|
LightIdx::default(), // no area light on animated shapes
|
||||||
mi,
|
mi,
|
||||||
alpha_ptr,
|
alpha_ptr,
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,11 @@ use shared::core::texture::{
|
||||||
UVMapping,
|
UVMapping,
|
||||||
};
|
};
|
||||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use shared::textures::*;
|
use shared::textures::{
|
||||||
|
FBmTexture, FloatBilerpTexture, FloatCheckerboardTexture, FloatConstantTexture,
|
||||||
|
FloatDotsTexture, MarbleTexture, SpectrumBilerpTexture, SpectrumCheckerboardTexture,
|
||||||
|
SpectrumConstantTexture, SpectrumDotsTexture, WindyTexture, WrinkledTexture,
|
||||||
|
};
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -45,16 +49,6 @@ pub enum FloatTexture {
|
||||||
Bilerp(FloatBilerpTexture),
|
Bilerp(FloatBilerpTexture),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatTexture {
|
|
||||||
fn upload_image(inner: &FloatImageTexture, _arena: &Arena) -> GPUFloatImageTexture {
|
|
||||||
GPUFloatImageTexture {
|
|
||||||
mapping: inner.base.mapping,
|
|
||||||
tex_obj: inner.base.mipmap.texture_object(),
|
|
||||||
scale: inner.base.scale,
|
|
||||||
invert: inner.base.invert,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FloatTexture {
|
impl Default for FloatTexture {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ impl RayIntegratorTrait for PathIntegrator {
|
||||||
if state.depth == 0 || state.specular_bounce {
|
if state.depth == 0 || state.specular_bounce {
|
||||||
state.l += state.beta * le;
|
state.l += state.beta * le;
|
||||||
} else if self.config.use_mis
|
} else if self.config.use_mis
|
||||||
&& !isect.area_light.is_null() {
|
&& !isect.area_light.is_none() {
|
||||||
let light = &isect.area_light;
|
let light = &isect.area_light;
|
||||||
let p_l = self.sampler.pmf_with_context(&state.prev_ctx, light)
|
let p_l = self.sampler.pmf_with_context(&state.prev_ctx, light)
|
||||||
* light.pdf_li(&state.prev_ctx, ray.d, true);
|
* light.pdf_li(&state.prev_ctx, ray.d, true);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::core::image::{HostImage, ImageIO};
|
use crate::core::image::{HostImage, ImageIO};
|
||||||
use crate::core::light::lookup_spectrum;
|
use crate::core::light::lookup_spectrum;
|
||||||
use crate::core::spectrum::spectrum_to_photometric;
|
use crate::core::spectrum::spectrum_to_photometric;
|
||||||
use crate::core::texture::FloatTexture;
|
|
||||||
use crate::utils::resolve_filename;
|
use crate::utils::resolve_filename;
|
||||||
use crate::utils::upload::ArenaUpload;
|
use crate::utils::upload::ArenaUpload;
|
||||||
use crate::{Arena, FileLoc, ParameterDictionary};
|
use crate::{Arena, FileLoc, ParameterDictionary};
|
||||||
|
|
@ -11,7 +10,8 @@ use shared::core::light::{Light, LightBase, LightType};
|
||||||
use shared::core::medium::{Medium, MediumInterface};
|
use shared::core::medium::{Medium, MediumInterface};
|
||||||
use shared::core::shape::{Shape, ShapeTrait};
|
use shared::core::shape::{Shape, ShapeTrait};
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::core::texture::{GPUFloatTexture, SpectrumType, TextureEvalContext};
|
use crate::core::texture::FloatTexture as HostFloatTexture;
|
||||||
|
use shared::core::texture::{FloatTexture, SpectrumType, TextureEvalContext};
|
||||||
use shared::lights::DiffuseAreaLight;
|
use shared::lights::DiffuseAreaLight;
|
||||||
use shared::spectra::RGBColorSpace;
|
use shared::spectra::RGBColorSpace;
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
|
|
@ -24,7 +24,7 @@ pub fn create(
|
||||||
params: &ParameterDictionary,
|
params: &ParameterDictionary,
|
||||||
loc: &FileLoc,
|
loc: &FileLoc,
|
||||||
shape: &Shape,
|
shape: &Shape,
|
||||||
alpha: &FloatTexture,
|
alpha: &HostFloatTexture,
|
||||||
colorspace: Option<&RGBColorSpace>,
|
colorspace: Option<&RGBColorSpace>,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Light> {
|
) -> Result<Light> {
|
||||||
|
|
@ -102,7 +102,7 @@ pub fn create(
|
||||||
// Upload alpha texture to GPU and check for null texture
|
// Upload alpha texture to GPU and check for null texture
|
||||||
let alpha_ptr = arena.upload(alpha);
|
let alpha_ptr = arena.upload(alpha);
|
||||||
let light_type = match alpha_ptr.get().unwrap() {
|
let light_type = match alpha_ptr.get().unwrap() {
|
||||||
GPUFloatTexture::Constant(t) if t.evaluate(&TextureEvalContext::default()) == 0.0 => {
|
FloatTexture::Constant(t) if t.evaluate(&TextureEvalContext::default()) == 0.0 => {
|
||||||
LightType::DeltaPosition
|
LightType::DeltaPosition
|
||||||
}
|
}
|
||||||
_ => LightType::Area,
|
_ => LightType::Area,
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,40 @@
|
||||||
use crate::Arena;
|
use crate::Arena;
|
||||||
use shared::core::light::{Light, LightTrait};
|
use shared::core::light::{Light, LightTrait};
|
||||||
use shared::lights::sampler::{
|
use shared::lights::sampler::{LightSampler, PowerLightSampler, UniformLightSampler};
|
||||||
LightSampler, PowerLightSampler, UniformLightSampler,
|
|
||||||
};
|
|
||||||
use shared::utils::sampling::AliasTable;
|
|
||||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
|
use shared::utils::sampling::AliasTable;
|
||||||
use shared::utils::Ptr;
|
use shared::utils::Ptr;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub fn create_light_sampler(
|
pub fn create_light_sampler(name: &str, lights: &[Light], arena: &Arena) -> LightSampler {
|
||||||
name: &str,
|
|
||||||
lights: &[Arc<Light>],
|
|
||||||
arena: &Arena,
|
|
||||||
) -> LightSampler {
|
|
||||||
let device_lights = lights_to_slice(lights, arena);
|
|
||||||
match name {
|
match name {
|
||||||
"uniform" => LightSampler::Uniform(create_uniform(device_lights, lights.len())),
|
"uniform" => LightSampler::Uniform(create_uniform(lights.len() as u32)),
|
||||||
"power" => LightSampler::Power(create_power(lights, device_lights, arena)),
|
"power" => LightSampler::Power(create_power(lights, arena)),
|
||||||
"bvh" => {
|
"bvh" => {
|
||||||
log::warn!("BVH light sampler not yet implemented, falling back to power");
|
log::warn!("BVH light sampler not yet implemented, falling back to power");
|
||||||
LightSampler::Power(create_power(lights, device_lights, arena))
|
LightSampler::Power(create_power(lights, arena))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Unknown light sampler \"{}\", using power", name);
|
log::error!("Unknown light sampler \"{}\", using power", name);
|
||||||
LightSampler::Power(create_power(lights, device_lights, arena))
|
LightSampler::Power(create_power(lights, arena))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lights_to_slice(lights: &[Arc<Light>], arena: &Arena) -> (Ptr<Light>, u32) {
|
fn create_uniform(lights_len: u32) -> UniformLightSampler {
|
||||||
|
UniformLightSampler::new(lights_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_power(lights: &[Light], arena: &Arena) -> PowerLightSampler {
|
||||||
if lights.is_empty() {
|
if lights.is_empty() {
|
||||||
return (Ptr::null(), 0);
|
|
||||||
}
|
|
||||||
let vals: Vec<Light> = lights.iter().map(|l| **l).collect();
|
|
||||||
let (ptr, _) = arena.alloc_slice(&vals);
|
|
||||||
(ptr, lights.len() as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_uniform(
|
|
||||||
(lights, lights_len): (Ptr<Light>, u32),
|
|
||||||
_count: usize,
|
|
||||||
) -> UniformLightSampler {
|
|
||||||
UniformLightSampler::new(lights, lights_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_power(
|
|
||||||
host_lights: &[Arc<Light>],
|
|
||||||
(lights, lights_len): (Ptr<Light>, u32),
|
|
||||||
arena: &Arena,
|
|
||||||
) -> PowerLightSampler {
|
|
||||||
if host_lights.is_empty() {
|
|
||||||
return PowerLightSampler {
|
return PowerLightSampler {
|
||||||
lights: Ptr::null(),
|
|
||||||
lights_len: 0,
|
lights_len: 0,
|
||||||
alias_table: Ptr::null(),
|
alias_table: Ptr::null(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let lambda = SampledWavelengths::sample_visible(0.5);
|
let lambda = SampledWavelengths::sample_visible(0.5);
|
||||||
let mut light_power: Vec<Float> = host_lights
|
let mut light_power: Vec<Float> = lights
|
||||||
.iter()
|
.iter()
|
||||||
.map(|l| {
|
.map(|l| {
|
||||||
let phi = SampledSpectrum::safe_div(&l.phi(lambda), &lambda.pdf());
|
let phi = SampledSpectrum::safe_div(&l.phi(lambda), &lambda.pdf());
|
||||||
|
|
@ -67,7 +42,7 @@ fn create_power(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// If all lights have zero power, treat as uniform
|
// If all lights have zero power, treat as uniform.
|
||||||
if light_power.iter().sum::<Float>() == 0.0 {
|
if light_power.iter().sum::<Float>() == 0.0 {
|
||||||
light_power.fill(1.0);
|
light_power.fill(1.0);
|
||||||
}
|
}
|
||||||
|
|
@ -76,8 +51,7 @@ fn create_power(
|
||||||
let alias_ptr = arena.alloc(alias_table);
|
let alias_ptr = arena.alloc(alias_table);
|
||||||
|
|
||||||
PowerLightSampler {
|
PowerLightSampler {
|
||||||
lights,
|
lights_len: lights.len() as u32,
|
||||||
lights_len,
|
|
||||||
alias_table: alias_ptr,
|
alias_table: alias_ptr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,6 @@ impl CreateMaterial for ConductorMaterial {
|
||||||
remap_roughness,
|
remap_roughness,
|
||||||
);
|
);
|
||||||
|
|
||||||
arena.alloc(material);
|
|
||||||
Ok(Material::Conductor(material))
|
Ok(Material::Conductor(material))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ use crate::core::texture::{
|
||||||
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture,
|
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture,
|
||||||
SpectrumTextureTrait,
|
SpectrumTextureTrait,
|
||||||
};
|
};
|
||||||
use crate::utils::mipmap::{FilterFunction, MIPMap, MIPMapFilterOptions};
|
use crate::utils::mipmap::{MIPMap, MIPMapFilterOptions};
|
||||||
use crate::utils::{FileLoc, TextureParameterDictionary, resolve_filename};
|
use crate::utils::{resolve_filename, FileLoc, TextureParameterDictionary};
|
||||||
use crate::{Arena};
|
use crate::Arena;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use shared::core::color::RGB;
|
use shared::core::color::RGB;
|
||||||
use shared::core::color::{ColorEncoding, SRGBEncoding};
|
use shared::core::color::{ColorEncoding, SRGBEncoding};
|
||||||
use shared::core::geometry::Vector2f;
|
use shared::core::geometry::Vector2f;
|
||||||
use shared::core::image::WrapMode;
|
use shared::core::image::{FilterFunction, WrapMode};
|
||||||
use shared::core::spectrum::SpectrumTrait;
|
use shared::core::spectrum::SpectrumTrait;
|
||||||
use shared::core::texture::{SpectrumType, TexCoord2D, TextureEvalContext, TextureMapping2D};
|
use shared::core::texture::{SpectrumType, TexCoord2D, TextureEvalContext, TextureMapping2D};
|
||||||
use shared::spectra::{
|
use shared::spectra::{
|
||||||
|
|
@ -143,7 +143,7 @@ impl SpectrumTextureTrait for SpectrumImageTexture {
|
||||||
return RGBUnboundedSpectrum::new(&cs, rgb).sample(lambda);
|
return RGBUnboundedSpectrum::new(&cs, rgb).sample(lambda);
|
||||||
}
|
}
|
||||||
SpectrumType::Albedo => {
|
SpectrumType::Albedo => {
|
||||||
return RGBAlbedoSpectrum::new(&cs, rgb).sample(lambda);
|
return RGBAlbedoSpectrum::new(&cs, rgb.clamp(0., 1.)).sample(lambda);
|
||||||
}
|
}
|
||||||
_ => return RGBIlluminantSpectrum::new(&cs, rgb).sample(lambda),
|
_ => return RGBIlluminantSpectrum::new(&cs, rgb).sample(lambda),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::core::image::{HostImage, ImageIO};
|
use crate::core::image::{HostImage, ImageIO};
|
||||||
use shared::core::color::{ColorEncoding, RGB};
|
use shared::core::color::{ColorEncoding, RGB};
|
||||||
use shared::core::geometry::{Point2f, Point2i, Vector2f, VectorLike};
|
use shared::core::geometry::{Point2f, Point2i, Vector2f, VectorLike};
|
||||||
use shared::core::image::{WrapMode, WrapMode2D};
|
use shared::core::image::{WrapMode, WrapMode2D, FilterFunction};
|
||||||
use shared::spectra::RGBColorSpace;
|
use shared::spectra::RGBColorSpace;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use shared::utils::math::{lerp, safe_sqrt, square};
|
use shared::utils::math::{lerp, safe_sqrt, square};
|
||||||
|
|
@ -13,39 +13,17 @@ use std::path::Path;
|
||||||
#[cfg(feature = "cuda")]
|
#[cfg(feature = "cuda")]
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
#[repr(C)]
|
// impl std::fmt::Display for FilterFunction {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
pub enum FilterFunction {
|
// let s = match self {
|
||||||
Point,
|
// FilterFunction::Ewa => "EWA",
|
||||||
Bilinear,
|
// FilterFunction::Trilinear => "trilinear",
|
||||||
Trilinear,
|
// FilterFunction::Bilinear => "bilinear",
|
||||||
Ewa,
|
// FilterFunction::Point => "point",
|
||||||
}
|
// };
|
||||||
|
// write!(f, "{}", s)
|
||||||
impl FilterFunction {
|
// }
|
||||||
pub fn parse(name: &str) -> Result<FilterFunction> {
|
// }
|
||||||
match name {
|
|
||||||
"ewa" | "EWA" => Ok(FilterFunction::Ewa),
|
|
||||||
"trilinear" => Ok(FilterFunction::Trilinear),
|
|
||||||
"bilinear" => Ok(FilterFunction::Bilinear),
|
|
||||||
"point" => Ok(FilterFunction::Point),
|
|
||||||
_ => bail!("Filter function unknown")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl std::fmt::Display for FilterFunction {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let s = match self {
|
|
||||||
FilterFunction::Ewa => "EWA",
|
|
||||||
FilterFunction::Trilinear => "trilinear",
|
|
||||||
FilterFunction::Bilinear => "bilinear",
|
|
||||||
FilterFunction::Point => "point",
|
|
||||||
};
|
|
||||||
write!(f, "{}", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
|
||||||
|
|
@ -907,6 +907,7 @@ impl TextureParameterDictionary {
|
||||||
if let Some(tex) = map.get(tex_name) {
|
if let Some(tex) = map.get(tex_name) {
|
||||||
return Some(Arc::clone(tex));
|
return Some(Arc::clone(tex));
|
||||||
}
|
}
|
||||||
|
|
||||||
panic!(
|
panic!(
|
||||||
"[{:?}] Couldn't find spectrum texture named '{}'",
|
"[{:?}] Couldn't find spectrum texture named '{}'",
|
||||||
p.loc, tex_name
|
p.loc, tex_name
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
|
||||||
use crate::core::image::HostImage;
|
use crate::core::image::HostImage;
|
||||||
use shared::core::image::Image;
|
use crate::core::texture::{FloatTexture as HostFloatTexture, SpectrumTexture as HostSpectrumTexture};
|
||||||
|
use crate::spectra::default_colorspace;
|
||||||
use crate::Arena;
|
use crate::Arena;
|
||||||
use shared::core::texture::{GPUFloatTexture, GPUSpectrumTexture};
|
use shared::core::image::Image;
|
||||||
|
use shared::core::texture::{FloatTexture, SpectrumTexture};
|
||||||
use shared::textures::*;
|
use shared::textures::*;
|
||||||
use shared::Ptr;
|
use shared::Ptr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -12,43 +13,46 @@ pub trait Upload {
|
||||||
fn upload(self, arena: &Arena) -> Self::Target;
|
fn upload(self, arena: &Arena) -> Self::Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_float(tex: &FloatTexture, arena: &Arena) -> GPUFloatTexture {
|
fn convert_float(tex: &HostFloatTexture, arena: &Arena) -> FloatTexture {
|
||||||
match tex {
|
match tex {
|
||||||
FloatTexture::Constant(t) => GPUFloatTexture::Constant(*t),
|
HostFloatTexture::Constant(t) => FloatTexture::Constant(*t),
|
||||||
FloatTexture::Bilerp(t) => GPUFloatTexture::Bilerp(*t),
|
HostFloatTexture::Bilerp(t) => FloatTexture::Bilerp(*t),
|
||||||
FloatTexture::Checkerboard(t) => GPUFloatTexture::Checkerboard(*t),
|
HostFloatTexture::Checkerboard(t) => FloatTexture::Checkerboard(*t),
|
||||||
FloatTexture::Dots(t) => GPUFloatTexture::Dots(*t),
|
HostFloatTexture::Dots(t) => FloatTexture::Dots(*t),
|
||||||
FloatTexture::FBm(t) => GPUFloatTexture::FBm(*t),
|
HostFloatTexture::FBm(t) => FloatTexture::FBm(*t),
|
||||||
FloatTexture::Windy(t) => GPUFloatTexture::Windy(*t),
|
HostFloatTexture::Windy(t) => FloatTexture::Windy(*t),
|
||||||
FloatTexture::Wrinkled(t) => GPUFloatTexture::Wrinkled(*t),
|
HostFloatTexture::Wrinkled(t) => FloatTexture::Wrinkled(*t),
|
||||||
|
|
||||||
FloatTexture::Scaled(t) => {
|
HostFloatTexture::Scaled(t) => {
|
||||||
let tex = arena.alloc(convert_float(&t.tex, arena));
|
let tex = arena.alloc(convert_float(t.tex.as_ref(), arena));
|
||||||
let scale = arena.alloc(convert_float(&t.scale, arena));
|
let scale = arena.alloc(convert_float(t.scale.as_ref(), arena));
|
||||||
GPUFloatTexture::Scaled(GPUFloatScaledTexture { tex, scale })
|
FloatTexture::Scaled(FloatScaledTexture { tex, scale })
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatTexture::Mix(t) => {
|
HostFloatTexture::Mix(t) => {
|
||||||
let tex1 = arena.alloc(convert_float(&t.tex1, arena));
|
let tex1 = arena.alloc(convert_float(t.tex1.as_ref(), arena));
|
||||||
let tex2 = arena.alloc(convert_float(&t.tex2, arena));
|
let tex2 = arena.alloc(convert_float(t.tex2.as_ref(), arena));
|
||||||
let amount = arena.alloc(convert_float(&t.amount, arena));
|
let amount = arena.alloc(convert_float(t.amount.as_ref(), arena));
|
||||||
GPUFloatTexture::Mix(GPUFloatMixTexture { tex1, tex2, amount })
|
FloatTexture::Mix(FloatMixTexture { tex1, tex2, amount })
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatTexture::DirectionMix(t) => {
|
HostFloatTexture::DirectionMix(t) => {
|
||||||
let tex1 = arena.alloc(convert_float(&t.tex1, arena));
|
let tex1 = arena.alloc(convert_float(t.tex1.as_ref(), arena));
|
||||||
let tex2 = arena.alloc(convert_float(&t.tex2, arena));
|
let tex2 = arena.alloc(convert_float(t.tex2.as_ref(), arena));
|
||||||
GPUFloatTexture::DirectionMix(GPUFloatDirectionMixTexture {
|
FloatTexture::DirectionMix(FloatDirectionMixTexture {
|
||||||
tex1,
|
tex1,
|
||||||
tex2,
|
tex2,
|
||||||
dir: t.dir,
|
dir: t.dir,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatTexture::Image(t) => {
|
HostFloatTexture::Image(t) => {
|
||||||
|
let image = arena.alloc(t.base.mipmap.base_image().inner.clone());
|
||||||
let tex_obj = arena.get_texture_object(&t.base.mipmap);
|
let tex_obj = arena.get_texture_object(&t.base.mipmap);
|
||||||
GPUFloatTexture::Image(GPUFloatImageTexture {
|
FloatTexture::Image(FloatImageTexture {
|
||||||
|
image,
|
||||||
mapping: t.base.mapping,
|
mapping: t.base.mapping,
|
||||||
|
wrap_mode: t.base.mipmap.wrap_mode,
|
||||||
tex_obj,
|
tex_obj,
|
||||||
scale: t.base.scale,
|
scale: t.base.scale,
|
||||||
invert: t.base.invert,
|
invert: t.base.invert,
|
||||||
|
|
@ -57,94 +61,92 @@ fn convert_float(tex: &FloatTexture, arena: &Arena) -> GPUFloatTexture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_spectrum(tex: &SpectrumTexture, arena: &Arena) -> GPUSpectrumTexture {
|
fn convert_spectrum(tex: &HostSpectrumTexture, arena: &Arena) -> SpectrumTexture {
|
||||||
match tex {
|
match tex {
|
||||||
SpectrumTexture::Constant(t) => GPUSpectrumTexture::Constant(*t),
|
HostSpectrumTexture::Constant(t) => SpectrumTexture::Constant(*t),
|
||||||
SpectrumTexture::Bilerp(t) => GPUSpectrumTexture::Bilerp(*t),
|
HostSpectrumTexture::Bilerp(t) => SpectrumTexture::Bilerp(*t),
|
||||||
SpectrumTexture::Checkerboard(t) => GPUSpectrumTexture::Checkerboard(*t),
|
HostSpectrumTexture::Checkerboard(t) => SpectrumTexture::Checkerboard(*t),
|
||||||
SpectrumTexture::Dots(t) => GPUSpectrumTexture::Dots(*t),
|
HostSpectrumTexture::Dots(t) => SpectrumTexture::Dots(*t),
|
||||||
SpectrumTexture::Marble(t) => GPUSpectrumTexture::Marble(*t),
|
HostSpectrumTexture::Marble(t) => SpectrumTexture::Marble(*t),
|
||||||
|
|
||||||
SpectrumTexture::Scaled(t) => {
|
HostSpectrumTexture::Scaled(t) => {
|
||||||
let tex = arena.alloc(convert_spectrum(&t.tex, arena));
|
let tex = arena.alloc(convert_spectrum(t.tex.as_ref(), arena));
|
||||||
let scale = arena.alloc(convert_float(&t.scale, arena));
|
let scale = arena.alloc(convert_float(t.scale.as_ref(), arena));
|
||||||
GPUSpectrumTexture::Scaled(GPUSpectrumScaledTexture { tex, scale })
|
SpectrumTexture::Scaled(SpectrumScaledTexture { tex, scale })
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectrumTexture::Mix(t) => {
|
HostSpectrumTexture::Mix(t) => {
|
||||||
let tex1 = arena.alloc(convert_spectrum(&t.tex1, arena));
|
let tex1 = arena.alloc(convert_spectrum(t.tex1.as_ref(), arena));
|
||||||
let tex2 = arena.alloc(convert_spectrum(&t.tex2, arena));
|
let tex2 = arena.alloc(convert_spectrum(t.tex2.as_ref(), arena));
|
||||||
let amount = arena.alloc(convert_float(&t.amount, arena));
|
let amount = arena.alloc(convert_float(t.amount.as_ref(), arena));
|
||||||
GPUSpectrumTexture::Mix(GPUSpectrumMixTexture { tex1, tex2, amount })
|
SpectrumTexture::Mix(SpectrumMixTexture { tex1, tex2, amount })
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectrumTexture::DirectionMix(t) => {
|
HostSpectrumTexture::DirectionMix(t) => {
|
||||||
let tex1 = arena.alloc(convert_spectrum(&t.tex1, arena));
|
let tex1 = arena.alloc(convert_spectrum(t.tex1.as_ref(), arena));
|
||||||
let tex2 = arena.alloc(convert_spectrum(&t.tex2, arena));
|
let tex2 = arena.alloc(convert_spectrum(t.tex2.as_ref(), arena));
|
||||||
GPUSpectrumTexture::DirectionMix(GPUSpectrumDirectionMixTexture {
|
SpectrumTexture::DirectionMix(SpectrumDirectionMixTexture {
|
||||||
tex1,
|
tex1,
|
||||||
tex2,
|
tex2,
|
||||||
dir: t.dir,
|
dir: t.dir,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectrumTexture::Image(t) => {
|
HostSpectrumTexture::Image(t) => {
|
||||||
|
let image = arena.alloc(t.base.mipmap.base_image().inner.clone());
|
||||||
let tex_obj = arena.get_texture_object(&t.base.mipmap);
|
let tex_obj = arena.get_texture_object(&t.base.mipmap);
|
||||||
GPUSpectrumTexture::Image(GPUSpectrumImageTexture {
|
SpectrumTexture::Image(SpectrumImageTexture {
|
||||||
mapping: t.base.mapping,
|
image,
|
||||||
tex_obj,
|
tex_obj,
|
||||||
|
wrap_mode: t.base.mipmap.wrap_mode,
|
||||||
|
color_space: arena
|
||||||
|
.alloc(t.base.mipmap.color_space.unwrap_or_else(default_colorspace)),
|
||||||
|
mapping: t.base.mapping,
|
||||||
scale: t.base.scale,
|
scale: t.base.scale,
|
||||||
invert: t.base.invert,
|
invert: t.base.invert,
|
||||||
is_single_channel: t.base.mipmap.is_single_channel(),
|
is_single_channel: t.base.mipmap.is_single_channel(),
|
||||||
spectrum_type: t.spectrum_type,
|
spectrum_type: t.spectrum_type,
|
||||||
|
|
||||||
color_space: arena.alloc(
|
|
||||||
t.base
|
|
||||||
.mipmap
|
|
||||||
.color_space
|
|
||||||
.unwrap_or_else(crate::spectra::default_colorspace),
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for Arc<FloatTexture> {
|
impl Upload for Arc<HostFloatTexture> {
|
||||||
type Target = Ptr<GPUFloatTexture>;
|
type Target = Ptr<FloatTexture>;
|
||||||
fn upload(self, arena: &Arena) -> Self::Target {
|
fn upload(self, arena: &Arena) -> Self::Target {
|
||||||
arena.alloc(convert_float(&self, arena))
|
arena.alloc(convert_float(&self, arena))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for Arc<SpectrumTexture> {
|
impl Upload for Arc<HostSpectrumTexture> {
|
||||||
type Target = Ptr<GPUSpectrumTexture>;
|
type Target = Ptr<SpectrumTexture>;
|
||||||
fn upload(self, arena: &Arena) -> Self::Target {
|
fn upload(self, arena: &Arena) -> Self::Target {
|
||||||
arena.alloc(convert_spectrum(&self, arena))
|
arena.alloc(convert_spectrum(&self, arena))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for &FloatTexture {
|
impl Upload for &HostFloatTexture {
|
||||||
type Target = Ptr<GPUFloatTexture>;
|
type Target = Ptr<FloatTexture>;
|
||||||
fn upload(self, arena: &Arena) -> Self::Target {
|
fn upload(self, arena: &Arena) -> Self::Target {
|
||||||
arena.alloc(convert_float(self, arena))
|
arena.alloc(convert_float(self, arena))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for &SpectrumTexture {
|
impl Upload for &HostSpectrumTexture {
|
||||||
type Target = Ptr<GPUSpectrumTexture>;
|
type Target = Ptr<SpectrumTexture>;
|
||||||
fn upload(self, arena: &Arena) -> Self::Target {
|
fn upload(self, arena: &Arena) -> Self::Target {
|
||||||
arena.alloc(convert_spectrum(self, arena))
|
arena.alloc(convert_spectrum(self, arena))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Upload for Option<Arc<FloatTexture>> {
|
impl Upload for Option<Arc<HostFloatTexture>> {
|
||||||
type Target = Ptr<GPUFloatTexture>;
|
type Target = Ptr<FloatTexture>;
|
||||||
fn upload(self, arena: &Arena) -> Self::Target {
|
fn upload(self, arena: &Arena) -> Self::Target {
|
||||||
arena.alloc_opt(self.map(|v| convert_float(&v, arena)))
|
arena.alloc_opt(self.map(|v| convert_float(&v, arena)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for Option<Arc<SpectrumTexture>> {
|
impl Upload for Option<Arc<HostSpectrumTexture>> {
|
||||||
type Target = Ptr<GPUSpectrumTexture>;
|
type Target = Ptr<SpectrumTexture>;
|
||||||
fn upload(self, arena: &Arena) -> Self::Target {
|
fn upload(self, arena: &Arena) -> Self::Target {
|
||||||
arena.alloc_opt(self.map(|v| convert_spectrum(&v, arena)))
|
arena.alloc_opt(self.map(|v| convert_spectrum(&v, arena)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,22 @@ use log::debug;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use shared::core::geometry::{Bounds3f, Ray, VectorLike};
|
use shared::core::geometry::{Bounds3f, Ray, VectorLike};
|
||||||
use shared::core::interaction::{InteractionTrait, SurfaceInteraction};
|
use shared::core::interaction::{InteractionTrait, SurfaceInteraction};
|
||||||
use shared::core::material::MaterialTrait;
|
use shared::core::material::{Material, MaterialTrait};
|
||||||
use shared::core::primitive::{Primitive, PrimitiveTrait};
|
use shared::core::primitive::{Primitive, PrimitiveTrait};
|
||||||
use shared::core::texture::BasicTextureEvaluator;
|
use shared::core::texture::BasicTextureEvaluator;
|
||||||
use shared::core::texture::TextureEvaluator;
|
use shared::core::texture::TextureEvaluator;
|
||||||
use shared::wavefront::workitems::*;
|
use shared::wavefront::workitems::*;
|
||||||
use shared::wavefront::WavefrontAggregate;
|
use shared::wavefront::WavefrontAggregate;
|
||||||
use shared::{Float, Ptr};
|
use shared::{Float, Ptr, GVec, gvec_from_slice};
|
||||||
|
|
||||||
pub struct CpuAggregate {
|
pub struct CpuAggregate {
|
||||||
pub aggregate: Primitive,
|
pub aggregate: Primitive,
|
||||||
|
pub materials: GVec<Material>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuAggregate {
|
impl CpuAggregate {
|
||||||
pub fn new(aggregate: Primitive) -> Self {
|
pub fn new(aggregate: Primitive, materials: &[Material]) -> Self {
|
||||||
Self { aggregate }
|
Self { aggregate, materials: gvec_from_slice(materials) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +71,7 @@ impl WavefrontAggregate for CpuAggregate {
|
||||||
let intr = &si.intr;
|
let intr = &si.intr;
|
||||||
|
|
||||||
// Medium transition
|
// Medium transition
|
||||||
if intr.material.is_null() {
|
if intr.material.is_none() {
|
||||||
let mut next = r;
|
let mut next = r;
|
||||||
next.ray = intr.spawn_ray(r.ray.d);
|
next.ray = intr.spawn_ray(r.ray.d);
|
||||||
next_ray_q.push(next);
|
next_ray_q.push(next);
|
||||||
|
|
@ -78,7 +79,7 @@ impl WavefrontAggregate for CpuAggregate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Area light hit
|
// Area light hit
|
||||||
if !intr.area_light.is_null() {
|
if !intr.area_light.is_none() {
|
||||||
hit_area_light_q.push(HitAreaLightWorkItem {
|
hit_area_light_q.push(HitAreaLightWorkItem {
|
||||||
area_light: intr.area_light,
|
area_light: intr.area_light,
|
||||||
p: intr.p(),
|
p: intr.p(),
|
||||||
|
|
@ -97,7 +98,7 @@ impl WavefrontAggregate for CpuAggregate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Material eval queue dispatch
|
// Material eval queue dispatch
|
||||||
let material = *intr.material.get().unwrap();
|
let material = &self.materials[intr.material.0 as usize];
|
||||||
let eval_q = if material.can_evaluate_textures(&BasicTextureEvaluator) {
|
let eval_q = if material.can_evaluate_textures(&BasicTextureEvaluator) {
|
||||||
basic_eval_mtl_q
|
basic_eval_mtl_q
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,11 @@ use shared::core::geometry::{
|
||||||
};
|
};
|
||||||
use shared::core::interaction::InteractionTrait;
|
use shared::core::interaction::InteractionTrait;
|
||||||
use shared::core::light::{Light, LightSampleContext, LightTrait};
|
use shared::core::light::{Light, LightSampleContext, LightTrait};
|
||||||
use shared::core::material::{MaterialEvalContext, MaterialTrait};
|
use shared::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
||||||
use shared::core::primitive::Primitive;
|
use shared::core::primitive::{Primitive, PrimitiveTrait};
|
||||||
use shared::core::sampler::{get_camera_sample, CameraSample, Sampler, SamplerTrait};
|
use shared::core::sampler::{get_camera_sample, CameraSample, Sampler, SamplerTrait};
|
||||||
use shared::core::texture::{BasicTextureEvaluator, TextureEvalContext, UniversalTextureEvaluator};
|
use shared::core::texture::{BasicTextureEvaluator, TextureEvalContext, UniversalTextureEvaluator};
|
||||||
|
use shared::core::LightIdx;
|
||||||
use shared::lights::sampler::{LightSampler, LightSamplerTrait};
|
use shared::lights::sampler::{LightSampler, LightSamplerTrait};
|
||||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use shared::utils::math::square;
|
use shared::utils::math::square;
|
||||||
|
|
@ -27,7 +28,7 @@ use shared::utils::sampling::power_heuristic;
|
||||||
use shared::utils::soa::{SoA, SoAAllocator, WorkQueue};
|
use shared::utils::soa::{SoA, SoAAllocator, WorkQueue};
|
||||||
use shared::wavefront::workitems::*;
|
use shared::wavefront::workitems::*;
|
||||||
use shared::wavefront::{WavefrontAggregate, WavefrontPathIntegrator, WavefrontRenderer};
|
use shared::wavefront::{WavefrontAggregate, WavefrontPathIntegrator, WavefrontRenderer};
|
||||||
use shared::{gvec, Ptr, SHADOW_EPSILON};
|
use shared::{gvec, gvec_from_slice, GVec, Ptr, SHADOW_EPSILON};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -55,7 +56,8 @@ where
|
||||||
camera: Arc<Camera>,
|
camera: Arc<Camera>,
|
||||||
sampler: Arc<Sampler>,
|
sampler: Arc<Sampler>,
|
||||||
aggregate: Arc<Primitive>,
|
aggregate: Arc<Primitive>,
|
||||||
lights: Vec<Arc<Light>>,
|
mut lights: Vec<Light>,
|
||||||
|
materials: Vec<Material>,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> CpuWavefrontRenderer {
|
) -> CpuWavefrontRenderer {
|
||||||
let max_depth = parameters
|
let max_depth = parameters
|
||||||
|
|
@ -75,15 +77,23 @@ where
|
||||||
let scanlines_per_pass = (max_samples / res_x).max(1);
|
let scanlines_per_pass = (max_samples / res_x).max(1);
|
||||||
let max_queue_size = res_x * scanlines_per_pass;
|
let max_queue_size = res_x * scanlines_per_pass;
|
||||||
|
|
||||||
let mut infinite_lights = gvec();
|
let mut infinite_lights: GVec<LightIdx> = gvec();
|
||||||
for light in &lights {
|
for (i, light) in lights.iter().enumerate() {
|
||||||
if light.light_type().is_infinite() {
|
if light.light_type().is_infinite() {
|
||||||
infinite_lights.push(arena.alloc(**light));
|
infinite_lights.push(LightIdx(i as u32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cpu_aggregate = CpuAggregate::new(*aggregate);
|
let cpu_aggregate = CpuAggregate::new(*aggregate);
|
||||||
|
|
||||||
|
let bounds = aggregate.bounds();
|
||||||
|
for light in &mut lights {
|
||||||
|
light.preprocess(&bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lights: GVec<Light> = gvec_from_slice(&lights);
|
||||||
|
let materials: GVec<Material> = gvec_from_slice(&materials);
|
||||||
|
|
||||||
CpuWavefrontRenderer(WavefrontPathIntegrator {
|
CpuWavefrontRenderer(WavefrontPathIntegrator {
|
||||||
aggregate: cpu_aggregate,
|
aggregate: cpu_aggregate,
|
||||||
camera: (*camera).clone(),
|
camera: (*camera).clone(),
|
||||||
|
|
@ -94,6 +104,8 @@ where
|
||||||
samples_per_pixel: spp,
|
samples_per_pixel: spp,
|
||||||
regularize,
|
regularize,
|
||||||
infinite_lights,
|
infinite_lights,
|
||||||
|
lights,
|
||||||
|
materials,
|
||||||
max_queue_size,
|
max_queue_size,
|
||||||
scanlines_per_pass,
|
scanlines_per_pass,
|
||||||
light_sampler,
|
light_sampler,
|
||||||
|
|
@ -298,8 +310,8 @@ impl CpuWavefrontRenderer {
|
||||||
|
|
||||||
let mut l_contrib = SampledSpectrum::new(0.0);
|
let mut l_contrib = SampledSpectrum::new(0.0);
|
||||||
|
|
||||||
for light_ptr in infinite_lights {
|
for idx in infinite_lights {
|
||||||
let light = light_ptr.get().unwrap();
|
let light = &self.lights[idx.0 as usize];
|
||||||
let ray = Ray::new(w.ray_o, w.ray_d, None, Ptr::null());
|
let ray = Ray::new(w.ray_o, w.ray_d, None, Ptr::null());
|
||||||
let le = light.le(&ray, &w.lambda);
|
let le = light.le(&ray, &w.lambda);
|
||||||
if le.is_black() {
|
if le.is_black() {
|
||||||
|
|
@ -311,7 +323,7 @@ impl CpuWavefrontRenderer {
|
||||||
} else {
|
} else {
|
||||||
// Compute MIS-weighted radiance contribution from infinite light
|
// Compute MIS-weighted radiance contribution from infinite light
|
||||||
let ctx = w.prev_intr_ctx;
|
let ctx = w.prev_intr_ctx;
|
||||||
let light_choice_pdf = light_sampler.pmf_with_context(&ctx, light);
|
let light_choice_pdf = light_sampler.pmf_with_context(&ctx, *idx);
|
||||||
let r_l = w.r_l * light_choice_pdf * light.pdf_li(&ctx, w.ray_d, true);
|
let r_l = w.r_l * light_choice_pdf * light.pdf_li(&ctx, w.ray_d, true);
|
||||||
l_contrib += w.beta * le / (w.r_u + r_l).average();
|
l_contrib += w.beta * le / (w.r_u + r_l).average();
|
||||||
}
|
}
|
||||||
|
|
@ -333,9 +345,12 @@ impl CpuWavefrontRenderer {
|
||||||
let hit_area_light_queue = &self.hit_area_light_queue;
|
let hit_area_light_queue = &self.hit_area_light_queue;
|
||||||
|
|
||||||
(0..n as usize).into_par_iter().for_each(|i| {
|
(0..n as usize).into_par_iter().for_each(|i| {
|
||||||
let w = unsafe { hit_area_light_queue.storage.get(i) };
|
let w = unsafe { hit_area_light_queue.get(i) };
|
||||||
|
if w.area_light.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let light = &self.lights[w.area_light.0 as usize];
|
||||||
|
|
||||||
let light = w.area_light.get().unwrap();
|
|
||||||
let le = light.l(w.p, w.n, w.uv, w.wo, &w.lambda);
|
let le = light.l(w.p, w.n, w.uv, w.wo, &w.lambda);
|
||||||
if le.is_black() {
|
if le.is_black() {
|
||||||
return;
|
return;
|
||||||
|
|
@ -346,7 +361,7 @@ impl CpuWavefrontRenderer {
|
||||||
} else {
|
} else {
|
||||||
let wi = -w.wo;
|
let wi = -w.wo;
|
||||||
let ctx = w.prev_intr_ctx;
|
let ctx = w.prev_intr_ctx;
|
||||||
let light_choice_pdf = light_sampler.pmf_with_context(&ctx, light);
|
let light_choice_pdf = light_sampler.pmf_with_context(&ctx, w.area_light);
|
||||||
// wi from previous interaction to this light hit
|
// wi from previous interaction to this light hit
|
||||||
let light_pdf = light_choice_pdf * light.pdf_li(&ctx, wi, true);
|
let light_pdf = light_choice_pdf * light.pdf_li(&ctx, wi, true);
|
||||||
let r_u = w.r_u;
|
let r_u = w.r_u;
|
||||||
|
|
@ -389,13 +404,13 @@ impl CpuWavefrontRenderer {
|
||||||
|
|
||||||
(0..n as usize).into_par_iter().for_each(|i| {
|
(0..n as usize).into_par_iter().for_each(|i| {
|
||||||
let w = unsafe { queue.storage.get(i) };
|
let w = unsafe { queue.storage.get(i) };
|
||||||
|
if w.material.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let material = &self.materials[w.material.0 as usize];
|
||||||
|
|
||||||
let pi = w.pixel_index as usize;
|
let pi = w.pixel_index as usize;
|
||||||
let rs = pixel_sample_state.samples.get(pi);
|
let rs = pixel_sample_state.samples.get(pi);
|
||||||
|
|
||||||
let Some(material) = w.material.get() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let _is_cond = material.is_conductor();
|
let _is_cond = material.is_conductor();
|
||||||
|
|
||||||
// GetMaterialEvalContext
|
// GetMaterialEvalContext
|
||||||
|
|
@ -516,12 +531,9 @@ impl CpuWavefrontRenderer {
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let light = &self.lights[sampled_light.light.0 as usize];
|
||||||
|
|
||||||
let Some(ls) =
|
let Some(ls) = light.sample_li(&light_ctx, rs.direct.u, &lambda, true) else {
|
||||||
sampled_light
|
|
||||||
.light
|
|
||||||
.sample_li(&light_ctx, rs.direct.u, &lambda, true)
|
|
||||||
else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -540,7 +552,7 @@ impl CpuWavefrontRenderer {
|
||||||
|
|
||||||
let beta = w.beta * f * wi.abs_dot(ns.into());
|
let beta = w.beta * f * wi.abs_dot(ns.into());
|
||||||
let light_pdf = ls.pdf * sampled_light.p;
|
let light_pdf = ls.pdf * sampled_light.p;
|
||||||
let bsdf_pdf = if sampled_light.light.light_type().is_delta_light() {
|
let bsdf_pdf = if light.light_type().is_delta_light() {
|
||||||
0.0
|
0.0
|
||||||
} else {
|
} else {
|
||||||
bsdf.pdf(wo, wi, FArgs::default())
|
bsdf.pdf(wo, wi, FArgs::default())
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue