Continuing cleanup
This commit is contained in:
parent
384a0019d8
commit
72acb8ccdf
40 changed files with 369 additions and 293 deletions
|
|
@ -167,6 +167,17 @@ impl Pixels {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn as_u8(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn as_f16(&mut self) -> &[u16] {
|
||||
assert_eq!(self.format, PixelFormat::F16);
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self.data.as_ptr() as *const u16, self.data.len() / 2)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_u8_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.data
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,4 +12,4 @@ pub use cylinder::*;
|
|||
pub use disk::*;
|
||||
pub use sphere::*;
|
||||
pub use triangle::*;
|
||||
pub use mesh::*;
|
||||
pub use mesh::{TriangleMesh, BilinearPatchMesh};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ use super::sampled::{LAMBDA_MAX, LAMBDA_MIN};
|
|||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||
use crate::spectra::{SampledSpectrum, SampledWavelengths, N_SPECTRUM_SAMPLES};
|
||||
use crate::utils::find_interval;
|
||||
use crate::{gvec, gvec_with_capacity, Float, GVec, Ptr};
|
||||
use crate::utils::math::square;
|
||||
use crate::{gvec, gvec_from_slice, gvec_with_capacity, Float, GVec, Ptr};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
|
|
@ -88,6 +89,41 @@ impl DenselySampledSpectrum {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn generate_cie_d(temperature: Float) -> Self {
|
||||
let cct = temperature * 1.4388 / 1.4380;
|
||||
|
||||
if cct < 4000.0 {
|
||||
return Self::from_function(
|
||||
|lambda| BlackbodySpectrum::new(cct).evaluate(lambda),
|
||||
LAMBDA_MIN,
|
||||
LAMBDA_MAX,
|
||||
);
|
||||
}
|
||||
|
||||
let x = if cct < 7000. {
|
||||
-4.607 * 1e9 / cct.powi(3) + 2.9678 * 1e6 / square(cct) + 0.09911 * 1e3 / cct + 0.244063
|
||||
} else {
|
||||
-2.0064 * 1e9 / cct.powi(3) + 1.9018 * 1e6 / square(cct) + 0.24748 * 1e3 / cct + 0.23704
|
||||
};
|
||||
let y = -3. * x + 2.87 * x - 0.275;
|
||||
let m = 0.0241 + 0.2562 * x - 0.7341 * y;
|
||||
let m1 = (-1.3515 - 1.7703 * x + 5.9114 * y) / m;
|
||||
let m2 = (0.0300 - 31.4424 * x + 30.0717 * y) / m;
|
||||
|
||||
let mut coarse_values = gvec_with_capacity(N_CIES);
|
||||
for i in 0..N_CIES {
|
||||
coarse_values.push((CIE_S0[i] + CIE_S1[i] * m1 + CIE_S2[i] * m2) * 0.01);
|
||||
}
|
||||
|
||||
let temp_pls = PiecewiseLinearSpectrum {
|
||||
lambdas: gvec_from_slice(&CIE_S_LAMBDA),
|
||||
values: gvec_from_slice(&coarse_values),
|
||||
count: N_CIES as u32,
|
||||
};
|
||||
|
||||
Self::from_function(|lambda| temp_pls.evaluate(lambda), LAMBDA_MIN, LAMBDA_MAX)
|
||||
}
|
||||
|
||||
pub fn scale(&mut self, s: Float) {
|
||||
for v in &mut self.values {
|
||||
*v *= s;
|
||||
|
|
@ -183,7 +219,6 @@ impl PiecewiseLinearSpectrum {
|
|||
self.count.try_into().unwrap()
|
||||
}
|
||||
|
||||
|
||||
#[inline(always)]
|
||||
pub fn lambda(&self, idx: u32) -> Float {
|
||||
unsafe { *self.lambdas.as_ptr().add(idx as usize) }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rayon::prelude::*;
|
||||
use shared::core::aggregates::{BVHAggregate, LinearBVHNode};
|
||||
use shared::core::aggregates::{BVHAggregate as DeviceBVHAggregate, LinearBVHNode};
|
||||
use shared::core::geometry::{Bounds3f, Point3f, Ray, Vector3f};
|
||||
use shared::core::primitive::{Primitive, PrimitiveTrait};
|
||||
use shared::core::shape::ShapeIntersection;
|
||||
|
|
@ -890,8 +890,6 @@ impl<P: PrimitiveTrait + Clone + Send + Sync> BVHAggregate<P> {
|
|||
|
||||
impl BVHAggregate<Primitive> {
|
||||
pub fn to_device(&self, arena: &mut Arena) -> DeviceBVHAggregate {
|
||||
let (prims_ptr, _) = arena.alloc_slice(&self.primitives);
|
||||
|
||||
let shared_nodes: Vec<shared::core::aggregates::LinearBVHNode> = self.nodes
|
||||
.iter()
|
||||
.map(|n| shared::core::aggregates::LinearBVHNode {
|
||||
|
|
@ -902,13 +900,12 @@ impl BVHAggregate<Primitive> {
|
|||
pad: 0,
|
||||
})
|
||||
.collect();
|
||||
let (nodes_ptr, _) = arena.alloc_slice(&shared_nodes);
|
||||
|
||||
DeviceBVHAggregate {
|
||||
max_prims_in_node: self.max_prims_in_node as u32,
|
||||
primitives: prims_ptr,
|
||||
primitives: gvec_from_slice(&self.primitives),
|
||||
primitive_count: self.primitives.len() as u32,
|
||||
nodes: nodes_ptr,
|
||||
nodes: gvec_from_slice(&self.shared_nodes),
|
||||
node_count: self.nodes.len() as u32,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use crate::core::image::ImageMetadata;
|
||||
use crate::core::image::{Image, ImageIO};
|
||||
use crate::core::image::{HostImage, ImageIO, ImageMetadata};
|
||||
use crate::globals::get_options;
|
||||
use crate::utils::read_float_file;
|
||||
use crate::{Arena, FileLoc, ParameterDictionary};
|
||||
use crate::{Arena, FileLoc, ParameterDictionary, ArenaUpload};
|
||||
use anyhow::{anyhow, Result};
|
||||
use shared::cameras::*;
|
||||
use shared::core::camera::{Camera, CameraBase, CameraTrait, CameraTransform};
|
||||
|
|
@ -232,8 +231,8 @@ impl CameraFactory for Camera {
|
|||
}
|
||||
|
||||
let builtin_res = 256;
|
||||
let rasterize = |vert: &[Point2f]| -> Image {
|
||||
let mut image = Image::new(
|
||||
let rasterize = |vert: &[Point2f]| -> HostImage {
|
||||
let mut image = HostImage::new(
|
||||
PixelFormat::F32,
|
||||
Point2i::new(builtin_res, builtin_res),
|
||||
&["Y"],
|
||||
|
|
@ -279,12 +278,12 @@ impl CameraFactory for Camera {
|
|||
};
|
||||
|
||||
let aperture_name = params.get_one_string("aperture", "")?;
|
||||
let mut aperture_image: Option<Image> = None;
|
||||
let mut aperture_image: Option<HostImage> = None;
|
||||
|
||||
if !aperture_name.is_empty() {
|
||||
match aperture_name.as_str() {
|
||||
"gaussian" => {
|
||||
let mut img = Image::new(
|
||||
let mut img = HostImage::new(
|
||||
PixelFormat::F32,
|
||||
Point2i::new(builtin_res, builtin_res),
|
||||
&["Y"],
|
||||
|
|
@ -306,7 +305,7 @@ impl CameraFactory for Camera {
|
|||
aperture_image = Some(img);
|
||||
}
|
||||
"square" => {
|
||||
let mut img = Image::new(
|
||||
let mut img = HostImage::new(
|
||||
PixelFormat::F32,
|
||||
Point2i::new(builtin_res, builtin_res),
|
||||
&["Y"],
|
||||
|
|
@ -316,7 +315,7 @@ impl CameraFactory for Camera {
|
|||
let high = (0.75 * builtin_res as Float) as i32;
|
||||
for y in low..high {
|
||||
for x in low..high {
|
||||
img.set_channel(Point2i::new(x, y), 0, 4.0);
|
||||
img.inner.set_channel(Point2i::new(x, y), 0, 4.0);
|
||||
}
|
||||
}
|
||||
aperture_image = Some(img);
|
||||
|
|
@ -353,9 +352,9 @@ impl CameraFactory for Camera {
|
|||
aperture_image = Some(rasterize(&vert));
|
||||
}
|
||||
_ => {
|
||||
if let Ok(im) = Image::read(Path::new(&aperture_name), None) {
|
||||
if let Ok(im) = HostImage::read(Path::new(&aperture_name), None) {
|
||||
if im.image.n_channels() > 1 {
|
||||
let mut mono = Image::new(
|
||||
let mut mono = HostImage::new(
|
||||
PixelFormat::F32,
|
||||
im.image.resolution(),
|
||||
&["Y"],
|
||||
|
|
@ -366,7 +365,7 @@ impl CameraFactory for Camera {
|
|||
for x in 0..res.x() {
|
||||
let avg =
|
||||
im.image.get_channels(Point2i::new(x, y)).average();
|
||||
mono.set_channel(Point2i::new(x, y), 0, avg);
|
||||
mono.inner.set_channel(Point2i::new(x, y), 0, avg);
|
||||
}
|
||||
}
|
||||
aperture_image = Some(mono);
|
||||
|
|
@ -383,7 +382,8 @@ impl CameraFactory for Camera {
|
|||
&lens_params,
|
||||
focal_distance,
|
||||
aperture_diameter,
|
||||
Ptr::from(&*aperture_image.unwrap()),
|
||||
arena.upload(aperture_image)
|
||||
|
||||
);
|
||||
|
||||
arena.alloc(camera);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ impl CreateRGBToSpectrumTable for RGBToSpectrumTable {
|
|||
assert_eq!(z_nodes.len(), RES as usize);
|
||||
assert_eq!(coeffs.len(), (RES * RES * RES) as usize * 3 * 3);
|
||||
Self {
|
||||
n_nodes: z_nodes.len().try_into().unwrap(),
|
||||
z_nodes: gvec_from_slice(z_nodes),
|
||||
coeffs: gvec_from_slice(unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
|
|
|
|||
|
|
@ -87,8 +87,10 @@ impl CreatePixelSensor for PixelSensor {
|
|||
DenselySampledSpectrum::generate_cie_d(white_balance_temp)
|
||||
};
|
||||
|
||||
let d_ptr = arena.alloc(d_illum);
|
||||
|
||||
let sensor_illum: Option<Arc<Spectrum>> = if white_balance_temp != 0. {
|
||||
Some(Spectrum::Dense(d_illum.device()).into())
|
||||
Some(Spectrum::Dense(d_ptr).into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -150,8 +152,8 @@ impl CreatePixelSensor for PixelSensor {
|
|||
let g_bar = DenselySampledSpectrum::from_spectrum(g);
|
||||
let b_bar = DenselySampledSpectrum::from_spectrum(b);
|
||||
let r_ptr = arena.alloc(r_bar);
|
||||
let g_ptr = arena.alloc(r_bar);
|
||||
let v_ptr = arena.alloc(r_bar);
|
||||
let g_ptr = arena.alloc(g_bar);
|
||||
let b_ptr = arena.alloc(b_bar);
|
||||
let mut rgb_camera = [[0.; 3]; N_SWATCH_REFLECTANCES];
|
||||
|
||||
let swatches = get_swatches();
|
||||
|
|
@ -203,6 +205,7 @@ impl CreatePixelSensor for PixelSensor {
|
|||
output_colorspace: &RGBColorSpace,
|
||||
sensor_illum: Option<&Spectrum>,
|
||||
imaging_ratio: Float,
|
||||
arena: &Arena
|
||||
) -> Self {
|
||||
let spectra = get_spectra_context();
|
||||
let r_bar = CIE_X_DATA.clone();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::utils::sampling::PiecewiseConstant2D;
|
||||
use crate::utils::{FileLoc, ParameterDictionary};
|
||||
use crate::Arena;
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{bail, Result};
|
||||
use shared::core::filter::Filter;
|
||||
use shared::core::geometry::{Bounds2f, Point2f, Vector2f};
|
||||
use shared::filters::*;
|
||||
|
|
@ -28,13 +28,14 @@ impl FilterFactory for Filter {
|
|||
let xw = params.get_one_float("xradius", 0.5)?;
|
||||
let yw = params.get_one_float("yradius", 0.5)?;
|
||||
let filter = BoxFilter::new(Vector2f::new(xw, yw));
|
||||
Ok(Filter::Box(filter))
|
||||
Ok(Filter::Box(arena.alloc(filter)))
|
||||
}
|
||||
"gaussian" => {
|
||||
let xw = params.get_one_float("xradius", 1.5)?;
|
||||
let yw = params.get_one_float("yradius", 1.5)?;
|
||||
let sigma = params.get_one_float("sigma", 0.5)?;
|
||||
let filter = GaussianFilter::new(Vector2f::new(xw, yw), sigma);
|
||||
Ok(Filter::Gaussian(arena.alloc(filter)))
|
||||
}
|
||||
"mitchell" => {
|
||||
let xw = params.get_one_float("xradius", 2.)?;
|
||||
|
|
@ -42,22 +43,22 @@ impl FilterFactory for Filter {
|
|||
let b = params.get_one_float("B", 1. / 3.)?;
|
||||
let c = params.get_one_float("C", 1. / 3.)?;
|
||||
let filter = MitchellFilter::new(Vector2f::new(xw, yw), b, c);
|
||||
Ok(Filter::Mitchell(filter))
|
||||
Ok(Filter::Mitchell(arena.alloc(filter)))
|
||||
}
|
||||
"sinc" => {
|
||||
let xw = params.get_one_float("xradius", 4.)?;
|
||||
let yw = params.get_one_float("yradius", 4.)?;
|
||||
let tau = params.get_one_float("tau", 3.)?;
|
||||
let filter = LanczosSincFilter::new(Vector2f::new(xw, yw), tau);
|
||||
Ok(Filter::LanczosSinc(filter))
|
||||
Ok(Filter::LanczosSinc(arena.alloc(filter)))
|
||||
}
|
||||
"triangle" => {
|
||||
let xw = params.get_one_float("xradius", 2.)?;
|
||||
let yw = params.get_one_float("yradius", 2.)?;
|
||||
let filter = TriangleFilter::new(Vector2f::new(xw, yw));
|
||||
Ok(Filter::Triangle(filter))
|
||||
Ok(Filter::Triangle(arena.alloc(filter)))
|
||||
}
|
||||
_ => Err(anyhow!("Film type '{}' unknown at {}", name, loc)),
|
||||
_ => bail!("Film type '{}' unknown at {}", name, loc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
use super::{HostImage, ImageAndMetadata, ImageMetadata};
|
||||
use crate::core::image::{PixelStorage, WrapMode};
|
||||
use crate::utils::error::ImageError;
|
||||
use crate::core::image::WrapMode;
|
||||
use anyhow::{Context, Result, bail};
|
||||
use exr::prelude::{read_first_rgba_layer_from_file, write_rgba_file};
|
||||
use image_rs::{DynamicImage, ImageReader};
|
||||
use shared::Float;
|
||||
use shared::core::color::{ColorEncoding, LINEAR, SRGB};
|
||||
use shared::core::geometry::Point2i;
|
||||
use shared::core::image::PixelFormat;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, BufWriter, Read, Write};
|
||||
use image_rs::{DynamicImage, ImageReader};
|
||||
use std::path::Path;
|
||||
|
||||
pub trait ImageIO {
|
||||
|
|
@ -40,55 +39,39 @@ impl ImageIO for HostImage {
|
|||
fn write(&self, filename: &str, metadata: &ImageMetadata) -> Result<()> {
|
||||
let path = Path::new(filename);
|
||||
let ext = path.extension().and_then(|s| s.to_str()).unwrap_or("");
|
||||
let res = match ext.to_lowercase().as_str() {
|
||||
match ext.to_lowercase().as_str() {
|
||||
"exr" => self.write_exr(path, metadata),
|
||||
"png" => self.write_png(path),
|
||||
"pfm" => self.write_pfm(path),
|
||||
"qoi" => self.write_qoi(path),
|
||||
_ => Err(anyhow::anyhow!("Unsupported write format: {}", ext)),
|
||||
};
|
||||
res.map_err(|e| ImageError::Io(std::io::Error::other(e)))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_png(&self, path: &Path) -> Result<()> {
|
||||
let w = self.resolution().x() as u32;
|
||||
let h = self.resolution().y() as u32;
|
||||
|
||||
// Convert whatever we have to u8 [0..255]
|
||||
let w = self.inner.resolution().x() as u32;
|
||||
let h = self.inner.resolution().y() as u32;
|
||||
let data = self.to_u8_buffer();
|
||||
let channels = self.n_channels();
|
||||
let channels = self.inner.n_channels();
|
||||
|
||||
match channels {
|
||||
1 => {
|
||||
// Luma
|
||||
image_rs::save_buffer_with_format(
|
||||
path,
|
||||
&data,
|
||||
w,
|
||||
h,
|
||||
path, &data, w, h,
|
||||
image_rs::ColorType::L8,
|
||||
image_rs::ImageFormat::Png,
|
||||
)?;
|
||||
}
|
||||
3 => {
|
||||
// RGB
|
||||
image_rs::save_buffer_with_format(
|
||||
path,
|
||||
&data,
|
||||
w,
|
||||
h,
|
||||
path, &data, w, h,
|
||||
image_rs::ColorType::Rgb8,
|
||||
image_rs::ImageFormat::Png,
|
||||
)?;
|
||||
}
|
||||
4 => {
|
||||
// RGBA
|
||||
image_rs::save_buffer_with_format(
|
||||
path,
|
||||
&data,
|
||||
w,
|
||||
h,
|
||||
path, &data, w, h,
|
||||
image_rs::ColorType::Rgba8,
|
||||
image_rs::ImageFormat::Png,
|
||||
)?;
|
||||
|
|
@ -99,37 +82,30 @@ impl ImageIO for HostImage {
|
|||
}
|
||||
|
||||
fn write_qoi(&self, path: &Path) -> Result<()> {
|
||||
let w = self.resolution().x() as u32;
|
||||
let h = self.resolution().y() as u32;
|
||||
let w = self.inner.resolution().x() as u32;
|
||||
let h = self.inner.resolution().y() as u32;
|
||||
let data = self.to_u8_buffer();
|
||||
|
||||
let color_type = match self.n_channels() {
|
||||
let color_type = match self.inner.n_channels() {
|
||||
3 => image_rs::ColorType::Rgb8,
|
||||
4 => image_rs::ColorType::Rgba8,
|
||||
_ => bail!("QOI only supports 3 or 4 channels"),
|
||||
};
|
||||
|
||||
image_rs::save_buffer_with_format(
|
||||
path,
|
||||
&data,
|
||||
w,
|
||||
h,
|
||||
color_type,
|
||||
image_rs::ImageFormat::Qoi,
|
||||
path, &data, w, h, color_type, image_rs::ImageFormat::Qoi,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_exr(&self, path: &Path, _metadata: &ImageMetadata) -> Result<()> {
|
||||
// EXR requires F32
|
||||
let w = self.resolution().x() as usize;
|
||||
let h = self.resolution().y() as usize;
|
||||
let c = self.n_channels();
|
||||
let w = self.inner.resolution().x() as usize;
|
||||
let h = self.inner.resolution().y() as usize;
|
||||
let c = self.inner.n_channels();
|
||||
|
||||
write_rgba_file(path, w, h, |x, y| {
|
||||
// Helper to get float value regardless of internal storage
|
||||
let get = |ch| {
|
||||
self.get_channel_with_wrap(
|
||||
self.inner.get_channel_with_wrap(
|
||||
Point2i::new(x as i32, y as i32),
|
||||
ch,
|
||||
WrapMode::Clamp.into(),
|
||||
|
|
@ -154,27 +130,22 @@ impl ImageIO for HostImage {
|
|||
let file = File::create(path)?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
|
||||
if self.n_channels() != 3 {
|
||||
if self.inner.n_channels() != 3 {
|
||||
bail!("PFM writing currently only supports 3 channels (RGB)");
|
||||
}
|
||||
|
||||
// Header
|
||||
let res = self.resolution();
|
||||
let res = self.inner.resolution();
|
||||
writeln!(writer, "PF")?;
|
||||
writeln!(writer, "{} {}", res.x(), res.y())?;
|
||||
let scale = if cfg!(target_endian = "little") {
|
||||
-1.0
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
let scale = if cfg!(target_endian = "little") { -1.0 } else { 1.0 };
|
||||
writeln!(writer, "{}", scale)?;
|
||||
|
||||
// PBRT stores top-to-bottom.
|
||||
for y in (0..res.y()).rev() {
|
||||
for x in 0..res.x() {
|
||||
for c in 0..3 {
|
||||
let val =
|
||||
self.get_channel_with_wrap(Point2i::new(x, y), c, WrapMode::Clamp.into());
|
||||
let val = self.inner.get_channel_with_wrap(
|
||||
Point2i::new(x, y), c, WrapMode::Clamp.into(),
|
||||
);
|
||||
writer.write_all(&val.to_le_bytes())?;
|
||||
}
|
||||
}
|
||||
|
|
@ -183,20 +154,18 @@ impl ImageIO for HostImage {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Change Image to use Vec for data, always. Only convert to Device types on
|
||||
// constructors/creation
|
||||
fn to_u8_buffer(&self) -> Vec<u8> {
|
||||
match &self.pixels {
|
||||
PixelStorage::U8(data) => data.to_vec(),
|
||||
PixelStorage::F16(data) => data
|
||||
.iter()
|
||||
.map(|v| (v.to_f32().clamp(0.0, 1.0) * 255.0 + 0.5) as u8)
|
||||
.collect(),
|
||||
PixelStorage::F32(data) => data
|
||||
.iter()
|
||||
.map(|v| (v.clamp(0.0, 1.0) * 255.0 + 0.5) as u8)
|
||||
.collect(),
|
||||
let res = self.inner.resolution();
|
||||
let n_pixels = (res.x() * res.y()) as usize;
|
||||
let nc = self.inner.n_channels() as usize;
|
||||
let total = n_pixels * nc;
|
||||
|
||||
let mut buf = Vec::with_capacity(total);
|
||||
for i in 0..total {
|
||||
let val = unsafe { self.inner.pixels.read(i, &self.inner.encoding) };
|
||||
buf.push((val.clamp(0.0, 1.0) * 255.0 + 0.5) as u8);
|
||||
}
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,21 +178,24 @@ fn read_generic(path: &Path, encoding: Option<ColorEncoding>) -> Result<ImageAnd
|
|||
let h = dyn_img.height() as i32;
|
||||
let res = Point2i::new(w, h);
|
||||
|
||||
// Check if it was loaded as high precision or standard
|
||||
let rgb_names = vec!["R", "G", "B"];
|
||||
let rgba_names = vec!["R", "G", "B", "A"];
|
||||
let rgb_names: &[&str] = &["R", "G", "B"];
|
||||
let rgba_names: &[&str] = &["R", "G", "B", "A"];
|
||||
|
||||
let image = match dyn_img {
|
||||
DynamicImage::ImageRgb32F(buf) => Image::from_f32(buf.into_raw(), res, &rgb_names),
|
||||
DynamicImage::ImageRgba32F(buf) => Image::from_f32(buf.into_raw(), res, &rgba_names),
|
||||
DynamicImage::ImageRgb32F(buf) => {
|
||||
HostImage::from_f32(&buf.into_raw(), res, rgb_names)
|
||||
}
|
||||
DynamicImage::ImageRgba32F(buf) => {
|
||||
HostImage::from_f32(&buf.into_raw(), res, rgba_names)
|
||||
}
|
||||
_ => {
|
||||
// Default to RGB8 for everything else
|
||||
let enc = encoding.unwrap_or(SRGB);
|
||||
if dyn_img.color().has_alpha() {
|
||||
let buf = dyn_img.to_rgba8();
|
||||
Image::from_u8(buf.into_raw(), res, &rgba_names, enc)
|
||||
HostImage::from_u8(&buf.into_raw(), res, rgba_names, enc)
|
||||
} else {
|
||||
let buf = dyn_img.to_rgb8();
|
||||
Image::from_u8(buf.into_raw(), res, &rgb_names, enc)
|
||||
HostImage::from_u8(&buf.into_raw(), res, rgb_names, enc)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -242,7 +214,6 @@ fn read_exr(path: &Path) -> Result<ImageAndMetadata> {
|
|||
|buffer, position, pixel| {
|
||||
let width = position.width();
|
||||
let idx = (position.y() * width + position.x()) * 4;
|
||||
// Map exr pixel struct to our buffer
|
||||
buffer[idx] = pixel.0;
|
||||
buffer[idx + 1] = pixel.1;
|
||||
buffer[idx + 2] = pixel.2;
|
||||
|
|
@ -254,10 +225,11 @@ fn read_exr(path: &Path) -> Result<ImageAndMetadata> {
|
|||
let w = image.layer_data.size.width() as i32;
|
||||
let h = image.layer_data.size.height() as i32;
|
||||
|
||||
let image = Image::from_f32(
|
||||
image.layer_data.channel_data.pixels,
|
||||
let rgba_names: &[&str] = &["R", "G", "B", "A"];
|
||||
let image = HostImage::from_f32(
|
||||
&image.layer_data.channel_data.pixels,
|
||||
Point2i::new(w, h),
|
||||
&vec!["R", "G", "B", "A"],
|
||||
rgba_names,
|
||||
);
|
||||
|
||||
let metadata = ImageMetadata::default();
|
||||
|
|
@ -268,7 +240,6 @@ fn read_pfm(path: &Path) -> Result<ImageAndMetadata> {
|
|||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
// PFM Headers are: "PF\nwidth height\nscale\n" (or Pf for grayscale)
|
||||
let mut header_word = String::new();
|
||||
reader.read_line(&mut header_word)?;
|
||||
let header_word = header_word.trim();
|
||||
|
|
@ -309,9 +280,7 @@ fn read_pfm(path: &Path) -> Result<ImageAndMetadata> {
|
|||
|
||||
let mut pixels = vec![0.0 as Float; (w * h * channels) as usize];
|
||||
|
||||
// PFM is Bottom-to-Top
|
||||
for y in 0..h {
|
||||
// Flippety-do
|
||||
let src_y = h - 1 - y;
|
||||
for x in 0..w {
|
||||
for c in 0..channels {
|
||||
|
|
@ -331,13 +300,9 @@ fn read_pfm(path: &Path) -> Result<ImageAndMetadata> {
|
|||
}
|
||||
}
|
||||
|
||||
let names = if channels == 1 {
|
||||
vec!["Y"]
|
||||
} else {
|
||||
vec!["R", "G", "B"]
|
||||
};
|
||||
let names: &[&str] = if channels == 1 { &["Y"] } else { &["R", "G", "B"] };
|
||||
|
||||
let image = Image::new(PixelFormat::F32, Point2i::new(w, h), &names, LINEAR.into());
|
||||
let image = HostImage::new(PixelFormat::F32, Point2i::new(w, h), names, LINEAR.into());
|
||||
let metadata = ImageMetadata::default();
|
||||
|
||||
Ok(ImageAndMetadata { image, metadata })
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
use crate::utils::containers::Array2D;
|
||||
use anyhow::{Result, anyhow};
|
||||
use anyhow::{anyhow, Result};
|
||||
use half::f16;
|
||||
use rayon::prelude::{IndexedParallelIterator, ParallelIterator, ParallelSliceMut};
|
||||
use shared::Float;
|
||||
use shared::Ptr;
|
||||
use shared::core::color::{ColorEncoding, ColorEncodingTrait, LINEAR};
|
||||
use shared::core::geometry::{Bounds2f, Point2f, Point2i};
|
||||
use shared::core::image::{Image, ImageBase, PixelFormat, Pixels, WrapMode, WrapMode2D};
|
||||
use shared::utils::math::square;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use shared::{Array2D, Float, Ptr};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -90,31 +88,32 @@ impl HostImage {
|
|||
let n_channels = channel_names.len() as i32;
|
||||
Self {
|
||||
inner: Image::from_u8(data, resolution, n_channels, encoding),
|
||||
channel_names: channel_names.iter().map(|s| s.as_ref().to_string()).collect(),
|
||||
channel_names: channel_names
|
||||
.iter()
|
||||
.map(|s| s.as_ref().to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_f32(
|
||||
data: &[f32],
|
||||
resolution: Point2i,
|
||||
channel_names: &[impl AsRef<str>],
|
||||
) -> Self {
|
||||
pub fn from_f32(data: &[f32], resolution: Point2i, channel_names: &[impl AsRef<str>]) -> Self {
|
||||
let n_channels = channel_names.len() as i32;
|
||||
Self {
|
||||
inner: Image::from_f32(data, resolution, n_channels),
|
||||
channel_names: channel_names.iter().map(|s| s.as_ref().to_string()).collect(),
|
||||
channel_names: channel_names
|
||||
.iter()
|
||||
.map(|s| s.as_ref().to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_f16(
|
||||
data: &[u16],
|
||||
resolution: Point2i,
|
||||
channel_names: &[impl AsRef<str>],
|
||||
) -> Self {
|
||||
pub fn from_f16(data: &[u16], resolution: Point2i, channel_names: &[impl AsRef<str>]) -> Self {
|
||||
let n_channels = channel_names.len() as i32;
|
||||
Self {
|
||||
inner: Image::from_f16(data, resolution, n_channels),
|
||||
channel_names: channel_names.iter().map(|s| s.as_ref().to_string()).collect(),
|
||||
channel_names: channel_names
|
||||
.iter()
|
||||
.map(|s| s.as_ref().to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +126,10 @@ impl HostImage {
|
|||
let n_channels = channel_names.len() as i32;
|
||||
Self {
|
||||
inner: Image::new(format, resolution, n_channels, encoding),
|
||||
channel_names: channel_names.iter().map(|s| s.as_ref().to_string()).collect(),
|
||||
channel_names: channel_names
|
||||
.iter()
|
||||
.map(|s| s.as_ref().to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +139,11 @@ impl HostImage {
|
|||
values: &[f32],
|
||||
) -> Self {
|
||||
let n_channels = channel_names.len();
|
||||
assert_eq!(values.len(), n_channels, "values length must match channel count");
|
||||
assert_eq!(
|
||||
values.len(),
|
||||
n_channels,
|
||||
"values length must match channel count"
|
||||
);
|
||||
|
||||
let n_pixels = (resolution.x() * resolution.y()) as usize;
|
||||
let mut data = Vec::with_capacity(n_pixels * n_channels);
|
||||
|
|
@ -179,14 +185,37 @@ impl HostImage {
|
|||
}
|
||||
|
||||
pub fn channel_names_from_desc(&self, desc: &ImageChannelDesc) -> Vec<&str> {
|
||||
desc.offset.iter().map(|&i| self.channel_names[i].as_str()).collect()
|
||||
desc.offset
|
||||
.iter()
|
||||
.map(|&i| self.channel_names[i].as_str())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn bilerp_channel_with_wrap(&self, p: Point2f, c: i32, wrap: WrapMode2D) -> Float {
|
||||
self.inner.bilerp_channel_with_wrap(p, c, wrap)
|
||||
}
|
||||
|
||||
pub fn bilerp_channel(&self, p: Point2f, c: i32) -> Float {
|
||||
self.bilerp_channel_with_wrap(p, c, WrapMode::Clamp.into())
|
||||
}
|
||||
|
||||
pub fn get_channel(&self, p: Point2i, c: i32) -> Float {
|
||||
self.get_channel_with_wrap(p, c, WrapMode::Clamp.into())
|
||||
}
|
||||
|
||||
pub fn get_channel_with_wrap(&self, p: Point2i, c: i32, wrap_mode: WrapMode2D) -> Float {
|
||||
self.inner.get_channel_with_wrap(p, c, wrap_mode)
|
||||
}
|
||||
|
||||
pub fn get_channels(&self, p: Point2i) -> ImageChannelValues {
|
||||
self.get_channels_with_wrap(p, WrapMode::Clamp.into())
|
||||
}
|
||||
|
||||
pub fn get_channels_with_wrap(&self, mut p: Point2i, wrap_mode: WrapMode2D) -> ImageChannelValues {
|
||||
pub fn get_channels_with_wrap(
|
||||
&self,
|
||||
mut p: Point2i,
|
||||
wrap_mode: WrapMode2D,
|
||||
) -> ImageChannelValues {
|
||||
if !self.inner.remap_pixel_coords(&mut p, wrap_mode) {
|
||||
return ImageChannelValues(SmallVec::from_elem(0.0, self.inner.n_channels() as usize));
|
||||
}
|
||||
|
|
@ -212,7 +241,11 @@ impl HostImage {
|
|||
let pixel_offset = self.inner.pixel_offset(pp);
|
||||
let mut values = SmallVec::with_capacity(desc.offset.len());
|
||||
for &c in &desc.offset {
|
||||
values.push(unsafe { self.inner.pixels.read(pixel_offset + c, &self.inner.encoding) });
|
||||
values.push(unsafe {
|
||||
self.inner
|
||||
.pixels
|
||||
.read(pixel_offset + c, &self.inner.encoding)
|
||||
});
|
||||
}
|
||||
ImageChannelValues(values)
|
||||
}
|
||||
|
|
@ -223,20 +256,29 @@ impl HostImage {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_channel(&mut self, p: Point2i, values: &ImageChannelValues) {
|
||||
self.inner.set_channel(p, values[i]);
|
||||
}
|
||||
|
||||
pub fn select_channels(&self, desc: &ImageChannelDesc) -> Self {
|
||||
let new_names: Vec<String> = desc.offset.iter().map(|&i| self.channel_names[i].clone()).collect();
|
||||
let new_names: Vec<String> = desc
|
||||
.offset
|
||||
.iter()
|
||||
.map(|&i| self.channel_names[i].clone())
|
||||
.collect();
|
||||
let res = self.inner.resolution();
|
||||
let pixel_count = (res.x() * res.y()) as usize;
|
||||
let src_nc = self.inner.n_channels() as usize;
|
||||
let dst_nc = desc.offset.len();
|
||||
|
||||
// Always produce f32 output for simplicity
|
||||
let mut dst = vec![0.0f32; pixel_count * dst_nc];
|
||||
for i in 0..pixel_count {
|
||||
let src_offset = i * src_nc;
|
||||
for (out_idx, &in_c) in desc.offset.iter().enumerate() {
|
||||
dst[i * dst_nc + out_idx] = unsafe {
|
||||
self.inner.pixels.read(src_offset + in_c, &self.inner.encoding)
|
||||
self.inner
|
||||
.pixels
|
||||
.read(src_offset + in_c, &self.inner.encoding)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +298,7 @@ impl HostImage {
|
|||
dist.as_mut_slice()
|
||||
.par_chunks_mut(width as usize)
|
||||
.enumerate()
|
||||
.for_each(|(y, row)| {
|
||||
.for_each(|(y, row): (usize, &mut [Float])| {
|
||||
let y = y as i32;
|
||||
for (x, out_val) in row.iter_mut().enumerate() {
|
||||
let x = x as i32;
|
||||
|
|
@ -310,15 +352,18 @@ impl HostImage {
|
|||
|
||||
for y in 0..res.y() {
|
||||
for x in 0..res.x() {
|
||||
let v = self.get_channels_with_desc(
|
||||
Point2i::new(x, y), desc, WrapMode::Clamp.into(),
|
||||
);
|
||||
let v =
|
||||
self.get_channels_with_desc(Point2i::new(x, y), desc, WrapMode::Clamp.into());
|
||||
let v_ref = ref_img.get_channels_with_desc(
|
||||
Point2i::new(x, y), &ref_desc, WrapMode::Clamp.into(),
|
||||
Point2i::new(x, y),
|
||||
&ref_desc,
|
||||
WrapMode::Clamp.into(),
|
||||
);
|
||||
for c in 0..n_channels {
|
||||
let se = square(v[c] as f64 - v_ref[c] as f64);
|
||||
if se.is_infinite() { continue; }
|
||||
if se.is_infinite() {
|
||||
continue;
|
||||
}
|
||||
sum_se[c] += se;
|
||||
if generate_mse_image {
|
||||
let idx = (y as usize * width + x as usize) * n_channels + c;
|
||||
|
|
|
|||
|
|
@ -191,19 +191,19 @@ impl HostImage {
|
|||
PixelFormat::U8 => downsample_kernel(
|
||||
next.inner.pixels.as_u8_mut(),
|
||||
new_res,
|
||||
&prev.inner,
|
||||
&prev,
|
||||
internal_wrap,
|
||||
),
|
||||
PixelFormat::F16 => downsample_kernel(
|
||||
next.inner.pixels.as_f16_mut(),
|
||||
new_res,
|
||||
&prev.inner,
|
||||
&prev,
|
||||
internal_wrap,
|
||||
),
|
||||
PixelFormat::F32 => downsample_kernel(
|
||||
next.inner.pixels.as_f32_slice_mut(),
|
||||
new_res,
|
||||
&prev.inner,
|
||||
&prev,
|
||||
internal_wrap,
|
||||
),
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ fn copy_rect_in_kernel<T: PixelStorageTrait>(
|
|||
fn downsample_kernel<T: PixelStorageTrait>(
|
||||
dst: &mut [T],
|
||||
dst_res: Point2i,
|
||||
prev: &Image,
|
||||
prev: &HostImage,
|
||||
wrap: WrapMode2D,
|
||||
) {
|
||||
let w = dst_res.x() as usize;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use shared::core::shape::Shape;
|
|||
use shared::spectra::DenselySampledSpectrum;
|
||||
use shared::core::spectrum::Spectrum;
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::Transform;
|
||||
use shared::{Ptr, Transform};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn lookup_spectrum(s: &Spectrum) -> Arc<DenselySampledSpectrum> {
|
||||
|
|
@ -117,7 +117,7 @@ pub fn create_area_light(
|
|||
shape: &Shape,
|
||||
alpha_tex: &FloatTexture,
|
||||
colorspace: Option<&RGBColorSpace>,
|
||||
arena: &mut Arena,
|
||||
arena: &Arena,
|
||||
) -> Result<Ptr<Light>> {
|
||||
let light = crate::lights::diffuse::create(
|
||||
render_from_light, medium, parameters, loc,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::Arena;
|
||||
use crate::core::image::Image;
|
||||
use crate::core::image::HostImage;
|
||||
use crate::utils::TextureParameterDictionary;
|
||||
use crate::utils::error::FileLoc;
|
||||
use anyhow::{Result, anyhow};
|
||||
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
|||
pub trait CreateMaterial: Sized {
|
||||
fn create(
|
||||
parameters: &TextureParameterDictionary,
|
||||
normal_map: Option<Arc<Image>>,
|
||||
normal_map: Option<Arc<HostImage>>,
|
||||
named_materials: &HashMap<String, Material>,
|
||||
loc: &FileLoc,
|
||||
arena: &Arena,
|
||||
|
|
@ -22,7 +22,7 @@ pub trait MaterialFactory {
|
|||
fn create(
|
||||
name: &str,
|
||||
params: &TextureParameterDictionary,
|
||||
normal_map: Option<Arc<Image>>,
|
||||
normal_map: Option<Arc<HostImage>>,
|
||||
named_materials: &HashMap<String, Material>,
|
||||
loc: FileLoc,
|
||||
arena: &Arena,
|
||||
|
|
@ -35,7 +35,7 @@ impl MaterialFactory for Material {
|
|||
fn create(
|
||||
name: &str,
|
||||
parameters: &TextureParameterDictionary,
|
||||
normal_map: Option<Arc<Image>>,
|
||||
normal_map: Option<Arc<HostImage>>,
|
||||
named_materials: &HashMap<String, Material>,
|
||||
loc: FileLoc,
|
||||
arena: &Arena,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use super::state::*;
|
|||
use crate::core::camera::CameraFactory;
|
||||
use crate::core::film::FilmFactory;
|
||||
use crate::core::filter::FilterFactory;
|
||||
use crate::core::image::{io::ImageIO, Image};
|
||||
use crate::core::image::{HostImage, ImageIO};
|
||||
use crate::core::material::MaterialFactory;
|
||||
use crate::core::primitive::{CreateGeometricPrimitive, CreateSimplePrimitive};
|
||||
use crate::core::sampler::SamplerFactory;
|
||||
|
|
@ -12,7 +12,7 @@ use crate::core::texture::{FloatTexture, SpectrumTexture};
|
|||
use crate::utils::parallel::{run_async, AsyncJob};
|
||||
use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary};
|
||||
use crate::utils::resolve_filename;
|
||||
use crate::{Arena, ArenaUpload, FileLoc, Upload};
|
||||
use crate::{Arena, ArenaUpload, FileLoc};
|
||||
use anyhow::{anyhow, Result};
|
||||
use parking_lot::Mutex;
|
||||
use shared::core::camera::{Camera, CameraTransform};
|
||||
|
|
@ -25,9 +25,9 @@ use shared::core::medium::{Medium, MediumInterface};
|
|||
use shared::core::primitive::{AnimatedPrimitive, GeometricPrimitive, Primitive, SimplePrimitive};
|
||||
use shared::core::sampler::Sampler;
|
||||
use shared::core::shape::Shape;
|
||||
use shared::core::texture::SpectrumType;
|
||||
use shared::core::texture::{GPUFloatTexture, SpectrumType};
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::Ptr;
|
||||
use shared::{Ptr, Transform};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -169,7 +169,6 @@ impl BasicScene {
|
|||
});
|
||||
self.sampler_state.lock().job = Some(sampler_job);
|
||||
|
||||
let arena_camera = Arc::clone(&arena);
|
||||
let camera_film = Arc::clone(&film_instance);
|
||||
let scene_ptr = Arc::clone(self);
|
||||
let camera_job = run_async(move || {
|
||||
|
|
@ -181,7 +180,7 @@ impl BasicScene {
|
|||
medium,
|
||||
camera_film,
|
||||
&camera.base.loc,
|
||||
&arena_camera,
|
||||
&arena,
|
||||
)
|
||||
.map_err(|e| anyhow!("Failed to create camera: {}", e))
|
||||
});
|
||||
|
|
@ -1027,7 +1026,7 @@ impl BasicScene {
|
|||
let filename_clone = filename.clone();
|
||||
let job = run_async(move || {
|
||||
let path = std::path::Path::new(&filename_clone);
|
||||
let immeta = Image::read(path, Some(LINEAR)).expect(&format!(
|
||||
let immeta = HostImage::read(path, Some(LINEAR)).expect(&format!(
|
||||
"{}: normal map must contain R, G, B channels",
|
||||
filename_clone
|
||||
));
|
||||
|
|
@ -1051,7 +1050,7 @@ impl BasicScene {
|
|||
&self,
|
||||
state: &MaterialState,
|
||||
params: &ParameterDictionary,
|
||||
) -> Result<Option<Arc<Image>>> {
|
||||
) -> Result<Option<Arc<HostImage>>> {
|
||||
let filename = resolve_filename(¶ms.get_one_string("normalmap", "")?);
|
||||
if filename.is_empty() {
|
||||
return Ok(None);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use super::{LightSceneEntity, SceneEntity, TextureSceneEntity};
|
||||
use crate::core::image::Image;
|
||||
use crate::core::image::HostImage;
|
||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||
use crate::utils::parallel::AsyncJob;
|
||||
use anyhow::Result;
|
||||
|
|
@ -22,8 +22,8 @@ pub struct TextureState {
|
|||
pub struct MaterialState {
|
||||
pub named_materials: Vec<(String, SceneEntity)>,
|
||||
pub materials: Vec<SceneEntity>,
|
||||
pub normal_map_jobs: HashMap<String, AsyncJob<Arc<Image>>>,
|
||||
pub normal_maps: HashMap<String, Arc<Image>>,
|
||||
pub normal_map_jobs: HashMap<String, AsyncJob<Arc<HostImage>>>,
|
||||
pub normal_maps: HashMap<String, Arc<HostImage>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
|
|||
|
|
@ -116,8 +116,8 @@ impl ShapeFactory for Shape {
|
|||
global_store.push(host_arc.clone());
|
||||
drop(global_store);
|
||||
|
||||
let n_tris = host_arc..n_triangles;
|
||||
let mesh_ptr = Ptr::from(&host_arc);
|
||||
let n_tris = host_arc.n_triangles;
|
||||
let mesh_ptr = arena.alloc_arc(host_arc);
|
||||
let shapes: Vec<Ptr<Shape>> = (0..n_tris)
|
||||
.map(|i| {
|
||||
let tri_shape = Shape::Triangle(TriangleShape {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::textures::*;
|
||||
use crate::utils::TextureParameterDictionary;
|
||||
use crate::utils::{MIPMap, MIPMapFilterOptions, TextureParameterDictionary};
|
||||
use crate::{Arena, FileLoc};
|
||||
use anyhow::{anyhow, Result};
|
||||
use enum_dispatch::enum_dispatch;
|
||||
|
|
@ -8,8 +8,8 @@ use shared::core::geometry::Vector3f;
|
|||
use shared::core::image::WrapMode;
|
||||
use shared::core::texture::SpectrumType;
|
||||
use shared::core::texture::{
|
||||
CylindricalMapping, GPUFloatTexture, GPUSpectrumTexture, PlanarMapping, SphericalMapping,
|
||||
TextureEvalContext, TextureMapping2D, UVMapping,
|
||||
CylindricalMapping, PlanarMapping, SphericalMapping, TextureEvalContext, TextureMapping2D,
|
||||
UVMapping,
|
||||
};
|
||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||
use shared::textures::*;
|
||||
|
|
@ -133,7 +133,10 @@ impl SpectrumTexture {
|
|||
invert: inner.base.invert,
|
||||
is_single_channel: inner.base.mipmap.is_single_channel(),
|
||||
color_space: arena.alloc(
|
||||
inner.base.mipmap.color_space
|
||||
inner
|
||||
.base
|
||||
.mipmap
|
||||
.color_space
|
||||
.clone()
|
||||
.unwrap_or_else(crate::spectra::default_colorspace),
|
||||
),
|
||||
|
|
@ -262,4 +265,3 @@ pub struct TexInfo {
|
|||
pub wrap_mode: WrapMode,
|
||||
pub encoding: ColorEncoding,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use super::*;
|
||||
use crate::core::film::{CreateFilmBase, PixelSensor};
|
||||
use crate::utils::containers::Array2D;
|
||||
use crate::core::film::{CreateFilmBase, CreatePixelSensor};
|
||||
use shared::core::film::PixelSensor;
|
||||
use anyhow::{Result, anyhow};
|
||||
use shared::core::film::{FilmBase, GBufferFilm};
|
||||
use shared::core::filter::FilterTrait;
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::AnimatedTransform;
|
||||
use std::path::Path;
|
||||
|
|
@ -16,13 +15,13 @@ impl CreateFilm for GBufferFilm {
|
|||
filter: Filter,
|
||||
camera_transform: Option<CameraTransform>,
|
||||
loc: &FileLoc,
|
||||
_arena: &Arena,
|
||||
arena: &Arena,
|
||||
) -> Result<Film> {
|
||||
let colorspace = params.color_space.as_ref().unwrap();
|
||||
let max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY)?;
|
||||
let write_fp16 = params.get_one_bool("savefp16", true)?;
|
||||
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 filename = params.get_one_string("filename", "pbrt.exr")?;
|
||||
if Path::new(&filename).extension() != Some("exr".as_ref()) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use super::*;
|
||||
use crate::core::film::{CreateFilmBase, PixelSensor};
|
||||
use crate::utils::containers::Array2D;
|
||||
use crate::Arena;
|
||||
use anyhow::Result;
|
||||
use shared::core::camera::CameraTransform;
|
||||
use shared::core::film::{Film, FilmBase, RGBFilm, RGBPixel};
|
||||
use shared::core::filter::FilterTrait;
|
||||
use shared::spectra::RGBColorSpace;
|
||||
|
||||
impl CreateFilm for RGBFilm {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
use super::*;
|
||||
use crate::core::film::{CreateFilmBase, PixelSensor};
|
||||
use crate::core::film::{CreateFilmBase, CreatePixelSensor};
|
||||
use crate::{Arena, FileLoc, ParameterDictionary};
|
||||
use anyhow::{Result, anyhow};
|
||||
use shared::Float;
|
||||
use anyhow::{anyhow, Result};
|
||||
use shared::core::camera::CameraTransform;
|
||||
use shared::core::film::{FilmBase, SpectralFilm};
|
||||
use shared::core::filter::FilterTrait;
|
||||
use shared::core::film::{FilmBase, PixelSensor, SpectralFilm};
|
||||
use shared::spectra::{LAMBDA_MAX, LAMBDA_MIN};
|
||||
use shared::utils::math::SquareMatrix;
|
||||
use shared::Float;
|
||||
use std::path::Path;
|
||||
|
||||
|
||||
impl CreateFilm for SpectralFilm {
|
||||
fn create(
|
||||
params: &ParameterDictionary,
|
||||
|
|
@ -18,14 +16,14 @@ impl CreateFilm for SpectralFilm {
|
|||
filter: Filter,
|
||||
_camera_transform: Option<CameraTransform>,
|
||||
loc: &FileLoc,
|
||||
_arena: &Arena,
|
||||
arena: &Arena,
|
||||
) -> Result<Film> {
|
||||
// Missing default illuminant, use srgb
|
||||
let colorspace = params.color_space.as_ref().unwrap();
|
||||
let max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY)?;
|
||||
let write_fp16 = params.get_one_bool("savefp16", true)?;
|
||||
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 filename = params.get_one_string("filename", "pbrt.exr")?;
|
||||
if Path::new(&filename).extension() != Some("exr".as_ref()) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use super::base::IntegratorBase;
|
|||
use super::RayIntegratorTrait;
|
||||
use crate::core::camera::InitMetadata;
|
||||
use crate::core::film::FilmTrait;
|
||||
use crate::core::image::{Image, ImageIO, ImageMetadata};
|
||||
use crate::core::image::{HostImage, ImageIO, ImageMetadata};
|
||||
use crate::globals::get_options;
|
||||
use crate::spectra::get_spectra_context;
|
||||
use crate::Arena;
|
||||
|
|
@ -108,12 +108,12 @@ pub fn render<T>(
|
|||
let mut wave_end = 1;
|
||||
let mut next_wave_size = 1;
|
||||
|
||||
let mut reference_image: Option<Image> = None;
|
||||
let mut reference_image: Option<HostImage> = None;
|
||||
let mut mse_out_file: Option<std::fs::File> = None;
|
||||
|
||||
if let Some(ref_path) = &options.mse_reference_image {
|
||||
let image_and_metadata =
|
||||
Image::read(Path::new(&ref_path), None).expect("Could not load image");
|
||||
HostImage::read(Path::new(&ref_path), None).expect("Could not load image");
|
||||
let image = image_and_metadata.image;
|
||||
let metadata = image_and_metadata.metadata;
|
||||
let resolution = image.resolution();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#[allow(dead_code)]
|
||||
pub mod core;
|
||||
pub mod films;
|
||||
pub mod filters;
|
||||
pub mod globals;
|
||||
pub mod integrators;
|
||||
pub mod lights;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use std::path::Path;
|
||||
|
||||
use crate::core::image::{Image, ImageIO};
|
||||
use crate::core::image::{HostImage, ImageIO};
|
||||
use crate::core::light::lookup_spectrum;
|
||||
use crate::core::spectrum::spectrum_to_photometric;
|
||||
use crate::core::texture::FloatTexture;
|
||||
|
|
@ -18,6 +16,7 @@ use shared::lights::DiffuseAreaLight;
|
|||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::Transform;
|
||||
use shared::{Float, PI};
|
||||
use std::path::Path;
|
||||
|
||||
pub fn create(
|
||||
render_from_light: Transform,
|
||||
|
|
@ -37,13 +36,13 @@ pub fn create(
|
|||
let two_sided = params.get_one_bool("twosided", false)?;
|
||||
|
||||
let filename = resolve_filename(¶ms.get_one_string("filename", "")?);
|
||||
let (image, image_color_space): (Option<Image>, Option<RGBColorSpace>) =
|
||||
let (image, image_color_space): (Option<HostImage>, Option<RGBColorSpace>) =
|
||||
if !filename.is_empty() {
|
||||
if l.is_some() {
|
||||
return Err(anyhow!("{}: both \"L\" and \"filename\" specified", loc));
|
||||
}
|
||||
|
||||
let im = Image::read(Path::new(&filename), None)?;
|
||||
let im = HostImage::read(Path::new(&filename), None)?;
|
||||
|
||||
if im.image.has_any_infinite_pixels() {
|
||||
return Err(anyhow!("{}: image has infinite pixel values", loc));
|
||||
|
|
@ -100,12 +99,13 @@ pub fn create(
|
|||
scale *= phi_v / k_e;
|
||||
}
|
||||
|
||||
// Upload alpha texture to GPU and check for constant-zero
|
||||
// Upload alpha texture to GPU and check for null texture
|
||||
let alpha_ptr = arena.upload(alpha);
|
||||
let light_type = if alpha_ptr.is_constant_zero() {
|
||||
let light_type = match alpha_ptr.as_ref() {
|
||||
GPUFloatTexture::Constant(t) if t.evaluate(&TextureEvalContext::default()) == 0.0 => {
|
||||
LightType::DeltaPosition
|
||||
} else {
|
||||
LightType::Area
|
||||
}
|
||||
_ => LightType::Area,
|
||||
};
|
||||
|
||||
let mi = match medium {
|
||||
|
|
@ -146,7 +146,7 @@ pub fn create(
|
|||
area: shape.area(),
|
||||
shape: arena.alloc(*shape),
|
||||
alpha: alpha_ptr,
|
||||
image: arena.alloc(image),
|
||||
image: arena.upload(image),
|
||||
colorspace: arena.alloc_opt(image_color_space),
|
||||
lemit: arena.alloc((*lookup_spectrum(l_for_scale)).clone()),
|
||||
two_sided,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::path::Path;
|
||||
|
||||
use crate::core::image::{Image, ImageIO};
|
||||
use crate::core::image::{HostImage, ImageIO};
|
||||
use crate::core::light::lookup_spectrum;
|
||||
use crate::core::spectrum::spectrum_to_photometric;
|
||||
use crate::core::texture::FloatTexture;
|
||||
|
|
@ -41,10 +41,10 @@ pub fn create(
|
|||
.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<Image> = if filename.is_empty() {
|
||||
let image: Ptr<HostImage> = if filename.is_empty() {
|
||||
Ptr::null()
|
||||
} else {
|
||||
let im = Image::read(Path::new(&filename), None)
|
||||
let im = HostImage::read(Path::new(&filename), None)
|
||||
.map_err(|e| anyhow!("could not load image '{}': {}", filename, e))?;
|
||||
|
||||
let loaded = im.image;
|
||||
|
|
@ -117,7 +117,7 @@ pub fn create(
|
|||
Ok(Light::Goniometric(specific))
|
||||
}
|
||||
|
||||
fn convert_to_luminance_image(image: &Image, filename: &str, loc: &FileLoc) -> Result<Image> {
|
||||
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"]);
|
||||
|
|
@ -142,7 +142,7 @@ fn convert_to_luminance_image(image: &Image, filename: &str, loc: &FileLoc) -> R
|
|||
}
|
||||
}
|
||||
|
||||
Ok(Image::from_f32(y_pixels, res, &["Y"].to_vec()))
|
||||
Ok(HostImage::from_f32(&y_pixels, res, &["Y"].to_vec()))
|
||||
}
|
||||
|
||||
(Err(_), Ok(_)) => {
|
||||
|
|
@ -158,7 +158,7 @@ fn convert_to_luminance_image(image: &Image, filename: &str, loc: &FileLoc) -> R
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_emissive_power(image: &Image) -> Float {
|
||||
fn compute_emissive_power(image: &HostImage) -> Float {
|
||||
let res = image.resolution();
|
||||
let mut sum_y = 0.0;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ use shared::core::camera::CameraTransform;
|
|||
use shared::core::geometry::{cos_theta, Bounds2f, Frame, Point2f, Point2i, Point3f, VectorLike};
|
||||
use shared::core::image::WrapMode;
|
||||
use shared::core::light::{Light, LightBase, LightType};
|
||||
use shared::core::medium::{Medium, MediumInterface};
|
||||
use shared::core::medium::Medium;
|
||||
use shared::core::spectrum::Spectrum;
|
||||
use shared::core::texture::SpectrumType;
|
||||
use shared::lights::{ImageInfiniteLight, PortalInfiniteLight, UniformInfiniteLight};
|
||||
use shared::spectra::{DenselySampledSpectrum, RGBColorSpace};
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::math::{equal_area_sphere_to_square, equal_area_square_to_sphere};
|
||||
use shared::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
|
||||
use shared::{Float, Ptr, Transform, PI};
|
||||
|
|
@ -63,7 +63,7 @@ pub fn create(
|
|||
}
|
||||
|
||||
let lemit = lookup_spectrum(&spectrum);
|
||||
let light = UniformInfiniteLight::new(render_from_light, scale, arena.alloc(*lemit));
|
||||
let light = UniformInfiniteLight::new(render_from_light, scale, arena.alloc_arc(lemit));
|
||||
return Ok(Light::InfiniteUniform(light));
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ pub fn create(
|
|||
fn create_image_light(
|
||||
render_from_light: Transform,
|
||||
scale: Float,
|
||||
image: Image,
|
||||
image: HostImage,
|
||||
image_cs: RGBColorSpace,
|
||||
arena: &Arena,
|
||||
) -> Result<Light> {
|
||||
|
|
@ -110,7 +110,6 @@ fn create_image_light(
|
|||
let (n_u, n_v) = (res.x() as usize, res.y() as usize);
|
||||
|
||||
// Extract luminance data
|
||||
let image_ptr = image.upload(arena);
|
||||
let value = ℑ
|
||||
let mut data: Vec<Float> = (0..n_v)
|
||||
.flat_map(|v| {
|
||||
|
|
@ -139,7 +138,7 @@ fn create_image_light(
|
|||
let light = ImageInfiniteLight::new(
|
||||
render_from_light,
|
||||
scale,
|
||||
image_ptr,
|
||||
arena.upload(image),
|
||||
arena.alloc(image_cs),
|
||||
arena.alloc(distrib),
|
||||
arena.alloc(compensated_distrib),
|
||||
|
|
@ -151,7 +150,7 @@ fn create_image_light(
|
|||
fn create_portal_light(
|
||||
render_from_light: Transform,
|
||||
scale: Float,
|
||||
image: Image,
|
||||
image: HostImage,
|
||||
image_cs: RGBColorSpace,
|
||||
portal_points: &[Point3f],
|
||||
camera_transform: CameraTransform,
|
||||
|
|
@ -198,7 +197,7 @@ fn create_portal_light(
|
|||
let light = PortalInfiniteLight::new(
|
||||
render_from_light,
|
||||
scale,
|
||||
arena.alloc(remapped),
|
||||
arena.upload(remapped),
|
||||
arena.alloc(image_cs),
|
||||
portal,
|
||||
portal_frame,
|
||||
|
|
@ -230,10 +229,10 @@ fn validate_and_build_portal_frame(portal: &[Point3f; 4], loc: &FileLoc) -> Resu
|
|||
}
|
||||
|
||||
fn remap_image_through_portal(
|
||||
image: &Image,
|
||||
image: &HostImage,
|
||||
render_from_light: &Transform,
|
||||
portal_frame: &Frame,
|
||||
) -> Image {
|
||||
) -> HostImage {
|
||||
let res = image.resolution();
|
||||
let (width, height) = (res.x() as usize, res.y() as usize);
|
||||
|
||||
|
|
@ -263,7 +262,7 @@ fn remap_image_through_portal(
|
|||
}
|
||||
});
|
||||
|
||||
Image::from_f32(pixels, res, &["R", "G", "B"])
|
||||
HostImage::from_f32(&pixels, res, &["R", "G", "B"])
|
||||
}
|
||||
|
||||
fn load_image(
|
||||
|
|
@ -271,16 +270,16 @@ fn load_image(
|
|||
l: &[Spectrum],
|
||||
colorspace: &RGBColorSpace,
|
||||
loc: &FileLoc,
|
||||
) -> Result<(Image, RGBColorSpace)> {
|
||||
) -> Result<(HostImage, RGBColorSpace)> {
|
||||
if filename.is_empty() {
|
||||
let stdspec = get_spectra_context();
|
||||
let rgb = l[0].to_rgb(colorspace, &stdspec);
|
||||
let image =
|
||||
Image::new_constant(Point2i::new(1, 1), &["R", "G", "B"], &[rgb.r, rgb.g, rgb.b]);
|
||||
HostImage::new_constant(Point2i::new(1, 1), &["R", "G", "B"], &[rgb.r, rgb.g, rgb.b]);
|
||||
return Ok((image, colorspace.clone()));
|
||||
}
|
||||
|
||||
let im = Image::read(Path::new(filename), None)
|
||||
let im = HostImage::read(Path::new(filename), None)
|
||||
.map_err(|e| anyhow!("failed to load '{}': {}", filename, e))?;
|
||||
|
||||
if im.image.has_any_infinite_pixels() || im.image.has_any_nan_pixels() {
|
||||
|
|
@ -296,7 +295,7 @@ fn load_image(
|
|||
Ok((im.image.select_channels(&desc), cs))
|
||||
}
|
||||
|
||||
fn compute_hemisphere_illuminance(image: &Image, cs: &RGBColorSpace) -> Float {
|
||||
fn compute_hemisphere_illuminance(image: &HostImage, cs: &RGBColorSpace) -> Float {
|
||||
let lum = cs.luminance_vector();
|
||||
let res = image.resolution();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::core::image::{Image, ImageIO};
|
||||
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};
|
||||
use crate::{Arena, FileLoc, ParameterDictionary, ArenaUpload};
|
||||
use anyhow::{Result, anyhow};
|
||||
use shared::Float;
|
||||
use shared::core::geometry::{
|
||||
|
|
@ -41,7 +41,7 @@ pub fn create(
|
|||
));
|
||||
}
|
||||
|
||||
let im = Image::read(Path::new(&filename), None)
|
||||
let im = HostImage::read(Path::new(&filename), None)
|
||||
.map_err(|e| anyhow!("{}: could not load image '{}': {}", loc, filename, e))?;
|
||||
|
||||
if im.image.has_any_infinite_pixels() {
|
||||
|
|
@ -125,9 +125,9 @@ pub fn create(
|
|||
|
||||
let specific = ProjectionLight {
|
||||
base,
|
||||
image: image.upload(arena),
|
||||
image_color_space: colorspace.upload(arena),
|
||||
distrib: distrib.upload(arena),
|
||||
image: arena.upload(image),
|
||||
image_color_space: arena.alloc(colorspace),
|
||||
distrib: arena.alloc(distrib),
|
||||
screen_bounds,
|
||||
screen_from_light,
|
||||
light_from_screen,
|
||||
|
|
@ -150,7 +150,7 @@ fn compute_screen_bounds(aspect: Float) -> Bounds2f {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_emissive_power(image: &Image, colorspace: &RGBColorSpace, fov: Float) -> Float {
|
||||
fn compute_emissive_power(image: &HostImage, colorspace: &RGBColorSpace, fov: Float) -> Float {
|
||||
let res = image.resolution();
|
||||
let aspect = res.x() as Float / res.y() as Float;
|
||||
let screen_bounds = compute_screen_bounds(aspect);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use shared::core::texture::SpectrumType;
|
|||
use shared::lights::SpotLight;
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::math::radians;
|
||||
use shared::utils::{Ptr, Transform};
|
||||
use shared::{Float, Ptr, Transform, PI};
|
||||
|
||||
trait CreateSpotLight {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::core::texture::SpectrumTexture;
|
|||
use crate::globals::get_options;
|
||||
use crate::spectra::data::get_named_spectrum;
|
||||
use crate::utils::TextureParameterDictionary;
|
||||
use crate::{Arena, FileLoc, Upload, ArenaUpload};
|
||||
use crate::{Arena, FileLoc, ArenaUpload};
|
||||
use anyhow::{bail, Result};
|
||||
use shared::core::material::Material;
|
||||
use shared::core::spectrum::Spectrum;
|
||||
|
|
@ -64,7 +64,7 @@ impl CreateMaterial for CoatedDiffuseMaterial {
|
|||
arena.upload(g),
|
||||
arena.upload(displacement),
|
||||
arena.alloc(eta),
|
||||
arena.alloc(normal_map),
|
||||
arena.upload(normal_map),
|
||||
remap_roughness,
|
||||
max_depth as u32,
|
||||
n_samples as u32,
|
||||
|
|
@ -154,7 +154,7 @@ impl CreateMaterial for CoatedConductorMaterial {
|
|||
let remap_roughness = parameters.get_one_bool("remaproughness", true)?;
|
||||
|
||||
let material = Self::new(
|
||||
arena.upload(displacement)
|
||||
arena.upload(displacement),
|
||||
arena.upload(interface_u_roughness),
|
||||
arena.upload(interface_v_roughness),
|
||||
arena.upload(thickness),
|
||||
|
|
@ -165,7 +165,7 @@ impl CreateMaterial for CoatedConductorMaterial {
|
|||
arena.upload(conductor_eta),
|
||||
arena.upload(k),
|
||||
arena.upload(reflectance),
|
||||
arena.alloc(normal_map),
|
||||
arena.upload(normal_map),
|
||||
arena.alloc(interface_eta),
|
||||
max_depth as u32,
|
||||
n_samples as u32,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::core::material::CreateMaterial;
|
|||
use crate::core::texture::SpectrumTexture;
|
||||
use crate::spectra::get_colorspace_device;
|
||||
use crate::utils::TextureParameterDictionary;
|
||||
use crate::{Arena, FileLoc, Upload, ArenaUpload};
|
||||
use crate::{Arena, ArenaUpload, FileLoc};
|
||||
use anyhow::Result;
|
||||
use shared::bxdfs::HairBxDF;
|
||||
use shared::core::material::Material;
|
||||
|
|
@ -60,7 +60,6 @@ impl CreateMaterial for HairMaterial {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl CreateMaterial for SubsurfaceMaterial {
|
||||
fn create(
|
||||
_parameters: &TextureParameterDictionary,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::core::image::{Image, ImageIO};
|
||||
use crate::core::image::{HostImage, ImageIO};
|
||||
use crate::core::shape::{CreateShape, ALL_BILINEAR_MESHES};
|
||||
use crate::core::texture::FloatTexture;
|
||||
use crate::utils::sampling::PiecewiseConstant2D;
|
||||
|
|
@ -6,7 +6,7 @@ use crate::{Arena, FileLoc, ParameterDictionary};
|
|||
use anyhow::{anyhow, Result};
|
||||
use log::warn;
|
||||
use shared::core::shape::Shape;
|
||||
use shared::shapes::BilinearPatchShape;
|
||||
use shared::shapes::{BilinearPatchMesh, BilinearPatchShape};
|
||||
use shared::{Ptr, Transform};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
|
@ -92,7 +92,7 @@ impl CreateShape for BilinearPatchShape {
|
|||
);
|
||||
None
|
||||
} else {
|
||||
let im = Image::read(Path::new(&filename), None)?;
|
||||
let im = HostImage::read(Path::new(&filename), None)?;
|
||||
let mut img = im.image;
|
||||
img.flip_y();
|
||||
Some(PiecewiseConstant2D::from_image(&img))
|
||||
|
|
@ -104,10 +104,10 @@ impl CreateShape for BilinearPatchShape {
|
|||
let host = BilinearPatchMesh::new(
|
||||
&render_from_object,
|
||||
reverse_orientation,
|
||||
vertex_indices,
|
||||
p,
|
||||
n,
|
||||
uv,
|
||||
&vertex_indices,
|
||||
&p,
|
||||
&n,
|
||||
&uv,
|
||||
image_dist,
|
||||
);
|
||||
|
||||
|
|
@ -116,8 +116,8 @@ impl CreateShape for BilinearPatchShape {
|
|||
// let mesh_index = global_store.len() as u32;
|
||||
global_store.push(host_arc.clone());
|
||||
drop(global_store);
|
||||
let n_patches = host_arc.device.n_patches;
|
||||
let mesh_ptr = Ptr::from(&host_arc.device);
|
||||
let n_patches = host_arc.n_patches;
|
||||
let mesh_ptr = arena.alloc_arc(host_arc);
|
||||
let mut shapes = Vec::with_capacity(n_patches as usize);
|
||||
for i in 0..n_patches as i32 {
|
||||
shapes.push(arena.alloc(Shape::BilinearPatch(BilinearPatchShape {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use crate::utils::sampling::PiecewiseConstant2D;
|
||||
use crate::Arena;
|
||||
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, Vector3f, VectorLike};
|
||||
use shared::shapes::mesh::{BilinearPatchMesh, TriangleMesh};
|
||||
use shared::{Ptr, Transform};
|
||||
use shared::core::geometry::{Normal3f, Point2f, Point3f, VectorLike};
|
||||
use shared::shapes::mesh::TriangleMesh;
|
||||
use shared::Transform;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
|
|
@ -269,11 +268,13 @@ impl TriQuadMesh {
|
|||
}
|
||||
|
||||
pub trait ReadTriangleMesh {
|
||||
pub fn from_ply<P: AsRef<Path>>(
|
||||
fn from_ply<P: AsRef<Path>>(
|
||||
filename: P,
|
||||
render_from_object: &Transform,
|
||||
reverse_orientation: bool,
|
||||
) -> AnyResult<Self>;
|
||||
) -> AnyResult<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl ReadTriangleMesh for TriangleMesh {
|
||||
|
|
|
|||
|
|
@ -99,8 +99,8 @@ impl CreateShape for TriangleShape {
|
|||
// let mesh_index = global_store.len() as u32;
|
||||
global_store.push(host_arc.clone());
|
||||
drop(global_store);
|
||||
let n_patches = host_arc.device.n_triangles;
|
||||
let mesh_ptr = Ptr::from(&host_arc.device);
|
||||
let n_patches = host_arc.n_triangles;
|
||||
let mesh_ptr = arena.alloc_arc(host_arc);
|
||||
let mut shapes = Vec::with_capacity(n_patches as usize);
|
||||
for i in 0..n_patches {
|
||||
shapes.push(arena.alloc(Shape::Triangle(TriangleShape {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ use shared::core::spectrum::{Spectrum, StandardSpectra};
|
|||
use shared::spectra::cie::{CIE_D65, CIE_X, CIE_Y, CIE_Z};
|
||||
use shared::spectra::{DenselySampledSpectrum, DeviceStandardColorSpaces, RGBColorSpace};
|
||||
use shared::Ptr;
|
||||
use std::sync::Arc;
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::{Arc, OnceLock, LazyLock};
|
||||
|
||||
pub mod colorspace;
|
||||
pub mod data;
|
||||
|
|
@ -68,7 +67,7 @@ pub static DCI_P3: LazyLock<Arc<RGBColorSpace>> = LazyLock::new(|| {
|
|||
Arc::new(RGBColorSpace::new(r, g, b, &illum, &table_ptr))
|
||||
});
|
||||
|
||||
pub static REC2020: LazyLock<Arc<RGBColorSpaceData>> = LazyLock::new(|| {
|
||||
pub static REC2020: LazyLock<Arc<RGBColorSpace>> = LazyLock::new(|| {
|
||||
let illum = get_d65_illuminant_buffer();
|
||||
let r = Point2f::new(0.708, 0.292);
|
||||
let g = Point2f::new(0.170, 0.797);
|
||||
|
|
@ -77,7 +76,7 @@ pub static REC2020: LazyLock<Arc<RGBColorSpaceData>> = LazyLock::new(|| {
|
|||
Arc::new(RGBColorSpace::new(r, g, b, &illum, &table_ptr))
|
||||
});
|
||||
|
||||
pub static ACES: LazyLock<Arc<RGBColorSpaceData>> = LazyLock::new(|| {
|
||||
pub static ACES: LazyLock<Arc<RGBColorSpace>> = LazyLock::new(|| {
|
||||
let illum = get_d65_illuminant_buffer();
|
||||
let r = Point2f::new(0.7347, 0.2653);
|
||||
let g = Point2f::new(0.0000, 1.0000);
|
||||
|
|
@ -88,10 +87,10 @@ pub static ACES: LazyLock<Arc<RGBColorSpaceData>> = LazyLock::new(|| {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StandardColorSpaces {
|
||||
pub srgb: Arc<RGBColorSpaceData>,
|
||||
pub dci_p3: Arc<RGBColorSpaceData>,
|
||||
pub rec2020: Arc<RGBColorSpaceData>,
|
||||
pub aces2065_1: Arc<RGBColorSpaceData>,
|
||||
pub srgb: Arc<RGBColorSpace>,
|
||||
pub dci_p3: Arc<RGBColorSpace>,
|
||||
pub rec2020: Arc<RGBColorSpace>,
|
||||
pub aces2065_1: Arc<RGBColorSpace>,
|
||||
}
|
||||
|
||||
impl StandardColorSpaces {
|
||||
|
|
@ -141,3 +140,4 @@ pub fn default_colorspace_ref() -> &'static RGBColorSpace {
|
|||
pub fn default_illuminant() -> Spectrum {
|
||||
Spectrum::Dense(default_colorspace().illuminant)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ use anyhow::Result;
|
|||
use shared::core::geometry::{Vector3f, VectorLike};
|
||||
use shared::core::texture::{SpectrumType, TextureEvalContext};
|
||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||
use shared::textures::{
|
||||
GPUFloatDirectionMixTexture, GPUFloatMixTexture, GPUSpectrumDirectionMixTexture,
|
||||
GPUSpectrumMixTexture,
|
||||
};
|
||||
use shared::utils::Transform;
|
||||
use shared::Float;
|
||||
use std::sync::Arc;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use crate::Arena;
|
|||
use anyhow::Result;
|
||||
use shared::core::texture::{SpectrumType, TextureEvalContext};
|
||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||
use shared::textures::{GPUFloatScaledTexture, GPUSpectrumScaledTexture};
|
||||
use shared::utils::Transform;
|
||||
use shared::Float;
|
||||
use std::sync::Arc;
|
||||
|
|
|
|||
|
|
@ -148,6 +148,13 @@ impl<A: GpuAllocator> Arena<A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn alloc_arc<T: Clone>(&self, value: Arc<T>) -> Ptr<T> {
|
||||
match Arc::try_unwrap(value) {
|
||||
Ok(inner) => self.alloc(inner),
|
||||
Err(arc) => self.alloc((*arc).clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_slice<T: Copy>(&self, values: &[T]) -> (Ptr<T>, usize) {
|
||||
let mut bump = self.bump.lock();
|
||||
let (ptr, len) = bump.alloc_slice(values);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::core::image::{Image, ImageIO};
|
||||
use shared::Float;
|
||||
use crate::core::image::{HostImage, ImageIO};
|
||||
use shared::core::color::{ColorEncoding, RGB};
|
||||
use shared::core::geometry::{Point2f, Point2i, Vector2f, VectorLike};
|
||||
use shared::core::image::{WrapMode, WrapMode2D};
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::math::{lerp, safe_sqrt, square};
|
||||
use shared::Float;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
use std::path::Path;
|
||||
|
|
@ -69,18 +69,18 @@ pub trait MIPMapSample:
|
|||
Copy + Add<Output = Self> + Sub<Output = Self> + Mul<Float, Output = Self> + std::fmt::Debug
|
||||
{
|
||||
fn zero() -> Self;
|
||||
fn sample_bilerp(image: &Image, st: Point2f, wrap: WrapMode2D) -> Self;
|
||||
fn sample_texel(image: &Image, st: Point2i, wrap: WrapMode2D) -> Self;
|
||||
fn sample_bilerp(image: &HostImage, st: Point2f, wrap: WrapMode2D) -> Self;
|
||||
fn sample_texel(image: &HostImage, st: Point2i, wrap: WrapMode2D) -> Self;
|
||||
}
|
||||
|
||||
impl MIPMapSample for Float {
|
||||
fn zero() -> Self {
|
||||
0.
|
||||
}
|
||||
fn sample_bilerp(image: &Image, st: Point2f, wrap: WrapMode2D) -> Self {
|
||||
fn sample_bilerp(image: &HostImage, st: Point2f, wrap: WrapMode2D) -> Self {
|
||||
image.bilerp_channel_with_wrap(st, 0, wrap)
|
||||
}
|
||||
fn sample_texel(image: &Image, st: Point2i, wrap: WrapMode2D) -> Self {
|
||||
fn sample_texel(image: &HostImage, st: Point2i, wrap: WrapMode2D) -> Self {
|
||||
image.get_channel_with_wrap(st, 0, wrap)
|
||||
}
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ impl MIPMapSample for RGB {
|
|||
fn zero() -> Self {
|
||||
RGB::new(0., 0., 0.)
|
||||
}
|
||||
fn sample_bilerp(image: &Image, st: Point2f, wrap: WrapMode2D) -> Self {
|
||||
fn sample_bilerp(image: &HostImage, st: Point2f, wrap: WrapMode2D) -> Self {
|
||||
let nc = image.n_channels();
|
||||
if nc >= 3 {
|
||||
let r = image.bilerp_channel_with_wrap(st, 0, wrap);
|
||||
|
|
@ -101,7 +101,7 @@ impl MIPMapSample for RGB {
|
|||
RGB::new(v, v, v)
|
||||
}
|
||||
}
|
||||
fn sample_texel(image: &Image, st: Point2i, wrap: WrapMode2D) -> Self {
|
||||
fn sample_texel(image: &HostImage, st: Point2i, wrap: WrapMode2D) -> Self {
|
||||
let nc = image.n_channels();
|
||||
if nc >= 3 {
|
||||
let r = image.get_channel_with_wrap(st, 0, wrap);
|
||||
|
|
@ -117,7 +117,7 @@ impl MIPMapSample for RGB {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MIPMap {
|
||||
pub pyramid: Vec<Image>,
|
||||
pub pyramid: Vec<HostImage>,
|
||||
pub color_space: Option<RGBColorSpace>,
|
||||
pub wrap_mode: WrapMode,
|
||||
pub options: MIPMapFilterOptions,
|
||||
|
|
@ -127,12 +127,12 @@ pub struct MIPMap {
|
|||
|
||||
impl MIPMap {
|
||||
pub fn new(
|
||||
image: Image,
|
||||
image: HostImage,
|
||||
color_space: Option<RGBColorSpace>,
|
||||
wrap_mode: WrapMode,
|
||||
options: MIPMapFilterOptions,
|
||||
) -> Self {
|
||||
let pyramid = Image::generate_pyramid(image, wrap_mode);
|
||||
let pyramid = HostImage::generate_pyramid(image, wrap_mode);
|
||||
Self {
|
||||
pyramid,
|
||||
color_space,
|
||||
|
|
@ -160,11 +160,11 @@ impl MIPMap {
|
|||
self.color_space.clone()
|
||||
}
|
||||
|
||||
pub fn get_level(&self, level: usize) -> &Image {
|
||||
pub fn get_level(&self, level: usize) -> &HostImage {
|
||||
&self.pyramid[level]
|
||||
}
|
||||
|
||||
pub fn base_image(&self) -> &Image {
|
||||
pub fn base_image(&self) -> &HostImage {
|
||||
&self.pyramid[0]
|
||||
}
|
||||
|
||||
|
|
@ -321,7 +321,7 @@ impl MIPMap {
|
|||
wrap_mode: WrapMode,
|
||||
encoding: ColorEncoding,
|
||||
) -> Result<MIPMap, ()> {
|
||||
let image_and_metadata = Image::read(filename, Some(encoding)).unwrap();
|
||||
let image_and_metadata = HostImage::read(filename, Some(encoding)).unwrap();
|
||||
let image = image_and_metadata.image;
|
||||
Ok(MIPMap::new(
|
||||
image,
|
||||
|
|
@ -345,7 +345,7 @@ impl MIPMap {
|
|||
}
|
||||
|
||||
#[cfg(feature = "cuda")]
|
||||
fn create_cuda_texture(pyramid: &[Image], wrap_mode: WrapMode) -> u64 {
|
||||
fn create_cuda_texture(pyramid: &[HostImage], wrap_mode: WrapMode) -> u64 {
|
||||
use cuda_runtime_sys::*;
|
||||
|
||||
let base = &pyramid[0];
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ pub mod mipmap;
|
|||
pub mod parallel;
|
||||
pub mod parameters;
|
||||
pub mod parser;
|
||||
pub mod sampling;
|
||||
pub mod strings;
|
||||
pub mod upload;
|
||||
|
||||
|
|
@ -18,6 +17,7 @@ pub use parameters::{
|
|||
ParameterDictionary, ParsedParameter, ParsedParameterVector, TextureParameterDictionary,
|
||||
};
|
||||
pub use strings::*;
|
||||
pub use mipmap::{MIPMap, MIPMapFilterOptions};
|
||||
pub use upload::{Upload, ArenaUpload};
|
||||
|
||||
#[cfg(feature = "vulkan")]
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use shared::spectra::{
|
|||
PiecewiseLinearSpectrum, RGBAlbedoSpectrum, RGBColorSpace, RGBIlluminantSpectrum,
|
||||
RGBUnboundedSpectrum,
|
||||
};
|
||||
use shared::Float;
|
||||
use shared::{gvec_from_slice, leak, Float};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{
|
||||
|
|
@ -682,8 +682,8 @@ impl ParameterDictionary {
|
|||
.unzip();
|
||||
|
||||
vec![Spectrum::Piecewise(leak(PiecewiseLinearSpectrum {
|
||||
lambdas: gvec_from_slice(lambdas),
|
||||
values: gvec_from_slice(values),
|
||||
lambdas: gvec_from_slice(&lambdas),
|
||||
values: gvec_from_slice(&values),
|
||||
count: lambdas.len() as u32,
|
||||
}))]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||
use crate::core::image::HostImage;
|
||||
use shared::core::image::Image;
|
||||
use crate::Arena;
|
||||
use shared::core::texture::{GPUFloatTexture, GPUSpectrumTexture};
|
||||
use shared::textures::*;
|
||||
|
|
@ -149,6 +151,27 @@ impl Upload for Option<Arc<SpectrumTexture>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Upload for HostImage {
|
||||
type Target = Ptr<Image>;
|
||||
fn upload(self, arena: &Arena) -> Ptr<Image> {
|
||||
arena.alloc(self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl Upload for Option<HostImage> {
|
||||
type Target = Ptr<Image>;
|
||||
fn upload(self, arena: &Arena) -> Ptr<Image> {
|
||||
arena.alloc_opt(self.map(|h| h.inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl Upload for Option<Arc<HostImage>> {
|
||||
type Target = Ptr<Image>;
|
||||
fn upload(self, arena: &Arena) -> Ptr<Image> {
|
||||
arena.alloc_opt(self.map(|h| h.as_ref().inner.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArenaUpload {
|
||||
fn upload<T: Upload>(&self, value: T) -> T::Target;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue