ALmost done with changes
This commit is contained in:
parent
72acb8ccdf
commit
82255e5046
18 changed files with 168 additions and 321 deletions
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ impl CameraFactory for Camera {
|
|||
|
||||
);
|
||||
|
||||
arena.alloc(camera);
|
||||
arena.alloc(camera.clone());
|
||||
Ok(Camera::Realistic(camera))
|
||||
}
|
||||
"spherical" => {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(¶ms.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"]);
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue