Finished work on the shared side. Now moving to host code. May god have mercy on my soul
This commit is contained in:
parent
5b4928e1aa
commit
050698c1d0
49 changed files with 818 additions and 357 deletions
|
|
@ -9,7 +9,7 @@ use_f64 = []
|
|||
use_gpu = ["dep:wgpu"]
|
||||
use_nvtx = ["dep:nvtx"]
|
||||
cuda = ["dep:cudarc", "dep:cust", "dep:cust_raw", "dep:cuda-runtime-sys"]
|
||||
vulkan = ["ash", "gpu-allocator"]
|
||||
vulkan = ["dep:ash", "dep:gpu-allocator", "shared/vulkan"]
|
||||
ash = ["dep:ash"]
|
||||
gpu-allocator = ["dep:gpu-allocator"]
|
||||
jemalloc = ["jemallocator"]
|
||||
|
|
|
|||
13
crates/ptex-filter/Cargo.toml
Normal file
13
crates/ptex-filter/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#![allow(unused)]
|
||||
|
||||
[package]
|
||||
name = "ptex-filter"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
pkg-config = "0.3"
|
||||
|
||||
[dependencies]
|
||||
ptex = "0.3.0"
|
||||
17
crates/ptex-filter/build.rs
Normal file
17
crates/ptex-filter/build.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
fn main() {
|
||||
println!("cargo:rerun-if-changed=cpp/ptex_filter_wrapper.cpp");
|
||||
|
||||
let home = std::env::var("HOME").unwrap();
|
||||
let ptex_include = format!("{}/.local/include", home);
|
||||
let ptex_lib = format!("{}/.local/lib", home);
|
||||
|
||||
cc::Build::new()
|
||||
.cpp(true)
|
||||
.file("cpp/ptex_filter_wrapper.cpp")
|
||||
.include(&ptex_include)
|
||||
.flag("-std=c++17")
|
||||
.compile("ptex_filter_wrapper");
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", ptex_lib);
|
||||
println!("cargo:rustc-link-lib=Ptex");
|
||||
}
|
||||
65
crates/ptex-filter/cpp/ptex_filter_wrapper.cpp
Normal file
65
crates/ptex-filter/cpp/ptex_filter_wrapper.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#include "ptex_filter_wrapper.h"
|
||||
#include <Ptexture.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
PtexFilterHandle ptex_filter_create(PtexTextureHandle texture, const PtexFilterOptions* opts) {
|
||||
Ptex::PtexTexture* tex = static_cast<Ptex::PtexTexture*>(texture);
|
||||
if (!tex || !opts) return nullptr;
|
||||
|
||||
Ptex::PtexFilter::Options ptex_opts;
|
||||
ptex_opts.filter = static_cast<Ptex::PtexFilter::FilterType>(opts->filter);
|
||||
ptex_opts.lerp = opts->lerp;
|
||||
ptex_opts.sharpness = opts->sharpness;
|
||||
ptex_opts.noedgeblend = opts->noedgeblend != 0;
|
||||
|
||||
return Ptex::PtexFilter::getFilter(tex, ptex_opts);
|
||||
}
|
||||
|
||||
void ptex_filter_eval(
|
||||
PtexFilterHandle filter,
|
||||
float* result,
|
||||
int32_t first_channel,
|
||||
int32_t num_channels,
|
||||
int32_t face_id,
|
||||
float u, float v,
|
||||
float dudx, float dvdx,
|
||||
float dudy, float dvdy
|
||||
) {
|
||||
Ptex::PtexFilter* f = static_cast<Ptex::PtexFilter*>(filter);
|
||||
if (f && result) {
|
||||
f->eval(result, first_channel, num_channels, face_id, u, v, dudx, dvdx, dudy, dvdy);
|
||||
}
|
||||
}
|
||||
|
||||
void ptex_filter_release(PtexFilterHandle filter) {
|
||||
Ptex::PtexFilter* f = static_cast<Ptex::PtexFilter*>(filter);
|
||||
if (f) {
|
||||
f->release();
|
||||
}
|
||||
}
|
||||
|
||||
PtexTextureHandle ptex_texture_open(const char* filename, char** error_str) {
|
||||
Ptex::String error;
|
||||
Ptex::PtexTexture* tex = Ptex::PtexTexture::open(filename, error);
|
||||
|
||||
if (!tex && error_str) {
|
||||
*error_str = strdup(error.c_str());
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void ptex_texture_release(PtexTextureHandle texture) {
|
||||
Ptex::PtexTexture* tex = static_cast<Ptex::PtexTexture*>(texture);
|
||||
if (tex) {
|
||||
tex->release();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ptex_texture_num_channels(PtexTextureHandle texture) {
|
||||
Ptex::PtexTexture* tex = static_cast<Ptex::PtexTexture*>(texture);
|
||||
return tex ? tex->numChannels() : 0;
|
||||
}
|
||||
|
||||
}
|
||||
51
crates/ptex-filter/cpp/ptex_filter_wrapper.h
Normal file
51
crates/ptex-filter/cpp/ptex_filter_wrapper.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void* PtexTextureHandle;
|
||||
typedef void* PtexFilterHandle;
|
||||
|
||||
typedef enum {
|
||||
PTEX_FILTER_POINT = 0,
|
||||
PTEX_FILTER_BILINEAR = 1,
|
||||
PTEX_FILTER_BOX = 2,
|
||||
PTEX_FILTER_GAUSSIAN = 3,
|
||||
PTEX_FILTER_BICUBIC = 4,
|
||||
PTEX_FILTER_BSPLINE = 5,
|
||||
PTEX_FILTER_CATMULLROM = 6,
|
||||
PTEX_FILTER_MITCHELL = 7
|
||||
} PtexFilterType;
|
||||
|
||||
typedef struct {
|
||||
PtexFilterType filter;
|
||||
int32_t lerp;
|
||||
float sharpness;
|
||||
int32_t noedgeblend;
|
||||
} PtexFilterOptions;
|
||||
|
||||
PtexTextureHandle ptex_texture_open(const char* filename, char** error_str);
|
||||
void ptex_filter_release(PtexFilterHandle filter);
|
||||
int32_t ptex_texture_num_channels(PtexTextureHandle texture);
|
||||
PtexFilterHandle ptex_filter_create(PtexTextureHandle texture, const PtexFilterOptions* opts);
|
||||
|
||||
|
||||
void ptex_filter_eval(
|
||||
PtexFilterHandle filter,
|
||||
float* result,
|
||||
int32_t first_channel,
|
||||
int32_t num_channels,
|
||||
int32_t face_id,
|
||||
float u, float v,
|
||||
float dudx, float dvdx,
|
||||
float dudy, float dvdy
|
||||
);
|
||||
void ptex_filter_release(PtexFilterHandle filter);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
60
crates/ptex-filter/src/ffi.rs
Normal file
60
crates/ptex-filter/src/ffi.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
use std::ffi::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PtexFilterType {
|
||||
Point = 0,
|
||||
Bilinear = 1,
|
||||
Box = 2,
|
||||
Gaussian = 3,
|
||||
Bicubic = 4,
|
||||
BSpline = 5,
|
||||
CatmullRom = 6,
|
||||
Mitchell = 7,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PtexFilterOptions {
|
||||
pub filter: PtexFilterType,
|
||||
pub lerp: i32,
|
||||
pub sharpness: f32,
|
||||
pub noedgeblend: i32,
|
||||
}
|
||||
|
||||
impl Default for PtexFilterOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
filter: PtexFilterType::BSpline,
|
||||
lerp: 1,
|
||||
sharpness: 0.0,
|
||||
noedgeblend: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn ptex_filter_create(texture: *mut c_void, opts: *const PtexFilterOptions) -> *mut c_void;
|
||||
|
||||
pub fn ptex_filter_eval(
|
||||
filter: *mut c_void,
|
||||
result: *mut f32,
|
||||
first_channel: i32,
|
||||
num_channels: i32,
|
||||
face_id: i32,
|
||||
u: f32,
|
||||
v: f32,
|
||||
dudx: f32,
|
||||
dvdx: f32,
|
||||
dudy: f32,
|
||||
dvdy: f32,
|
||||
);
|
||||
|
||||
pub fn ptex_filter_release(filter: *mut c_void);
|
||||
pub fn ptex_texture_open(
|
||||
filename: *const std::ffi::c_char,
|
||||
error_str: *mut *mut std::ffi::c_char,
|
||||
) -> *mut c_void;
|
||||
pub fn ptex_texture_release(texture: *mut c_void);
|
||||
pub fn ptex_texture_num_channels(texture: *mut c_void) -> i32;
|
||||
}
|
||||
66
crates/ptex-filter/src/lib.rs
Normal file
66
crates/ptex-filter/src/lib.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#![allow(unused)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod ffi;
|
||||
|
||||
pub use ffi::{ptex_filter_create, PtexFilterOptions, PtexFilterType};
|
||||
|
||||
use std::ffi::c_void;
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub struct PtexFilter {
|
||||
handle: NonNull<c_void>,
|
||||
_marker: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
impl PtexFilter {
|
||||
/// Creates a new Ptex filter pointer
|
||||
///
|
||||
/// # Safety
|
||||
pub unsafe fn new(texture_ptr: *mut c_void, opts: &PtexFilterOptions) -> Option<Self> {
|
||||
let handle = ffi::ptex_filter_create(texture_ptr, opts);
|
||||
NonNull::new(handle).map(|h| Self {
|
||||
handle: h,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn eval(
|
||||
&self,
|
||||
face_id: i32,
|
||||
u: f32,
|
||||
v: f32,
|
||||
dudx: f32,
|
||||
dvdx: f32,
|
||||
dudy: f32,
|
||||
dvdy: f32,
|
||||
num_channels: i32,
|
||||
) -> [f32; 4] {
|
||||
let mut result = [0.0f32; 4];
|
||||
unsafe {
|
||||
ffi::ptex_filter_eval(
|
||||
self.handle.as_ptr(),
|
||||
result.as_mut_ptr(),
|
||||
0,
|
||||
num_channels.min(4),
|
||||
face_id,
|
||||
u,
|
||||
v,
|
||||
dudx,
|
||||
dvdx,
|
||||
dudy,
|
||||
dvdy,
|
||||
);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PtexFilter {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::ptex_filter_release(self.handle.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,12 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "2.10.0"
|
||||
half = "2.7.1"
|
||||
bytemuck = { version = "1.24.0", features = ["derive"] }
|
||||
enum_dispatch = "0.3.13"
|
||||
ash = { version = "0.38", optional = true }
|
||||
parking_lot = { version = "0.12.5", optional = true }
|
||||
gpu-allocator = { version = "0.28", features = ["vulkan"], optional = true }
|
||||
num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }
|
||||
cuda_std = { git = "https://github.com/Rust-GPU/Rust-CUDA", branch = "main", default-features = false, optional = true }
|
||||
|
||||
|
|
@ -14,3 +18,4 @@ cuda_std = { git = "https://github.com/Rust-GPU/Rust-CUDA", branch = "main", def
|
|||
use_f64 = []
|
||||
cuda = ["cuda_std"]
|
||||
cpu_debug = []
|
||||
vulkan = ["dep:ash", "dep:gpu-allocator", "dep:parking_lot"]
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ use num_traits::Float as NumFloat;
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MeasuredBxDFData {
|
||||
pub wavelengths: Ptr<Float>,
|
||||
pub spectra: PiecewiseLinear2D<3>,
|
||||
pub ndf: PiecewiseLinear2D<0>,
|
||||
pub vndf: PiecewiseLinear2D<2>,
|
||||
pub sigma: PiecewiseLinear2D<0>,
|
||||
pub isotropic: bool,
|
||||
pub luminance: PiecewiseLinear2D<2>,
|
||||
pub wavelengths: Ptr<Float>,
|
||||
pub spectra: Ptr<PiecewiseLinear2D<3>>,
|
||||
pub ndf: Ptr<PiecewiseLinear2D<0>>,
|
||||
pub vndf: Ptr<PiecewiseLinear2D<2>>,
|
||||
pub sigma: Ptr<PiecewiseLinear2D<0>>,
|
||||
pub luminance: Ptr<PiecewiseLinear2D<2>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::core::sampler::CameraSample;
|
|||
use crate::core::scattering::refract;
|
||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||
use crate::utils::math::{lerp, quadratic, square};
|
||||
use crate::{Float, GVec, Ptr, PI};
|
||||
use crate::{Float, GVec, Ptr, PI, gvec};
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
#[repr(C)]
|
||||
|
|
@ -32,7 +32,7 @@ pub struct ExitPupilSample {
|
|||
pub const EXIT_PUPIL_SAMPLES: usize = 64;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RealisticCamera {
|
||||
pub base: CameraBase,
|
||||
pub focus_distance: Float,
|
||||
|
|
@ -75,7 +75,8 @@ impl RealisticCamera {
|
|||
if curvature_radius == 0.0 {
|
||||
aperture_diameter /= 1000.0;
|
||||
if set_aperture_diameter > aperture_diameter {
|
||||
println!("Aperture is larger than possible")
|
||||
// println!("Aperture is larger than possible")
|
||||
aperture_diameter = -1.;
|
||||
} else {
|
||||
aperture_diameter = set_aperture_diameter;
|
||||
}
|
||||
|
|
@ -113,6 +114,10 @@ impl RealisticCamera {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn lens(&self, idx: usize) -> &LensElementInterface {
|
||||
unsafe { &*self.element_interfaces.as_ptr().add(idx) }
|
||||
}
|
||||
|
||||
pub fn compute_cardinal_points(r_in: Ray, r_out: Ray) -> (Float, Float) {
|
||||
let tf = -r_out.o.x() / r_out.d.x();
|
||||
let tp = (r_in.o.x() - r_out.o.x()) / r_out.d.x();
|
||||
|
|
@ -162,14 +167,12 @@ impl RealisticCamera {
|
|||
);
|
||||
}
|
||||
let delta = (pz[1] - z + pz[0] - c.sqrt()) / 2.;
|
||||
let last_interface = unsafe { self.element_interfaces.add(self.n_elements) };
|
||||
let last_interface = unsafe { self.lens(self.n_elements - 1) };
|
||||
last_interface.thickness + delta
|
||||
}
|
||||
|
||||
pub fn bound_exit_pupil(&self, film_x_0: Float, film_x_1: Float) -> Bounds2f {
|
||||
let interface_array = unsafe {
|
||||
core::slice::from_raw_parts(self.element_interfaces.as_raw(), self.n_elements as usize)
|
||||
};
|
||||
let interface_array = self.element_interfaces.as_slice();
|
||||
Self::compute_exit_pupil_bounds(interface_array, film_x_0, film_x_1)
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +194,6 @@ impl RealisticCamera {
|
|||
let trace_lenses_from_film = |_ray: Ray, _place: Option<Ray>| true;
|
||||
for i in 0..n_samples {
|
||||
// Find location of sample points on $x$ segment and rear lens element
|
||||
//
|
||||
let p_film = Point3f::new(
|
||||
lerp((i as Float + 0.5) / n_samples as Float, film_x_0, film_x_1),
|
||||
0.,
|
||||
|
|
@ -272,7 +274,7 @@ impl RealisticCamera {
|
|||
);
|
||||
|
||||
for i in (0..self.n_elements - 1).rev() {
|
||||
let element: &LensElementInterface = unsafe { &self.element_interfaces.add(i) };
|
||||
let element: &LensElementInterface = unsafe { self.lens(i) };
|
||||
// Update ray from film accounting for interaction with _element_
|
||||
element_z -= element.thickness;
|
||||
|
||||
|
|
@ -311,7 +313,7 @@ impl RealisticCamera {
|
|||
// Update ray path for element interface interaction
|
||||
if !is_stop {
|
||||
let eta_i = element.eta;
|
||||
let interface_i = unsafe { self.element_interfaces.add(i - 1) };
|
||||
let interface_i = unsafe { self.lens(i) };
|
||||
let eta_t = if i > 0 && interface_i.eta != 0. {
|
||||
interface_i.eta
|
||||
} else {
|
||||
|
|
@ -372,21 +374,21 @@ impl RealisticCamera {
|
|||
}
|
||||
|
||||
pub fn lens_rear_z(&self) -> Float {
|
||||
let last_interface = unsafe { self.element_interfaces.add(self.n_elements - 1) };
|
||||
let last_interface = unsafe { self.lens(self.n_elements - 1) };
|
||||
last_interface.thickness
|
||||
}
|
||||
|
||||
pub fn lens_front_z(&self) -> Float {
|
||||
let mut z_sum = 0.;
|
||||
for i in 0..self.n_elements {
|
||||
let element = unsafe { self.element_interfaces.add(i) };
|
||||
let element = unsafe { self.lens(i) };
|
||||
z_sum += element.thickness;
|
||||
}
|
||||
z_sum
|
||||
}
|
||||
|
||||
pub fn rear_element_radius(&self) -> Float {
|
||||
let last_interface = unsafe { self.element_interfaces.add(self.n_elements - 1) };
|
||||
let last_interface = unsafe { self.lens(self.n_elements - 1) };
|
||||
last_interface.aperture_radius
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use crate::core::geometry::{Bounds3f, Ray, Vector3f};
|
||||
use crate::core::pbrt::Float;
|
||||
use crate::core::primitive::{Primitive, PrimitiveTrait};
|
||||
use crate::core::shape::ShapeIntersection;
|
||||
use crate::{Float, Ptr, GVec, gvec};
|
||||
use crate::utils::Ptr;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -18,11 +16,11 @@ pub struct LinearBVHNode {
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BVHAggregate {
|
||||
pub max_prims_in_node: u32,
|
||||
pub primitives: GVec<Primitive>,
|
||||
pub primitive_count: u32,
|
||||
pub nodes: GVec<LinearBVHNode>,
|
||||
pub node_count: u32,
|
||||
pub max_prims_in_node: u32,
|
||||
pub primitive_count: u32,
|
||||
pub primitives: GVec<Primitive>,
|
||||
pub nodes: GVec<LinearBVHNode>,
|
||||
}
|
||||
|
||||
impl BVHAggregate {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ pub struct CameraBase {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[enum_dispatch(CameraTrait)]
|
||||
pub enum Camera {
|
||||
Perspective(PerspectiveCamera),
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
use crate::core::geometry::Point2f;
|
||||
use crate::core::spectrum::Spectrum;
|
||||
use crate::utils::find_interval;
|
||||
use crate::utils::math::{clamp, evaluate_polynomial, lerp, SquareMatrix, SquareMatrix3f};
|
||||
use crate::{Float, GVec, Ptr};
|
||||
use core::any::TypeId;
|
||||
use core::fmt;
|
||||
use core::ops::{
|
||||
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
||||
};
|
||||
|
||||
use crate::Float;
|
||||
use crate::core::geometry::Point2f;
|
||||
use crate::core::spectrum::Spectrum;
|
||||
use crate::utils::Ptr;
|
||||
use crate::utils::find_interval;
|
||||
use crate::utils::math::{SquareMatrix, SquareMatrix3f, clamp, evaluate_polynomial, lerp};
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
|
|
@ -311,17 +308,33 @@ impl RGB {
|
|||
|
||||
pub fn min_component_index(&self) -> u32 {
|
||||
if self.r < self.g {
|
||||
if self.r < self.b { 0 } else { 2 }
|
||||
if self.r < self.b {
|
||||
0
|
||||
} else {
|
||||
if self.g < self.b { 1 } else { 2 }
|
||||
2
|
||||
}
|
||||
} else {
|
||||
if self.g < self.b {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_component_index(&self) -> u32 {
|
||||
if self.r > self.g {
|
||||
if self.r > self.b { 0 } else { 2 }
|
||||
if self.r > self.b {
|
||||
0
|
||||
} else {
|
||||
if self.g > self.b { 1 } else { 2 }
|
||||
2
|
||||
}
|
||||
} else {
|
||||
if self.g > self.b {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1086,10 +1099,10 @@ impl Mul<Float> for Coeffs {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct RGBToSpectrumTable {
|
||||
pub z_nodes: GVec<Float>,
|
||||
pub coeffs: GVec<Coeffs>,
|
||||
pub z_nodes: Ptr<Float>,
|
||||
pub coeffs: Ptr<Coeffs>,
|
||||
pub n_nodes: u32,
|
||||
}
|
||||
|
||||
|
|
@ -1114,7 +1127,11 @@ impl RGBToSpectrumTable {
|
|||
|
||||
// Identify the primary bucket (c) based on the dominant axis
|
||||
let c_idx = if rgb[0] > rgb[1] {
|
||||
if rgb[0] > rgb[2] { 0 } else { 2 }
|
||||
if rgb[0] > rgb[2] {
|
||||
0
|
||||
} else {
|
||||
2
|
||||
}
|
||||
} else if rgb[1] > rgb[2] {
|
||||
1
|
||||
} else {
|
||||
|
|
@ -1136,7 +1153,7 @@ impl RGBToSpectrumTable {
|
|||
let x = coord_a / z;
|
||||
let y = coord_b / z;
|
||||
|
||||
let z_nodes = &self.z_nodes;
|
||||
let z_nodes = unsafe { core::slice::from_raw_parts(self.z_nodes.as_raw(), RES as usize) };
|
||||
let zi = find_interval(RES, |i| z_nodes[i as usize] < z) as usize;
|
||||
let dz = (z - z_nodes[zi]) / (z_nodes[zi + 1] - z_nodes[zi]);
|
||||
let x_float = x * (RES - 1) as Float;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::utils::math::{wrap_equal_area_square, SquareMatrix};
|
|||
use crate::utils::sampling::VarianceEstimator;
|
||||
use crate::utils::transform::AnimatedTransform;
|
||||
use crate::utils::{gpu_array_from_fn, AtomicFloat};
|
||||
use crate::{gvec_with_capacity, Array2D, Float, Ptr};
|
||||
use crate::{gvec_from_slice, gvec_with_capacity, Array2D, Float, GVec, Ptr};
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
#[repr(C)]
|
||||
|
|
@ -84,7 +84,7 @@ impl RGBFilm {
|
|||
filter_integral,
|
||||
output_rgbf_from_sensor_rgb,
|
||||
pixels,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base(&self) -> &FilmBase {
|
||||
|
|
@ -465,7 +465,7 @@ impl SpectralFilm {
|
|||
}
|
||||
|
||||
SpectralFilm {
|
||||
base,
|
||||
base: *base,
|
||||
colorspace: colorspace.clone(),
|
||||
lambda_min,
|
||||
lambda_max,
|
||||
|
|
@ -474,12 +474,7 @@ impl SpectralFilm {
|
|||
write_fp16,
|
||||
filter_integral: base.filter.integral(),
|
||||
output_rgbf_from_sensor_rgb: SquareMatrix::identity(),
|
||||
|
||||
pixels: Array2D {
|
||||
values: pixels.values.as_mut_ptr(),
|
||||
extent: base.pixel_bounds,
|
||||
},
|
||||
|
||||
pixels: Array2D::from_slice(base.pixel_bounds, pixels.as_slice()),
|
||||
bucket_sums,
|
||||
weight_sums,
|
||||
bucket_splats,
|
||||
|
|
@ -522,9 +517,9 @@ impl SpectralFilm {
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PixelSensor {
|
||||
pub xyz_from_sensor_rgb: SquareMatrix<Float, 3>,
|
||||
pub r_bar: DenselySampledSpectrum,
|
||||
pub g_bar: DenselySampledSpectrum,
|
||||
pub b_bar: DenselySampledSpectrum,
|
||||
pub r_bar: Ptr<DenselySampledSpectrum>,
|
||||
pub g_bar: Ptr<DenselySampledSpectrum>,
|
||||
pub b_bar: Ptr<DenselySampledSpectrum>,
|
||||
pub imaging_ratio: Float,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::core::geometry::{Bounds2f, Bounds2i, Point2f, Point2i, Vector2f};
|
|||
use crate::filters::*;
|
||||
use crate::utils::math::{gaussian, gaussian_integral, lerp, sample_tent, windowed_sinc};
|
||||
use crate::utils::sampling::PiecewiseConstant2D;
|
||||
use crate::{Array2D, Float};
|
||||
use crate::{Array2D, Float, Ptr};
|
||||
use enum_dispatch::enum_dispatch;
|
||||
|
||||
pub struct FilterSample {
|
||||
|
|
@ -11,7 +11,7 @@ pub struct FilterSample {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FilterSampler {
|
||||
pub domain: Bounds2f,
|
||||
pub distrib: PiecewiseConstant2D,
|
||||
|
|
@ -66,9 +66,26 @@ pub trait FilterTrait {
|
|||
#[enum_dispatch(FilterTrait)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Filter {
|
||||
Box(BoxFilter),
|
||||
Gaussian(GaussianFilter),
|
||||
Mitchell(MitchellFilter),
|
||||
LanczosSinc(LanczosSincFilter),
|
||||
Triangle(TriangleFilter),
|
||||
Box(Ptr<BoxFilter>),
|
||||
Gaussian(Ptr<GaussianFilter>),
|
||||
Mitchell(Ptr<MitchellFilter>),
|
||||
LanczosSinc(Ptr<LanczosSincFilter>),
|
||||
Triangle(Ptr<TriangleFilter>),
|
||||
}
|
||||
|
||||
impl<T: FilterTrait> FilterTrait for Ptr<T> {
|
||||
fn radius(&self) -> Vector2f {
|
||||
unsafe { self.as_ref().radius() }
|
||||
}
|
||||
fn integral(&self) -> Float {
|
||||
unsafe { self.as_ref().integral() }
|
||||
}
|
||||
|
||||
fn evaluate(&self, p: Point2f) -> Float {
|
||||
unsafe { self.as_ref().evaluate(p) }
|
||||
}
|
||||
|
||||
fn sample(&self, p: Point2f) -> FilterSample {
|
||||
unsafe { self.as_ref().sample(p) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use crate::core::color::{ColorEncoding, ColorEncodingTrait, LINEAR};
|
||||
use crate::core::geometry::{Bounds2f, Point2f, Point2fi, Point2i};
|
||||
use crate::utils::math::{f16_to_f32_software, lerp, square};
|
||||
use crate::Float;
|
||||
use crate::GVec;
|
||||
use crate::{gvec_with_capacity, Float, GVec};
|
||||
use core::hash;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use num_traits::Float as NumFloat;
|
||||
|
|
@ -69,7 +68,7 @@ impl PixelFormat {
|
|||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Pixels {
|
||||
pixels: GVec<u8>,
|
||||
data: GVec<u8>,
|
||||
format: PixelFormat,
|
||||
}
|
||||
|
||||
|
|
@ -95,17 +94,17 @@ impl Pixels {
|
|||
}
|
||||
|
||||
pub unsafe fn read_u8(&self, texel_offset: usize) -> u8 {
|
||||
*self.data.as_ptr().add(texel_offset)
|
||||
unsafe { *self.data.as_ptr().add(texel_offset) }
|
||||
}
|
||||
|
||||
pub unsafe fn read_f16(&self, texel_offset: usize) -> u16 {
|
||||
let byte_offset = texel_offset * 2;
|
||||
*(self.data.as_ptr().add(byte_offset) as *const u16)
|
||||
unsafe { *(self.data.as_ptr().add(byte_offset) as *const u16) }
|
||||
}
|
||||
|
||||
pub unsafe fn read_f32(&self, texel_offset: usize) -> f32 {
|
||||
let byte_offset = texel_offset * 4;
|
||||
*(self.data.as_ptr().add(byte_offset) as *const f32)
|
||||
unsafe { *(self.data.as_ptr().add(byte_offset) as *const f32) }
|
||||
}
|
||||
|
||||
pub unsafe fn read(&self, texel_offset: usize, encoding: &ColorEncoding) -> Float {
|
||||
|
|
@ -117,17 +116,17 @@ impl Pixels {
|
|||
}
|
||||
|
||||
pub unsafe fn write_u8(&mut self, texel_offset: usize, val: u8) {
|
||||
*self.data.as_mut_ptr().add(texel_offset) = val;
|
||||
unsafe { *self.data.as_mut_ptr().add(texel_offset) = val };
|
||||
}
|
||||
|
||||
pub unsafe fn write_f16(&mut self, texel_offset: usize, val: u16) {
|
||||
let byte_offset = texel_offset * 2;
|
||||
*(self.data.as_mut_ptr().add(byte_offset) as *mut u16) = val;
|
||||
unsafe { *(self.data.as_mut_ptr().add(byte_offset) as *mut u16) = val };
|
||||
}
|
||||
|
||||
pub unsafe fn write_f32(&mut self, texel_offset: usize, val: f32) {
|
||||
let byte_offset = texel_offset * 4;
|
||||
*(self.data.as_mut_ptr().add(byte_offset) as *mut f32) = val;
|
||||
unsafe { *(self.data.as_mut_ptr().add(byte_offset) as *mut f32) = val };
|
||||
}
|
||||
|
||||
pub fn empty(texel_count: usize, format: PixelFormat) -> Self {
|
||||
|
|
@ -194,6 +193,14 @@ impl Pixels {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ImageBase {
|
||||
pub format: PixelFormat,
|
||||
pub encoding: ColorEncoding,
|
||||
pub resolution: Point2i,
|
||||
pub n_channels: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Image {
|
||||
pub format: PixelFormat,
|
||||
|
|
@ -299,6 +306,15 @@ impl Image {
|
|||
true
|
||||
}
|
||||
|
||||
pub fn base(&self) -> ImageBase {
|
||||
ImageBase {
|
||||
format: self.format,
|
||||
encoding: self.encoding,
|
||||
resolution: self.resolution,
|
||||
n_channels: self.n_channels,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_channel(&self, p: Point2i, c: i32) -> Float {
|
||||
self.get_channel_with_wrap(p, c, WrapMode::Clamp.into())
|
||||
}
|
||||
|
|
@ -329,11 +345,11 @@ impl Image {
|
|||
self.get_channel_with_wrap(pi, c, wrap_mode)
|
||||
}
|
||||
|
||||
pub fn get_channels_array<const N: usize>(&self, p: Point2i) -> [Float; N] {
|
||||
self.get_channels_array_with_wrap(p, WrapMode::Clamp.into())
|
||||
pub fn get_channels<const N: usize>(&self, p: Point2i) -> [Float; N] {
|
||||
self.get_channels_with_wrap(p, WrapMode::Clamp.into())
|
||||
}
|
||||
|
||||
pub fn get_channels_array_with_wrap<const N: usize>(
|
||||
pub fn get_channels_with_wrap<const N: usize>(
|
||||
&self,
|
||||
mut p: Point2i,
|
||||
wrap_mode: WrapMode2D,
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ impl MajorantGrid {
|
|||
let idx = x + self.res.x() * (y + self.res.y() * z);
|
||||
|
||||
unsafe {
|
||||
*self.voxels.as_ptr().add(idx as usize) = v;
|
||||
*self.voxels.as_mut_ptr().add(idx as usize) = v;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ pub struct DDAMajorantIterator {
|
|||
sigma_t: SampledSpectrum,
|
||||
t_min: Float,
|
||||
t_max: Float,
|
||||
grid: MajorantGrid,
|
||||
grid: Ptr<MajorantGrid>,
|
||||
next_crossing_t: [Float; 3],
|
||||
delta_t: [Float; 3],
|
||||
step: [i32; 3],
|
||||
|
|
@ -249,7 +249,7 @@ impl DDAMajorantIterator {
|
|||
t_min,
|
||||
t_max,
|
||||
sigma_t: *sigma_t,
|
||||
grid: *grid,
|
||||
grid: Ptr::from(&*grid),
|
||||
next_crossing_t: [0.0; 3],
|
||||
delta_t: [0.0; 3],
|
||||
step: [0; 3],
|
||||
|
|
@ -452,9 +452,9 @@ pub enum Medium {
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct HomogeneousMedium {
|
||||
pub sigma_a_spec: DenselySampledSpectrum,
|
||||
pub sigma_s_spec: DenselySampledSpectrum,
|
||||
pub le_spec: DenselySampledSpectrum,
|
||||
pub sigma_a_spec: Ptr<DenselySampledSpectrum>,
|
||||
pub sigma_s_spec: Ptr<DenselySampledSpectrum>,
|
||||
pub le_spec: Ptr<DenselySampledSpectrum>,
|
||||
pub phase: HGPhaseFunction,
|
||||
}
|
||||
|
||||
|
|
@ -496,15 +496,15 @@ impl MediumTrait for HomogeneousMedium {
|
|||
pub struct GridMedium {
|
||||
pub bounds: Bounds3f,
|
||||
pub render_from_medium: Transform,
|
||||
pub sigma_a_spec: DenselySampledSpectrum,
|
||||
pub sigma_s_spec: DenselySampledSpectrum,
|
||||
pub density_grid: SampledGrid<Float>,
|
||||
pub sigma_a_spec: Ptr<DenselySampledSpectrum>,
|
||||
pub sigma_s_spec: Ptr<DenselySampledSpectrum>,
|
||||
pub density_grid: Ptr<SampledGrid<Float>>,
|
||||
pub phase: HGPhaseFunction,
|
||||
pub temperature_grid: Option<SampledGrid<Float>>,
|
||||
pub le_spec: DenselySampledSpectrum,
|
||||
pub le_scale: SampledGrid<Float>,
|
||||
pub temperature_grid: Ptr<SampledGrid<Float>>,
|
||||
pub le_spec: Ptr<DenselySampledSpectrum>,
|
||||
pub le_scale: Ptr<SampledGrid<Float>>,
|
||||
pub is_emissive: bool,
|
||||
pub majorant_grid: MajorantGrid,
|
||||
pub majorant_grid: Ptr<MajorantGrid>,
|
||||
}
|
||||
|
||||
impl MediumTrait for GridMedium {
|
||||
|
|
@ -527,8 +527,8 @@ impl MediumTrait for GridMedium {
|
|||
};
|
||||
|
||||
let le = if scale > 0.0 {
|
||||
let raw_emission = if let Some(temp_grid) = &self.temperature_grid {
|
||||
let temp = temp_grid.lookup(p);
|
||||
let raw_emission = if !self.temperature_grid.is_null() {
|
||||
let temp = self.temperature_grid.lookup(p);
|
||||
BlackbodySpectrum::new(temp).sample(lambda)
|
||||
} else {
|
||||
self.le_spec.sample(lambda)
|
||||
|
|
@ -592,10 +592,10 @@ pub struct RGBGridMedium {
|
|||
pub phase: HGPhaseFunction,
|
||||
pub le_scale: Float,
|
||||
pub sigma_scale: Float,
|
||||
pub sigma_a_grid: SampledGrid<RGBUnboundedSpectrum>,
|
||||
pub sigma_s_grid: SampledGrid<RGBUnboundedSpectrum>,
|
||||
pub le_grid: SampledGrid<RGBIlluminantSpectrum>,
|
||||
pub majorant_grid: MajorantGrid,
|
||||
pub sigma_a_grid: Ptr<SampledGrid<RGBUnboundedSpectrum>>,
|
||||
pub sigma_s_grid: Ptr<SampledGrid<RGBUnboundedSpectrum>>,
|
||||
pub le_grid: Ptr<SampledGrid<RGBIlluminantSpectrum>>,
|
||||
pub majorant_grid: Ptr<MajorantGrid>,
|
||||
}
|
||||
|
||||
impl MediumTrait for RGBGridMedium {
|
||||
|
|
|
|||
|
|
@ -213,6 +213,23 @@ pub enum Primitive {
|
|||
Geometric(GeometricPrimitive),
|
||||
Transformed(TransformedPrimitive),
|
||||
Animated(AnimatedPrimitive),
|
||||
BVH(BVHAggregate),
|
||||
BVH(Ptr<BVHAggregate>),
|
||||
KdTree(KdTreeAggregate),
|
||||
}
|
||||
|
||||
|
||||
impl<T: PrimitiveTrait> PrimitiveTrait for Ptr<T> {
|
||||
fn bounds(&self) -> Bounds3f {
|
||||
unsafe { self.as_ref().bounds() }
|
||||
}
|
||||
|
||||
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
|
||||
unsafe { self.as_ref().intersect(r, t_max) }
|
||||
}
|
||||
|
||||
fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool {
|
||||
unsafe { self.as_ref().intersect_p(r, t_max) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ pub struct HaltonSampler {
|
|||
pub mult_inverse: [u64; 2],
|
||||
pub halton_index: u64,
|
||||
pub dim: u32,
|
||||
pub digit_permutations: GVec<DigitPermutation>,
|
||||
pub digit_permutations: Ptr<DigitPermutation>,
|
||||
}
|
||||
|
||||
#[allow(clippy::derivable_impls)]
|
||||
|
|
@ -114,7 +114,7 @@ impl Default for HaltonSampler {
|
|||
mult_inverse: [0; 2],
|
||||
halton_index: 0,
|
||||
dim: 0,
|
||||
digit_permutations: gvec(),
|
||||
digit_permutations: Ptr::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Float;
|
||||
use crate::{Float, Ptr};
|
||||
use crate::core::color::{RGB, XYZ};
|
||||
use enum_dispatch::enum_dispatch;
|
||||
|
||||
pub use crate::spectra::*;
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait SpectrumTrait: Copy {
|
||||
pub trait SpectrumTrait {
|
||||
fn evaluate(&self, lambda: Float) -> Float;
|
||||
fn sample(&self, lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||
SampledSpectrum::from_fn(|i| self.evaluate(lambda[i]))
|
||||
|
|
@ -16,10 +16,10 @@ pub trait SpectrumTrait: Copy {
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct StandardSpectra {
|
||||
pub x: DenselySampledSpectrum,
|
||||
pub y: DenselySampledSpectrum,
|
||||
pub z: DenselySampledSpectrum,
|
||||
pub d65: DenselySampledSpectrum,
|
||||
pub x: Ptr<DenselySampledSpectrum>,
|
||||
pub y: Ptr<DenselySampledSpectrum>,
|
||||
pub z: Ptr<DenselySampledSpectrum>,
|
||||
pub d65: Ptr<DenselySampledSpectrum>,
|
||||
}
|
||||
|
||||
unsafe impl Send for StandardSpectra {}
|
||||
|
|
@ -30,14 +30,23 @@ unsafe impl Sync for StandardSpectra {}
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Spectrum {
|
||||
Constant(ConstantSpectrum),
|
||||
Dense(DenselySampledSpectrum),
|
||||
Piecewise(PiecewiseLinearSpectrum),
|
||||
Dense(Ptr<DenselySampledSpectrum>),
|
||||
Piecewise(Ptr<PiecewiseLinearSpectrum>),
|
||||
Blackbody(BlackbodySpectrum),
|
||||
RGBAlbedo(RGBAlbedoSpectrum),
|
||||
RGBIlluminant(RGBIlluminantSpectrum),
|
||||
RGBUnbounded(RGBUnboundedSpectrum),
|
||||
}
|
||||
|
||||
impl<T: SpectrumTrait> SpectrumTrait for Ptr<T> {
|
||||
fn evaluate(&self, lambda: Float) -> Float {
|
||||
unsafe { self.as_ref().evaluate(lambda) }
|
||||
}
|
||||
fn max_value(&self) -> Float {
|
||||
unsafe { self.as_ref().max_value() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Spectrum {
|
||||
pub fn std_illuminant_d65() -> Self {
|
||||
unimplemented!("Use crate::spectra::default_illuminant() on host")
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::core::filter::{FilterSample, FilterSampler, FilterTrait};
|
||||
use crate::core::geometry::{Point2f, Vector2f};
|
||||
use crate::utils::math::{gaussian, gaussian_integral};
|
||||
use crate::Float;
|
||||
use crate::{Ptr, Float};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GaussianFilter {
|
||||
pub radius: Vector2f,
|
||||
pub sigma: Float,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use crate::core::filter::{FilterSampler, FilterSample, FilterTrait};
|
||||
use crate::core::geometry::{Point2f, Vector2f};
|
||||
use crate::utils::math::{lerp, windowed_sinc};
|
||||
use crate::utils::rng::Rng;
|
||||
use crate::Float;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LanczosSincFilter {
|
||||
pub radius: Vector2f,
|
||||
pub tau: Float,
|
||||
|
|
@ -14,15 +15,34 @@ pub struct LanczosSincFilter {
|
|||
|
||||
impl LanczosSincFilter {
|
||||
pub fn new(radius: Vector2f, tau: Float) -> Self {
|
||||
let sampler = FilterSampler::new(radius, move |p: Point2f| {
|
||||
let evaluate = move |p: Point2f| -> Float {
|
||||
windowed_sinc(p.x(), radius.x(), tau) * windowed_sinc(p.y(), radius.y(), tau)
|
||||
});
|
||||
Self {
|
||||
radius,
|
||||
tau,
|
||||
sampler,
|
||||
};
|
||||
|
||||
let sampler = FilterSampler::new(radius, evaluate);
|
||||
|
||||
let sqrt_samples = 64u32;
|
||||
let n_samples = sqrt_samples * sqrt_samples;
|
||||
let area = (2.0 * radius.x()) * (2.0 * radius.y());
|
||||
let mut sum = 0.0;
|
||||
let mut rng = Rng::new(0);
|
||||
for y in 0..sqrt_samples {
|
||||
for x in 0..sqrt_samples {
|
||||
let u = Point2f::new(
|
||||
(x as Float + rng.uniform::<Float>()) / sqrt_samples as Float,
|
||||
(y as Float + rng.uniform::<Float>()) / sqrt_samples as Float,
|
||||
);
|
||||
let p = Point2f::new(
|
||||
lerp(u.x(), -radius.x(), radius.x()),
|
||||
lerp(u.y(), -radius.y(), radius.y()),
|
||||
);
|
||||
sum += evaluate(p);
|
||||
}
|
||||
}
|
||||
let integral = sum / n_samples as Float * area;
|
||||
|
||||
Self { radius, tau, sampler, integral }
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterTrait for LanczosSincFilter {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::core::filter::{FilterSampler, FilterSample, FilterTrait};
|
||||
use crate::core::filter::{FilterSample, FilterSampler, FilterTrait};
|
||||
use crate::core::geometry::{Point2f, Vector2f};
|
||||
use crate::Float;
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MitchellFilter {
|
||||
pub radius: Vector2f,
|
||||
pub b: Float,
|
||||
|
|
@ -12,8 +12,7 @@ pub struct MitchellFilter {
|
|||
pub sampler: FilterSampler,
|
||||
}
|
||||
|
||||
impl MitchellFilter {
|
||||
pub fn mitchell_1d_eval(b: Float, c: Float, x: Float) -> Float {
|
||||
pub fn mitchell_1d_eval(b: Float, c: Float, x: Float) -> Float {
|
||||
let x = x.abs();
|
||||
if x <= 1.0 {
|
||||
((12.0 - 9.0 * b - 6.0 * c) * x.powi(3)
|
||||
|
|
@ -29,15 +28,12 @@ impl MitchellFilter {
|
|||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
fn mitchell_1d(&self, x: Float) -> Float {
|
||||
Self::mitchell_1d_eval(self.b, self.c, x)
|
||||
}
|
||||
}
|
||||
|
||||
impl MitchellFilter {
|
||||
pub fn new(radius: Vector2f, b: Float, c: Float) -> Self {
|
||||
let sampler = FilterSampler::new(radius, move |p: Point2f| {
|
||||
mitchell_1d(p.x() / radius.x(), b, c) * mitchell_1d(p.y() / radius.y(), b, c)
|
||||
mitchell_1d_eval(p.x() / radius.x(), b, c) * mitchell_1d_eval(p.y() / radius.y(), b, c)
|
||||
});
|
||||
Self {
|
||||
radius,
|
||||
|
|
@ -46,6 +42,10 @@ impl MitchellFilter {
|
|||
sampler,
|
||||
}
|
||||
}
|
||||
|
||||
fn mitchell_1d(&self, x: Float) -> Float {
|
||||
mitchell_1d_eval(self.b, self.c, x)
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterTrait for MitchellFilter {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#![allow(unused_imports, dead_code)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
|
|
@ -17,5 +18,5 @@ pub mod textures;
|
|||
pub mod utils;
|
||||
|
||||
pub use core::pbrt::*;
|
||||
pub use utils::alloc::{gbox, gvec, gvec_from_slice, gvec_with_capacity, GVec, Gbox};
|
||||
pub use utils::{Transform, Ptr, Array2D, PBRTOptions};
|
||||
pub use utils::alloc::{gbox, gvec, gvec_from_slice, gvec_with_capacity, GVec, GBox};
|
||||
pub use utils::{Array2D, PBRTOptions, Ptr, Transform};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::core::color::{RGB, XYZ};
|
||||
use crate::core::geometry::*;
|
||||
use crate::core::image::{Image, ImageAccess};
|
||||
use crate::core::image::Image;
|
||||
use crate::core::interaction::{
|
||||
Interaction, InteractionTrait, MediumInteraction, SurfaceInteraction,
|
||||
};
|
||||
|
|
@ -171,8 +171,8 @@ impl LightTrait for DiffuseAreaLight {
|
|||
fn bounds(&self) -> Option<LightBounds> {
|
||||
let mut phi = 0.;
|
||||
if !self.image.is_null() {
|
||||
for y in 0..self.image.base.resolution.y() {
|
||||
for x in 0..self.image.base.resolution.x() {
|
||||
for y in 0..self.image.resolution().y() {
|
||||
for x in 0..self.image.resolution().x() {
|
||||
for c in 0..3 {
|
||||
phi += self.image.get_channel(Point2i::new(x, y), c);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,22 +20,6 @@ pub struct DistantLight {
|
|||
}
|
||||
|
||||
impl DistantLight {
|
||||
pub fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaDirection,
|
||||
render_from_light,
|
||||
MediumInterface::empty(),
|
||||
);
|
||||
let lemit = lookup_spectrum(&le);
|
||||
Self {
|
||||
base,
|
||||
lemit: Ptr::from(&lemit.device()),
|
||||
scale,
|
||||
scene_center: Point3f::default(),
|
||||
scene_radius: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sample_li_base(
|
||||
&self,
|
||||
ctx_p: Point3f,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::core::geometry::{Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f};
|
||||
use crate::core::image::{Image, ImageAccess};
|
||||
use crate::core::image::Image;
|
||||
use crate::core::light::{
|
||||
LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait, LightType,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::core::geometry::{
|
|||
Bounds2f, Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector2f, Vector3f,
|
||||
};
|
||||
use crate::core::geometry::{Frame, VectorLike};
|
||||
use crate::core::image::{Image, ImageAccess, PixelFormat, WrapMode};
|
||||
use crate::core::image::{Image, PixelFormat, WrapMode};
|
||||
use crate::core::interaction::InteractionBase;
|
||||
use crate::core::interaction::{Interaction, SimpleInteraction};
|
||||
use crate::core::light::{
|
||||
|
|
@ -15,7 +15,7 @@ use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths
|
|||
use crate::spectra::{RGBColorSpace, RGBIlluminantSpectrum};
|
||||
use crate::utils::math::{clamp, equal_area_sphere_to_square, equal_area_square_to_sphere, square};
|
||||
use crate::utils::sampling::{
|
||||
sample_uniform_sphere, uniform_sphere_pdf, AliasTable, DevicePiecewiseConstant2D,
|
||||
sample_uniform_sphere, uniform_sphere_pdf, AliasTable, PiecewiseConstant2D,
|
||||
WindowedPiecewiseConstant2D,
|
||||
};
|
||||
use crate::utils::{Ptr, Transform};
|
||||
|
|
@ -151,7 +151,7 @@ impl ImageInfiniteLight {
|
|||
pub fn new(
|
||||
render_from_light: Transform,
|
||||
scale: Float,
|
||||
image: Ptr<HostImage>,
|
||||
image: Ptr<Image>,
|
||||
image_color_space: Ptr<RGBColorSpace>,
|
||||
distrib: Ptr<PiecewiseConstant2D>,
|
||||
compensated_distrib: Ptr<PiecewiseConstant2D>,
|
||||
|
|
@ -176,7 +176,11 @@ impl ImageInfiniteLight {
|
|||
fn image_le(&self, uv: Point2f, lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||
let mut rgb = RGB::default();
|
||||
for c in 0..3 {
|
||||
rgb[c] = self.image.get_ch(uv, c, WrapMode::OctahedralSphere.into());
|
||||
rgb[c] = self.image.lookup_nearest_channel_with_wrap(
|
||||
uv,
|
||||
c,
|
||||
WrapMode::OctahedralSphere.into(),
|
||||
);
|
||||
}
|
||||
let spec = RGBIlluminantSpectrum::new(&self.image_color_space, rgb.clamp_zero());
|
||||
self.scale * spec.sample(lambda)
|
||||
|
|
@ -297,7 +301,7 @@ pub struct PortalInfiniteLight {
|
|||
pub scale: Float,
|
||||
pub portal: [Point3f; 4],
|
||||
pub portal_frame: Frame,
|
||||
pub distribution: WindowedPiecewiseConstant2D,
|
||||
pub distribution: Ptr<WindowedPiecewiseConstant2D>,
|
||||
pub scene_center: Point3f,
|
||||
pub scene_radius: Float,
|
||||
}
|
||||
|
|
@ -306,7 +310,7 @@ impl PortalInfiniteLight {
|
|||
pub fn new(
|
||||
render_from_light: Transform,
|
||||
scale: Float,
|
||||
image: Ptr<HostImage>,
|
||||
image: Ptr<Image>,
|
||||
image_color_space: Ptr<RGBColorSpace>,
|
||||
portal: [Point3f; 4],
|
||||
portal_frame: Frame,
|
||||
|
|
@ -324,7 +328,7 @@ impl PortalInfiniteLight {
|
|||
scale,
|
||||
portal,
|
||||
portal_frame,
|
||||
distribution: *distribution,
|
||||
distribution,
|
||||
scene_center: Point3f::default(),
|
||||
scene_radius: 0.0,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,25 +18,6 @@ pub struct PointLight {
|
|||
pub i: Ptr<DenselySampledSpectrum>,
|
||||
}
|
||||
|
||||
impl PointLight {
|
||||
pub fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaPosition,
|
||||
render_from_light,
|
||||
medium_interface,
|
||||
);
|
||||
let iemit = lookup_spectrum(&le);
|
||||
let i = Ptr::from(&iemit.device());
|
||||
|
||||
Self { base, scale, i }
|
||||
}
|
||||
}
|
||||
|
||||
impl LightTrait for PointLight {
|
||||
fn base(&self) -> &LightBase {
|
||||
&self.base
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::core::color::RGB;
|
|||
use crate::core::geometry::{
|
||||
Bounds2f, Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f, VectorLike, cos_theta,
|
||||
};
|
||||
use crate::core::image::{Image, ImageAccess};
|
||||
use crate::core::image::Image;
|
||||
use crate::core::light::{
|
||||
LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait, LightType,
|
||||
};
|
||||
|
|
@ -13,7 +13,7 @@ use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
|||
use crate::utils::math::{radians, square};
|
||||
use crate::{
|
||||
spectra::{RGBColorSpace, RGBIlluminantSpectrum},
|
||||
utils::{Ptr, Transform, sampling::DevicePiecewiseConstant2D},
|
||||
utils::{Ptr, Transform, sampling::PiecewiseConstant2D},
|
||||
};
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ pub struct ProjectionLight {
|
|||
pub light_from_screen: Transform,
|
||||
pub a: Float,
|
||||
pub image: Ptr<Image>,
|
||||
pub distrib: Ptr<DevicePiecewiseConstant2D>,
|
||||
pub distrib: Ptr<PiecewiseConstant2D>,
|
||||
pub image_color_space: Ptr<RGBColorSpace>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ pub struct Alias {
|
|||
pub struct PowerLightSampler {
|
||||
pub lights: Ptr<Light>,
|
||||
pub lights_len: u32,
|
||||
pub alias_table: AliasTable,
|
||||
pub alias_table: Ptr<AliasTable>,
|
||||
}
|
||||
|
||||
unsafe impl Send for PowerLightSampler {}
|
||||
|
|
|
|||
|
|
@ -19,31 +19,6 @@ pub struct SpotLight {
|
|||
}
|
||||
|
||||
impl SpotLight {
|
||||
pub fn new(
|
||||
render_from_light: Transform,
|
||||
_medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: shared::Float,
|
||||
cos_falloff_start: Float,
|
||||
total_width: Float,
|
||||
) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaPosition,
|
||||
render_from_light,
|
||||
MediumInterface::empty(),
|
||||
);
|
||||
|
||||
let i = lookup_spectrum(&le);
|
||||
let iemit = Ptr::from(&i.device());
|
||||
Self {
|
||||
base,
|
||||
iemit,
|
||||
scale,
|
||||
cos_falloff_end: radians(total_width).cos(),
|
||||
cos_falloff_start: radians(cos_falloff_start).cos(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn i(&self, w: Vector3f, lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||
let cos_theta = w.z(); // assuming normalized in light space
|
||||
let falloff = crate::utils::math::smooth_step(
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ impl BilinearPatchShape {
|
|||
#[inline(always)]
|
||||
fn get_vertex_indices(&self) -> [usize; 4] {
|
||||
unsafe {
|
||||
let base_ptr = self.mesh.vertex_indices.add((self.blp_index as usize) * 4);
|
||||
let base_ptr = self.mesh.vertex_indices.as_ptr().add((self.blp_index as usize) * 4);
|
||||
[
|
||||
*base_ptr.add(0) as usize,
|
||||
*base_ptr.add(1) as usize,
|
||||
|
|
@ -73,47 +73,29 @@ impl BilinearPatchShape {
|
|||
|
||||
#[inline(always)]
|
||||
fn get_points(&self) -> [Point3f; 4] {
|
||||
let mesh = self.mesh();
|
||||
let [v0, v1, v2, v3] = self.get_vertex_indices();
|
||||
unsafe {
|
||||
[
|
||||
*self.mesh.p.add(v0),
|
||||
*self.mesh.p.add(v1),
|
||||
*self.mesh.p.add(v2),
|
||||
*self.mesh.p.add(v3),
|
||||
]
|
||||
}
|
||||
[mesh.p[v0], mesh.p[v1], mesh.p[v2], mesh.p[v3]]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_uvs(&self) -> Option<[Point2f; 4]> {
|
||||
if self.mesh.uv.is_null() {
|
||||
let mesh = self.mesh();
|
||||
if mesh.uv.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let [v0, v1, v2, v3] = self.get_vertex_indices();
|
||||
unsafe {
|
||||
Some([
|
||||
*self.mesh.uv.add(v0),
|
||||
*self.mesh.uv.add(v1),
|
||||
*self.mesh.uv.add(v2),
|
||||
*self.mesh.uv.add(v3),
|
||||
])
|
||||
}
|
||||
Some([mesh.uv[v0], mesh.uv[v1], mesh.uv[v2], mesh.uv[v3]])
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_shading_normals(&self) -> Option<[Normal3f; 4]> {
|
||||
if self.mesh.n.is_null() {
|
||||
let mesh = self.mesh();
|
||||
if mesh.n.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let [v0, v1, v2, v3] = self.get_vertex_indices();
|
||||
unsafe {
|
||||
Some([
|
||||
*self.mesh.n.add(v0),
|
||||
*self.mesh.n.add(v1),
|
||||
*self.mesh.n.add(v2),
|
||||
*self.mesh.n.add(v3),
|
||||
])
|
||||
}
|
||||
Some([mesh.n[v0], mesh.n[v1], mesh.n[v2], mesh.n[v3]])
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use crate::core::geometry::{Normal3f, Point2f, Point3f, Vector3f};
|
||||
use crate::utils::sampling::PiecewiseConstant2D;
|
||||
use crate::utils::Transform;
|
||||
use crate::{Float, Gvec};
|
||||
use crate::{gvec_from_slice, gvec_with_capacity, Float, GVec, Ptr, Transform};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TriangleMesh {
|
||||
pub p: GVec<Point3f>,
|
||||
pub n: GVec<Normal3f>,
|
||||
|
|
@ -19,7 +18,7 @@ pub struct TriangleMesh {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BilinearPatchMesh {
|
||||
pub p: GVec<Point3f>,
|
||||
pub n: GVec<Normal3f>,
|
||||
|
|
@ -121,7 +120,7 @@ impl BilinearPatchMesh {
|
|||
p: &[Point3f],
|
||||
n: &[Normal3f],
|
||||
uv: &[Point2f],
|
||||
image_distribution: Option<PiecewiseConstant2D>,
|
||||
image_distribution: Option<&PiecewiseConstant2D>,
|
||||
) -> Self {
|
||||
let n_patches = (vertex_indices.len() / 4) as u32;
|
||||
let n_vertices = p.len() as u32;
|
||||
|
|
|
|||
|
|
@ -41,8 +41,11 @@ impl TriangleShape {
|
|||
pub const MIN_SPHERICAL_SAMPLE_AREA: Float = 3e-4;
|
||||
pub const MAX_SPHERICAL_SAMPLE_AREA: Float = 6.22;
|
||||
|
||||
fn mesh(&self) -> &TriangleMesh {
|
||||
&*self.mesh
|
||||
}
|
||||
fn get_vertex_indices(&self) -> [usize; 3] {
|
||||
let mesh = unsafe { &*self.mesh };
|
||||
let mesh = self.mesh();
|
||||
let base = (self.tri_index as usize) * 3;
|
||||
[
|
||||
mesh.vertex_indices[base] as usize,
|
||||
|
|
@ -52,13 +55,13 @@ impl TriangleShape {
|
|||
}
|
||||
|
||||
fn get_points(&self) -> [Point3f; 3] {
|
||||
let mesh = unsafe { &*self.mesh };
|
||||
let mesh = self.mesh();
|
||||
let [v0, v1, v2] = self.get_vertex_indices();
|
||||
[mesh.p[v0], mesh.p[v1], mesh.p[v2]]
|
||||
}
|
||||
|
||||
fn get_shading_normals(&self) -> Option<[Normal3f; 3]> {
|
||||
let mesh = unsafe { &*self.mesh };
|
||||
let mesh = self.mesh();
|
||||
if mesh.n.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -67,7 +70,7 @@ impl TriangleShape {
|
|||
}
|
||||
|
||||
fn get_tangents(&self) -> Option<[Vector3f; 3]> {
|
||||
let mesh = unsafe { &*self.mesh };
|
||||
let mesh = self.mesh();
|
||||
if mesh.s.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -75,6 +78,16 @@ impl TriangleShape {
|
|||
Some([mesh.s[v0], mesh.s[v1], mesh.s[v2]])
|
||||
}
|
||||
|
||||
|
||||
fn get_uvs(&self) -> Option<[Point2f; 3]> {
|
||||
let mesh = self.mesh();
|
||||
if mesh.s.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let [v0, v1, v2] = self.get_vertex_indices();
|
||||
Some([mesh.uv[v0], mesh.uv[v1], mesh.uv[v2]])
|
||||
}
|
||||
|
||||
pub fn new(mesh: Ptr<TriangleMesh>, tri_index: i32) -> Self {
|
||||
Self { mesh, tri_index }
|
||||
}
|
||||
|
|
@ -172,8 +185,8 @@ impl TriangleShape {
|
|||
flip_normal,
|
||||
);
|
||||
|
||||
isect.face_index = if !self.mesh.face_indices.is_null() {
|
||||
unsafe { *self.mesh.face_indices.add(self.tri_index as usize) }
|
||||
isect.face_index = if !self.mesh.face_indices.is_empty() {
|
||||
unsafe { *self.mesh.face_indices.as_ptr().add(self.tri_index as usize) }
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
|
@ -181,7 +194,7 @@ impl TriangleShape {
|
|||
isect.common.n = ng;
|
||||
isect.shading.n = ng;
|
||||
|
||||
if !self.mesh.p.is_null() || !self.mesh.s.is_null() {
|
||||
if !self.mesh.p.is_empty() || !self.mesh.s.is_empty() {
|
||||
self.compute_shading_geometry(&mut isect, &ti, uv, dpdu, determinant, degenerate);
|
||||
}
|
||||
isect
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ pub struct RGBColorSpace {
|
|||
pub xyz_from_rgb: SquareMatrix3f,
|
||||
pub rgb_from_xyz: SquareMatrix3f,
|
||||
pub illuminant: Ptr<DenselySampledSpectrum>,
|
||||
pub rgb_to_spectrum_table: Ptr<RGBToSpectrumTable>,
|
||||
pub rgb_to_spectrum_table: RGBToSpectrumTable,
|
||||
}
|
||||
|
||||
unsafe impl Send for RGBColorSpace {}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl RGBIlluminantSpectrum {
|
|||
Self {
|
||||
scale,
|
||||
rsp,
|
||||
illuminant: Ptr::from(&illuminant),
|
||||
illuminant,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,11 +180,13 @@ pub struct PiecewiseLinearSpectrum {
|
|||
impl PiecewiseLinearSpectrum {
|
||||
#[inline(always)]
|
||||
pub fn count(&self) -> usize {
|
||||
if self.values.is_empty() {
|
||||
0
|
||||
} else {
|
||||
(self.lambda_max - self.lambda_min + 1) as usize
|
||||
self.count.try_into().unwrap()
|
||||
}
|
||||
|
||||
|
||||
#[inline(always)]
|
||||
pub fn lambda(&self, idx: u32) -> Float {
|
||||
unsafe { *self.lambdas.as_ptr().add(idx as usize) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -263,7 +265,7 @@ impl SpectrumTrait for PiecewiseLinearSpectrum {
|
|||
|
||||
for i in 0..n {
|
||||
unsafe {
|
||||
let val = *self.values.add(i as usize);
|
||||
let val = *self.values.as_ptr().add(i as usize);
|
||||
if val > max_val {
|
||||
max_val = val;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub struct GPUSpectrumImageTexture {
|
|||
pub scale: Float,
|
||||
pub invert: bool,
|
||||
pub is_single_channel: bool,
|
||||
pub color_space: RGBColorSpace,
|
||||
pub color_space: Ptr<RGBColorSpace>,
|
||||
pub spectrum_type: SpectrumType,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#![feature(allocator_api)]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::alloc::Global;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::boxed::Box;
|
||||
use core::alloc::{AllocError, Allocator, Layout};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,22 @@ impl<T: Default + Clone> Array2D<T> {
|
|||
values.resize(n, val);
|
||||
Self { extent, values }
|
||||
}
|
||||
|
||||
pub fn from_slice(extent: Bounds2i, slice: &[T]) -> Self {
|
||||
assert_eq!(slice.len(), extent.area() as usize);
|
||||
Self {
|
||||
extent,
|
||||
values: gvec_from_slice(slice),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, p: Point2i) -> &T {
|
||||
&self[p]
|
||||
}
|
||||
|
||||
pub fn get_linear_mut(&mut self, index: usize) -> &mut T {
|
||||
unsafe { &mut *self.values.as_mut_ptr().add(index) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Index<(i32, i32)> for Array2D<T> {
|
||||
|
|
@ -93,8 +109,25 @@ impl<T> IndexMut<(i32, i32)> for Array2D<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Index<Point2i> for Array2D<T> {
|
||||
type Output = T;
|
||||
fn index(&self, p: Point2i) -> &T {
|
||||
let offset =
|
||||
(p.y() - self.extent.p_min.y()) * self.stride() + (p.x() - self.extent.p_min.x());
|
||||
&self.values[offset as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IndexMut<Point2i> for Array2D<T> {
|
||||
fn index_mut(&mut self, p: Point2i) -> &mut T {
|
||||
let offset =
|
||||
(p.y() - self.extent.p_min.y()) * self.stride() + (p.x() - self.extent.p_min.x());
|
||||
&mut self.values[offset as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SampledGrid<T> {
|
||||
pub values: GVec<T>,
|
||||
pub values_len: u32,
|
||||
|
|
@ -106,7 +139,7 @@ pub struct SampledGrid<T> {
|
|||
unsafe impl<T: Sync> Sync for SampledGrid<T> {}
|
||||
unsafe impl<T: Send> Send for SampledGrid<T> {}
|
||||
|
||||
impl<T> SampledGrid<T> {
|
||||
impl<T: core::clone::Clone> SampledGrid<T> {
|
||||
pub fn new(slice: &[T], nx: i32, ny: i32, nz: i32) -> Self {
|
||||
assert_eq!(slice.len(), (nx * ny * nz) as usize);
|
||||
Self {
|
||||
|
|
@ -129,7 +162,7 @@ impl<T> SampledGrid<T> {
|
|||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool {
|
||||
!self.values.is_null() && self.nx > 0 && self.ny > 0 && self.nz > 0
|
||||
!self.values.is_empty() && self.nx > 0 && self.ny > 0 && self.nz > 0
|
||||
}
|
||||
|
||||
pub fn bytes_allocated(&self) -> u32 {
|
||||
|
|
@ -168,7 +201,7 @@ impl<T> SampledGrid<T> {
|
|||
|
||||
let idx = (p.z() * self.ny + p.y()) * self.nx + p.x();
|
||||
unsafe {
|
||||
let val = &*self.values.add(idx as usize);
|
||||
let val = &*self.values.as_ptr().add(idx as usize);
|
||||
convert(val)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use crate::core::color::{RGB, XYZ};
|
||||
use crate::core::geometry::{Lerp, MulAdd, Point, Point2f, Point2i, Vector, Vector3f, VectorLike};
|
||||
use crate::core::pbrt::{Float, FloatBitOps, FloatBits, ONE_MINUS_EPSILON, PI, PI_OVER_4};
|
||||
use crate::utils::gpu_array_from_fn;
|
||||
use crate::utils::hash::{hash_buffer, mix_bits};
|
||||
use crate::utils::math::permutation_element;
|
||||
use crate::utils::sobol::{SOBOL_MATRICES_32, VDC_SOBOL_MATRICES, VDC_SOBOL_MATRICES_INV};
|
||||
|
||||
use crate::utils::{gpu_array_from_fn, Ptr};
|
||||
use crate::{gvec, gvec_with_capacity, GVec, Ptr};
|
||||
use core::fmt::{self, Display, Write};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::mem;
|
||||
|
|
@ -770,13 +769,23 @@ pub fn inverse_radical_inverse(mut inverse: u64, base: u64, n_digits: u64) -> u6
|
|||
|
||||
// Digit scrambling
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DigitPermutation {
|
||||
pub base: i32,
|
||||
pub n_digits: u32,
|
||||
pub permutations: GVec<u16>,
|
||||
}
|
||||
|
||||
impl Default for DigitPermutation {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base: i32::default(),
|
||||
n_digits: u32::default(),
|
||||
permutations: gvec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DigitPermutation {
|
||||
pub fn new(base: i32, seed: u64) -> Self {
|
||||
assert!(base < 65536);
|
||||
|
|
@ -804,9 +813,9 @@ impl DigitPermutation {
|
|||
}
|
||||
|
||||
Self {
|
||||
device,
|
||||
permutations,
|
||||
base,
|
||||
n_digits,
|
||||
permutations,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -818,11 +827,7 @@ impl DigitPermutation {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn scrambled_radical_inverse(
|
||||
base_index: u32,
|
||||
mut a: u64,
|
||||
perm: &DigitPermutation,
|
||||
) -> Float {
|
||||
pub fn scrambled_radical_inverse(base_index: u32, mut a: u64, perm: &DigitPermutation) -> Float {
|
||||
let base = PRIMES[base_index as usize] as u64;
|
||||
|
||||
let limit = (u64::MAX / base).saturating_sub(base);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod alloc;
|
||||
pub mod complex;
|
||||
pub mod containers;
|
||||
pub mod hash;
|
||||
|
|
@ -16,6 +17,7 @@ pub mod transform;
|
|||
pub use options::PBRTOptions;
|
||||
pub use ptr::Ptr;
|
||||
pub use transform::{AnimatedTransform, Transform, TransformGeneric};
|
||||
pub use containers::Array2D;
|
||||
|
||||
use crate::Float;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ impl<T> Ptr<T> {
|
|||
unsafe { &*self.ptr }
|
||||
}
|
||||
|
||||
/// Get as Option - safe for optional fields
|
||||
#[inline(always)]
|
||||
pub fn get<'a>(self) -> Option<&'a T> {
|
||||
if self.is_null() {
|
||||
|
|
@ -141,3 +140,12 @@ impl<T> From<*const T> for Ptr<T> {
|
|||
Self { ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<&T>> for Ptr<T> {
|
||||
fn from(opt: Option<&T>) -> Self {
|
||||
match opt {
|
||||
Some(r) => Ptr::from(r),
|
||||
None => Ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::core::geometry::{
|
||||
Bounds2f, Frame, Point2f, Point2i, Point3f, Vector2f, Vector2i, Vector3f, VectorLike,
|
||||
};
|
||||
use crate::core::image::Image;
|
||||
use crate::utils::find_interval;
|
||||
use crate::utils::math::{
|
||||
catmull_rom_weights, clamp, difference_of_products, evaluate_polynomial, lerp, logistic,
|
||||
newton_bisection, safe_sqrt, square, sum_of_products,
|
||||
};
|
||||
use crate::utils::ptr::Ptr;
|
||||
use crate::utils::rng::Rng;
|
||||
use crate::{gvec_from_slice, gvec_with_capacity, Array2D, GVec};
|
||||
use crate::{gvec, gvec_from_slice, gvec_with_capacity, Array2D, GVec, Ptr};
|
||||
use crate::{Float, INV_2_PI, INV_4_PI, INV_PI, ONE_MINUS_EPSILON, PI, PI_OVER_2, PI_OVER_4};
|
||||
use num_traits::Float as NumFloat;
|
||||
use num_traits::Num;
|
||||
|
|
@ -751,9 +751,11 @@ impl PiecewiseConstant1D {
|
|||
F: Fn(Float) -> Float,
|
||||
{
|
||||
let delta = (max - min) / n as Float;
|
||||
let values: Vec<Float> = (0..n)
|
||||
.map(|i| f(min + (i as Float + 0.5) * delta))
|
||||
.collect();
|
||||
let delta = (max - min) / n as Float;
|
||||
let mut values = gvec_with_capacity(n);
|
||||
for i in 0..n {
|
||||
values.push(f(min + (i as Float + 0.5) * delta));
|
||||
}
|
||||
Self::new_with_bounds(&values, min, max)
|
||||
}
|
||||
|
||||
|
|
@ -830,12 +832,12 @@ impl PiecewiseConstant2D {
|
|||
assert_eq!(data.len(), n_u * n_v);
|
||||
|
||||
let mut conditionals = gvec_with_capacity(n_v);
|
||||
let mut marginal_func = GVec::with_capacity(n_v);
|
||||
let mut marginal_func = gvec_with_capacity(n_v);
|
||||
|
||||
for v in 0..n_v {
|
||||
let row = &data[v * n_u..(v + 1) * n_u];
|
||||
let row = data[v * n_u..(v + 1) * n_u].to_vec();
|
||||
let conditional =
|
||||
PiecewiseConstant1D::new_with_bounds(row, domain.p_min.x(), domain.p_max.x());
|
||||
PiecewiseConstant1D::new_with_bounds(&row, domain.p_min.x(), domain.p_max.x());
|
||||
marginal_func.push(conditional.integral());
|
||||
conditionals.push(conditional);
|
||||
}
|
||||
|
|
@ -846,37 +848,41 @@ impl PiecewiseConstant2D {
|
|||
domain.p_max.y(),
|
||||
);
|
||||
|
||||
Self {
|
||||
conditionals,
|
||||
marginal,
|
||||
n_u: n_u.try_into().unwrap(),
|
||||
n_v: n_v.try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_image(image: &Image) -> Self {
|
||||
let res = image.resolution();
|
||||
let n_u = res.x() as usize;
|
||||
let n_v = res.y() as usize;
|
||||
|
||||
let mut data = Vec::with_capacity(n_u * n_v);
|
||||
let mut data = gvec_with_capacity(n_u * n_v);
|
||||
for v in 0..n_v {
|
||||
for u in 0..n_u {
|
||||
data.push(
|
||||
image
|
||||
.get_channels(Point2i::new(u as i32, v as i32))
|
||||
.average(),
|
||||
);
|
||||
data.push(image.get_channels_average(Point2i::new(u as i32, v as i32)));
|
||||
}
|
||||
}
|
||||
|
||||
Self::from_slice(&data, n_u, n_v, Bounds2f::unit())
|
||||
}
|
||||
|
||||
Self {
|
||||
conditionals,
|
||||
marginal,
|
||||
n_u: n_u as u32,
|
||||
n_v: n_v as u32,
|
||||
}
|
||||
PiecewiseConstant2D::from_slice(&data, n_u, n_v, Bounds2f::unit())
|
||||
}
|
||||
|
||||
pub fn integral(&self) -> Float {
|
||||
self.marginal.integral()
|
||||
}
|
||||
|
||||
pub fn pdf(&self, p: Point2f) -> Float {
|
||||
let u_offset = ((p.x() * self.n_u as Float) as usize).min(self.n_u as usize - 1);
|
||||
let v_offset = ((p.y() * self.n_v as Float) as usize).min(self.n_v as usize - 1);
|
||||
let conditional = unsafe { &*self.conditionals.as_ptr().add(v_offset) };
|
||||
let func_val = unsafe { *conditional.func.as_ptr().add(u_offset) };
|
||||
func_val / self.integral()
|
||||
}
|
||||
|
||||
pub fn sample(&self, u: Point2f) -> (Point2f, Float, Point2i) {
|
||||
let (d1, pdf1, off_y) = self.marginal.sample(u.y());
|
||||
let (d0, pdf0, off_x) = self.conditionals[off_y].sample(u.x());
|
||||
|
|
@ -890,7 +896,7 @@ impl PiecewiseConstant2D {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SummedAreaTable {
|
||||
pub sum: Array2D<f64>,
|
||||
}
|
||||
|
|
@ -964,7 +970,7 @@ impl SummedAreaTable {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowedPiecewiseConstant2D {
|
||||
pub sat: SummedAreaTable,
|
||||
pub func: Array2D<Float>,
|
||||
|
|
@ -989,7 +995,8 @@ impl WindowedPiecewiseConstant2D {
|
|||
};
|
||||
|
||||
let nx = self.func.x_size();
|
||||
let px_val = Self::sample_bisection(px, u.x(), b.p_min.x(), b.p_max.x(), nx);
|
||||
let px_val =
|
||||
Self::sample_bisection(px, u.x(), b.p_min.x(), b.p_max.x(), nx.try_into().unwrap());
|
||||
|
||||
let nx_f = nx as Float;
|
||||
|
||||
|
|
@ -1017,7 +1024,8 @@ impl WindowedPiecewiseConstant2D {
|
|||
};
|
||||
|
||||
let ny = self.func.y_size();
|
||||
let py_val = Self::sample_bisection(py, u.y(), b.p_min.y(), b.p_max.y(), ny);
|
||||
let py_val =
|
||||
Self::sample_bisection(py, u.y(), b.p_min.y(), b.p_max.y(), ny.try_into().unwrap());
|
||||
|
||||
let p = Point2f::new(px_val, py_val);
|
||||
|
||||
|
|
@ -1117,8 +1125,8 @@ impl AliasTable {
|
|||
index: usize,
|
||||
}
|
||||
|
||||
let mut under = Vec::with_capacity(n);
|
||||
let mut over = Vec::with_capacity(n);
|
||||
let mut under = gvec_with_capacity(n);
|
||||
let mut over = gvec_with_capacity(n);
|
||||
|
||||
for (i, bin) in bins.iter().enumerate() {
|
||||
let p_hat = (bin.p as f64) * (n as f64);
|
||||
|
|
@ -1201,7 +1209,7 @@ impl AliasTable {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PiecewiseLinear2D<const N: usize> {
|
||||
pub size: Vector2i,
|
||||
pub inv_patch_size: Vector2f,
|
||||
|
|
@ -1233,7 +1241,8 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
|
||||
let mut param_size = [0u32; N];
|
||||
let mut param_strides = [0u32; N];
|
||||
let owned_param_values: [Vec<Float>; N] = gpu_array_from_fn(|i| param_values[i].to_vec());
|
||||
let owned_param_values: [GVec<Float>; N] =
|
||||
core::array::from_fn(|i| gvec_from_slice(param_values[i]));
|
||||
|
||||
let mut slices: u32 = 1;
|
||||
for i in (0..N).rev() {
|
||||
|
|
@ -1244,16 +1253,23 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
}
|
||||
|
||||
let n_values = (x_size * y_size) as usize;
|
||||
let mut new_data = vec![0.0; slices as usize * n_values];
|
||||
let mut new_data = gvec_with_capacity(slices as usize * n_values);
|
||||
new_data.resize(slices as usize * n_values, 0.0);
|
||||
|
||||
let mut marginal_cdf = if build_cdf {
|
||||
vec![0.0; slices as usize * y_size as usize]
|
||||
let mut v = gvec_with_capacity(slices as usize * y_size as usize);
|
||||
v.resize(slices as usize * y_size as usize, 0.0);
|
||||
v
|
||||
} else {
|
||||
Vec::new()
|
||||
gvec()
|
||||
};
|
||||
|
||||
let mut conditional_cdf = if build_cdf {
|
||||
vec![0.0; slices as usize * n_values]
|
||||
let mut v = gvec_with_capacity(slices as usize * n_values);
|
||||
v.resize(slices as usize * n_values, 0.0);
|
||||
v
|
||||
} else {
|
||||
Vec::new()
|
||||
gvec()
|
||||
};
|
||||
|
||||
let mut data_offset = 0;
|
||||
|
|
@ -1314,7 +1330,6 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
inv_patch_size,
|
||||
param_size,
|
||||
param_strides,
|
||||
storage,
|
||||
data: new_data,
|
||||
marginal_cdf,
|
||||
conditional_cdf,
|
||||
|
|
@ -1336,7 +1351,7 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
let conditional_offset = slice_offset * conditional_size;
|
||||
let fetch_marginal = |idx: u32| {
|
||||
self.lookup(
|
||||
self.marginal_cdf,
|
||||
&self.marginal_cdf,
|
||||
marginal_offset + idx,
|
||||
marginal_size,
|
||||
¶m_weights,
|
||||
|
|
@ -1346,13 +1361,13 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
let marginal_cdf_row = fetch_marginal(row);
|
||||
sample[1] -= marginal_cdf_row;
|
||||
let r0 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_offset + (row + 1) * self.size.x() as u32 - 1,
|
||||
conditional_size,
|
||||
¶m_weights,
|
||||
);
|
||||
let r1 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_offset + (row + 2) * self.size.x() as u32 - 1,
|
||||
conditional_size,
|
||||
¶m_weights,
|
||||
|
|
@ -1369,13 +1384,13 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
let conditional_row_offset = conditional_offset + row * self.size.x() as u32;
|
||||
let fetch_conditional = |idx: u32| {
|
||||
let v0 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_row_offset + idx,
|
||||
conditional_size,
|
||||
¶m_weights,
|
||||
);
|
||||
let v1 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_row_offset + idx + self.size.x() as u32,
|
||||
conditional_size,
|
||||
¶m_weights,
|
||||
|
|
@ -1387,16 +1402,16 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
});
|
||||
sample[0] -= fetch_conditional(col);
|
||||
let offset = conditional_row_offset + col;
|
||||
let v00 = self.lookup(self.data, offset, slice_size, ¶m_weights);
|
||||
let v10 = self.lookup(self.data, offset + 1, slice_size, ¶m_weights);
|
||||
let v00 = self.lookup(&self.data, offset, slice_size, ¶m_weights);
|
||||
let v10 = self.lookup(&self.data, offset + 1, slice_size, ¶m_weights);
|
||||
let v01 = self.lookup(
|
||||
self.data,
|
||||
&self.data,
|
||||
offset + self.size.x() as u32,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
);
|
||||
let v11 = self.lookup(
|
||||
self.data,
|
||||
&self.data,
|
||||
offset + self.size.x() as u32 + 1,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
|
|
@ -1433,16 +1448,16 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
let frac = Point2f::new(p.x() - col as Float, p.y() - row as Float);
|
||||
let slice_size = (self.size.x() * self.size.y()) as u32;
|
||||
let offset = slice_offset * slice_size + (row * self.size.x() + col) as u32;
|
||||
let v00 = self.lookup(self.data, offset, slice_size, ¶m_weights);
|
||||
let v10 = self.lookup(self.data, offset + 1, slice_size, ¶m_weights);
|
||||
let v00 = self.lookup(&self.data, offset, slice_size, ¶m_weights);
|
||||
let v10 = self.lookup(&self.data, offset + 1, slice_size, ¶m_weights);
|
||||
let v01 = self.lookup(
|
||||
self.data,
|
||||
&self.data,
|
||||
offset + self.size.x() as u32,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
);
|
||||
let v11 = self.lookup(
|
||||
self.data,
|
||||
&self.data,
|
||||
offset + self.size.x() as u32 + 1,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
|
|
@ -1456,26 +1471,26 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
u[0] = w1.x() * (c0 + 0.5 * w1.x() * (c1 - c0));
|
||||
let conditional_row_offset = slice_offset * slice_size + (row * self.size.x()) as u32;
|
||||
let v0 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_row_offset + col as u32,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
);
|
||||
let v1 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_row_offset + col as u32 + self.size.x() as u32,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
);
|
||||
u[0] += (1.0 - u.y()) * v0 + u.y() * v1;
|
||||
let r0 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_row_offset + self.size.x() as u32 - 1,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
);
|
||||
let r1 = self.lookup(
|
||||
self.conditional_cdf,
|
||||
&self.conditional_cdf,
|
||||
conditional_row_offset + self.size.x() as u32 * 2 - 1,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
|
|
@ -1484,7 +1499,7 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
u[1] = w1.y() * (r0 + 0.5 * w1.y() * (r1 - r0));
|
||||
let marginal_offset = slice_offset * self.size.y() as u32 + row as u32;
|
||||
u[1] += self.lookup(
|
||||
self.marginal_cdf,
|
||||
&self.marginal_cdf,
|
||||
marginal_offset,
|
||||
self.size.y() as u32,
|
||||
¶m_weights,
|
||||
|
|
@ -1508,16 +1523,16 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
let w0 = Point2f::new(1.0 - w1.x(), 1.0 - w1.y());
|
||||
let slice_size = (self.size.x() * self.size.y()) as u32;
|
||||
let offset = slice_offset * slice_size + (row * self.size.x() + col) as u32;
|
||||
let v00 = self.lookup(self.data, offset, slice_size, ¶m_weights);
|
||||
let v10 = self.lookup(self.data, offset + 1, slice_size, ¶m_weights);
|
||||
let v00 = self.lookup(&self.data, offset, slice_size, ¶m_weights);
|
||||
let v10 = self.lookup(&self.data, offset + 1, slice_size, ¶m_weights);
|
||||
let v01 = self.lookup(
|
||||
self.data,
|
||||
&self.data,
|
||||
offset + self.size.x() as u32,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
);
|
||||
let v11 = self.lookup(
|
||||
self.data,
|
||||
&self.data,
|
||||
offset + self.size.x() as u32 + 1,
|
||||
slice_size,
|
||||
¶m_weights,
|
||||
|
|
@ -1529,8 +1544,7 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
|
||||
#[inline(always)]
|
||||
fn get_param_value(&self, dim: usize, idx: usize) -> Float {
|
||||
// Safety: Bounds checking against param_size ensures this is valid
|
||||
unsafe { *self.param_values[dim].add(idx) }
|
||||
unsafe { *self.param_values[dim].as_ptr().add(idx) }
|
||||
}
|
||||
|
||||
fn get_slice_info(&self, params: [Float; N]) -> (u32, [(Float, Float); N]) {
|
||||
|
|
@ -1570,7 +1584,7 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
|
||||
fn lookup(
|
||||
&self,
|
||||
data: Ptr<Float>,
|
||||
data: &GVec<Float>,
|
||||
i0: u32,
|
||||
size: u32,
|
||||
param_weight: &[(Float, Float); N],
|
||||
|
|
@ -1592,7 +1606,7 @@ impl<const N: usize> PiecewiseLinear2D<N> {
|
|||
current_mask >>= 1;
|
||||
}
|
||||
let idx = (i0 + offset) as usize;
|
||||
let val = unsafe { *data.add(idx) };
|
||||
let val = unsafe { *data.as_ptr().add(idx) };
|
||||
result += weight * val;
|
||||
}
|
||||
result
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use crate::core::spectrum::spectrum_to_photometric;
|
|||
use crate::core::texture::FloatTexture;
|
||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||
use anyhow::Result;
|
||||
use shared::Float;
|
||||
use shared::core::geometry::{Point3f, VectorLike};
|
||||
use shared::core::light::{Light, LightBase, LightType};
|
||||
use shared::core::medium::{Medium, MediumInterface};
|
||||
|
|
@ -13,6 +12,29 @@ use shared::core::texture::SpectrumType;
|
|||
use shared::lights::DistantLight;
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::{Ptr, Transform};
|
||||
use shared::Float;
|
||||
|
||||
trait CreateDistantLight {
|
||||
fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self;
|
||||
}
|
||||
|
||||
impl CreateDistantLight for DistantLight {
|
||||
fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaDirection,
|
||||
render_from_light,
|
||||
MediumInterface::empty(),
|
||||
);
|
||||
let lemit = lookup_spectrum(&le);
|
||||
Self {
|
||||
base,
|
||||
lemit: Ptr::from(&lemit.device()),
|
||||
scale,
|
||||
scene_center: Point3f::default(),
|
||||
scene_radius: 0.,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
render_from_light: Transform,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,35 @@ use shared::lights::PointLight;
|
|||
use shared::spectra::RGBColorSpace;
|
||||
use shared::{Float, PI, Ptr, Transform};
|
||||
|
||||
pub trait CreatePointLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
arena: &Arena,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl CreatePointLight for PointLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
arena: &Arena,
|
||||
) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaPosition,
|
||||
render_from_light,
|
||||
medium_interface,
|
||||
);
|
||||
let iemit = lookup_spectrum(&le);
|
||||
let i = arena.alloc((*iemit).clone());
|
||||
Self { base, scale, i }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn create(
|
||||
render_from_light: Transform,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,45 @@ use shared::lights::SpotLight;
|
|||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::math::radians;
|
||||
use shared::utils::{Ptr, Transform};
|
||||
use shared::{Float, PI, Ptr, Transform};
|
||||
use shared::{Float, Ptr, Transform, PI};
|
||||
|
||||
trait CreateSpotLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
_medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
cos_falloff_start: Float,
|
||||
total_width: Float,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl CreateSpotLight for SpotLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
_medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
cos_falloff_start: Float,
|
||||
total_width: Float,
|
||||
) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaPosition,
|
||||
render_from_light,
|
||||
MediumInterface::empty(),
|
||||
);
|
||||
|
||||
let i = lookup_spectrum(&le);
|
||||
let iemit = Ptr::from(&i.device());
|
||||
Self {
|
||||
base,
|
||||
iemit,
|
||||
scale,
|
||||
cos_falloff_end: radians(total_width).cos(),
|
||||
cos_falloff_start: radians(cos_falloff_start).cos(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
render_from_light: Transform,
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ pub fn cie_d65() -> Spectrum {
|
|||
|
||||
pub fn get_spectra_context() -> StandardSpectra {
|
||||
StandardSpectra {
|
||||
x: CIE_X_DATA,
|
||||
y: CIE_Y_DATA,
|
||||
z: CIE_Z_DATA,
|
||||
d65: CIE_D65_DATA,
|
||||
x: Ptr::from(&*CIE_X_DATA),
|
||||
y: Ptr::from(&*CIE_Y_DATA),
|
||||
z: Ptr::from(&*CIE_Z_DATA),
|
||||
d65: Ptr::from(&*CIE_D65_DATA),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue