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::aggregates::BVHAggregate;
|
||||||
|
use crate::core::geometry::{Bounds3f, Ray};
|
||||||
use crate::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction};
|
use crate::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction};
|
||||||
use crate::core::light::Light;
|
use crate::core::light::Light;
|
||||||
use crate::core::material::Material;
|
use crate::core::material::Material;
|
||||||
|
|
@ -104,7 +104,12 @@ impl PrimitiveTrait for SimplePrimitive {
|
||||||
|
|
||||||
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
|
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
|
||||||
let mut si = self.shape.intersect(r, t_max)?;
|
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)
|
Some(si)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,7 +188,7 @@ impl PrimitiveTrait for AnimatedPrimitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
pub struct LinearBVHNode {
|
pub struct LinearBVHNode {
|
||||||
bounds: Bounds3f,
|
bounds: Bounds3f,
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +222,6 @@ pub enum Primitive {
|
||||||
KdTree(KdTreeAggregate),
|
KdTree(KdTreeAggregate),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T: PrimitiveTrait> PrimitiveTrait for Ptr<T> {
|
impl<T: PrimitiveTrait> PrimitiveTrait for Ptr<T> {
|
||||||
fn bounds(&self) -> Bounds3f {
|
fn bounds(&self) -> Bounds3f {
|
||||||
unsafe { self.as_ref().bounds() }
|
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) }
|
unsafe { self.as_ref().intersect_p(r, t_max) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::Arena;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use shared::core::aggregates::{BVHAggregate as DeviceBVHAggregate, LinearBVHNode};
|
use shared::core::aggregates::{BVHAggregate as DeviceBVHAggregate, LinearBVHNode};
|
||||||
use shared::core::geometry::{Bounds3f, Point3f, Ray, Vector3f};
|
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::core::shape::ShapeIntersection;
|
||||||
use shared::utils::math::encode_morton_3;
|
use shared::utils::math::encode_morton_3;
|
||||||
use shared::utils::{find_interval, partition_slice};
|
use shared::utils::{find_interval, partition_slice};
|
||||||
use crate::Arena;
|
use shared::{gvec_from_slice, Float};
|
||||||
use shared::Float;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
|
|
||||||
|
|
@ -26,7 +26,6 @@ struct BVHSplitBucket {
|
||||||
pub bounds: Bounds3f,
|
pub bounds: Bounds3f,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
struct MortonPrimitive {
|
struct MortonPrimitive {
|
||||||
primitive_index: usize,
|
primitive_index: usize,
|
||||||
|
|
@ -890,7 +889,8 @@ impl<P: PrimitiveTrait + Clone + Send + Sync> BVHAggregate<P> {
|
||||||
|
|
||||||
impl BVHAggregate<Primitive> {
|
impl BVHAggregate<Primitive> {
|
||||||
pub fn to_device(&self, arena: &mut Arena) -> DeviceBVHAggregate {
|
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()
|
.iter()
|
||||||
.map(|n| shared::core::aggregates::LinearBVHNode {
|
.map(|n| shared::core::aggregates::LinearBVHNode {
|
||||||
bounds: n.bounds,
|
bounds: n.bounds,
|
||||||
|
|
@ -905,7 +905,7 @@ impl BVHAggregate<Primitive> {
|
||||||
max_prims_in_node: self.max_prims_in_node as u32,
|
max_prims_in_node: self.max_prims_in_node as u32,
|
||||||
primitives: gvec_from_slice(&self.primitives),
|
primitives: gvec_from_slice(&self.primitives),
|
||||||
primitive_count: self.primitives.len() as u32,
|
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,
|
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))
|
Ok(Camera::Realistic(camera))
|
||||||
}
|
}
|
||||||
"spherical" => {
|
"spherical" => {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use shared::spectra::{
|
||||||
cie::SWATCHES_RAW, DenselySampledSpectrum, PiecewiseLinearSpectrum, RGBColorSpace,
|
cie::SWATCHES_RAW, DenselySampledSpectrum, PiecewiseLinearSpectrum, RGBColorSpace,
|
||||||
};
|
};
|
||||||
use shared::utils::math::{linear_least_squares, SquareMatrix};
|
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::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ const SWATCH_REFLECTANCES: LazyLock<[Spectrum; N_SWATCH_REFLECTANCES]> = LazyLoc
|
||||||
std::array::from_fn(|i| {
|
std::array::from_fn(|i| {
|
||||||
let raw_data = SWATCHES_RAW[i];
|
let raw_data = SWATCHES_RAW[i];
|
||||||
let pls = PiecewiseLinearSpectrum::from_interleaved(raw_data, false);
|
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::Arena;
|
||||||
|
use crate::{FileLoc, ParameterDictionary};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use shared::core::filter::Filter;
|
use shared::core::filter::Filter;
|
||||||
use shared::core::geometry::{Bounds2f, Point2f, Vector2f};
|
use shared::core::geometry::{Bounds2f, Point2f, Vector2f};
|
||||||
use shared::filters::*;
|
use shared::filters::*;
|
||||||
|
use shared::utils::sampling::PiecewiseConstant2D;
|
||||||
use shared::{Array2D, Float};
|
use shared::{Array2D, Float};
|
||||||
|
|
||||||
pub trait FilterFactory {
|
pub trait FilterFactory {
|
||||||
|
|
|
||||||
|
|
@ -256,8 +256,8 @@ impl HostImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_channel(&mut self, p: Point2i, values: &ImageChannelValues) {
|
pub fn set_channel(&mut self, p: Point2i, c: i32, val: Float) {
|
||||||
self.inner.set_channel(p, values[i]);
|
self.inner.set_channel(p, c, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_channels(&self, desc: &ImageChannelDesc) -> Self {
|
pub fn select_channels(&self, desc: &ImageChannelDesc) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
use super::HostImage;
|
use super::HostImage;
|
||||||
use crate::core::image::pixel::PixelStorageTrait;
|
|
||||||
use crate::core::image::PixelStorage;
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use shared::core::color::ColorEncoding;
|
use shared::core::color::ColorEncoding;
|
||||||
use shared::core::geometry::{Bounds2i, Point2i};
|
use shared::core::geometry::{Bounds2i, Point2i};
|
||||||
|
|
@ -18,98 +16,84 @@ pub struct ResampleWeight {
|
||||||
impl HostImage {
|
impl HostImage {
|
||||||
pub fn flip_y(&mut self) {
|
pub fn flip_y(&mut self) {
|
||||||
let res = self.inner.resolution;
|
let res = self.inner.resolution;
|
||||||
let nc = self.inner.n_channels as usize;
|
let nc = self.inner.n_channels;
|
||||||
|
|
||||||
match self.inner.format {
|
for y in 0..res.y() / 2 {
|
||||||
PixelFormat::U8 => flip_y_kernel(self.inner.pixels.as_u8_mut(), res, nc),
|
let y2 = res.y() - 1 - y;
|
||||||
PixelFormat::F16 => flip_y_kernel(self.inner.pixels.as_f16_mut(), res, nc),
|
for x in 0..res.x() {
|
||||||
PixelFormat::F32 => flip_y_kernel(self.inner.pixels.as_f32_slice_mut(), res, nc),
|
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 {
|
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(
|
let new_res = Point2i::new(
|
||||||
bounds.p_max.x() - bounds.p_min.x(),
|
bounds.p_max.x() - bounds.p_min.x(),
|
||||||
bounds.p_max.y() - bounds.p_min.y(),
|
bounds.p_max.y() - bounds.p_min.y(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let new_names = self.channel_names.clone();
|
|
||||||
let mut new_image =
|
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 {
|
for y in 0..new_res.y() {
|
||||||
PixelFormat::U8 => crop_kernel(
|
for x in 0..new_res.x() {
|
||||||
self.inner.pixels.as_u8(),
|
let src = Point2i::new(bounds.p_min.x() + x, bounds.p_min.y() + y);
|
||||||
new_image.inner.pixels.as_u8_mut(),
|
let dst = Point2i::new(x, y);
|
||||||
self.inner.resolution,
|
for c in 0..nc {
|
||||||
bounds,
|
let val = self.inner.get_channel(src, c);
|
||||||
n_channels,
|
new_image.inner.set_channel(dst, c, val);
|
||||||
),
|
}
|
||||||
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,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new_image
|
new_image
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_rect_out(&self, extent: Bounds2i, buf: &mut [Float], wrap: WrapMode2D) {
|
pub fn copy_rect_out(&self, extent: Bounds2i, buf: &mut [Float], wrap: WrapMode2D) {
|
||||||
match self.inner.format {
|
let w = (extent.p_max.x() - extent.p_min.x()) as usize;
|
||||||
PixelFormat::U8 => {
|
let channels = self.inner.n_channels as usize;
|
||||||
copy_rect_out_kernel(self.inner.pixels.as_u8(), self, extent, buf, wrap)
|
|
||||||
}
|
buf.par_chunks_mut(w * channels)
|
||||||
PixelFormat::F16 => {
|
.enumerate()
|
||||||
copy_rect_out_kernel(self.inner.pixels.as_f16(), self, extent, buf, wrap)
|
.for_each(|(y_rel, row_buf)| {
|
||||||
}
|
let y = extent.p_min.y() + y_rel as i32;
|
||||||
PixelFormat::F32 => {
|
for x_rel in 0..w {
|
||||||
copy_rect_out_kernel(self.inner.pixels.as_f32_slice(), self, extent, buf, wrap)
|
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]) {
|
pub fn copy_rect_in(&mut self, extent: Bounds2i, buf: &[Float]) {
|
||||||
let res = self.inner.resolution;
|
let w = (extent.p_max.x() - extent.p_min.x()) as usize;
|
||||||
let n_channels = self.inner.n_channels as usize;
|
let channels = self.inner.n_channels as usize;
|
||||||
let encoding = self.inner.encoding;
|
|
||||||
let format = self.inner.format;
|
|
||||||
|
|
||||||
match format {
|
for (y_rel, row) in buf.chunks(w * channels).enumerate() {
|
||||||
PixelFormat::U8 => copy_rect_in_kernel(
|
let y = extent.p_min.y() + y_rel as i32;
|
||||||
self.inner.pixels.as_u8_mut(),
|
if y < 0 || y >= self.inner.resolution.y() {
|
||||||
res,
|
continue;
|
||||||
n_channels,
|
}
|
||||||
encoding,
|
|
||||||
extent,
|
for x_rel in 0..w {
|
||||||
buf,
|
let x = extent.p_min.x() + x_rel as i32;
|
||||||
),
|
if x < 0 || x >= self.inner.resolution.x() {
|
||||||
PixelFormat::F16 => copy_rect_in_kernel(
|
continue;
|
||||||
self.inner.pixels.as_f16_mut(),
|
}
|
||||||
res,
|
for c in 0..channels {
|
||||||
n_channels,
|
let val = row[x_rel * channels + c];
|
||||||
encoding,
|
self.inner.set_channel(Point2i::new(x, y), c as i32, val);
|
||||||
extent,
|
}
|
||||||
buf,
|
}
|
||||||
),
|
|
||||||
PixelFormat::F32 => copy_rect_in_kernel(
|
|
||||||
self.inner.pixels.as_f32_slice_mut(),
|
|
||||||
res,
|
|
||||||
n_channels,
|
|
||||||
encoding,
|
|
||||||
extent,
|
|
||||||
buf,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,6 +164,7 @@ impl HostImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_res = Point2i::new((old.x() / 2).max(1), (old.y() / 2).max(1));
|
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(
|
let mut next = HostImage::new(
|
||||||
prev.inner.format,
|
prev.inner.format,
|
||||||
new_res,
|
new_res,
|
||||||
|
|
@ -187,177 +172,37 @@ impl HostImage {
|
||||||
prev.inner.encoding,
|
prev.inner.encoding,
|
||||||
);
|
);
|
||||||
|
|
||||||
match next.inner.format {
|
for y in 0..new_res.y() {
|
||||||
PixelFormat::U8 => downsample_kernel(
|
for x in 0..new_res.x() {
|
||||||
next.inner.pixels.as_u8_mut(),
|
let src_x = x * 2;
|
||||||
new_res,
|
let src_y = y * 2;
|
||||||
&prev,
|
for c in 0..nc {
|
||||||
internal_wrap,
|
let mut sum = 0.0;
|
||||||
),
|
let mut count = 0.0;
|
||||||
PixelFormat::F16 => downsample_kernel(
|
for dy in 0..2i32 {
|
||||||
next.inner.pixels.as_f16_mut(),
|
for dx in 0..2i32 {
|
||||||
new_res,
|
let sx = src_x + dx;
|
||||||
&prev,
|
let sy = src_y + dy;
|
||||||
internal_wrap,
|
if sx < old.x() && sy < old.y() {
|
||||||
),
|
sum += prev.inner.get_channel_with_wrap(
|
||||||
PixelFormat::F32 => downsample_kernel(
|
Point2i::new(sx, sy), c, internal_wrap,
|
||||||
next.inner.pixels.as_f32_slice_mut(),
|
);
|
||||||
new_res,
|
count += 1.0;
|
||||||
&prev,
|
}
|
||||||
internal_wrap,
|
}
|
||||||
),
|
}
|
||||||
|
let avg = if count > 0.0 { sum / count } else { 0.0 };
|
||||||
|
next.inner.set_channel(Point2i::new(x, y), c, avg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
levels.push(next);
|
levels.push(next);
|
||||||
}
|
}
|
||||||
levels
|
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 {
|
|
||||||
let src_x = x * 2;
|
|
||||||
for c in 0..channels {
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resample_weights(old_res: usize, new_res: usize) -> Vec<ResampleWeight> {
|
fn resample_weights(old_res: usize, new_res: usize) -> Vec<ResampleWeight> {
|
||||||
let filter_radius = 2.0;
|
let filter_radius = 2.0;
|
||||||
let tau = 2.0;
|
let tau = 2.0;
|
||||||
|
|
@ -416,7 +261,6 @@ fn compute_resize_tile(
|
||||||
|
|
||||||
let mut x_buf = vec![0.0; n_channels * ny_in * nx_out];
|
let mut x_buf = vec![0.0; n_channels * ny_in * nx_out];
|
||||||
|
|
||||||
// Resize X
|
|
||||||
for y in 0..ny_in {
|
for y in 0..ny_in {
|
||||||
for x in 0..nx_out {
|
for x in 0..nx_out {
|
||||||
let x_global = out_extent.p_min.x() + x as i32;
|
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];
|
let mut out_buf = vec![0.0; n_channels * nx_out * ny_out];
|
||||||
|
|
||||||
// Resize Y
|
|
||||||
for x in 0..nx_out {
|
for x in 0..nx_out {
|
||||||
for y in 0..ny_out {
|
for y in 0..ny_out {
|
||||||
let y_global = out_extent.p_min.y() + y as i32;
|
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 media: &'a HashMap<String, Arc<Medium>>,
|
||||||
pub named_materials: &'a HashMap<String, Material>,
|
pub named_materials: &'a HashMap<String, Material>,
|
||||||
pub materials: &'a Vec<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> {
|
impl<'a> SceneLookup<'a> {
|
||||||
|
|
@ -154,7 +154,6 @@ impl BasicScene {
|
||||||
job: None,
|
job: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let arena_sampler = Arc::clone(&arena);
|
|
||||||
let sampler_film = Arc::clone(&film_instance);
|
let sampler_film = Arc::clone(&film_instance);
|
||||||
let sampler_job = run_async(move || {
|
let sampler_job = run_async(move || {
|
||||||
let res = sampler_film.as_ref().base().full_resolution;
|
let res = sampler_film.as_ref().base().full_resolution;
|
||||||
|
|
@ -163,7 +162,7 @@ impl BasicScene {
|
||||||
&sampler.parameters,
|
&sampler.parameters,
|
||||||
res,
|
res,
|
||||||
&sampler.loc,
|
&sampler.loc,
|
||||||
&arena_sampler,
|
&arena,
|
||||||
)
|
)
|
||||||
.map_err(|e| anyhow!("Failed to create sampler: {}", e))
|
.map_err(|e| anyhow!("Failed to create sampler: {}", e))
|
||||||
});
|
});
|
||||||
|
|
@ -556,9 +555,9 @@ impl BasicScene {
|
||||||
shape_entities: &[ShapeSceneEntity],
|
shape_entities: &[ShapeSceneEntity],
|
||||||
textures: &NamedTextures,
|
textures: &NamedTextures,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> HashMap<usize, Vec<Light>> {
|
) -> HashMap<usize, Vec<Ptr<Light>>> {
|
||||||
let light_state = self.light_state.lock();
|
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() {
|
for (i, entity) in shape_entities.iter().enumerate() {
|
||||||
let light_idx = match entity.light_index {
|
let light_idx = match entity.light_index {
|
||||||
|
|
@ -592,7 +591,7 @@ impl BasicScene {
|
||||||
|
|
||||||
let render_from_light = *entity.render_from_object;
|
let render_from_light = *entity.render_from_object;
|
||||||
|
|
||||||
let lights: Vec<Light> = shapes
|
let lights: Vec<Ptr<Light>> = shapes
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|shape| {
|
.filter_map(|shape| {
|
||||||
match crate::core::light::create_area_light(
|
match crate::core::light::create_area_light(
|
||||||
|
|
@ -676,7 +675,7 @@ impl BasicScene {
|
||||||
mtl: Material,
|
mtl: Material,
|
||||||
alpha_tex: &Option<Arc<FloatTexture>>,
|
alpha_tex: &Option<Arc<FloatTexture>>,
|
||||||
mi: MediumInterface,
|
mi: MediumInterface,
|
||||||
al_params: Option<&AreaLightEntity>,
|
al_params: Option<&SceneEntity>,
|
||||||
render_from_light: Transform,
|
render_from_light: Transform,
|
||||||
film_cs: Option<&RGBColorSpace>,
|
film_cs: Option<&RGBColorSpace>,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
|
|
@ -938,16 +937,15 @@ impl BasicScene {
|
||||||
.get(&shape_ctx.entity_index)
|
.get(&shape_ctx.entity_index)
|
||||||
.and_then(|lights| lights.get(shape_ctx.shape_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 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)))
|
Primitive::Simple(SimplePrimitive::new(shape_ptr, Ptr::from(&mtl)))
|
||||||
} else {
|
} else {
|
||||||
Primitive::Geometric(GeometricPrimitive::new(
|
Primitive::Geometric(GeometricPrimitive::new(
|
||||||
shape_ptr,
|
shape_ptr,
|
||||||
arena.alloc(mtl),
|
arena.alloc(mtl),
|
||||||
area_light,
|
light_ptr,
|
||||||
mi.clone(),
|
mi.clone(),
|
||||||
arena.upload(alpha_tex),
|
arena.upload(alpha_tex),
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::core::film::{CreateFilmBase, PixelSensor};
|
use crate::core::film::{CreateFilmBase, CreatePixelSensor};
|
||||||
use crate::Arena;
|
use crate::Arena;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use shared::core::camera::CameraTransform;
|
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;
|
use shared::spectra::RGBColorSpace;
|
||||||
|
|
||||||
impl CreateFilm for RGBFilm {
|
impl CreateFilm for RGBFilm {
|
||||||
|
|
@ -13,13 +13,13 @@ impl CreateFilm for RGBFilm {
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
_camera_transform: Option<CameraTransform>,
|
_camera_transform: Option<CameraTransform>,
|
||||||
loc: &FileLoc,
|
loc: &FileLoc,
|
||||||
_arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Film> {
|
) -> Result<Film> {
|
||||||
let colorspace = params.color_space.as_ref().cloned().unwrap_or_else(crate::spectra::default_colorspace_arc);
|
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 max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY)?;
|
||||||
let write_fp16 = params.get_one_bool("savefp16", true)?;
|
let write_fp16 = params.get_one_bool("savefp16", true)?;
|
||||||
let sensor = PixelSensor::create(params, colorspace.clone(), exposure_time, loc)?;
|
let sensor = PixelSensor::create(params, colorspace.clone(), exposure_time, loc, arena)?;
|
||||||
let film_base = FilmBase::create(params, filter, Some(&sensor.device()), loc)?;
|
let film_base = FilmBase::create(params, filter, Some(&sensor), loc)?;
|
||||||
let film = RGBFilm::new(film_base, &colorspace, max_component_value, write_fp16);
|
let film = RGBFilm::new(film_base, &colorspace, max_component_value, write_fp16);
|
||||||
Ok(Film::RGB(film))
|
Ok(Film::RGB(film))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use shared::core::light::{Light, LightBase, LightType};
|
||||||
use shared::core::medium::{Medium, MediumInterface};
|
use shared::core::medium::{Medium, MediumInterface};
|
||||||
use shared::core::shape::{Shape, ShapeTrait};
|
use shared::core::shape::{Shape, ShapeTrait};
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::core::texture::{SpectrumType, TextureEvalContext};
|
use shared::core::texture::{SpectrumType, TextureEvalContext, GPUFloatTexture};
|
||||||
use shared::lights::DiffuseAreaLight;
|
use shared::lights::DiffuseAreaLight;
|
||||||
use shared::spectra::RGBColorSpace;
|
use shared::spectra::RGBColorSpace;
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use crate::core::image::{HostImage, ImageIO};
|
use crate::core::image::{HostImage, ImageIO};
|
||||||
use crate::core::light::lookup_spectrum;
|
use crate::core::light::lookup_spectrum;
|
||||||
use crate::core::spectrum::spectrum_to_photometric;
|
use crate::core::spectrum::spectrum_to_photometric;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::sampling::PiecewiseConstant2D;
|
|
||||||
use crate::utils::resolve_filename;
|
use crate::utils::resolve_filename;
|
||||||
use crate::{Arena, FileLoc, ParameterDictionary};
|
use crate::{Arena, FileLoc, ParameterDictionary};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{anyhow, Result};
|
||||||
use shared::core::geometry::Point2i;
|
use shared::core::geometry::Point2i;
|
||||||
use shared::core::light::{Light, LightBase, LightType};
|
use shared::core::light::{Light, LightBase, LightType};
|
||||||
use shared::core::medium::{Medium, MediumInterface};
|
use shared::core::medium::{Medium, MediumInterface};
|
||||||
|
|
@ -16,8 +13,10 @@ use shared::core::spectrum::Spectrum;
|
||||||
use shared::core::texture::SpectrumType;
|
use shared::core::texture::SpectrumType;
|
||||||
use shared::lights::GoniometricLight;
|
use shared::lights::GoniometricLight;
|
||||||
use shared::spectra::RGBColorSpace;
|
use shared::spectra::RGBColorSpace;
|
||||||
|
use shared::utils::sampling::PiecewiseConstant2D;
|
||||||
use shared::utils::{Ptr, Transform};
|
use shared::utils::{Ptr, Transform};
|
||||||
use shared::{Float, PI};
|
use shared::{Float, PI};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
pub fn create(
|
pub fn create(
|
||||||
render_from_light: Transform,
|
render_from_light: Transform,
|
||||||
|
|
@ -25,11 +24,10 @@ pub fn create(
|
||||||
params: &ParameterDictionary,
|
params: &ParameterDictionary,
|
||||||
loc: &FileLoc,
|
loc: &FileLoc,
|
||||||
_shape: &Shape,
|
_shape: &Shape,
|
||||||
_alpha_text: &FloatTexture,
|
_alpha_tex: &FloatTexture,
|
||||||
colorspace: Option<&RGBColorSpace>,
|
colorspace: Option<&RGBColorSpace>,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Light> {
|
) -> Result<Light> {
|
||||||
|
|
||||||
let default_cs = crate::spectra::default_colorspace();
|
let default_cs = crate::spectra::default_colorspace();
|
||||||
let cs = colorspace.unwrap_or(&default_cs);
|
let cs = colorspace.unwrap_or(&default_cs);
|
||||||
let i = params
|
let i = params
|
||||||
|
|
@ -39,14 +37,13 @@ pub fn create(
|
||||||
SpectrumType::Illuminant,
|
SpectrumType::Illuminant,
|
||||||
)
|
)
|
||||||
.expect("Could not retrieve spectrum");
|
.expect("Could not retrieve spectrum");
|
||||||
|
|
||||||
let mut scale = params.get_one_float("scale", 1.)?;
|
let mut scale = params.get_one_float("scale", 1.)?;
|
||||||
let filename = resolve_filename(¶ms.get_one_string("filename", "")?);
|
let filename = resolve_filename(¶ms.get_one_string("filename", "")?);
|
||||||
let image: Ptr<HostImage> = if filename.is_empty() {
|
|
||||||
Ptr::null()
|
let host_image = if !filename.is_empty() {
|
||||||
} else {
|
|
||||||
let im = HostImage::read(Path::new(&filename), None)
|
let im = HostImage::read(Path::new(&filename), None)
|
||||||
.map_err(|e| anyhow!("could not load image '{}': {}", filename, e))?;
|
.map_err(|e| anyhow!("could not load image '{}': {}", filename, e))?;
|
||||||
|
|
||||||
let loaded = im.image;
|
let loaded = im.image;
|
||||||
let res = loaded.resolution();
|
let res = loaded.resolution();
|
||||||
|
|
||||||
|
|
@ -56,7 +53,6 @@ pub fn create(
|
||||||
filename
|
filename
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.x() != res.y() {
|
if res.x() != res.y() {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"image resolution ({}, {}) is non-square; unlikely to be an equal-area map",
|
"image resolution ({}, {}) is non-square; unlikely to be an equal-area map",
|
||||||
|
|
@ -65,15 +61,19 @@ 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);
|
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 {
|
if phi_v > 0.0 {
|
||||||
let k_e = compute_emissive_power(&image);
|
if let Some(ref img) = host_image {
|
||||||
scale *= phi_v / k_e;
|
let k_e = compute_emissive_power(img);
|
||||||
|
scale *= phi_v / k_e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let swap_yz: [Float; 16] = [
|
let swap_yz: [Float; 16] = [
|
||||||
|
|
@ -81,7 +81,7 @@ pub fn create(
|
||||||
];
|
];
|
||||||
let t =
|
let t =
|
||||||
Transform::from_flat(&swap_yz).expect("Could not create transform for GoniometricLight");
|
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 {
|
let mi = match medium {
|
||||||
Some(m) => {
|
Some(m) => {
|
||||||
|
|
@ -93,31 +93,35 @@ pub fn create(
|
||||||
}
|
}
|
||||||
None => MediumInterface::default(),
|
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 iemit = lookup_spectrum(&i);
|
||||||
|
|
||||||
let image_ptr = if !image.is_null() {
|
// Build distribution from host image, then upload both to arena
|
||||||
let distrib = PiecewiseConstant2D::from_image(&image);
|
let (image_ptr, distrib_ptr) = match host_image {
|
||||||
let distrib_ptr = arena.alloc(distrib);
|
Some(img) => {
|
||||||
let img_ptr = arena.alloc(image);
|
let distrib = PiecewiseConstant2D::from_image(&img.inner);
|
||||||
(img_ptr, distrib_ptr)
|
(arena.alloc(img.inner), arena.alloc(distrib))
|
||||||
} else {
|
}
|
||||||
(Ptr::null(), Ptr::null())
|
None => (Ptr::null(), Ptr::null()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let specific = GoniometricLight {
|
let specific = GoniometricLight {
|
||||||
base,
|
base,
|
||||||
iemit: arena.alloc(*iemit),
|
iemit: arena.alloc((*iemit).clone()),
|
||||||
scale,
|
scale,
|
||||||
image: image_ptr.0,
|
image: image_ptr,
|
||||||
distrib: image_ptr.1,
|
distrib: distrib_ptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Light::Goniometric(specific))
|
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 res = image.resolution();
|
||||||
let rgb_desc = image.get_channel_desc(&["R", "G", "B"]);
|
let rgb_desc = image.get_channel_desc(&["R", "G", "B"]);
|
||||||
let y_desc = image.get_channel_desc(&["Y"]);
|
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::core::spectrum::spectrum_to_photometric;
|
||||||
use crate::spectra::get_spectra_context;
|
use crate::spectra::get_spectra_context;
|
||||||
use crate::utils::resolve_filename;
|
use crate::utils::resolve_filename;
|
||||||
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
|
|
||||||
use crate::{Arena, FileLoc, ParameterDictionary, ArenaUpload, Upload};
|
use crate::{Arena, FileLoc, ParameterDictionary, ArenaUpload, Upload};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
use crate::core::image::{HostImage, ImageIO};
|
use crate::core::image::{HostImage, ImageIO};
|
||||||
use crate::core::spectrum::spectrum_to_photometric;
|
use crate::core::spectrum::spectrum_to_photometric;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::sampling::PiecewiseConstant2D;
|
|
||||||
use crate::utils::resolve_filename;
|
use crate::utils::resolve_filename;
|
||||||
use crate::{Arena, FileLoc, ParameterDictionary, ArenaUpload};
|
use crate::{Arena, ArenaUpload, FileLoc, ParameterDictionary};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{anyhow, Result};
|
||||||
use shared::Float;
|
|
||||||
use shared::core::geometry::{
|
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::light::{Light, LightBase, LightType};
|
||||||
use shared::core::medium::{Medium, MediumInterface};
|
use shared::core::medium::{Medium, MediumInterface};
|
||||||
|
|
@ -15,8 +13,10 @@ use shared::core::shape::Shape;
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::lights::ProjectionLight;
|
use shared::lights::ProjectionLight;
|
||||||
use shared::spectra::RGBColorSpace;
|
use shared::spectra::RGBColorSpace;
|
||||||
use shared::utils::Transform;
|
|
||||||
use shared::utils::math::{radians, square};
|
use shared::utils::math::{radians, square};
|
||||||
|
use shared::utils::sampling::PiecewiseConstant2D;
|
||||||
|
use shared::utils::Transform;
|
||||||
|
use shared::Float;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub fn create(
|
pub fn create(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::core::light::lookup_spectrum;
|
use crate::core::light::lookup_spectrum;
|
||||||
use crate::core::spectrum::spectrum_to_photometric;
|
use crate::core::spectrum::spectrum_to_photometric;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
use crate::{Arena, FileLoc, ParameterDictionary};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use shared::core::geometry::{Frame, Point3f, VectorLike};
|
use shared::core::geometry::{Frame, Point3f, VectorLike};
|
||||||
use shared::core::light::{Light, LightBase, LightType};
|
use shared::core::light::{Light, LightBase, LightType};
|
||||||
|
|
@ -22,6 +22,7 @@ trait CreateSpotLight {
|
||||||
scale: Float,
|
scale: Float,
|
||||||
cos_falloff_start: Float,
|
cos_falloff_start: Float,
|
||||||
total_width: Float,
|
total_width: Float,
|
||||||
|
arena: &Arena
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,6 +34,7 @@ impl CreateSpotLight for SpotLight {
|
||||||
scale: Float,
|
scale: Float,
|
||||||
cos_falloff_start: Float,
|
cos_falloff_start: Float,
|
||||||
total_width: Float,
|
total_width: Float,
|
||||||
|
arena: &Arena
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let base = LightBase::new(
|
let base = LightBase::new(
|
||||||
LightType::DeltaPosition,
|
LightType::DeltaPosition,
|
||||||
|
|
@ -41,7 +43,7 @@ impl CreateSpotLight for SpotLight {
|
||||||
);
|
);
|
||||||
|
|
||||||
let i = lookup_spectrum(&le);
|
let i = lookup_spectrum(&le);
|
||||||
let iemit = arena.alloc(i);
|
let iemit = arena.alloc_arc(i);
|
||||||
Self {
|
Self {
|
||||||
base,
|
base,
|
||||||
iemit,
|
iemit,
|
||||||
|
|
@ -100,7 +102,7 @@ pub fn create(
|
||||||
None => MediumInterface::default(),
|
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);
|
arena.alloc(specific);
|
||||||
Ok(Light::Spot(specific))
|
Ok(Light::Spot(specific))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::core::image::{HostImage, ImageIO};
|
use crate::core::image::{HostImage, ImageIO};
|
||||||
use crate::core::shape::{CreateShape, ALL_BILINEAR_MESHES};
|
use crate::core::shape::{CreateShape, ALL_BILINEAR_MESHES};
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::sampling::PiecewiseConstant2D;
|
|
||||||
use crate::{Arena, FileLoc, ParameterDictionary};
|
use crate::{Arena, FileLoc, ParameterDictionary};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::shapes::{BilinearPatchMesh, BilinearPatchShape};
|
use shared::shapes::{BilinearPatchMesh, BilinearPatchShape};
|
||||||
|
use shared::utils::sampling::PiecewiseConstant2D;
|
||||||
use shared::{Ptr, Transform};
|
use shared::{Ptr, Transform};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
@ -95,7 +95,7 @@ impl CreateShape for BilinearPatchShape {
|
||||||
let im = HostImage::read(Path::new(&filename), None)?;
|
let im = HostImage::read(Path::new(&filename), None)?;
|
||||||
let mut img = im.image;
|
let mut img = im.image;
|
||||||
img.flip_y();
|
img.flip_y();
|
||||||
Some(PiecewiseConstant2D::from_image(&img))
|
Some(PiecewiseConstant2D::from_image(&img.inner))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -108,7 +108,7 @@ impl CreateShape for BilinearPatchShape {
|
||||||
&p,
|
&p,
|
||||||
&n,
|
&n,
|
||||||
&uv,
|
&uv,
|
||||||
image_dist,
|
image_dist.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let host_arc = Arc::new(host);
|
let host_arc = Arc::new(host);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::utils::sampling::PiecewiseConstant2D;
|
|
||||||
use anyhow::{bail, Context, Result as AnyResult};
|
use anyhow::{bail, Context, Result as AnyResult};
|
||||||
use ply_rs::parser::Parser;
|
use ply_rs::parser::Parser;
|
||||||
use ply_rs::ply::{DefaultElement, Property};
|
use ply_rs::ply::{DefaultElement, Property};
|
||||||
use shared::core::geometry::{Normal3f, Point2f, Point3f, VectorLike};
|
use shared::core::geometry::{Normal3f, Point2f, Point3f, VectorLike};
|
||||||
use shared::shapes::mesh::TriangleMesh;
|
use shared::shapes::mesh::TriangleMesh;
|
||||||
|
use shared::utils::sampling::PiecewiseConstant2D;
|
||||||
use shared::Transform;
|
use shared::Transform;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::spectra::cie::*;
|
use shared::spectra::cie::*;
|
||||||
use shared::spectra::{DenselySampledSpectrum, PiecewiseLinearSpectrum};
|
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::collections::HashMap;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
|
@ -11,13 +11,11 @@ pub fn create_cie(data: &[Float]) -> DenselySampledSpectrum {
|
||||||
95 => (300.0, 5.0),
|
95 => (300.0, 5.0),
|
||||||
n => panic!("Unexpected CIE data length: {}", n),
|
n => panic!("Unexpected CIE data length: {}", n),
|
||||||
};
|
};
|
||||||
|
|
||||||
let lambdas: Vec<Float> = (0..data.len())
|
let lambdas: Vec<Float> = (0..data.len())
|
||||||
.map(|i| start_lambda + i as Float * step)
|
.map(|i| start_lambda + i as Float * step)
|
||||||
.collect();
|
.collect();
|
||||||
|
let buffer = PiecewiseLinearSpectrum::new(gvec_from_slice(&lambdas), gvec_from_slice(data));
|
||||||
let buffer = PiecewiseLinearSpectrum::new(lambdas, data.to_vec());
|
let spec = Spectrum::Piecewise(leak(buffer));
|
||||||
let spec = Spectrum::Piecewise(Ptr::from(&*buffer));
|
|
||||||
DenselySampledSpectrum::from_spectrum(&spec)
|
DenselySampledSpectrum::from_spectrum(&spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,8 @@ pub fn default_colorspace_arc() -> Arc<RGBColorSpace> {
|
||||||
|
|
||||||
pub fn default_colorspace_ref() -> &'static RGBColorSpace {
|
pub fn default_colorspace_ref() -> &'static RGBColorSpace {
|
||||||
static CS: OnceLock<RGBColorSpace> = OnceLock::new();
|
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 {
|
pub fn default_illuminant() -> Spectrum {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue