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 {
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) {
let tf = -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::transform::AnimatedTransform;
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;
#[repr(C)]
@ -50,6 +50,43 @@ impl Default for RGBPixel {
}
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 {
&self.base
}
@ -214,6 +251,37 @@ pub struct 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 {
&self.base
}
@ -351,24 +419,73 @@ impl Default for SpectralPixel {
#[cfg_attr(target_os = "cuda", derive(Copy, Clone))]
pub struct SpectralFilm {
pub base: FilmBase,
pub colorspace: RGBColorSpace,
pub lambda_min: Float,
pub lambda_max: Float,
pub n_buckets: usize,
pub max_component_value: Float,
pub write_fp16: bool,
pub filter_integral: Float,
pub colorspace: RGBColorSpace,
pub pixels: Array2D<SpectralPixel>,
pub output_rgbf_from_sensor_rgb: SquareMatrix<Float, 3>,
pub bucket_sums: *mut f64,
pub weight_sums: *mut f64,
pub bucket_splats: *mut AtomicFloat,
pub bucket_sums: GVec<f64>,
pub weight_sums: GVec<f64>,
pub bucket_splats: GVec<AtomicFloat>,
}
unsafe impl Send for SpectralFilm {}
unsafe impl Sync for 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 {
&self.base
}

View file

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

View file

@ -1,6 +1,5 @@
use crate::core::color::{ColorEncoding, ColorEncodingTrait, LINEAR};
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::Float;
use crate::GVec;

View file

@ -1,19 +1,18 @@
use enum_dispatch::enum_dispatch;
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::spectrum::{Spectrum, SpectrumTrait};
use crate::spectra::{
BlackbodySpectrum, DenselySampledSpectrum, LAMBDA_MAX, LAMBDA_MIN, RGBIlluminantSpectrum,
RGBUnboundedSpectrum, SampledSpectrum, SampledWavelengths,
BlackbodySpectrum, DenselySampledSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum,
SampledSpectrum, SampledWavelengths, LAMBDA_MAX, LAMBDA_MIN,
};
use crate::utils::containers::SampledGrid;
use crate::utils::math::{clamp, square};
use crate::utils::ptr::Ptr;
use crate::utils::rng::Rng;
use crate::utils::transform::Transform;
use crate::{gvec_with_capacity, GVec, Ptr};
use enum_dispatch::enum_dispatch;
use num_traits::Float as NumFloat;
#[repr(C)]
@ -90,11 +89,11 @@ impl PhaseFunctionTrait for HGPhaseFunction {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone)]
pub struct MajorantGrid {
pub bounds: Bounds3f,
pub res: Point3i,
pub voxels: *mut Float,
pub voxels: GVec<Float>,
pub n_voxels: u32,
}
@ -102,21 +101,21 @@ unsafe impl Send for MajorantGrid {}
unsafe impl Sync for MajorantGrid {}
impl MajorantGrid {
// #[cfg(not(target_os = "cuda"))]
// pub fn new(bounds: Bounds3f, res: Point3i) -> Self {
// let n_voxels = (res.x() * res.y() * res.z()) as usize;
// let voxels = Vec::with_capacity(n_voxels);
// Self {
// bounds,
// res,
// voxels: voxels.as_ptr(),
// n_voxels: n_voxels as u32,
// }
// }
//
#[cfg(not(target_os = "cuda"))]
pub fn new(bounds: Bounds3f, res: Point3i) -> Self {
let n_voxels = (res.x() * res.y() * res.z()) as usize;
let voxels = gvec_with_capacity(n_voxels);
Self {
bounds,
res,
voxels,
n_voxels: n_voxels as u32,
}
}
#[inline(always)]
fn is_valid(&self) -> bool {
!self.voxels.is_null()
!self.voxels.is_empty()
}
#[inline(always)]
@ -128,7 +127,7 @@ impl MajorantGrid {
let idx = z * self.res.x() * self.res.y() + y * self.res.x() + x;
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 {
0.0
}
@ -143,7 +142,7 @@ impl MajorantGrid {
let idx = x + self.res.x() * (y + self.res.y() * z);
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,
owen_scrambled_radical_inverse, permutation_element, radical_inverse, round_up_pow2,
scrambled_radical_inverse, sobol_interval_to_index, sobol_sample, BinaryPermuteScrambler,
DeviceDigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler, Scrambler,
DigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler, Scrambler,
PRIME_TABLE_SIZE,
};
use crate::utils::rng::Rng;
@ -100,7 +100,7 @@ pub struct HaltonSampler {
pub mult_inverse: [u64; 2],
pub halton_index: u64,
pub dim: u32,
pub digit_permutations: GVec<DeviceDigitPermutation>,
pub digit_permutations: GVec<DigitPermutation>,
}
#[allow(clippy::derivable_impls)]

View file

@ -20,6 +20,22 @@ pub struct 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(
&self,
ctx_p: Point3f,

View file

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

View file

@ -7,8 +7,7 @@ use crate::core::light::{
};
use crate::core::spectrum::SpectrumTrait;
use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths};
use crate::utils::Ptr;
use crate::{Float, PI};
use crate::{Float, PI, Ptr, Transform};
use num_traits::Float as NumFloat;
#[repr(C)]
@ -19,6 +18,25 @@ pub struct PointLight {
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 {
fn base(&self) -> &LightBase {
&self.base

View file

@ -198,12 +198,12 @@ pub enum LightSampler {
#[derive(Clone, Debug)]
pub struct UniformLightSampler {
lights: *const Light,
lights: Ptr<Light>,
lights_len: u32,
}
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 }
}

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::spectrum::SpectrumTrait;
use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths};
use crate::utils::Ptr;
use crate::{Float, PI};
use crate::{Float, PI, Ptr, Transform};
use num_traits::Float as NumFloat;
#[repr(C)]
@ -20,6 +19,31 @@ pub struct 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 {
let cos_theta = w.z(); // assuming normalized in light space
let falloff = crate::utils::math::smooth_step(

View file

@ -821,7 +821,7 @@ impl DigitPermutation {
pub fn scrambled_radical_inverse(
base_index: u32,
mut a: u64,
perm: &DeviceDigitPermutation,
perm: &DigitPermutation,
) -> Float {
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::{Image, ImageIO};
use crate::globals::get_options;
use crate::utils::read_float_file;
use crate::utils::{Arena, FileLoc, ParameterDictionary};
use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::{anyhow, Result};
use shared::cameras::*;
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::medium::Medium;
use shared::utils::math::square;
use shared::Ptr;
use shared::{Float, PI};
use shared::{Float, Ptr, PI};
use std::path::Path;
use std::sync::Arc;
@ -380,16 +378,16 @@ impl CameraFactory for Camera {
}
}
let camera = RealisticCameraHost::new(
let camera = RealisticCamera::new(
base,
&lens_params,
focal_distance,
aperture_diameter,
Arc::from(aperture_image.unwrap()),
Ptr::from(&*aperture_image.unwrap()),
);
arena.alloc(camera);
Ok(Camera::Realistic(camera.device()))
Ok(Camera::Realistic(camera))
}
"spherical" => {
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::spectrum::{Spectrum, SpectrumTrait};
use shared::spectra::{RGBIlluminantSpectrum, RGBUnboundedSpectrum, DenselySampledSpectrum};
use shared::utils::Transform;
use shared::utils::containers::SampledGrid;
use shared::{Float, 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 }
}
}
use shared::{Float, Transform, core::medium::MajorantGrid};
pub trait RGBGridMediumCreator {
fn new(
@ -52,7 +30,7 @@ impl RGBGridMediumCreator for RGBGridMedium {
le_grid: SampledGrid<RGBIlluminantSpectrum>,
le_scale: Float,
) -> 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 y in 0..majorant_grid.res.y() {
for x in 0..majorant_grid.res.x() {
@ -116,7 +94,7 @@ impl GridMediumCreator for GridMedium {
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() {
true
} else {

View file

@ -12,7 +12,7 @@ use crate::core::texture::{FloatTexture, SpectrumTexture};
use crate::utils::parallel::{run_async, AsyncJob};
use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary};
use crate::utils::resolve_filename;
use crate::{Arena, DeviceRepr, FileLoc};
use crate::{Arena, FileLoc};
use anyhow::{anyhow, Result};
use parking_lot::Mutex;
use shared::core::camera::{Camera, CameraTransform};

View file

@ -8,44 +8,6 @@ use shared::spectra::RGBColorSpace;
use shared::utils::AnimatedTransform;
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 {
fn create(
@ -85,7 +47,7 @@ impl CreateFilm for GBufferFilm {
.into());
};
let film = GBufferFilmHost::new(
let film = GBufferFilm::new(
&film_base,
&output_from_render,
apply_inverse,
@ -94,6 +56,6 @@ impl CreateFilm for GBufferFilm {
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::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 {
fn create(
params: &ParameterDictionary,
@ -74,7 +22,7 @@ impl CreateFilm for RGBFilm {
let write_fp16 = params.get_one_bool("savefp16", true)?;
let sensor = PixelSensor::create(params, colorspace.clone(), exposure_time, loc)?;
let film_base = FilmBase::create(params, filter, Some(&sensor.device()), loc)?;
let film = RGBFilmHost::new(film_base, &colorspace, max_component_value, write_fp16);
Ok(Film::RGB(film.device))
let film = RGBFilm::new(film_base, &colorspace, max_component_value, write_fp16);
Ok(Film::RGB(film))
}
}

View file

@ -1,91 +1,15 @@
use super::*;
use crate::core::film::{CreateFilmBase, PixelSensor};
use crate::utils::containers::Array2D;
use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::{Result, anyhow};
use shared::Float;
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::spectra::{LAMBDA_MAX, LAMBDA_MIN, RGBColorSpace};
use shared::utils::AtomicFloat;
use shared::utils::containers::Array2D;
use shared::spectra::{LAMBDA_MAX, LAMBDA_MIN};
use shared::utils::math::SquareMatrix;
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 {
fn create(
@ -96,6 +20,7 @@ impl CreateFilm for SpectralFilm {
loc: &FileLoc,
_arena: &Arena,
) -> Result<Film> {
// Missing default illuminant, use srgb
let colorspace = params.color_space.as_ref().unwrap();
let max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY)?;
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,
lambda_min,
lambda_max,
@ -127,6 +52,6 @@ impl CreateFilm for SpectralFilm {
write_fp16,
);
Ok(Film::Spectral(film.device))
Ok(Film::Spectral(film))
}
}

View file

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

View file

@ -14,28 +14,6 @@ use shared::lights::DistantLight;
use shared::spectra::RGBColorSpace;
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(
render_from_light: Transform,
_medium: Option<Medium>,

View file

@ -21,106 +21,6 @@ use shared::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
use shared::{Float, Ptr, Transform, PI};
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(
render_from_light: Transform,
_medium: Option<Medium>,

View file

@ -6,10 +6,3 @@ pub mod point;
pub mod projection;
pub mod sampler;
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::lights::PointLight;
use shared::spectra::RGBColorSpace;
use shared::utils::{Ptr, Transform};
use shared::{Float, PI};
use shared::{Float, PI, Ptr, Transform};
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(
render_from_light: Transform,

View file

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

View file

@ -13,45 +13,7 @@ use shared::lights::SpotLight;
use shared::spectra::RGBColorSpace;
use shared::utils::math::radians;
use shared::utils::{Ptr, Transform};
use shared::{Float, PI};
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(),
}
}
}
use shared::{Float, PI, Ptr, Transform};
pub fn create(
render_from_light: Transform,