Continuing refactoring, deleted camera construction on host side

This commit is contained in:
Wito Wiala 2026-05-19 01:44:38 +01:00
parent 31106696bd
commit 5b4928e1aa
29 changed files with 393 additions and 574 deletions

View file

@ -45,6 +45,74 @@ pub struct RealisticCamera {
} }
impl RealisticCamera { impl RealisticCamera {
pub fn new(
base: CameraBase,
lens_params: &[Float],
focus_distance: Float,
set_aperture_diameter: Float,
aperture_image: Ptr<Image>,
) -> Self {
let film_ptr = base.film;
if film_ptr.is_null() {
panic!("Camera must have a film");
}
let film = &*film_ptr;
let aspect = film.full_resolution().x() as Float / film.full_resolution().y() as Float;
let diagonal = film.diagonal();
let x = (square(diagonal) / (1.0 + square(diagonal))).sqrt();
let y = x * aspect;
let physical_extent =
Bounds2f::from_points(Point2f::new(-x / 2., -y / 2.), Point2f::new(x / 2., y / 2.));
let mut element_interfaces: GVec<LensElementInterface> = gvec();
for i in (0..lens_params.len()).step_by(4) {
let curvature_radius = lens_params[i] / 1000.0;
let thickness = lens_params[i + 1] / 1000.0;
let eta = lens_params[i + 2];
let mut aperture_diameter = lens_params[i + 3] / 1000.0;
if curvature_radius == 0.0 {
aperture_diameter /= 1000.0;
if set_aperture_diameter > aperture_diameter {
println!("Aperture is larger than possible")
} else {
aperture_diameter = set_aperture_diameter;
}
}
let el_int = LensElementInterface {
curvature_radius,
thickness,
eta,
aperture_radius: aperture_diameter / 2.0,
};
element_interfaces.push(el_int);
}
let half_diag = film.diagonal() / 2.0;
let mut exit_pupil_bounds = [Bounds2f::default(); EXIT_PUPIL_SAMPLES];
for i in 0..EXIT_PUPIL_SAMPLES {
let r0 = (i as Float / EXIT_PUPIL_SAMPLES as Float) * half_diag;
let r1 = ((i + 1) as Float / EXIT_PUPIL_SAMPLES as Float) * half_diag;
exit_pupil_bounds[i] =
RealisticCamera::compute_exit_pupil_bounds(&element_interfaces, r0, r1);
}
let n_elements = element_interfaces.len();
RealisticCamera {
base,
focus_distance,
element_interfaces,
n_elements,
physical_extent,
set_aperture_diameter,
aperture_image,
exit_pupil_bounds,
}
}
pub fn compute_cardinal_points(r_in: Ray, r_out: Ray) -> (Float, Float) { pub fn compute_cardinal_points(r_in: Ray, r_out: Ray) -> (Float, Float) {
let tf = -r_out.o.x() / r_out.d.x(); let tf = -r_out.o.x() / r_out.d.x();
let tp = (r_in.o.x() - r_out.o.x()) / r_out.d.x(); let tp = (r_in.o.x() - r_out.o.x()) / r_out.d.x();

View file

@ -17,7 +17,7 @@ use crate::utils::math::{wrap_equal_area_square, SquareMatrix};
use crate::utils::sampling::VarianceEstimator; use crate::utils::sampling::VarianceEstimator;
use crate::utils::transform::AnimatedTransform; use crate::utils::transform::AnimatedTransform;
use crate::utils::{gpu_array_from_fn, AtomicFloat}; use crate::utils::{gpu_array_from_fn, AtomicFloat};
use crate::{Array2D, Float, Ptr}; use crate::{gvec_with_capacity, Array2D, Float, Ptr};
use num_traits::Float as NumFloat; use num_traits::Float as NumFloat;
#[repr(C)] #[repr(C)]
@ -50,6 +50,43 @@ impl Default for RGBPixel {
} }
impl RGBFilm { impl RGBFilm {
pub fn new(
base: FilmBase,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
let sensor_ptr = base.sensor;
// TODO: This wont work on gpu, need to add check on host side
if sensor_ptr.is_null() {
panic!("Film must have a sensor");
}
let sensor = &*sensor_ptr;
let filter_integral = base.filter.integral();
let sensor_matrix = sensor.xyz_from_sensor_rgb;
let output_rgbf_from_sensor_rgb = colorspace.rgb_from_xyz * sensor_matrix;
let width = base.pixel_bounds.p_max.x() - base.pixel_bounds.p_min.x();
let height = base.pixel_bounds.p_max.y() - base.pixel_bounds.p_min.y();
let count = (width * height) as usize;
let mut pixel_vec = gvec_with_capacity(count);
for _ in 0..count {
pixel_vec.push(RGBPixel::default());
}
let pixels: Array2D<RGBPixel> = Array2D::new(base.pixel_bounds);
RGBFilm {
base,
max_component_value,
write_fp16,
filter_integral,
output_rgbf_from_sensor_rgb,
pixels,
};
}
pub fn base(&self) -> &FilmBase { pub fn base(&self) -> &FilmBase {
&self.base &self.base
} }
@ -214,6 +251,37 @@ pub struct GBufferFilm {
} }
impl GBufferFilm { impl GBufferFilm {
pub fn new(
base: &FilmBase,
output_from_render: &AnimatedTransform,
apply_inverse: bool,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
assert!(!base.pixel_bounds.is_empty());
let sensor_ptr = base.sensor;
if sensor_ptr.is_null() {
panic!("Film must have a sensor");
}
let sensor = &*sensor_ptr;
let output_rgbf_from_sensor_rgb = colorspace.rgb_from_xyz * sensor.xyz_from_sensor_rgb;
let filter_integral = base.filter.integral();
let pixels = Array2D::new(base.pixel_bounds);
GBufferFilm {
base: base.clone(),
output_from_render: *output_from_render,
apply_inverse,
pixels,
colorspace: colorspace.clone(),
max_component_value,
write_fp16,
filter_integral,
output_rgbf_from_sensor_rgb,
}
}
pub fn base(&self) -> &FilmBase { pub fn base(&self) -> &FilmBase {
&self.base &self.base
} }
@ -351,24 +419,73 @@ impl Default for SpectralPixel {
#[cfg_attr(target_os = "cuda", derive(Copy, Clone))] #[cfg_attr(target_os = "cuda", derive(Copy, Clone))]
pub struct SpectralFilm { pub struct SpectralFilm {
pub base: FilmBase, pub base: FilmBase,
pub colorspace: RGBColorSpace,
pub lambda_min: Float, pub lambda_min: Float,
pub lambda_max: Float, pub lambda_max: Float,
pub n_buckets: usize, pub n_buckets: usize,
pub max_component_value: Float, pub max_component_value: Float,
pub write_fp16: bool, pub write_fp16: bool,
pub filter_integral: Float, pub filter_integral: Float,
pub colorspace: RGBColorSpace,
pub pixels: Array2D<SpectralPixel>, pub pixels: Array2D<SpectralPixel>,
pub output_rgbf_from_sensor_rgb: SquareMatrix<Float, 3>, pub output_rgbf_from_sensor_rgb: SquareMatrix<Float, 3>,
pub bucket_sums: *mut f64, pub bucket_sums: GVec<f64>,
pub weight_sums: *mut f64, pub weight_sums: GVec<f64>,
pub bucket_splats: *mut AtomicFloat, pub bucket_splats: GVec<AtomicFloat>,
} }
unsafe impl Send for SpectralFilm {} unsafe impl Send for SpectralFilm {}
unsafe impl Sync for SpectralFilm {} unsafe impl Sync for SpectralFilm {}
impl SpectralFilm { impl SpectralFilm {
pub fn new(
base: &FilmBase,
lambda_min: Float,
lambda_max: Float,
n_buckets: usize,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
let n_pixels = base.pixel_bounds.area() as usize;
let total_buckets = n_pixels * n_buckets;
let bucket_sums = gvec_with_capacity(total_buckets);
let weight_sums = gvec_with_capacity(total_buckets);
let mut bucket_splats = gvec_with_capacity(total_buckets);
for _ in 0..total_buckets {
bucket_splats.push(AtomicFloat::new(0.0));
}
let mut pixels = Array2D::<SpectralPixel>::new(base.pixel_bounds);
for i in 0..n_pixels {
let pixel = pixels.get_linear_mut(i);
pixel.bucket_offset = i * n_buckets;
}
SpectralFilm {
base,
colorspace: colorspace.clone(),
lambda_min,
lambda_max,
n_buckets,
max_component_value,
write_fp16,
filter_integral: base.filter.integral(),
output_rgbf_from_sensor_rgb: SquareMatrix::identity(),
pixels: Array2D {
values: pixels.values.as_mut_ptr(),
extent: base.pixel_bounds,
},
bucket_sums,
weight_sums,
bucket_splats,
}
}
pub fn base(&self) -> &FilmBase { pub fn base(&self) -> &FilmBase {
&self.base &self.base
} }

View file

@ -2,7 +2,7 @@ use crate::core::geometry::{Bounds2f, Bounds2i, Point2f, Point2i, Vector2f};
use crate::filters::*; use crate::filters::*;
use crate::utils::math::{gaussian, gaussian_integral, lerp, sample_tent, windowed_sinc}; use crate::utils::math::{gaussian, gaussian_integral, lerp, sample_tent, windowed_sinc};
use crate::utils::sampling::PiecewiseConstant2D; use crate::utils::sampling::PiecewiseConstant2D;
use crate::{DeviceArray2D, Float}; use crate::{Array2D, Float};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
pub struct FilterSample { pub struct FilterSample {

View file

@ -1,6 +1,5 @@
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::containers::DeviceArray2D;
use crate::utils::math::{f16_to_f32_software, lerp, square}; use crate::utils::math::{f16_to_f32_software, lerp, square};
use crate::Float; use crate::Float;
use crate::GVec; use crate::GVec;

View file

@ -1,19 +1,18 @@
use enum_dispatch::enum_dispatch;
use crate::core::geometry::{ use crate::core::geometry::{
Bounds3f, Frame, Point2f, Point3f, Point3i, Ray, Vector3f, VectorLike, spherical_direction, spherical_direction, Bounds3f, Frame, Point2f, Point3f, Point3i, Ray, Vector3f, VectorLike,
}; };
use crate::core::pbrt::{Float, INV_4_PI, PI}; use crate::core::pbrt::{Float, INV_4_PI, PI};
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::spectra::{ use crate::spectra::{
BlackbodySpectrum, DenselySampledSpectrum, LAMBDA_MAX, LAMBDA_MIN, RGBIlluminantSpectrum, BlackbodySpectrum, DenselySampledSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum,
RGBUnboundedSpectrum, SampledSpectrum, SampledWavelengths, SampledSpectrum, SampledWavelengths, LAMBDA_MAX, LAMBDA_MIN,
}; };
use crate::utils::containers::SampledGrid; use crate::utils::containers::SampledGrid;
use crate::utils::math::{clamp, square}; use crate::utils::math::{clamp, square};
use crate::utils::ptr::Ptr;
use crate::utils::rng::Rng; use crate::utils::rng::Rng;
use crate::utils::transform::Transform; use crate::utils::transform::Transform;
use crate::{gvec_with_capacity, GVec, Ptr};
use enum_dispatch::enum_dispatch;
use num_traits::Float as NumFloat; use num_traits::Float as NumFloat;
#[repr(C)] #[repr(C)]
@ -90,11 +89,11 @@ impl PhaseFunctionTrait for HGPhaseFunction {
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
pub struct MajorantGrid { pub struct MajorantGrid {
pub bounds: Bounds3f, pub bounds: Bounds3f,
pub res: Point3i, pub res: Point3i,
pub voxels: *mut Float, pub voxels: GVec<Float>,
pub n_voxels: u32, pub n_voxels: u32,
} }
@ -102,21 +101,21 @@ unsafe impl Send for MajorantGrid {}
unsafe impl Sync for MajorantGrid {} unsafe impl Sync for MajorantGrid {}
impl MajorantGrid { impl MajorantGrid {
// #[cfg(not(target_os = "cuda"))] #[cfg(not(target_os = "cuda"))]
// pub fn new(bounds: Bounds3f, res: Point3i) -> Self { pub fn new(bounds: Bounds3f, res: Point3i) -> Self {
// let n_voxels = (res.x() * res.y() * res.z()) as usize; let n_voxels = (res.x() * res.y() * res.z()) as usize;
// let voxels = Vec::with_capacity(n_voxels); let voxels = gvec_with_capacity(n_voxels);
// Self { Self {
// bounds, bounds,
// res, res,
// voxels: voxels.as_ptr(), voxels,
// n_voxels: n_voxels as u32, n_voxels: n_voxels as u32,
// } }
// } }
//
#[inline(always)] #[inline(always)]
fn is_valid(&self) -> bool { fn is_valid(&self) -> bool {
!self.voxels.is_null() !self.voxels.is_empty()
} }
#[inline(always)] #[inline(always)]
@ -128,7 +127,7 @@ impl MajorantGrid {
let idx = z * self.res.x() * self.res.y() + y * self.res.x() + x; let idx = z * self.res.x() * self.res.y() + y * self.res.x() + x;
if idx >= 0 && (idx as u32) < self.n_voxels { if idx >= 0 && (idx as u32) < self.n_voxels {
unsafe { *self.voxels.add(idx as usize) } unsafe { *self.voxels.as_ptr().add(idx as usize) }
} else { } else {
0.0 0.0
} }
@ -143,7 +142,7 @@ impl MajorantGrid {
let idx = x + self.res.x() * (y + self.res.y() * z); let idx = x + self.res.x() * (y + self.res.y() * z);
unsafe { unsafe {
*self.voxels.add(idx as usize) = v; *self.voxels.as_ptr().add(idx as usize) = v;
} }
} }

View file

@ -5,7 +5,7 @@ use crate::utils::math::{
clamp, encode_morton_2, inverse_radical_inverse, lerp, log2_int, clamp, encode_morton_2, inverse_radical_inverse, lerp, log2_int,
owen_scrambled_radical_inverse, permutation_element, radical_inverse, round_up_pow2, owen_scrambled_radical_inverse, permutation_element, radical_inverse, round_up_pow2,
scrambled_radical_inverse, sobol_interval_to_index, sobol_sample, BinaryPermuteScrambler, scrambled_radical_inverse, sobol_interval_to_index, sobol_sample, BinaryPermuteScrambler,
DeviceDigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler, Scrambler, DigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler, Scrambler,
PRIME_TABLE_SIZE, PRIME_TABLE_SIZE,
}; };
use crate::utils::rng::Rng; use crate::utils::rng::Rng;
@ -100,7 +100,7 @@ pub struct HaltonSampler {
pub mult_inverse: [u64; 2], pub mult_inverse: [u64; 2],
pub halton_index: u64, pub halton_index: u64,
pub dim: u32, pub dim: u32,
pub digit_permutations: GVec<DeviceDigitPermutation>, pub digit_permutations: GVec<DigitPermutation>,
} }
#[allow(clippy::derivable_impls)] #[allow(clippy::derivable_impls)]

View file

@ -20,6 +20,22 @@ pub struct DistantLight {
} }
impl DistantLight { impl DistantLight {
pub fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self {
let base = LightBase::new(
LightType::DeltaDirection,
render_from_light,
MediumInterface::empty(),
);
let lemit = lookup_spectrum(&le);
Self {
base,
lemit: Ptr::from(&lemit.device()),
scale,
scene_center: Point3f::default(),
scene_radius: 0.,
}
}
pub fn sample_li_base( pub fn sample_li_base(
&self, &self,
ctx_p: Point3f, ctx_p: Point3f,

View file

@ -15,8 +15,8 @@ use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths
use crate::spectra::{RGBColorSpace, RGBIlluminantSpectrum}; use crate::spectra::{RGBColorSpace, RGBIlluminantSpectrum};
use crate::utils::math::{clamp, equal_area_sphere_to_square, equal_area_square_to_sphere, square}; use crate::utils::math::{clamp, equal_area_sphere_to_square, equal_area_square_to_sphere, square};
use crate::utils::sampling::{ use crate::utils::sampling::{
AliasTable, DevicePiecewiseConstant2D, WindowedPiecewiseConstant2D, sample_uniform_sphere, uniform_sphere_pdf, AliasTable, DevicePiecewiseConstant2D,
sample_uniform_sphere, uniform_sphere_pdf, WindowedPiecewiseConstant2D,
}; };
use crate::utils::{Ptr, Transform}; use crate::utils::{Ptr, Transform};
use crate::{Float, PI}; use crate::{Float, PI};
@ -35,6 +35,27 @@ pub struct UniformInfiniteLight {
unsafe impl Send for UniformInfiniteLight {} unsafe impl Send for UniformInfiniteLight {}
unsafe impl Sync for UniformInfiniteLight {} unsafe impl Sync for UniformInfiniteLight {}
impl UniformInfiniteLight {
pub fn new(
render_from_light: Transform,
scale: Float,
lemit: Ptr<DenselySampledSpectrum>,
) -> Self {
let base = LightBase::new(
LightType::Infinite,
render_from_light,
MediumInterface::default(),
);
Self {
base,
lemit,
scale,
scene_center: Point3f::default(),
scene_radius: 0.0,
}
}
}
impl LightTrait for UniformInfiniteLight { impl LightTrait for UniformInfiniteLight {
fn base(&self) -> &LightBase { fn base(&self) -> &LightBase {
&self.base &self.base
@ -116,8 +137,8 @@ pub struct ImageInfiniteLight {
pub base: LightBase, pub base: LightBase,
pub image: Ptr<Image>, pub image: Ptr<Image>,
pub image_color_space: Ptr<RGBColorSpace>, pub image_color_space: Ptr<RGBColorSpace>,
pub distrib: Ptr<DevicePiecewiseConstant2D>, pub distrib: Ptr<PiecewiseConstant2D>,
pub compensated_distrib: Ptr<DevicePiecewiseConstant2D>, pub compensated_distrib: Ptr<PiecewiseConstant2D>,
pub scale: Float, pub scale: Float,
pub scene_radius: Float, pub scene_radius: Float,
pub scene_center: Point3f, pub scene_center: Point3f,
@ -127,14 +148,35 @@ unsafe impl Send for ImageInfiniteLight {}
unsafe impl Sync for ImageInfiniteLight {} unsafe impl Sync for ImageInfiniteLight {}
impl ImageInfiniteLight { impl ImageInfiniteLight {
pub fn new(
render_from_light: Transform,
scale: Float,
image: Ptr<HostImage>,
image_color_space: Ptr<RGBColorSpace>,
distrib: Ptr<PiecewiseConstant2D>,
compensated_distrib: Ptr<PiecewiseConstant2D>,
) -> Self {
let base = LightBase::new(
LightType::Infinite,
render_from_light,
MediumInterface::default(),
);
Self {
base,
image,
image_color_space,
scale,
distrib,
compensated_distrib,
scene_center: Point3f::default(),
scene_radius: 0.0,
}
}
fn image_le(&self, uv: Point2f, lambda: &SampledWavelengths) -> SampledSpectrum { fn image_le(&self, uv: Point2f, lambda: &SampledWavelengths) -> SampledSpectrum {
let mut rgb = RGB::default(); let mut rgb = RGB::default();
for c in 0..3 { for c in 0..3 {
rgb[c] = self.image.lookup_nearest_channel_with_wrap( rgb[c] = self.image.get_ch(uv, c, WrapMode::OctahedralSphere.into());
uv,
c,
WrapMode::OctahedralSphere.into(),
);
} }
let spec = RGBIlluminantSpectrum::new(&self.image_color_space, rgb.clamp_zero()); let spec = RGBIlluminantSpectrum::new(&self.image_color_space, rgb.clamp_zero());
self.scale * spec.sample(lambda) self.scale * spec.sample(lambda)
@ -261,6 +303,33 @@ pub struct PortalInfiniteLight {
} }
impl PortalInfiniteLight { impl PortalInfiniteLight {
pub fn new(
render_from_light: Transform,
scale: Float,
image: Ptr<HostImage>,
image_color_space: Ptr<RGBColorSpace>,
portal: [Point3f; 4],
portal_frame: Frame,
distribution: Ptr<WindowedPiecewiseConstant2D>,
) -> Self {
let base = LightBase::new(
LightType::Infinite,
render_from_light,
MediumInterface::default(),
);
Self {
base,
image,
image_color_space,
scale,
portal,
portal_frame,
distribution: *distribution,
scene_center: Point3f::default(),
scene_radius: 0.0,
}
}
pub fn image_lookup(&self, uv: Point2f, lambda: &SampledWavelengths) -> SampledSpectrum { pub fn image_lookup(&self, uv: Point2f, lambda: &SampledWavelengths) -> SampledSpectrum {
let mut rgb = RGB::default(); let mut rgb = RGB::default();
for c in 0..3 { for c in 0..3 {

View file

@ -7,8 +7,7 @@ use crate::core::light::{
}; };
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::{Float, PI, Ptr, Transform};
use crate::{Float, PI};
use num_traits::Float as NumFloat; use num_traits::Float as NumFloat;
#[repr(C)] #[repr(C)]
@ -19,6 +18,25 @@ pub struct PointLight {
pub i: Ptr<DenselySampledSpectrum>, pub i: Ptr<DenselySampledSpectrum>,
} }
impl PointLight {
pub fn new(
render_from_light: Transform,
medium_interface: MediumInterface,
le: Spectrum,
scale: Float,
) -> Self {
let base = LightBase::new(
LightType::DeltaPosition,
render_from_light,
medium_interface,
);
let iemit = lookup_spectrum(&le);
let i = Ptr::from(&iemit.device());
Self { base, scale, i }
}
}
impl LightTrait for PointLight { impl LightTrait for PointLight {
fn base(&self) -> &LightBase { fn base(&self) -> &LightBase {
&self.base &self.base

View file

@ -198,12 +198,12 @@ pub enum LightSampler {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct UniformLightSampler { pub struct UniformLightSampler {
lights: *const Light, lights: Ptr<Light>,
lights_len: u32, lights_len: u32,
} }
impl UniformLightSampler { impl UniformLightSampler {
pub fn new(lights: *const Light, lights_len: u32) -> Self { pub fn new(lights: Ptr<Light>, lights_len: u32) -> Self {
Self { lights, lights_len } Self { lights, lights_len }
} }

View file

@ -5,8 +5,7 @@ use crate::core::interaction::{Interaction, InteractionBase, InteractionTrait, S
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::{Float, PI, Ptr, Transform};
use crate::{Float, PI};
use num_traits::Float as NumFloat; use num_traits::Float as NumFloat;
#[repr(C)] #[repr(C)]
@ -20,6 +19,31 @@ pub struct SpotLight {
} }
impl SpotLight { impl SpotLight {
pub fn new(
render_from_light: Transform,
_medium_interface: MediumInterface,
le: Spectrum,
scale: shared::Float,
cos_falloff_start: Float,
total_width: Float,
) -> Self {
let base = LightBase::new(
LightType::DeltaPosition,
render_from_light,
MediumInterface::empty(),
);
let i = lookup_spectrum(&le);
let iemit = Ptr::from(&i.device());
Self {
base,
iemit,
scale,
cos_falloff_end: radians(total_width).cos(),
cos_falloff_start: radians(cos_falloff_start).cos(),
}
}
pub fn i(&self, w: Vector3f, lambda: &SampledWavelengths) -> SampledSpectrum { pub fn i(&self, w: Vector3f, lambda: &SampledWavelengths) -> SampledSpectrum {
let cos_theta = w.z(); // assuming normalized in light space let cos_theta = w.z(); // assuming normalized in light space
let falloff = crate::utils::math::smooth_step( let falloff = crate::utils::math::smooth_step(

View file

@ -821,7 +821,7 @@ impl DigitPermutation {
pub fn scrambled_radical_inverse( pub fn scrambled_radical_inverse(
base_index: u32, base_index: u32,
mut a: u64, mut a: u64,
perm: &DeviceDigitPermutation, perm: &DigitPermutation,
) -> Float { ) -> Float {
let base = PRIMES[base_index as usize] as u64; let base = PRIMES[base_index as usize] as u64;

View file

@ -1,3 +0,0 @@
pub mod perspective;
pub mod realistic;
pub mod spherical;

View file

@ -1 +0,0 @@

View file

@ -1,100 +0,0 @@
use crate::core::image::Image;
use shared::cameras::{EXIT_PUPIL_SAMPLES, LensElementInterface, RealisticCamera};
use shared::core::camera::CameraBase;
use shared::core::geometry::{Bounds2f, Point2f};
use shared::utils::math::square;
use shared::{Float, Ptr};
use std::sync::Arc;
#[derive(Clone)]
struct RealisticCameraData {
aperture_image: Arc<Image>,
element_interfaces: Vec<LensElementInterface>,
}
#[derive(Clone)]
pub struct RealisticCameraHost {
device: RealisticCamera,
data: RealisticCameraData,
}
impl RealisticCameraHost {
pub fn device(&self) -> RealisticCamera {
self.device
}
pub fn new(
base: CameraBase,
lens_params: &[Float],
focus_distance: Float,
set_aperture_diameter: Float,
aperture_image: Arc<Image>,
) -> Self {
let film_ptr = base.film;
if film_ptr.is_null() {
panic!("Camera must have a film");
}
let film = &*film_ptr;
let aspect = film.full_resolution().x() as Float / film.full_resolution().y() as Float;
let diagonal = film.diagonal();
let x = (square(diagonal) / (1.0 + square(diagonal))).sqrt();
let y = x * aspect;
let physical_extent =
Bounds2f::from_points(Point2f::new(-x / 2., -y / 2.), Point2f::new(x / 2., y / 2.));
let mut element_interfaces: Vec<LensElementInterface> = Vec::new();
for i in (0..lens_params.len()).step_by(4) {
let curvature_radius = lens_params[i] / 1000.0;
let thickness = lens_params[i + 1] / 1000.0;
let eta = lens_params[i + 2];
let mut aperture_diameter = lens_params[i + 3] / 1000.0;
if curvature_radius == 0.0 {
aperture_diameter /= 1000.0;
if set_aperture_diameter > aperture_diameter {
println!("Aperture is larger than possible")
} else {
aperture_diameter = set_aperture_diameter;
}
}
let el_int = LensElementInterface {
curvature_radius,
thickness,
eta,
aperture_radius: aperture_diameter / 2.0,
};
element_interfaces.push(el_int);
}
let half_diag = film.diagonal() / 2.0;
let mut exit_pupil_bounds = [Bounds2f::default(); EXIT_PUPIL_SAMPLES];
for i in 0..EXIT_PUPIL_SAMPLES {
let r0 = (i as Float / EXIT_PUPIL_SAMPLES as Float) * half_diag;
let r1 = ((i + 1) as Float / EXIT_PUPIL_SAMPLES as Float) * half_diag;
exit_pupil_bounds[i] =
RealisticCamera::compute_exit_pupil_bounds(&element_interfaces, r0, r1);
}
let n_elements = element_interfaces.len();
let data = RealisticCameraData {
element_interfaces: element_interfaces.clone(),
aperture_image: aperture_image.clone(),
};
let device = RealisticCamera {
base,
focus_distance,
element_interfaces: Ptr::from(element_interfaces.as_ptr()),
n_elements,
physical_extent,
set_aperture_diameter,
aperture_image: Ptr::from(aperture_image.device()),
exit_pupil_bounds,
};
Self { device, data }
}
}

View file

@ -1 +0,0 @@

View file

@ -1,9 +1,8 @@
use crate::cameras::realistic::RealisticCameraHost;
use crate::core::image::ImageMetadata; use crate::core::image::ImageMetadata;
use crate::core::image::{Image, ImageIO}; use crate::core::image::{Image, ImageIO};
use crate::globals::get_options; use crate::globals::get_options;
use crate::utils::read_float_file; use crate::utils::read_float_file;
use crate::utils::{Arena, FileLoc, ParameterDictionary}; use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use shared::cameras::*; use shared::cameras::*;
use shared::core::camera::{Camera, CameraBase, CameraTrait, CameraTransform}; use shared::core::camera::{Camera, CameraBase, CameraTrait, CameraTransform};
@ -13,8 +12,7 @@ use shared::core::geometry::{Bounds2f, Point2f, Point2i, Vector2f, Vector3f};
use shared::core::image::PixelFormat; use shared::core::image::PixelFormat;
use shared::core::medium::Medium; use shared::core::medium::Medium;
use shared::utils::math::square; use shared::utils::math::square;
use shared::Ptr; use shared::{Float, Ptr, PI};
use shared::{Float, PI};
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
@ -380,16 +378,16 @@ impl CameraFactory for Camera {
} }
} }
let camera = RealisticCameraHost::new( let camera = RealisticCamera::new(
base, base,
&lens_params, &lens_params,
focal_distance, focal_distance,
aperture_diameter, aperture_diameter,
Arc::from(aperture_image.unwrap()), Ptr::from(&*aperture_image.unwrap()),
); );
arena.alloc(camera); arena.alloc(camera);
Ok(Camera::Realistic(camera.device())) Ok(Camera::Realistic(camera))
} }
"spherical" => { "spherical" => {
let _full_res = film.full_resolution(); let _full_res = film.full_resolution();

View file

@ -2,30 +2,8 @@ use shared::core::geometry::{Bounds3f, Point3i};
use shared::core::medium::{GridMedium, HGPhaseFunction, HomogeneousMedium, RGBGridMedium}; use shared::core::medium::{GridMedium, HGPhaseFunction, HomogeneousMedium, RGBGridMedium};
use shared::core::spectrum::{Spectrum, SpectrumTrait}; use shared::core::spectrum::{Spectrum, SpectrumTrait};
use shared::spectra::{RGBIlluminantSpectrum, RGBUnboundedSpectrum, DenselySampledSpectrum}; use shared::spectra::{RGBIlluminantSpectrum, RGBUnboundedSpectrum, DenselySampledSpectrum};
use shared::utils::Transform;
use shared::utils::containers::SampledGrid; use shared::utils::containers::SampledGrid;
use shared::{Float, core::medium::MajorantGrid}; use shared::{Float, Transform, core::medium::MajorantGrid};
pub struct MajorantGridHost {
pub device: MajorantGrid,
voxels: Vec<Float>,
}
impl MajorantGridHost {
pub fn new(bounds: Bounds3f, res: Point3i) -> Self {
let n = (res.x() * res.y() * res.z()) as usize;
let voxels = vec![0.0; n];
let device = MajorantGrid {
bounds,
res,
voxels: std::ptr::null_mut(),
n_voxels: n as u32,
};
Self { device, voxels }
}
}
pub trait RGBGridMediumCreator { pub trait RGBGridMediumCreator {
fn new( fn new(
@ -52,7 +30,7 @@ impl RGBGridMediumCreator for RGBGridMedium {
le_grid: SampledGrid<RGBIlluminantSpectrum>, le_grid: SampledGrid<RGBIlluminantSpectrum>,
le_scale: Float, le_scale: Float,
) -> Self { ) -> Self {
let mut majorant_grid = MajorantGridHost::new(*bounds, Point3i::new(16, 16, 16)).device; let mut majorant_grid = MajorantGrid::new(*bounds, Point3i::new(16, 16, 16));
for z in 0..majorant_grid.res.x() { for z in 0..majorant_grid.res.x() {
for y in 0..majorant_grid.res.y() { for y in 0..majorant_grid.res.y() {
for x in 0..majorant_grid.res.x() { for x in 0..majorant_grid.res.x() {
@ -116,7 +94,7 @@ impl GridMediumCreator for GridMedium {
let le_spec = DenselySampledSpectrum::from_spectrum(le); let le_spec = DenselySampledSpectrum::from_spectrum(le);
let mut majorant_grid = MajorantGridHost::new(*bounds, Point3i::new(16, 16, 16)).device; let mut majorant_grid = MajorantGrid::new(*bounds, Point3i::new(16, 16, 16)).device;
let is_emissive = if temperature_grid.is_some() { let is_emissive = if temperature_grid.is_some() {
true true
} else { } else {

View file

@ -12,7 +12,7 @@ use crate::core::texture::{FloatTexture, SpectrumTexture};
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::{Arena, DeviceRepr, FileLoc}; use crate::{Arena, FileLoc};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use parking_lot::Mutex; use parking_lot::Mutex;
use shared::core::camera::{Camera, CameraTransform}; use shared::core::camera::{Camera, CameraTransform};

View file

@ -8,44 +8,6 @@ use shared::spectra::RGBColorSpace;
use shared::utils::AnimatedTransform; use shared::utils::AnimatedTransform;
use std::path::Path; use std::path::Path;
pub struct GBufferFilmHost {
pub device: GBufferFilm,
}
impl GBufferFilmHost {
pub fn new(
base: &FilmBase,
output_from_render: &AnimatedTransform,
apply_inverse: bool,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
assert!(!base.pixel_bounds.is_empty());
let sensor_ptr = base.sensor;
if sensor_ptr.is_null() {
panic!("Film must have a sensor");
}
let sensor = &*sensor_ptr;
let output_rgbf_from_sensor_rgb = colorspace.rgb_from_xyz * sensor.xyz_from_sensor_rgb;
let filter_integral = base.filter.integral();
let pixels = Array2D::new(base.pixel_bounds);
let device = GBufferFilm {
base: base.clone(),
output_from_render: *output_from_render,
apply_inverse,
pixels,
colorspace: colorspace.clone(),
max_component_value,
write_fp16,
filter_integral,
output_rgbf_from_sensor_rgb,
};
Self { device }
}
}
impl CreateFilm for GBufferFilm { impl CreateFilm for GBufferFilm {
fn create( fn create(
@ -85,7 +47,7 @@ impl CreateFilm for GBufferFilm {
.into()); .into());
}; };
let film = GBufferFilmHost::new( let film = GBufferFilm::new(
&film_base, &film_base,
&output_from_render, &output_from_render,
apply_inverse, apply_inverse,
@ -94,6 +56,6 @@ impl CreateFilm for GBufferFilm {
write_fp16, write_fp16,
); );
Ok(Film::GBuffer(film.device)) Ok(Film::GBuffer(film))
} }
} }

View file

@ -8,58 +8,6 @@ use shared::core::film::{Film, FilmBase, RGBFilm, RGBPixel};
use shared::core::filter::FilterTrait; use shared::core::filter::FilterTrait;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
struct RGBFilmStorage {
pixels: Array2D<RGBPixel>,
}
pub struct RGBFilmHost {
pub device: RGBFilm,
storage: RGBFilmStorage,
}
impl RGBFilmHost {
pub fn new(
base: FilmBase,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
let sensor_ptr = base.sensor;
if sensor_ptr.is_null() {
panic!("Film must have a sensor");
}
let sensor = &*sensor_ptr;
let filter_integral = base.filter.integral();
let sensor_matrix = sensor.xyz_from_sensor_rgb;
let output_rgbf_from_sensor_rgb = colorspace.rgb_from_xyz * sensor_matrix;
let width = base.pixel_bounds.p_max.x() - base.pixel_bounds.p_min.x();
let height = base.pixel_bounds.p_max.y() - base.pixel_bounds.p_min.y();
let count = (width * height) as usize;
let mut pixel_vec = Vec::with_capacity(count);
for _ in 0..count {
pixel_vec.push(RGBPixel::default());
}
let pixels: Array2D<RGBPixel> = Array2D::new(base.pixel_bounds);
let device_pixels = pixels.device.clone();
let storage = RGBFilmStorage { pixels };
let device = RGBFilm {
base,
max_component_value,
write_fp16,
filter_integral,
output_rgbf_from_sensor_rgb,
pixels: device_pixels,
};
Self { device, storage }
}
}
impl CreateFilm for RGBFilm { impl CreateFilm for RGBFilm {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,
@ -74,7 +22,7 @@ impl CreateFilm for RGBFilm {
let write_fp16 = params.get_one_bool("savefp16", true)?; let write_fp16 = params.get_one_bool("savefp16", true)?;
let sensor = PixelSensor::create(params, colorspace.clone(), exposure_time, loc)?; let sensor = PixelSensor::create(params, colorspace.clone(), exposure_time, loc)?;
let film_base = FilmBase::create(params, filter, Some(&sensor.device()), loc)?; let film_base = FilmBase::create(params, filter, Some(&sensor.device()), loc)?;
let film = RGBFilmHost::new(film_base, &colorspace, max_component_value, write_fp16); let film = RGBFilm::new(film_base, &colorspace, max_component_value, write_fp16);
Ok(Film::RGB(film.device)) Ok(Film::RGB(film))
} }
} }

View file

@ -1,91 +1,15 @@
use super::*; use super::*;
use crate::core::film::{CreateFilmBase, PixelSensor}; use crate::core::film::{CreateFilmBase, PixelSensor};
use crate::utils::containers::Array2D;
use crate::{Arena, FileLoc, ParameterDictionary}; use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::{Result, anyhow}; use anyhow::{Result, anyhow};
use shared::Float; use shared::Float;
use shared::core::camera::CameraTransform; use shared::core::camera::CameraTransform;
use shared::core::film::{FilmBase, SpectralFilm, SpectralPixel}; use shared::core::film::{FilmBase, SpectralFilm};
use shared::core::filter::FilterTrait; use shared::core::filter::FilterTrait;
use shared::spectra::{LAMBDA_MAX, LAMBDA_MIN, RGBColorSpace}; use shared::spectra::{LAMBDA_MAX, LAMBDA_MIN};
use shared::utils::AtomicFloat;
use shared::utils::containers::Array2D;
use shared::utils::math::SquareMatrix; use shared::utils::math::SquareMatrix;
use std::path::Path; use std::path::Path;
use std::sync::Arc;
struct SpectralFilmStorage {
pixels: Array2D<SpectralPixel>,
bucket_sums: Vec<f64>,
weight_sums: Vec<f64>,
bucket_splats: Vec<AtomicFloat>,
}
pub struct SpectralFilmHost {
pub device: SpectralFilm,
storage: Arc<SpectralFilmStorage>,
}
impl SpectralFilmHost {
pub fn new(
base: &FilmBase,
lambda_min: Float,
lambda_max: Float,
n_buckets: usize,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
let n_pixels = base.pixel_bounds.area() as usize;
let total_buckets = n_pixels * n_buckets;
let bucket_sums = vec![0.0; total_buckets];
let weight_sums = vec![0.0; total_buckets];
let mut bucket_splats = Vec::with_capacity(total_buckets);
for _ in 0..total_buckets {
bucket_splats.push(AtomicFloat::new(0.0));
}
let mut pixels = Array2D::<SpectralPixel>::new(base.pixel_bounds);
for i in 0..n_pixels {
let pixel = pixels.get_linear_mut(i);
pixel.bucket_offset = i * n_buckets;
}
let storage = Arc::new(SpectralFilmStorage {
pixels: pixels.device,
bucket_sums,
weight_sums,
bucket_splats,
});
let device = SpectralFilm {
base: *base,
colorspace: colorspace.clone(),
lambda_min,
lambda_max,
n_buckets,
max_component_value,
write_fp16,
filter_integral: base.filter.integral(),
output_rgbf_from_sensor_rgb: SquareMatrix::identity(),
pixels: Array2D {
values: pixels.values.as_mut_ptr(),
extent: base.pixel_bounds,
stride: base.pixel_bounds.p_max.x() - base.pixel_bounds.p_min.x(),
},
bucket_sums: storage.bucket_sums.as_ptr() as *mut f64,
weight_sums: storage.weight_sums.as_ptr() as *mut f64,
bucket_splats: storage.bucket_splats.as_ptr() as *mut AtomicFloat,
};
Self { device, storage }
}
}
impl CreateFilm for SpectralFilm { impl CreateFilm for SpectralFilm {
fn create( fn create(
@ -96,6 +20,7 @@ impl CreateFilm for SpectralFilm {
loc: &FileLoc, loc: &FileLoc,
_arena: &Arena, _arena: &Arena,
) -> Result<Film> { ) -> Result<Film> {
// Missing default illuminant, use srgb
let colorspace = params.color_space.as_ref().unwrap(); let colorspace = params.color_space.as_ref().unwrap();
let max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY)?; let max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY)?;
let write_fp16 = params.get_one_bool("savefp16", true)?; let write_fp16 = params.get_one_bool("savefp16", true)?;
@ -117,7 +42,7 @@ impl CreateFilm for SpectralFilm {
)); ));
} }
let film = SpectralFilmHost::new( let film = SpectralFilm::new(
&film_base, &film_base,
lambda_min, lambda_min,
lambda_max, lambda_max,
@ -127,6 +52,6 @@ impl CreateFilm for SpectralFilm {
write_fp16, write_fp16,
); );
Ok(Film::Spectral(film.device)) Ok(Film::Spectral(film))
} }
} }

View file

@ -1,6 +1,5 @@
#![feature(f16)] #![feature(f16)]
#[allow(dead_code)] #[allow(dead_code)]
pub mod cameras;
pub mod core; pub mod core;
pub mod films; pub mod films;
pub mod filters; pub mod filters;

View file

@ -14,28 +14,6 @@ use shared::lights::DistantLight;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::{Ptr, Transform}; use shared::utils::{Ptr, Transform};
pub trait CreateDistantLight {
fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self;
}
impl CreateDistantLight for DistantLight {
fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self {
let base = LightBase::new(
LightType::DeltaDirection,
render_from_light,
MediumInterface::empty(),
);
let lemit = lookup_spectrum(&le);
Self {
base,
lemit: Ptr::from(&lemit.device()),
scale,
scene_center: Point3f::default(),
scene_radius: 0.,
}
}
}
pub fn create( pub fn create(
render_from_light: Transform, render_from_light: Transform,
_medium: Option<Medium>, _medium: Option<Medium>,

View file

@ -21,106 +21,6 @@ use shared::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
use shared::{Float, Ptr, Transform, PI}; use shared::{Float, Ptr, Transform, PI};
use std::path::Path; use std::path::Path;
pub trait CreateImageInfiniteLight {
fn new(
render_from_light: Transform,
scale: Float,
image: Ptr<HostImage>,
image_color_space: Ptr<RGBColorSpace>,
distrib: Ptr<PiecewiseConstant2D>,
compensated_distrib: Ptr<PiecewiseConstant2D>,
) -> Self;
}
impl CreateImageInfiniteLight for ImageInfiniteLight {
fn new(
render_from_light: Transform,
scale: Float,
image: Ptr<HostImage>,
image_color_space: Ptr<RGBColorSpace>,
distrib: Ptr<PiecewiseConstant2D>,
compensated_distrib: Ptr<PiecewiseConstant2D>,
) -> Self {
let base = LightBase::new(
LightType::Infinite,
render_from_light,
MediumInterface::default(),
);
Self {
base,
image,
image_color_space,
scale,
distrib,
compensated_distrib,
scene_center: Point3f::default(),
scene_radius: 0.0,
}
}
}
pub trait CreatePortalInfiniteLight {
fn new(
render_from_light: Transform,
scale: Float,
image: Ptr<HostImage>,
image_color_space: Ptr<RGBColorSpace>,
portal: [Point3f; 4],
portal_frame: Frame,
distribution: Ptr<WindowedPiecewiseConstant2D>,
) -> Self;
}
impl CreatePortalInfiniteLight for PortalInfiniteLight {
fn new(
render_from_light: Transform,
scale: Float,
image: Ptr<HostImage>,
image_color_space: Ptr<RGBColorSpace>,
portal: [Point3f; 4],
portal_frame: Frame,
distribution: Ptr<WindowedPiecewiseConstant2D>,
) -> Self {
let base = LightBase::new(
LightType::Infinite,
render_from_light,
MediumInterface::default(),
);
Self {
base,
image,
image_color_space,
scale,
portal,
portal_frame,
distribution: *distribution,
scene_center: Point3f::default(),
scene_radius: 0.0,
}
}
}
pub trait CreateUniformInfiniteLight {
fn new(render_from_light: Transform, scale: Float, lemit: Ptr<DenselySampledSpectrum>) -> Self;
}
impl CreateUniformInfiniteLight for UniformInfiniteLight {
fn new(render_from_light: Transform, scale: Float, lemit: Ptr<DenselySampledSpectrum>) -> Self {
let base = LightBase::new(
LightType::Infinite,
render_from_light,
MediumInterface::default(),
);
Self {
base,
lemit,
scale,
scene_center: Point3f::default(),
scene_radius: 0.0,
}
}
}
pub fn create( pub fn create(
render_from_light: Transform, render_from_light: Transform,
_medium: Option<Medium>, _medium: Option<Medium>,

View file

@ -6,10 +6,3 @@ pub mod point;
pub mod projection; pub mod projection;
pub mod sampler; pub mod sampler;
pub mod spot; pub mod spot;
pub use distant::CreateDistantLight;
pub use infinite::{
CreateImageInfiniteLight, CreatePortalInfiniteLight, CreateUniformInfiniteLight,
};
pub use point::CreatePointLight;
pub use spot::CreateSpotLight;

View file

@ -11,36 +11,8 @@ use shared::core::spectrum::Spectrum;
use shared::core::texture::SpectrumType; use shared::core::texture::SpectrumType;
use shared::lights::PointLight; use shared::lights::PointLight;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::{Ptr, Transform}; use shared::{Float, PI, Ptr, Transform};
use shared::{Float, PI};
pub trait CreatePointLight {
fn new(
render_from_light: Transform,
medium_interface: MediumInterface,
le: Spectrum,
scale: Float,
) -> Self;
}
impl CreatePointLight for PointLight {
fn new(
render_from_light: Transform,
medium_interface: MediumInterface,
le: Spectrum,
scale: Float,
) -> Self {
let base = LightBase::new(
LightType::DeltaPosition,
render_from_light,
medium_interface,
);
let iemit = lookup_spectrum(&le);
let i = Ptr::from(&iemit.device());
Self { base, scale, i }
}
}
pub fn create( pub fn create(
render_from_light: Transform, render_from_light: Transform,

View file

@ -1,7 +1,7 @@
use crate::utils::sampling::AliasTableHost;
use crate::Arena; use crate::Arena;
use shared::core::light::{Light, LightTrait}; use shared::core::light::{Light, LightTrait};
use shared::lights::sampler::PowerLightSampler; use shared::lights::sampler::PowerLightSampler;
use shared::utils::sampling::AliasTable;
use shared::spectra::{SampledSpectrum, SampledWavelengths}; use shared::spectra::{SampledSpectrum, SampledWavelengths};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
@ -9,7 +9,7 @@ use std::sync::Arc;
pub struct PowerSamplerHost { pub struct PowerSamplerHost {
pub lights: Vec<Arc<Light>>, pub lights: Vec<Arc<Light>>,
pub light_to_index: HashMap<usize, usize>, pub light_to_index: HashMap<usize, usize>,
pub alias_table: AliasTableHost, pub alias_table: AliasTable,
} }
impl PowerSamplerHost { impl PowerSamplerHost {
@ -18,7 +18,7 @@ impl PowerSamplerHost {
return Self { return Self {
lights: Vec::new(), lights: Vec::new(),
light_to_index: HashMap::new(), light_to_index: HashMap::new(),
alias_table: AliasTableHost::new(&[]), alias_table: AliasTable::new(&[]),
}; };
} }
@ -38,7 +38,7 @@ impl PowerSamplerHost {
light_power.push(phi.average()); light_power.push(phi.average());
} }
let alias_table = AliasTableHost::new(&light_power); let alias_table = AliasTable::new(&light_power);
Self { Self {
lights: lights_vec, lights: lights_vec,
@ -46,16 +46,15 @@ impl PowerSamplerHost {
alias_table, alias_table,
} }
} }
// pub fn to_device(&self, arena: &Arena) -> PowerLightSampler {
pub fn to_device(&self, arena: &Arena) -> PowerLightSampler { // let device_lights: Vec<Light> = self.lights.iter().map(|l| (**l).clone()).collect();
let device_lights: Vec<Light> = self.lights.iter().map(|l| (**l).clone()).collect(); // let (lights_ptr, _) = arena.alloc_slice(&device_lights);
let (lights_ptr, _) = arena.alloc_slice(&device_lights); // let alias_device = self.alias_table.to_device(arena);
let alias_device = self.alias_table.to_device(arena); //
// PowerLightSampler {
PowerLightSampler { // lights: lights_ptr,
lights: lights_ptr, // lights_len: self.lights.len() as u32,
lights_len: self.lights.len() as u32, // alias_table: alias_device,
alias_table: alias_device, // }
} // }
}
} }

View file

@ -13,45 +13,7 @@ use shared::lights::SpotLight;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::math::radians; use shared::utils::math::radians;
use shared::utils::{Ptr, Transform}; use shared::utils::{Ptr, Transform};
use shared::{Float, PI}; use shared::{Float, PI, Ptr, Transform};
pub trait CreateSpotLight {
fn new(
render_from_light: Transform,
medium_interface: MediumInterface,
le: Spectrum,
scale: shared::Float,
cos_falloff_start: Float,
total_width: Float,
) -> Self;
}
impl CreateSpotLight for SpotLight {
fn new(
render_from_light: Transform,
_medium_interface: MediumInterface,
le: Spectrum,
scale: shared::Float,
cos_falloff_start: Float,
total_width: Float,
) -> Self {
let base = LightBase::new(
LightType::DeltaPosition,
render_from_light,
MediumInterface::empty(),
);
let i = lookup_spectrum(&le);
let iemit = Ptr::from(&i.device());
Self {
base,
iemit,
scale,
cos_falloff_end: radians(total_width).cos(),
cos_falloff_start: radians(cos_falloff_start).cos(),
}
}
}
pub fn create( pub fn create(
render_from_light: Transform, render_from_light: Transform,