ALmost done with changes

This commit is contained in:
Wito Wiala 2026-05-20 20:52:34 +01:00
parent 72acb8ccdf
commit 82255e5046
18 changed files with 168 additions and 321 deletions

View file

@ -1,5 +1,5 @@
use crate::core::geometry::{Bounds3f, Ray};
use crate::core::aggregates::BVHAggregate;
use crate::core::geometry::{Bounds3f, Ray};
use crate::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction};
use crate::core::light::Light;
use crate::core::material::Material;
@ -104,7 +104,12 @@ impl PrimitiveTrait for SimplePrimitive {
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
let mut si = self.shape.intersect(r, t_max)?;
si.set_intersection_properties(self.material, Ptr::null(), MediumInterface::default(), r.medium);
si.set_intersection_properties(
self.material,
Ptr::null(),
MediumInterface::default(),
r.medium,
);
Some(si)
}
@ -183,7 +188,7 @@ impl PrimitiveTrait for AnimatedPrimitive {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Default, Debug, Clone, Copy)]
pub struct LinearBVHNode {
bounds: Bounds3f,
}
@ -217,7 +222,6 @@ pub enum Primitive {
KdTree(KdTreeAggregate),
}
impl<T: PrimitiveTrait> PrimitiveTrait for Ptr<T> {
fn bounds(&self) -> Bounds3f {
unsafe { self.as_ref().bounds() }
@ -231,5 +235,3 @@ impl<T: PrimitiveTrait> PrimitiveTrait for Ptr<T> {
unsafe { self.as_ref().intersect_p(r, t_max) }
}
}

View file

@ -1,3 +1,4 @@
use crate::Arena;
use rayon::prelude::*;
use shared::core::aggregates::{BVHAggregate as DeviceBVHAggregate, LinearBVHNode};
use shared::core::geometry::{Bounds3f, Point3f, Ray, Vector3f};
@ -5,8 +6,7 @@ use shared::core::primitive::{Primitive, PrimitiveTrait};
use shared::core::shape::ShapeIntersection;
use shared::utils::math::encode_morton_3;
use shared::utils::{find_interval, partition_slice};
use crate::Arena;
use shared::Float;
use shared::{gvec_from_slice, Float};
use std::cmp::Ordering;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
@ -26,7 +26,6 @@ struct BVHSplitBucket {
pub bounds: Bounds3f,
}
#[derive(Debug, Clone, Copy, Default)]
struct MortonPrimitive {
primitive_index: usize,
@ -890,7 +889,8 @@ impl<P: PrimitiveTrait + Clone + Send + Sync> BVHAggregate<P> {
impl BVHAggregate<Primitive> {
pub fn to_device(&self, arena: &mut Arena) -> DeviceBVHAggregate {
let shared_nodes: Vec<shared::core::aggregates::LinearBVHNode> = self.nodes
let shared_nodes: Vec<shared::core::aggregates::LinearBVHNode> = self
.nodes
.iter()
.map(|n| shared::core::aggregates::LinearBVHNode {
bounds: n.bounds,
@ -905,7 +905,7 @@ impl BVHAggregate<Primitive> {
max_prims_in_node: self.max_prims_in_node as u32,
primitives: gvec_from_slice(&self.primitives),
primitive_count: self.primitives.len() as u32,
nodes: gvec_from_slice(&self.shared_nodes),
nodes: gvec_from_slice(&shared_nodes),
node_count: self.nodes.len() as u32,
}
}

View file

@ -386,7 +386,7 @@ impl CameraFactory for Camera {
);
arena.alloc(camera);
arena.alloc(camera.clone());
Ok(Camera::Realistic(camera))
}
"spherical" => {

View file

@ -15,7 +15,7 @@ use shared::spectra::{
cie::SWATCHES_RAW, DenselySampledSpectrum, PiecewiseLinearSpectrum, RGBColorSpace,
};
use shared::utils::math::{linear_least_squares, SquareMatrix};
use shared::{Float, Ptr};
use shared::{Float, Ptr, leak};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, LazyLock};
@ -27,7 +27,7 @@ const SWATCH_REFLECTANCES: LazyLock<[Spectrum; N_SWATCH_REFLECTANCES]> = LazyLoc
std::array::from_fn(|i| {
let raw_data = SWATCHES_RAW[i];
let pls = PiecewiseLinearSpectrum::from_interleaved(raw_data, false);
Spectrum::Piecewise(pls)
Spectrum::Piecewise(leak(pls))
})
});

View file

@ -1,10 +1,10 @@
use crate::utils::sampling::PiecewiseConstant2D;
use crate::utils::{FileLoc, ParameterDictionary};
use crate::Arena;
use crate::{FileLoc, ParameterDictionary};
use anyhow::{bail, Result};
use shared::core::filter::Filter;
use shared::core::geometry::{Bounds2f, Point2f, Vector2f};
use shared::filters::*;
use shared::utils::sampling::PiecewiseConstant2D;
use shared::{Array2D, Float};
pub trait FilterFactory {

View file

@ -256,8 +256,8 @@ impl HostImage {
}
}
pub fn set_channel(&mut self, p: Point2i, values: &ImageChannelValues) {
self.inner.set_channel(p, values[i]);
pub fn set_channel(&mut self, p: Point2i, c: i32, val: Float) {
self.inner.set_channel(p, c, val);
}
pub fn select_channels(&self, desc: &ImageChannelDesc) -> Self {

View file

@ -1,6 +1,4 @@
use super::HostImage;
use crate::core::image::pixel::PixelStorageTrait;
use crate::core::image::PixelStorage;
use rayon::prelude::*;
use shared::core::color::ColorEncoding;
use shared::core::geometry::{Bounds2i, Point2i};
@ -18,98 +16,84 @@ pub struct ResampleWeight {
impl HostImage {
pub fn flip_y(&mut self) {
let res = self.inner.resolution;
let nc = self.inner.n_channels as usize;
let nc = self.inner.n_channels;
match self.inner.format {
PixelFormat::U8 => flip_y_kernel(self.inner.pixels.as_u8_mut(), res, nc),
PixelFormat::F16 => flip_y_kernel(self.inner.pixels.as_f16_mut(), res, nc),
PixelFormat::F32 => flip_y_kernel(self.inner.pixels.as_f32_slice_mut(), res, nc),
for y in 0..res.y() / 2 {
let y2 = res.y() - 1 - y;
for x in 0..res.x() {
for c in 0..nc {
let a = self.inner.get_channel(Point2i::new(x, y), c);
let b = self.inner.get_channel(Point2i::new(x, y2), c);
self.inner.set_channel(Point2i::new(x, y), c, b);
self.inner.set_channel(Point2i::new(x, y2), c, a);
}
}
}
}
pub fn crop(&self, bounds: Bounds2i) -> HostImage {
let n_channels = self.inner.n_channels as usize;
let nc = self.inner.n_channels;
let new_res = Point2i::new(
bounds.p_max.x() - bounds.p_min.x(),
bounds.p_max.y() - bounds.p_min.y(),
);
let new_names = self.channel_names.clone();
let mut new_image =
HostImage::new(self.inner.format, new_res, &new_names, self.inner.encoding);
HostImage::new(self.inner.format, new_res, &self.channel_names, self.inner.encoding);
match self.inner.format {
PixelFormat::U8 => crop_kernel(
self.inner.pixels.as_u8(),
new_image.inner.pixels.as_u8_mut(),
self.inner.resolution,
bounds,
n_channels,
),
PixelFormat::F16 => crop_kernel(
self.inner.pixels.as_f16(),
new_image.inner.pixels.as_f16_mut(),
self.inner.resolution,
bounds,
n_channels,
),
PixelFormat::F32 => crop_kernel(
self.inner.pixels.as_f32_slice(),
new_image.inner.pixels.as_f32_slice_mut(),
self.inner.resolution,
bounds,
n_channels,
),
for y in 0..new_res.y() {
for x in 0..new_res.x() {
let src = Point2i::new(bounds.p_min.x() + x, bounds.p_min.y() + y);
let dst = Point2i::new(x, y);
for c in 0..nc {
let val = self.inner.get_channel(src, c);
new_image.inner.set_channel(dst, c, val);
}
}
}
new_image
}
pub fn copy_rect_out(&self, extent: Bounds2i, buf: &mut [Float], wrap: WrapMode2D) {
match self.inner.format {
PixelFormat::U8 => {
copy_rect_out_kernel(self.inner.pixels.as_u8(), self, extent, buf, wrap)
}
PixelFormat::F16 => {
copy_rect_out_kernel(self.inner.pixels.as_f16(), self, extent, buf, wrap)
}
PixelFormat::F32 => {
copy_rect_out_kernel(self.inner.pixels.as_f32_slice(), self, extent, buf, wrap)
let w = (extent.p_max.x() - extent.p_min.x()) as usize;
let channels = self.inner.n_channels as usize;
buf.par_chunks_mut(w * channels)
.enumerate()
.for_each(|(y_rel, row_buf)| {
let y = extent.p_min.y() + y_rel as i32;
for x_rel in 0..w {
let x = extent.p_min.x() + x_rel as i32;
let p = Point2i::new(x, y);
for c in 0..channels {
row_buf[x_rel * channels + c] =
self.inner.get_channel_with_wrap(p, c as i32, wrap);
}
}
});
}
pub fn copy_rect_in(&mut self, extent: Bounds2i, buf: &[Float]) {
let res = self.inner.resolution;
let n_channels = self.inner.n_channels as usize;
let encoding = self.inner.encoding;
let format = self.inner.format;
let w = (extent.p_max.x() - extent.p_min.x()) as usize;
let channels = self.inner.n_channels as usize;
match format {
PixelFormat::U8 => copy_rect_in_kernel(
self.inner.pixels.as_u8_mut(),
res,
n_channels,
encoding,
extent,
buf,
),
PixelFormat::F16 => copy_rect_in_kernel(
self.inner.pixels.as_f16_mut(),
res,
n_channels,
encoding,
extent,
buf,
),
PixelFormat::F32 => copy_rect_in_kernel(
self.inner.pixels.as_f32_slice_mut(),
res,
n_channels,
encoding,
extent,
buf,
),
for (y_rel, row) in buf.chunks(w * channels).enumerate() {
let y = extent.p_min.y() + y_rel as i32;
if y < 0 || y >= self.inner.resolution.y() {
continue;
}
for x_rel in 0..w {
let x = extent.p_min.x() + x_rel as i32;
if x < 0 || x >= self.inner.resolution.x() {
continue;
}
for c in 0..channels {
let val = row[x_rel * channels + c];
self.inner.set_channel(Point2i::new(x, y), c as i32, val);
}
}
}
}
@ -180,6 +164,7 @@ impl HostImage {
}
let new_res = Point2i::new((old.x() / 2).max(1), (old.y() / 2).max(1));
let nc = prev.n_channels();
let mut next = HostImage::new(
prev.inner.format,
new_res,
@ -187,175 +172,35 @@ impl HostImage {
prev.inner.encoding,
);
match next.inner.format {
PixelFormat::U8 => downsample_kernel(
next.inner.pixels.as_u8_mut(),
new_res,
&prev,
internal_wrap,
),
PixelFormat::F16 => downsample_kernel(
next.inner.pixels.as_f16_mut(),
new_res,
&prev,
internal_wrap,
),
PixelFormat::F32 => downsample_kernel(
next.inner.pixels.as_f32_slice_mut(),
new_res,
&prev,
internal_wrap,
),
}
levels.push(next);
}
levels
}
}
fn flip_y_kernel<T: PixelStorageTrait>(pixels: &mut [T], res: Point2i, channels: usize) {
let w = res.x() as usize;
let h = res.y() as usize;
let stride = w * channels;
for y in 0..(h / 2) {
let bot = h - 1 - y;
for i in 0..stride {
pixels.swap(y * stride + i, bot * stride + i);
}
}
}
fn crop_kernel<T: PixelStorageTrait>(
src: &[T],
dst: &mut [T],
src_res: Point2i,
bounds: Bounds2i,
channels: usize,
) {
let dst_w = (bounds.p_max.x() - bounds.p_min.x()) as usize;
// let dst_h = (bounds.p_max.y() - bounds.p_min.y()) as usize;
dst.par_chunks_mut(dst_w * channels)
.enumerate()
.for_each(|(dy, dst_row)| {
let sy = bounds.p_min.y() as usize + dy;
let sx_start = bounds.p_min.x() as usize;
let src_offset = (sy * src_res.x() as usize + sx_start) * channels;
let count = dst_w * channels;
dst_row.copy_from_slice(&src[src_offset..src_offset + count]);
});
}
fn copy_rect_out_kernel<T: PixelStorageTrait>(
src: &[T],
image: &HostImage,
extent: Bounds2i,
buf: &mut [Float],
wrap: WrapMode2D,
) {
let w = (extent.p_max.x() - extent.p_min.x()) as usize;
let channels = image.n_channels() as usize;
let enc = image.encoding();
let res = image.resolution();
buf.par_chunks_mut(w * channels)
.enumerate()
.for_each(|(y_rel, row_buf)| {
let y = extent.p_min.y() + y_rel as i32;
for x_rel in 0..w {
let x = extent.p_min.x() + x_rel as i32;
if x >= 0 && x < res.x() && y >= 0 && y < res.y() {
let offset = (y as usize * res.x() as usize + x as usize) * channels;
for c in 0..channels {
row_buf[x_rel * channels + c] = T::to_linear(src[offset + c], enc);
}
} else {
// We fall back to get_channel which handles the wrapping math.
let p = Point2i::new(x, y);
for c in 0..channels {
row_buf[x_rel * channels + c] =
image.get_channel_with_wrap(p, c.try_into().unwrap(), wrap);
}
}
}
});
}
fn copy_rect_in_kernel<T: PixelStorageTrait>(
dst: &mut [T],
res: Point2i,
channels: usize,
enc: ColorEncoding,
extent: Bounds2i,
buf: &[Float],
) {
let w = (extent.p_max.x() - extent.p_min.x()) as usize;
let res_x = res.x() as usize;
let rows = buf.chunks(w * channels);
for (y_rel, row) in rows.enumerate() {
let y = extent.p_min.y() + y_rel as i32;
if y < 0 || y >= res.y() {
continue;
}
let dst_row_start = (y as usize * res_x) * channels;
for (x_rel, &val) in row.iter().enumerate() {
let c = x_rel % channels;
let x_pixel = x_rel / channels;
let x = extent.p_min.x() + x_pixel as i32;
if x >= 0 && x < res.x() {
let idx = dst_row_start + (x as usize * channels) + c;
dst[idx] = T::from_linear(val, enc);
}
}
}
}
fn downsample_kernel<T: PixelStorageTrait>(
dst: &mut [T],
dst_res: Point2i,
prev: &HostImage,
wrap: WrapMode2D,
) {
let w = dst_res.x() as usize;
let channels = prev.n_channels();
let enc = prev.encoding();
let old_res = prev.resolution();
dst.par_chunks_mut(w * channels as usize)
.enumerate()
.for_each(|(y, row)| {
let src_y = y * 2;
for x in 0..w {
for y in 0..new_res.y() {
for x in 0..new_res.x() {
let src_x = x * 2;
for c in 0..channels {
let src_y = y * 2;
for c in 0..nc {
let mut sum = 0.0;
let mut count = 0.0;
for dy in 0..2 {
for dx in 0..2 {
let sx = src_x as i32 + dx;
let sy = src_y as i32 + dy;
if sx < old_res.x() && sy < old_res.y() {
sum += prev.get_channel_with_wrap(Point2i::new(sx, sy), c, wrap);
for dy in 0..2i32 {
for dx in 0..2i32 {
let sx = src_x + dx;
let sy = src_y + dy;
if sx < old.x() && sy < old.y() {
sum += prev.inner.get_channel_with_wrap(
Point2i::new(sx, sy), c, internal_wrap,
);
count += 1.0;
}
}
}
let avg = if count > 0.0 { sum / count } else { 0.0 };
row[x * channels as usize + c as usize] = T::from_linear(avg, enc);
next.inner.set_channel(Point2i::new(x, y), c, avg);
}
}
});
}
levels.push(next);
}
levels
}
}
fn resample_weights(old_res: usize, new_res: usize) -> Vec<ResampleWeight> {
@ -416,7 +261,6 @@ fn compute_resize_tile(
let mut x_buf = vec![0.0; n_channels * ny_in * nx_out];
// Resize X
for y in 0..ny_in {
for x in 0..nx_out {
let x_global = out_extent.p_min.x() + x as i32;
@ -438,7 +282,6 @@ fn compute_resize_tile(
let mut out_buf = vec![0.0; n_channels * nx_out * ny_out];
// Resize Y
for x in 0..nx_out {
for y in 0..ny_out {
let y_global = out_extent.p_min.y() + y as i32;

View file

@ -36,7 +36,7 @@ pub struct SceneLookup<'a> {
pub media: &'a HashMap<String, Arc<Medium>>,
pub named_materials: &'a HashMap<String, Material>,
pub materials: &'a Vec<Material>,
pub shape_lights: &'a HashMap<usize, Vec<Light>>,
pub shape_lights: &'a HashMap<usize, Vec<Ptr<Light>>>,
}
impl<'a> SceneLookup<'a> {
@ -154,7 +154,6 @@ impl BasicScene {
job: None,
};
let arena_sampler = Arc::clone(&arena);
let sampler_film = Arc::clone(&film_instance);
let sampler_job = run_async(move || {
let res = sampler_film.as_ref().base().full_resolution;
@ -163,7 +162,7 @@ impl BasicScene {
&sampler.parameters,
res,
&sampler.loc,
&arena_sampler,
&arena,
)
.map_err(|e| anyhow!("Failed to create sampler: {}", e))
});
@ -556,9 +555,9 @@ impl BasicScene {
shape_entities: &[ShapeSceneEntity],
textures: &NamedTextures,
arena: &Arena,
) -> HashMap<usize, Vec<Light>> {
) -> HashMap<usize, Vec<Ptr<Light>>> {
let light_state = self.light_state.lock();
let mut shape_lights: HashMap<usize, Vec<Light>> = HashMap::new();
let mut shape_lights: HashMap<usize, Vec<Ptr<Light>>> = HashMap::new();
for (i, entity) in shape_entities.iter().enumerate() {
let light_idx = match entity.light_index {
@ -592,7 +591,7 @@ impl BasicScene {
let render_from_light = *entity.render_from_object;
let lights: Vec<Light> = shapes
let lights: Vec<Ptr<Light>> = shapes
.iter()
.filter_map(|shape| {
match crate::core::light::create_area_light(
@ -676,7 +675,7 @@ impl BasicScene {
mtl: Material,
alpha_tex: &Option<Arc<FloatTexture>>,
mi: MediumInterface,
al_params: Option<&AreaLightEntity>,
al_params: Option<&SceneEntity>,
render_from_light: Transform,
film_cs: Option<&RGBColorSpace>,
arena: &mut Arena,
@ -938,16 +937,15 @@ impl BasicScene {
.get(&shape_ctx.entity_index)
.and_then(|lights| lights.get(shape_ctx.shape_index));
let light_ptr = arena.alloc_opt(shape_lights_opt);
let light_ptr = shape_lights_opt.copied().unwrap_or(Ptr::null());
let shape_ptr = shape_ctx.shape;
let prim = if area_light.is_null() && !mi.is_medium_transition() && alpha_tex.is_none()
{
let prim = if light_ptr.is_null() && !mi.is_medium_transition() && alpha_tex.is_none() {
Primitive::Simple(SimplePrimitive::new(shape_ptr, Ptr::from(&mtl)))
} else {
Primitive::Geometric(GeometricPrimitive::new(
shape_ptr,
arena.alloc(mtl),
area_light,
light_ptr,
mi.clone(),
arena.upload(alpha_tex),
))

View file

@ -1,9 +1,9 @@
use super::*;
use crate::core::film::{CreateFilmBase, PixelSensor};
use crate::core::film::{CreateFilmBase, CreatePixelSensor};
use crate::Arena;
use anyhow::Result;
use shared::core::camera::CameraTransform;
use shared::core::film::{Film, FilmBase, RGBFilm, RGBPixel};
use shared::core::film::{Film, FilmBase, RGBFilm, RGBPixel, PixelSensor};
use shared::spectra::RGBColorSpace;
impl CreateFilm for RGBFilm {
@ -13,13 +13,13 @@ impl CreateFilm for RGBFilm {
filter: Filter,
_camera_transform: Option<CameraTransform>,
loc: &FileLoc,
_arena: &Arena,
arena: &Arena,
) -> Result<Film> {
let colorspace = params.color_space.as_ref().cloned().unwrap_or_else(crate::spectra::default_colorspace_arc);
let max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY)?;
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 sensor = PixelSensor::create(params, colorspace.clone(), exposure_time, loc, arena)?;
let film_base = FilmBase::create(params, filter, Some(&sensor), loc)?;
let film = RGBFilm::new(film_base, &colorspace, max_component_value, write_fp16);
Ok(Film::RGB(film))
}

View file

@ -11,7 +11,7 @@ use shared::core::light::{Light, LightBase, LightType};
use shared::core::medium::{Medium, MediumInterface};
use shared::core::shape::{Shape, ShapeTrait};
use shared::core::spectrum::Spectrum;
use shared::core::texture::{SpectrumType, TextureEvalContext};
use shared::core::texture::{SpectrumType, TextureEvalContext, GPUFloatTexture};
use shared::lights::DiffuseAreaLight;
use shared::spectra::RGBColorSpace;
use shared::utils::Transform;

View file

@ -1,13 +1,10 @@
use std::path::Path;
use crate::core::image::{HostImage, ImageIO};
use crate::core::light::lookup_spectrum;
use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::FloatTexture;
use crate::utils::sampling::PiecewiseConstant2D;
use crate::utils::resolve_filename;
use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::{Result, anyhow};
use anyhow::{anyhow, Result};
use shared::core::geometry::Point2i;
use shared::core::light::{Light, LightBase, LightType};
use shared::core::medium::{Medium, MediumInterface};
@ -16,8 +13,10 @@ use shared::core::spectrum::Spectrum;
use shared::core::texture::SpectrumType;
use shared::lights::GoniometricLight;
use shared::spectra::RGBColorSpace;
use shared::utils::sampling::PiecewiseConstant2D;
use shared::utils::{Ptr, Transform};
use shared::{Float, PI};
use std::path::Path;
pub fn create(
render_from_light: Transform,
@ -25,11 +24,10 @@ pub fn create(
params: &ParameterDictionary,
loc: &FileLoc,
_shape: &Shape,
_alpha_text: &FloatTexture,
_alpha_tex: &FloatTexture,
colorspace: Option<&RGBColorSpace>,
arena: &Arena,
) -> Result<Light> {
let default_cs = crate::spectra::default_colorspace();
let cs = colorspace.unwrap_or(&default_cs);
let i = params
@ -39,14 +37,13 @@ pub fn create(
SpectrumType::Illuminant,
)
.expect("Could not retrieve spectrum");
let mut scale = params.get_one_float("scale", 1.)?;
let filename = resolve_filename(&params.get_one_string("filename", "")?);
let image: Ptr<HostImage> = if filename.is_empty() {
Ptr::null()
} else {
let host_image = if !filename.is_empty() {
let im = HostImage::read(Path::new(&filename), None)
.map_err(|e| anyhow!("could not load image '{}': {}", filename, e))?;
let loaded = im.image;
let res = loaded.resolution();
@ -56,7 +53,6 @@ pub fn create(
filename
));
}
if res.x() != res.y() {
return Err(anyhow!(
"image resolution ({}, {}) is non-square; unlikely to be an equal-area map",
@ -65,23 +61,27 @@ pub fn create(
));
}
Ptr::from(&convert_to_luminance_image(&loaded, &filename, loc)?)
Some(convert_to_luminance_image(&loaded, &filename, loc)?)
} else {
None
};
scale /= spectrum_to_photometric(i);
let phi_v = params.get_one_float("power", -1.0)?;
let phi_v = params.get_one_float("power", -1.0)?;
if phi_v > 0.0 {
let k_e = compute_emissive_power(&image);
if let Some(ref img) = host_image {
let k_e = compute_emissive_power(img);
scale *= phi_v / k_e;
}
}
let swap_yz: [Float; 16] = [
1., 0., 0., 0., 0., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 1.,
];
let t =
Transform::from_flat(&swap_yz).expect("Could not create transform for GoniometricLight");
let _final_render_from_light = render_from_light * t;
let final_render_from_light = render_from_light * t;
let mi = match medium {
Some(m) => {
@ -93,31 +93,35 @@ pub fn create(
}
None => MediumInterface::default(),
};
let base = LightBase::new(LightType::DeltaPosition, render_from_light, mi);
let base = LightBase::new(LightType::DeltaPosition, final_render_from_light, mi);
let iemit = lookup_spectrum(&i);
let image_ptr = if !image.is_null() {
let distrib = PiecewiseConstant2D::from_image(&image);
let distrib_ptr = arena.alloc(distrib);
let img_ptr = arena.alloc(image);
(img_ptr, distrib_ptr)
} else {
(Ptr::null(), Ptr::null())
// Build distribution from host image, then upload both to arena
let (image_ptr, distrib_ptr) = match host_image {
Some(img) => {
let distrib = PiecewiseConstant2D::from_image(&img.inner);
(arena.alloc(img.inner), arena.alloc(distrib))
}
None => (Ptr::null(), Ptr::null()),
};
let specific = GoniometricLight {
base,
iemit: arena.alloc(*iemit),
iemit: arena.alloc((*iemit).clone()),
scale,
image: image_ptr.0,
distrib: image_ptr.1,
image: image_ptr,
distrib: distrib_ptr,
};
Ok(Light::Goniometric(specific))
}
fn convert_to_luminance_image(image: &HostImage, filename: &str, loc: &FileLoc) -> Result<HostImage> {
fn convert_to_luminance_image(
image: &HostImage,
filename: &str,
loc: &FileLoc,
) -> Result<HostImage> {
let res = image.resolution();
let rgb_desc = image.get_channel_desc(&["R", "G", "B"]);
let y_desc = image.get_channel_desc(&["Y"]);

View file

@ -3,7 +3,6 @@ use crate::core::light::lookup_spectrum;
use crate::core::spectrum::spectrum_to_photometric;
use crate::spectra::get_spectra_context;
use crate::utils::resolve_filename;
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
use crate::{Arena, FileLoc, ParameterDictionary, ArenaUpload, Upload};
use anyhow::{anyhow, Result};
use rayon::prelude::*;

View file

@ -1,13 +1,11 @@
use crate::core::image::{HostImage, ImageIO};
use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::FloatTexture;
use crate::utils::sampling::PiecewiseConstant2D;
use crate::utils::resolve_filename;
use crate::{Arena, FileLoc, ParameterDictionary, ArenaUpload};
use anyhow::{Result, anyhow};
use shared::Float;
use crate::{Arena, ArenaUpload, FileLoc, ParameterDictionary};
use anyhow::{anyhow, Result};
use shared::core::geometry::{
Bounds2f, Point2f, Point2i, Point3f, Vector3f, VectorLike, cos_theta,
cos_theta, Bounds2f, Point2f, Point2i, Point3f, Vector3f, VectorLike,
};
use shared::core::light::{Light, LightBase, LightType};
use shared::core::medium::{Medium, MediumInterface};
@ -15,8 +13,10 @@ use shared::core::shape::Shape;
use shared::core::spectrum::Spectrum;
use shared::lights::ProjectionLight;
use shared::spectra::RGBColorSpace;
use shared::utils::Transform;
use shared::utils::math::{radians, square};
use shared::utils::sampling::PiecewiseConstant2D;
use shared::utils::Transform;
use shared::Float;
use std::path::Path;
pub fn create(

View file

@ -1,7 +1,7 @@
use crate::core::light::lookup_spectrum;
use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::FloatTexture;
use crate::utils::{Arena, FileLoc, ParameterDictionary};
use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::Result;
use shared::core::geometry::{Frame, Point3f, VectorLike};
use shared::core::light::{Light, LightBase, LightType};
@ -22,6 +22,7 @@ trait CreateSpotLight {
scale: Float,
cos_falloff_start: Float,
total_width: Float,
arena: &Arena
) -> Self;
}
@ -33,6 +34,7 @@ impl CreateSpotLight for SpotLight {
scale: Float,
cos_falloff_start: Float,
total_width: Float,
arena: &Arena
) -> Self {
let base = LightBase::new(
LightType::DeltaPosition,
@ -41,7 +43,7 @@ impl CreateSpotLight for SpotLight {
);
let i = lookup_spectrum(&le);
let iemit = arena.alloc(i);
let iemit = arena.alloc_arc(i);
Self {
base,
iemit,
@ -100,7 +102,7 @@ pub fn create(
None => MediumInterface::default(),
};
let specific = SpotLight::new(final_render, mi, i, scale, coneangle, coneangle - conedelta);
let specific = SpotLight::new(final_render, mi, i, scale, coneangle, coneangle - conedelta, arena);
arena.alloc(specific);
Ok(Light::Spot(specific))
}

View file

@ -1,12 +1,12 @@
use crate::core::image::{HostImage, ImageIO};
use crate::core::shape::{CreateShape, ALL_BILINEAR_MESHES};
use crate::core::texture::FloatTexture;
use crate::utils::sampling::PiecewiseConstant2D;
use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::{anyhow, Result};
use log::warn;
use shared::core::shape::Shape;
use shared::shapes::{BilinearPatchMesh, BilinearPatchShape};
use shared::utils::sampling::PiecewiseConstant2D;
use shared::{Ptr, Transform};
use std::collections::HashMap;
use std::path::Path;
@ -95,7 +95,7 @@ impl CreateShape for BilinearPatchShape {
let im = HostImage::read(Path::new(&filename), None)?;
let mut img = im.image;
img.flip_y();
Some(PiecewiseConstant2D::from_image(&img))
Some(PiecewiseConstant2D::from_image(&img.inner))
}
} else {
None
@ -108,7 +108,7 @@ impl CreateShape for BilinearPatchShape {
&p,
&n,
&uv,
image_dist,
image_dist.as_ref(),
);
let host_arc = Arc::new(host);

View file

@ -1,9 +1,9 @@
use crate::utils::sampling::PiecewiseConstant2D;
use anyhow::{bail, Context, Result as AnyResult};
use ply_rs::parser::Parser;
use ply_rs::ply::{DefaultElement, Property};
use shared::core::geometry::{Normal3f, Point2f, Point3f, VectorLike};
use shared::shapes::mesh::TriangleMesh;
use shared::utils::sampling::PiecewiseConstant2D;
use shared::Transform;
use std::fs::File;
use std::path::Path;

View file

@ -1,7 +1,7 @@
use shared::core::spectrum::Spectrum;
use shared::spectra::cie::*;
use shared::spectra::{DenselySampledSpectrum, PiecewiseLinearSpectrum};
use shared::{gbox, leak, Float, Ptr};
use shared::{gbox, gvec_from_slice, leak, Float, Ptr};
use std::collections::HashMap;
use std::sync::LazyLock;
@ -11,13 +11,11 @@ pub fn create_cie(data: &[Float]) -> DenselySampledSpectrum {
95 => (300.0, 5.0),
n => panic!("Unexpected CIE data length: {}", n),
};
let lambdas: Vec<Float> = (0..data.len())
.map(|i| start_lambda + i as Float * step)
.collect();
let buffer = PiecewiseLinearSpectrum::new(lambdas, data.to_vec());
let spec = Spectrum::Piecewise(Ptr::from(&*buffer));
let buffer = PiecewiseLinearSpectrum::new(gvec_from_slice(&lambdas), gvec_from_slice(data));
let spec = Spectrum::Piecewise(leak(buffer));
DenselySampledSpectrum::from_spectrum(&spec)
}

View file

@ -134,7 +134,8 @@ pub fn default_colorspace_arc() -> Arc<RGBColorSpace> {
pub fn default_colorspace_ref() -> &'static RGBColorSpace {
static CS: OnceLock<RGBColorSpace> = OnceLock::new();
CS.get_or_init(|| stdcs.srgb)
let stdcs = get_colorspace_device();
CS.get_or_init(|| *stdcs.srgb)
}
pub fn default_illuminant() -> Spectrum {