This commit is contained in:
pingu 2026-01-18 16:29:27 +00:00
parent 3b3f9eb155
commit 86c9a90f2e
114 changed files with 1548 additions and 2421 deletions

View file

@ -6,13 +6,14 @@ edition = "2024"
[features] [features]
default = [] default = []
use_f64 = [] use_f64 = []
use_gpu = []
use_nvtx = []
cuda = ["cust", "cuda_builder", "shared/cuda", ] cuda = ["cust", "cuda_builder", "shared/cuda", ]
[dependencies] [dependencies]
anyhow = "1.0.100" anyhow = "1.0.100"
exr = "1.73.0" exr = "1.73.0"
flate2 = "1.1.5" flate2 = "1.1.5"
gpu = "0.2.3"
half = "2.7.1" half = "2.7.1"
image_rs = { package = "image", version = "0.25.8" } image_rs = { package = "image", version = "0.25.8" }
indicatif = "0.18.3" indicatif = "0.18.3"
@ -40,6 +41,11 @@ slice = "0.0.4"
crossbeam-channel = "0.5.15" crossbeam-channel = "0.5.15"
num_cpus = "1.17.0" num_cpus = "1.17.0"
ply-rs = "0.1.3" ply-rs = "0.1.3"
enum_dispatch = "0.3.13"
bytemuck = "1.24.0"
once_cell = "1.21.3"
smallvec = "1.15.1"
cuda-runtime-sys = "0.3.0-alpha.1"
[build-dependencies] [build-dependencies]
spirv-builder = { git = "https://github.com/rust-gpu/rust-gpu", branch = "main", optional = true } spirv-builder = { git = "https://github.com/rust-gpu/rust-gpu", branch = "main", optional = true }

View file

@ -1,447 +1,16 @@
#![no_std]
use cuda_std::prelude::*; use cuda_std::prelude::*;
use shared::Float;
pub mod wavefront; #[kernel]
pub mod workitem; pub unsafe fn scale_array_kernel(data: *mut Float, n: u32, scale: Float) {
let i = thread::index_1d() as usize;
use cust::context::{CacheConfig, CurrentContext, ResourceLimit};
use cust::device::DeviceAttribute;
use cust::memory::{DeviceCopy, DeviceMemory};
use cust::prelude::*;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use std::error::Error;
use std::ffi::c_void;
use std::sync::Arc;
use crate::Float;
use crate::core::geometry::{Normal, Point, Vector};
use crate::core::medium::Medium;
use crate::core::options::{PBRTOptions, get_options};
use crate::impl_gpu_traits;
use crate::impl_math_gpu_traits;
use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::interval::Interval;
pub use workitem::{
EscapedRayQueue, GetBSSRDFAndProbeRayQueue, HitAreaLightQueue, MaterialEvalQueue,
MediumSampleQueue, MediumScatterQueue, PixelSampleStateStorage, RayQueue, ShadowRayQueue,
SubsurfaceScatterQueue,
};
#[repr(C, align(16))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Float4 {
pub v: [f32; 4],
}
pub type Vec4 = Vector<Float, 4>;
impl From<Vec4> for Float4 {
#[inline]
fn from(vec: Vector<f32, 4>) -> Self {
Self { v: vec.0 }
}
}
impl From<Float4> for Vec4 {
#[inline]
fn from(storage: Float4) -> Self {
Vector(storage.v)
}
}
impl_math_gpu_traits!(Vector);
impl_math_gpu_traits!(Normal);
impl_math_gpu_traits!(Point);
impl_gpu_traits!(Interval);
impl_gpu_traits!(Float4);
impl_gpu_traits!(SampledSpectrum);
impl_gpu_traits!(SampledWavelengths);
struct KernelStats {
description: String,
num_launches: usize,
sum_ms: f32,
min_ms: f32,
max_ms: f32,
}
impl KernelStats {
fn new(description: &str) -> Self {
Self {
description: description.to_string(),
num_launches: 0,
sum_ms: 0.0,
min_ms: 0.0,
max_ms: 0.0,
}
}
}
struct ProfilerEvent {
start: Event,
stop: Event,
active: bool,
stats: Option<Arc<Mutex<KernelStats>>>,
}
impl ProfilerEvent {
fn new() -> Result<Self, cust::error::CudaError> {
let start = Event::new(EventFlags::DEFAULT)?;
let stop = Event::new(EventFlags::DEFAULT)?;
Ok(Self {
start,
stop,
active: false,
stats: None,
})
}
fn sync(&mut self) {
if !self.active {
return;
}
if self.stop.synchronize().is_ok() {
// Check timing between start and stop
match self.stop.elapsed_time_f32(&self.start) {
Ok(ms) => {
if let Some(stats_arc) = &self.stats {
let mut stats = stats_arc.lock();
stats.num_launches += 1;
if stats.num_launches == 1 {
stats.sum_ms = ms;
stats.min_ms = ms;
stats.max_ms = ms;
} else {
stats.sum_ms += ms;
stats.min_ms = stats.min_ms.min(ms);
stats.max_ms = stats.max_ms.max(ms);
}
}
}
Err(e) => log::error!("Failed to get elapsed time: {:?}", e),
}
}
self.active = false;
}
}
// --- Profiler Manager ---
struct Profiler {
kernel_stats: Vec<Arc<Mutex<KernelStats>>>,
event_pool: Vec<ProfilerEvent>,
pool_offset: usize,
}
impl Profiler {
fn new() -> Self {
Self {
kernel_stats: Vec::new(),
event_pool: Vec::new(),
pool_offset: 0,
}
}
/// Prepares an event from the pool.
/// Returns a mutable reference to the event, valid as long as the borrow of self.
fn prepare<'a>(&'a mut self, description: &str) -> &'a mut ProfilerEvent {
// Grow pool if empty or needed (simple heuristic)
if self.event_pool.is_empty() {
for _ in 0..128 {
if let Ok(e) = ProfilerEvent::new() {
self.event_pool.push(e);
}
}
}
if self.pool_offset >= self.event_pool.len() {
self.pool_offset = 0;
}
let idx = self.pool_offset;
self.pool_offset += 1;
let pe = &mut self.event_pool[idx];
if pe.active {
pe.sync();
}
pe.active = true;
pe.stats = None;
// Find or create stats
let mut found = None;
for s in &self.kernel_stats {
if s.lock().description == description {
found = Some(s.clone());
break;
}
}
if found.is_none() {
let new_stats = Arc::new(Mutex::new(KernelStats::new(description)));
self.kernel_stats.push(new_stats.clone());
found = Some(new_stats);
}
pe.stats = found;
pe
}
}
pub struct GpuState {
context: Context,
stream: Stream,
profiler: Profiler,
}
impl GpuState {
fn init(device_index: u32) -> Result<Self, Box<dyn Error>> {
cust::init(CudaFlags::empty())?;
let device = Device::get_device(device_index)?;
let name = device.name().unwrap_or_else(|_| "Unknown".into());
let memory = device.total_memory().unwrap_or(0);
let memory_gb = memory as f64 / (1024.0 * 1024.0 * 1024.0);
let major = device
.get_attribute(DeviceAttribute::ComputeCapabilityMajor)
.unwrap_or(0);
let minor = device
.get_attribute(DeviceAttribute::ComputeCapabilityMinor)
.unwrap_or(0);
log::info!(
"Selected GPU: {} ({:.2} GB, SM {}.{})",
name,
memory_gb,
major,
minor
);
let has_unified = device
.get_attribute(DeviceAttribute::UnifiedAddressing)
.unwrap_or(0);
if has_unified == 0 {
panic!("Selected GPU does not support unified addressing.");
}
let context = Context::new(device)?;
CurrentContext::set_resource_limit(ResourceLimit::StackSize, 8192)?;
let stack_size = CurrentContext::get_resource_limit(ResourceLimit::StackSize)?;
log::info!("Reset stack size to {}", stack_size);
CurrentContext::set_resource_limit(ResourceLimit::PrintfFifoSize, 32 * 1024 * 1024)?;
CurrentContext::set_cache_config(CacheConfig::PreferL1)?;
let stream = Stream::new(StreamFlags::DEFAULT, None)?;
Ok(Self {
context,
stream,
profiler: Profiler::new(),
})
}
}
lazy_static! {
static ref GPU_STATE: Mutex<Option<GpuState>> = Mutex::new(None);
}
pub fn gpu_init() {
if !get_options().use_gpu {
return;
}
let device_id = get_options().gpu_device.unwrap_or(0);
log::info!("Initializing GPU Device {}", device_id);
match GpuState::init(device_id) {
Ok(state) => {
#[cfg(feature = "use_nvtx")]
nvtx::name_thread("MAIN_THREAD");
*GPU_STATE.lock() = Some(state);
}
Err(e) => {
panic!("Failed to initialize GPU: {:?}", e);
}
}
}
pub fn gpu_thread_init() {
if let Some(state) = GPU_STATE.lock().as_ref() {
if let Err(e) = CurrentContext::set_current(&state.context) {
log::error!("Failed to set CUDA context for thread: {:?}", e);
}
}
}
pub fn gpu_wait() {
let mut guard = GPU_STATE.lock();
if let Some(state) = guard.as_mut() {
if let Err(e) = state.stream.synchronize() {
log::error!("GPU Wait failed: {:?}", e);
}
}
}
/// Launches a parallel for loop on the GPU.
///
/// # Arguments
/// * `description`: Name for profiling.
/// * `n_items`: Total items (threads).
/// * `function`: Compiled kernel function handle.
/// * `params`: Kernel parameters (must be DeviceCopy).
pub fn gpu_parallel_for<T: DeviceCopy>(
description: &str,
n_items: i32,
function: &Function,
params: &T,
) {
#[cfg(feature = "use_nvtx")]
nvtx::range_push(description);
let mut guard = GPU_STATE.lock();
let state = guard.as_mut().expect("GPU not initialized");
let (_, block_size) = match function.suggested_launch_configuration(0, 0.into()) {
Ok(cfg) => cfg,
Err(e) => panic!(
"Failed to calculate launch config for {}: {:?}",
description, e
),
};
#[cfg(debug_assertions)]
log::debug!("[{}] Block size: {}", description, block_size);
let grid_size = (n_items as u32 + block_size - 1) / block_size;
let stream = &state.stream;
let profiler = &mut state.profiler;
// Save the index we are about to use so we can retrieve the STOP event later
let event_idx = profiler.pool_offset;
{
let pe = profiler.prepare(description);
if let Err(e) = pe.start.record(stream) {
log::error!("Failed to record start event: {:?}", e);
}
}
let params_ptr = params as *const T as *mut c_void;
let n_items_ptr = &n_items as *const i32 as *mut c_void;
let args = [params_ptr, n_items_ptr];
if i < n as usize {
let ptr = unsafe { data.add(i) };
unsafe { unsafe {
if let Err(e) = *ptr = *ptr * scale;
state
.stream
.launch(function, (grid_size, 1, 1), (block_size, 1, 1), 0, &args)
{
panic!("CUDA Launch failed for {}: {:?}", description, e);
} }
} }
// Retrieve the specific event we just set up.
// Pool_offset was incremented in prepare().
// If event_idx was the one used, the event is at event_idx.
if event_idx < profiler.event_pool.len() {
let pe = &mut profiler.event_pool[event_idx];
if let Err(e) = pe.stop.record(stream) {
log::error!("Failed to record stop event: {:?}", e);
}
}
#[cfg(debug_assertions)]
let _ = state.stream.synchronize();
#[cfg(feature = "use_nvtx")]
nvtx::range_pop();
}
pub fn report_kernel_stats() {
let mut guard = GPU_STATE.lock();
if let Some(state) = guard.as_mut() {
let _ = state.stream.synchronize();
// Process all pending events
for pe in &mut state.profiler.event_pool {
if pe.active {
pe.sync();
}
}
let mut total_ms = 0.0;
for s in &state.profiler.kernel_stats {
total_ms += s.lock().sum_ms;
}
println!("Wavefront Kernel Profile:");
for s in &state.profiler.kernel_stats {
let stats = s.lock();
let percent = if total_ms > 0.0 {
100.0 * stats.sum_ms / total_ms
} else {
0.0
};
println!(
" {:<45} {:5} launches {:9.2} ms / {:5.1}% (avg {:6.3})",
stats.description,
stats.num_launches,
stats.sum_ms,
percent,
if stats.num_launches > 0 {
stats.sum_ms / stats.num_launches as f32
} else {
0.0
}
);
}
println!("\nTotal: {:.2} ms", total_ms);
}
}
pub fn gpu_memset<T: DeviceCopy>(dst: &mut DeviceSlice<T>, value: u8) {
unsafe {
let ptr = dst.as_raw_ptr(); // Returns CUdeviceptr (u64)
let len = dst.len() * std::mem::size_of::<T>();
// We need the `cust::external::cuda` or equivalent sys crate function
log::warn!("gpu_memset requested but raw memset not exposed via safe cust API yet.");
}
}
#[macro_export]
macro_rules! impl_gpu_traits {
($name:ty) => {
unsafe impl cust::memory::DeviceCopy for $name {}
unsafe impl bytemuck::Zeroable for $name {}
unsafe impl bytemuck::Pod for $name {}
};
}
#[macro_export]
macro_rules! impl_math_gpu_traits {
($Struct:ident) => {
#[cfg(feature = "use_gpu")]
unsafe impl<T, const N: usize> cust::memory::DeviceCopy for $Struct<T, N> where
T: cust::memory::DeviceCopy + Copy
{
}
unsafe impl<T, const N: usize> bytemuck::Zeroable for $Struct<T, N> where
T: bytemuck::Zeroable
{
}
unsafe impl<T, const N: usize> bytemuck::Pod for $Struct<T, N> where T: bytemuck::Pod {}
};
} }

View file

@ -1,47 +0,0 @@
use image_rs::Pixel;
use crate::camera::Camera;
use crate::core::film::Film;
use crate::core::filter::Filter;
use crate::core::sampler::Sampler;
use crate::core::scene::BasicScene;
use crate::lights::Light;
use crate::lights::LightSampler;
use crate::{
EscapedRayQueue, GetBSSRDFAndProbeRayQueue, HitAreaLightQueue, MaterialEvalQueue,
MediumSampleQueue, MediumScatterQueue, PixelSampleStateStorage, RayQueue, ShadowRayQueue,
SubsurfaceScatterQueue,
};
use std::sync::Arc;
pub struct WavefrontPathIntegrator {
pub film: Film,
pub filter: Filter,
pub sampler: Sampler,
pub camera: Arc<Camera>,
pub light_sampler: LightSampler,
pub infinite_lights: Option<Vec<Arc<Light>>>,
pub max_depth: i32,
pub samples_per_pixel: i32,
pub regularize: bool,
pub scanlines_per_pixel: i32,
pub max_queue_size: i32,
pub pixel_sample_state: PixelSampleStateStorage,
pub ray_queue: [RayQueue; 2],
pub hit_area_light_queue: HitAreaLightQueue,
pub shadow_ray_queue: ShadowRayQueue,
pub escaped_ray_queue: Option<EscapedRayQueue>,
pub basic_material_queue: Option<MaterialEvalQueue>,
pub universal_material_queue: Option<MaterialEvalQueue>,
pub medium_sample_queue: Option<MediumSampleQueue>,
pub medium_scatter_queue: Option<MediumScatterQueue>,
pub bssrf_queue: Option<GetBSSRDFAndProbeRayQueue>,
pub subsurface_queue: Option<SubsurfaceScatterQueue>,
}
#[cfg(feature = "use_gpu")]
impl WavefrontPathIntegrator {
pub fn new(scene: BasicScene) -> Self {
todo!()
}
}

View file

@ -1,535 +0,0 @@
#![allow(clippy::too_many_arguments)]
use super::Float4;
use crate::Float;
use crate::core::geometry::{Normal3f, Point2f, Point2i, Point3f, Point3fi, Ray, Vector3f};
use crate::lights::LightSampleContext;
use crate::soa_struct;
use crate::spectra::{SampledSpectrum, SampledWavelengths};
use cust::memory::{CopyDestination, DeviceMemory};
use cust::prelude::*;
#[macro_export]
macro_rules! soa_struct {
(
$(#[$outer:meta])*
pub struct $name:ident {
$(
pub $field:ident : $type:ty
),* $(,)?
}
) => {
#[cfg(feature = "use_gpu")]
$(#[$outer])*
pub struct $name {
capacity: u32,
pub count: cust::memory::DeviceBuffer<u32>,
$(
pub $field: cust::memory::DeviceBuffer<$type>,
)*
}
#[cfg(feature = "use_gpu")]
impl $name {
pub fn new(capacity: usize) -> cust::error::CudaResult<Self> {
use cust::memory::DeviceBuffer;
Ok(Self {
capacity: capacity as u32,
count: DeviceBuffer::zeroed(1)?,
$(
$field: DeviceBuffer::zeroed(capacity)?,
)*
})
}
pub fn len(&self) -> cust::error::CudaResult<u32> {
let mut host_count = [0u32; 1];
self.count.copy_to(&mut host_count)?;
Ok(host_count[0])
}
pub fn reset(&mut self) -> cust::error::CudaResult<()> {
self.count.copy_from(&[0])
}
// Generate the View name
pub fn as_view(&mut self) -> paste::paste! { [<$name View>] } {
paste::paste! {
[<$name View>] {
capacity: self.capacity,
count: self.count.as_device_ptr().as_mut_ptr(),
$(
$field: self.$field.as_device_ptr().as_raw() as *mut $type,
)*
}
}
}
}
paste::paste! {
#[repr(C)]
#[derive(Clone, Copy)]
pub struct [<$name View>] {
pub capacity: u32,
pub count: *mut u32,
$(
pub $field: *mut $type,
)*
}
unsafe impl cust::memory::DeviceCopy for [<$name View>] {}
impl [<$name View>] {
// The raw push that fills every field
#[cfg(feature = "use_gpu")]
pub unsafe fn push(&self, $( $field : $type ),* ) -> Option<u32> {
use core::sync::atomic::{AtomicU32, Ordering};
let index = unsafe {
let counter_ptr = self.count as *mut AtomicU32;
(*counter_ptr).fetch_add(1, Ordering::Relaxed)
};
if index >= self.capacity {
return None;
}
unsafe {
$(
*self.$field.add(index as usize) = $field;
)*
}
Some(index)
}
#[cfg(feature = "use_gpu")]
pub unsafe fn size(&self) -> u32 {
use core::sync::atomic::{AtomicU32, Ordering};
unsafe {
(*(self.count as *const AtomicU32)).load(Ordering::Relaxed)
}
}
$(
#[cfg(feature = "use_gpu")]
pub fn [<$field _ptr>](&self) -> *mut $type {
self.$field
}
)*
}
}
};
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct RaySamplesDirect {
pub u: Point2f,
pub uc: Float,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct RaySamplesIndirect {
pub uc: Float,
pub rr: Float,
pub u: Point2f,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct RaySamplesSubsurface {
pub uc: Float,
pub u: Point2f,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct RaySamples {
pub direct: RaySamplesDirect,
pub indirect: RaySamplesIndirect,
pub have_subsurface: bool,
pub subsurface: RaySamplesSubsurface,
}
soa_struct! {
pub struct RayQueue {
pub ray_o: Point3f,
pub ray_d: Vector3f,
pub depth: i32,
pub lambda: SampledWavelengths,
pub pixel_index: u32,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub ctx_pi: Point3f,
pub ctx_n: Normal3f,
pub ctx_ns: Normal3f,
pub eta_scale: Float,
pub specular_bounce: u32,
pub any_non_specular_bounces: u32,
}
}
soa_struct! {
pub struct PixelSampleStateStorage {
pub p_pixel: Point2i,
pub l: SampledSpectrum,
pub lambda: SampledWavelengths,
pub filter_weight: Float,
pub visible_surface: u32,
pub camera_ray_weight: SampledSpectrum,
pub rs_direct_packed: Float4,
pub rs_indirect_packed: Float4,
pub rs_subsurface_packed: Float4,
}
}
soa_struct! {
pub struct EscapedRayQueue {
pub ray_o: Point3f,
pub ray_d: Vector3f,
pub depth: i32,
pub lambda: SampledWavelengths,
pub pixel_index: u32,
pub beta: SampledSpectrum,
pub specular_bounce: u32,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub ctx_pi: Point3f,
pub ctx_n: Normal3f,
pub ctx_ns: Normal3f,
}
}
soa_struct! {
pub struct HitAreaLightQueue {
pub area_light_id: u32, // Light ID
pub p: Point3f,
pub n: Normal3f,
pub uv: Point2f,
pub wo: Vector3f,
pub lambda: SampledWavelengths,
pub depth: i32,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub ctx_pi: Point3f,
pub ctx_n: Normal3f,
pub ctx_ns: Normal3f,
pub specular_bounce: u32,
pub pixel_index: u32,
}
}
soa_struct! {
pub struct ShadowRayQueue {
pub ray_o: Point3f,
pub ray_d: Vector3f,
pub t_max: Float,
pub lambda: SampledWavelengths,
pub ld: SampledSpectrum,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub pixel_index: u32,
}
}
soa_struct! {
pub struct GetBSSRDFAndProbeRayQueue {
pub material_id: u32,
pub lambda: SampledWavelengths,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub p: Point3f,
pub wo: Vector3f,
pub n: Normal3f,
pub ns: Normal3f,
pub dpdus: Vector3f,
pub uv: Point2f,
pub depth: i32,
pub mi_inside: u32,
pub mi_outside: u32,
pub eta_scale: Float,
pub pixel_index: u32,
}
}
soa_struct! {
pub struct SubsurfaceScatterQueue {
pub p0: Point3f,
pub p1: Point3f,
pub depth: i32,
pub material_id: u32,
pub lambda: SampledWavelengths,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub mi_inside: u32,
pub mi_outside: u32,
pub eta_scale: Float,
pub pixel_index: u32,
}
}
soa_struct! {
pub struct MediumSampleQueue {
pub ray_o: Point3f,
pub ray_d: Vector3f,
pub t_max: Float,
pub lambda: SampledWavelengths,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub pixel_index: u32,
pub ctx_pi: Point3f,
pub ctx_n: Normal3f,
pub ctx_ns: Normal3f,
pub specular_bounce: u32,
pub any_non_specular_bounces: u32,
pub eta_scale: Float,
pub area_light_id: u32,
pub pi: Point3fi,
pub n: Normal3f,
pub dpdu: Vector3f,
pub dpdv: Vector3f,
pub wo: Vector3f,
pub uv: Point2f,
pub material_id: u32,
pub ns: Normal3f,
pub dpdus: Vector3f,
pub dpdvs: Vector3f,
pub dndus: Normal3f,
pub dndvs: Normal3f,
pub face_index: i32,
pub mi_inside: u32,
pub mi_outside: u32,
}
}
soa_struct! {
pub struct MaterialEvalQueue {
pub material_id: u32,
pub pi: Point3fi,
pub n: Normal3f,
pub dpdu: Vector3f,
pub dpdv: Vector3f,
pub time: Float,
pub depth: i32,
pub ns: Normal3f,
pub dpdus: Vector3f,
pub dpdvs: Vector3f,
pub dndus: Normal3f,
pub dndvs: Normal3f,
pub uv: Point2f,
pub face_index: i32,
pub lambda: SampledWavelengths,
pub pixel_index: u32,
pub any_non_specular_bounces: u32,
pub wo: Vector3f,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub eta_scale: Float,
pub mi_inside: u32,
pub mi_outside: u32,
}
}
soa_struct! {
pub struct MediumScatterQueue {
pub p: Point3f,
pub depth: usize,
pub lambda: SampledWavelengths,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub wo: Vector3f,
pub time: Float,
pub eta_scale: Float,
pub pixel_index: usize,
// ID
pub phase_function: u32,
pub medium: u32,
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct RayWorkItem {
pub ray: Ray,
pub depth: i32,
pub lambda: SampledWavelengths,
pub pixel_index: u32,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub prev_intr_ctx: LightSampleContext,
pub eta_scale: Float,
pub specular_bounce: bool,
pub any_non_specular_bounces: bool,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct EscapedRayWorkItem {
pub ray_o: Point3f,
pub ray_d: Vector3f,
pub depth: i32,
pub lambda: SampledWavelengths,
pub pixel_index: u32,
pub beta: SampledSpectrum,
pub specular_bounce: bool,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub prev_intr_ctx: LightSampleContext,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ShadowRayWorkItem {
pub ray: Ray,
pub t_max: Float,
pub lambda: SampledWavelengths,
pub ld: SampledSpectrum,
pub r_u: SampledSpectrum,
pub r_l: SampledSpectrum,
pub pixel_index: u32,
}
impl RayQueueView {
#[cfg(feature = "use_gpu")]
pub unsafe fn push_work_item(&self, item: RayWorkItem) -> Option<u32> {
unsafe {
self.push(
item.ray.o,
item.ray.d,
item.depth,
item.lambda,
item.pixel_index,
item.beta,
item.r_u,
item.r_l,
item.prev_intr_ctx.pi.into(),
item.prev_intr_ctx.n,
item.prev_intr_ctx.ns,
item.eta_scale,
if item.specular_bounce { 1 } else { 0 },
if item.any_non_specular_bounces { 1 } else { 0 },
)
}
}
}
impl EscapedRayQueueView {
#[cfg(feature = "use_gpu")]
pub unsafe fn push_work_item(&self, r: &RayWorkItem) -> Option<u32> {
unsafe {
self.push(
r.ray.o,
r.ray.d,
r.depth,
r.lambda,
r.pixel_index,
r.beta,
if r.specular_bounce { 1 } else { 0 },
r.r_u,
r.r_l,
r.prev_intr_ctx.pi.into(),
r.prev_intr_ctx.n,
r.prev_intr_ctx.ns,
)
}
}
}
impl PixelSampleStateStorageView {
#[cfg(feature = "use_gpu")]
pub unsafe fn get_samples(&self, index: u32) -> RaySamples {
let i = index as usize;
let (dir, ind, ss) = unsafe {
(
*self.rs_direct_packed.add(i),
*self.rs_indirect_packed.add(i),
*self.rs_subsurface_packed.add(i),
)
};
let direct_u = Point2f::new(dir.v[0], dir.v[1]);
let direct_uc = dir.v[2];
let flags = dir.v[3] as i32;
let have_subsurface = (flags & 1) != 0;
let indirect_uc = ind.v[0];
let indirect_rr = ind.v[1];
let indirect_u = Point2f::new(ind.v[2], ind.v[3]);
let subsurface_uc = ss.v[0];
let subsurface_u = Point2f::new(ss.v[1], ss.v[2]);
RaySamples {
direct: RaySamplesDirect {
u: direct_u,
uc: direct_uc,
},
indirect: RaySamplesIndirect {
uc: indirect_uc,
rr: indirect_rr,
u: indirect_u,
},
have_subsurface,
subsurface: RaySamplesSubsurface {
uc: subsurface_uc,
u: subsurface_u,
},
}
}
#[cfg(feature = "use_gpu")]
pub unsafe fn set_samples(&self, index: u32, rs: RaySamples) {
if index >= self.capacity {
return;
}
let i = index as usize;
let flags = if rs.have_subsurface { 1.0 } else { 0.0 };
let dir = Float4 {
v: [rs.direct.u.0[0], rs.direct.u.0[1], rs.direct.uc, flags],
};
let ind = Float4 {
v: [
rs.indirect.uc,
rs.indirect.rr,
rs.indirect.u.0[0],
rs.indirect.u.0[1],
],
};
unsafe {
*self.rs_direct_packed.add(i) = dir;
*self.rs_indirect_packed.add(i) = ind;
}
if rs.have_subsurface {
let ss = Float4 {
v: [
rs.subsurface.uc,
rs.subsurface.u.0[0],
rs.subsurface.u.0[1],
0.0,
],
};
unsafe {
*self.rs_subsurface_packed.add(i) = ss;
}
}
}
}

5
shared/build.rs Normal file
View file

@ -0,0 +1,5 @@
fn main() {
// This allows "spirv" to be used in #[cfg(target_arch = "...")]
// without triggering a warning.
println!("cargo:rustc-check-cfg=cfg(target_arch, values(\"spirv\"))");
}

View file

@ -19,7 +19,6 @@ use crate::spectra::{
N_SPECTRUM_SAMPLES, RGBColorSpace, RGBUnboundedSpectrum, SampledSpectrum, SampledWavelengths, N_SPECTRUM_SAMPLES, RGBColorSpace, RGBUnboundedSpectrum, SampledSpectrum, SampledWavelengths,
StandardColorSpaces, StandardColorSpaces,
}; };
use crate::utils::DevicePtr;
use crate::utils::hash::hash_buffer; use crate::utils::hash::hash_buffer;
use crate::utils::math::{ use crate::utils::math::{
clamp, fast_exp, i0, lerp, log_i0, radians, safe_acos, safe_asin, safe_sqrt, sample_discrete, clamp, fast_exp, i0, lerp, log_i0, radians, safe_acos, safe_asin, safe_sqrt, sample_discrete,
@ -91,8 +90,8 @@ where
thickness: Float, thickness: Float,
g: Float, g: Float,
albedo: SampledSpectrum, albedo: SampledSpectrum,
max_depth: usize, max_depth: u32,
n_samples: usize, n_samples: u32,
} }
impl<T, B, const TWO_SIDED: bool> LayeredBxDF<T, B, TWO_SIDED> impl<T, B, const TWO_SIDED: bool> LayeredBxDF<T, B, TWO_SIDED>
@ -106,8 +105,8 @@ where
thickness: Float, thickness: Float,
albedo: SampledSpectrum, albedo: SampledSpectrum,
g: Float, g: Float,
max_depth: usize, max_depth: u32,
n_samples: usize, n_samples: u32,
) -> Self { ) -> Self {
Self { Self {
top, top,

View file

@ -8,7 +8,7 @@ use crate::core::geometry::{
use crate::core::scattering::reflect; use crate::core::scattering::reflect;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::math::square; use crate::utils::math::square;
use crate::utils::ptr::{DevicePtr, Slice}; use crate::utils::ptr::Ptr;
use crate::utils::sampling::{PiecewiseLinear2D, cosine_hemisphere_pdf, sample_cosine_hemisphere}; use crate::utils::sampling::{PiecewiseLinear2D, cosine_hemisphere_pdf, sample_cosine_hemisphere};
use crate::{Float, INV_PI, PI, PI_OVER_2}; use crate::{Float, INV_PI, PI, PI_OVER_2};
use core::any::Any; use core::any::Any;
@ -16,7 +16,7 @@ use core::any::Any;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct MeasuredBxDFData { pub struct MeasuredBxDFData {
pub wavelengths: Slice<Float>, pub wavelengths: Ptr<Float>,
pub spectra: PiecewiseLinear2D<3>, pub spectra: PiecewiseLinear2D<3>,
pub ndf: PiecewiseLinear2D<0>, pub ndf: PiecewiseLinear2D<0>,
pub vndf: PiecewiseLinear2D<2>, pub vndf: PiecewiseLinear2D<2>,
@ -28,7 +28,7 @@ pub struct MeasuredBxDFData {
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct MeasuredBxDF { pub struct MeasuredBxDF {
pub brdf: DevicePtr<MeasuredBxDFData>, pub brdf: Ptr<MeasuredBxDFData>,
pub lambda: SampledWavelengths, pub lambda: SampledWavelengths,
} }
@ -38,7 +38,7 @@ unsafe impl Sync for MeasuredBxDF {}
impl MeasuredBxDF { impl MeasuredBxDF {
pub fn new(brdf: &MeasuredBxDFData, lambda: &SampledWavelengths) -> Self { pub fn new(brdf: &MeasuredBxDFData, lambda: &SampledWavelengths) -> Self {
Self { Self {
brdf: DevicePtr::from(brdf), brdf: Ptr::from(brdf),
lambda: *lambda, lambda: *lambda,
} }
} }

View file

@ -6,4 +6,4 @@ mod spherical;
pub use orthographic::OrthographicCamera; pub use orthographic::OrthographicCamera;
pub use perspective::PerspectiveCamera; pub use perspective::PerspectiveCamera;
pub use realistic::RealisticCamera; pub use realistic::RealisticCamera;
pub use spherical::SphericalCamera; pub use spherical::{SphericalCamera, Mapping};

View file

@ -11,6 +11,7 @@ use crate::core::pbrt::Float;
use crate::core::sampler::CameraSample; use crate::core::sampler::CameraSample;
use crate::core::scattering::refract; use crate::core::scattering::refract;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::Ptr;
use crate::utils::math::{lerp, quadratic, square}; use crate::utils::math::{lerp, quadratic, square};
#[repr(C)] #[repr(C)]
@ -37,8 +38,8 @@ pub struct RealisticCamera {
base: CameraBase, base: CameraBase,
focus_distance: Float, focus_distance: Float,
set_aperture_diameter: Float, set_aperture_diameter: Float,
aperture_image: *const DeviceImage, aperture_image: Ptr<DeviceImage>,
element_interfaces: *const LensElementInterface, element_interfaces: Ptr<LensElementInterface>,
n_elements: usize, n_elements: usize,
physical_extent: Bounds2f, physical_extent: Bounds2f,
exit_pupil_bounds: [Bounds2f; EXIT_PUPIL_SAMPLES], exit_pupil_bounds: [Bounds2f; EXIT_PUPIL_SAMPLES],
@ -51,13 +52,13 @@ impl RealisticCamera {
lens_params: &[Float], lens_params: &[Float],
focus_distance: Float, focus_distance: Float,
set_aperture_diameter: Float, set_aperture_diameter: Float,
aperture_image: Option<DeviceImage>, aperture_image: Ptr<DeviceImage>,
) -> Self { ) -> Self {
let film_ptr = base.film; let film_ptr = base.film;
if film_ptr.is_null() { if film_ptr.is_null() {
panic!("Camera must have a film"); panic!("Camera must have a film");
} }
let film = unsafe { &*film_ptr }; let film = &*film_ptr;
let aspect = film.full_resolution().x() as Float / film.full_resolution().y() as Float; let aspect = film.full_resolution().x() as Float / film.full_resolution().y() as Float;
let diagonal = film.diagonal(); let diagonal = film.diagonal();
@ -90,7 +91,6 @@ impl RealisticCamera {
element_interface.push(el_int); element_interface.push(el_int);
} }
let n_samples = 64;
let half_diag = film.diagonal() / 2.0; let half_diag = film.diagonal() / 2.0;
let mut exit_pupil_bounds = [Bounds2f::default(); EXIT_PUPIL_SAMPLES]; let mut exit_pupil_bounds = [Bounds2f::default(); EXIT_PUPIL_SAMPLES];
@ -107,7 +107,7 @@ impl RealisticCamera {
Self { Self {
base, base,
focus_distance, focus_distance,
element_interfaces, element_interfaces: Ptr::from(element_interfaces),
n_elements, n_elements,
physical_extent, physical_extent,
set_aperture_diameter, set_aperture_diameter,
@ -123,14 +123,16 @@ impl RealisticCamera {
} }
pub fn compute_thick_lens_approximation(&self) -> ([Float; 2], [Float; 2]) { pub fn compute_thick_lens_approximation(&self) -> ([Float; 2], [Float; 2]) {
use crate::utils::Ptr;
let x = 0.001 * self.get_film().diagonal(); let x = 0.001 * self.get_film().diagonal();
let r_scene = Ray::new( let r_scene = Ray::new(
Point3f::new(0., x, self.lens_front_z() + 1.), Point3f::new(0., x, self.lens_front_z() + 1.),
Vector3f::new(0., 0., -1.), Vector3f::new(0., 0., -1.),
None, None,
None, &Ptr::null(),
); );
let Some(r_film) = self.trace_lenses_from_film(r_scene) else { let Some((_, r_film)) = self.trace_lenses_from_film(&r_scene) else {
panic!( panic!(
"Unable to trace ray from scene to film for thick lens approx. Is aperture very small?" "Unable to trace ray from scene to film for thick lens approx. Is aperture very small?"
) )
@ -140,14 +142,14 @@ impl RealisticCamera {
Point3f::new(x, 0., self.lens_rear_z() - 1.), Point3f::new(x, 0., self.lens_rear_z() - 1.),
Vector3f::new(0., 0., 1.), Vector3f::new(0., 0., 1.),
None, None,
None, &Ptr::null(),
); );
let Some(r_scene) = self.trace_lenses_from_film(r_film) else { let Some((_, r_scene)) = self.trace_lenses_from_film(&r_film) else {
panic!( panic!(
"Unable to trace ray from scene to film for thick lens approx. Is aperture very small?" "Unable to trace ray from scene to film for thick lens approx. Is aperture very small?"
) )
}; };
let (pz1, f_1) = Self::compute_cardinal_points(r_film, r_scene); let (pz1, fz1) = Self::compute_cardinal_points(r_film, r_scene);
([pz0, pz1], [fz0, fz1]) ([pz0, pz1], [fz0, fz1])
} }
@ -155,19 +157,23 @@ impl RealisticCamera {
let (pz, fz) = self.compute_thick_lens_approximation(); let (pz, fz) = self.compute_thick_lens_approximation();
let f = fz[0] - pz[0]; let f = fz[0] - pz[0];
let z = -focus_distance; let z = -focus_distance;
let c = (pz[1] - z - pz[0]) * (pz[1] - z - 4 * f - pz[0]); let c = (pz[1] - z - pz[0]) * (pz[1] - z - 4. * f - pz[0]);
if c <= 0 { if c <= 0. {
panic!( panic!(
"Coefficient must be positive. It looks focusDistance {} is too short for a given lenses configuration", "Coefficient must be positive. It looks focusDistance {} is too short for a given lenses configuration",
focusDistance focus_distance
); );
} }
let delta = (pz[1] - z + pz[0] - c.sqrt()) / 2.; let delta = (pz[1] - z + pz[0] - c.sqrt()) / 2.;
self.element_interface.last().thickness + delta let last_interface = unsafe { self.element_interfaces.add(self.n_elements) };
last_interface.thickness + delta
} }
pub fn bound_exit_pupil(&self, film_x_0: Float, film_x_1: Float) -> Bounds2f { pub fn bound_exit_pupil(&self, film_x_0: Float, film_x_1: Float) -> Bounds2f {
Self::compute_exit_pupil_bounds(&self.element_interface, film_x_0, film_x_1) let interface_array = unsafe {
core::slice::from_raw_parts(self.element_interfaces.as_raw(), self.n_elements as usize)
};
Self::compute_exit_pupil_bounds(interface_array, film_x_0, film_x_1)
} }
fn compute_exit_pupil_bounds( fn compute_exit_pupil_bounds(
@ -203,7 +209,10 @@ impl RealisticCamera {
// Expand pupil bounds if ray makes it through the lens system // Expand pupil bounds if ray makes it through the lens system
if !pupil_bounds.contains(Point2f::new(p_rear.x(), p_rear.y())) if !pupil_bounds.contains(Point2f::new(p_rear.x(), p_rear.y()))
&& trace_lenses_from_film(Ray::new(p_film, p_rear - p_film, None, None), None) && trace_lenses_from_film(
Ray::new(p_film, p_rear - p_film, None, &Ptr::null()),
None,
)
{ {
pupil_bounds = pupil_bounds.union_point(Point2f::new(p_rear.x(), p_rear.y())); pupil_bounds = pupil_bounds.union_point(Point2f::new(p_rear.x(), p_rear.y()));
} }
@ -223,7 +232,7 @@ impl RealisticCamera {
pub fn sample_exit_pupil(&self, p_film: Point2f, u_lens: Point2f) -> Option<ExitPupilSample> { pub fn sample_exit_pupil(&self, p_film: Point2f, u_lens: Point2f) -> Option<ExitPupilSample> {
// Find exit pupil bound for sample distance from film center // Find exit pupil bound for sample distance from film center
let film = self.film(); let film = self.get_film();
let r_film = (square(p_film.x()) + square(p_film.y())).sqrt(); let r_film = (square(p_film.x()) + square(p_film.y())).sqrt();
let mut r_index = (r_film / (film.diagonal() / 2.)) as usize * self.exit_pupil_bounds.len(); let mut r_index = (r_film / (film.diagonal() / 2.)) as usize * self.exit_pupil_bounds.len();
r_index = (self.exit_pupil_bounds.len() - 1).min(r_index); r_index = (self.exit_pupil_bounds.len() - 1).min(r_index);
@ -265,11 +274,11 @@ impl RealisticCamera {
Point3f::new(r_camera.o.x(), r_camera.o.y(), -r_camera.o.z()), Point3f::new(r_camera.o.x(), r_camera.o.y(), -r_camera.o.z()),
Vector3f::new(r_camera.d.x(), r_camera.d.y(), -r_camera.d.z()), Vector3f::new(r_camera.d.x(), r_camera.d.y(), -r_camera.d.z()),
Some(r_camera.time), Some(r_camera.time),
None, &Ptr::null(),
); );
for i in (0..self.element_interface.len() - 1).rev() { for i in (0..self.n_elements - 1).rev() {
let element: &LensElementInterface = &self.element_interface[i]; let element: &LensElementInterface = unsafe { &self.element_interfaces.add(i) };
// Update ray from film accounting for interaction with _element_ // Update ray from film accounting for interaction with _element_
element_z -= element.thickness; element_z -= element.thickness;
@ -308,8 +317,9 @@ impl RealisticCamera {
// Update ray path for element interface interaction // Update ray path for element interface interaction
if !is_stop { if !is_stop {
let eta_i = element.eta; let eta_i = element.eta;
let eta_t = if i > 0 && self.element_interface[i - 1].eta != 0. { let interface_i = unsafe { self.element_interfaces.add(i - 1) };
self.element_interface[i - 1].eta let eta_t = if i > 0 && interface_i.eta != 0. {
interface_i.eta
} else { } else {
1. 1.
}; };
@ -331,7 +341,7 @@ impl RealisticCamera {
Point3f::new(r_lens.o.x(), r_lens.o.y(), -r_lens.o.z()), Point3f::new(r_lens.o.x(), r_lens.o.y(), -r_lens.o.z()),
Vector3f::new(r_lens.d.x(), r_lens.d.y(), -r_lens.d.z()), Vector3f::new(r_lens.d.x(), r_lens.d.y(), -r_lens.d.z()),
Some(r_lens.time), Some(r_lens.time),
None, &Ptr::null(),
); );
Some((weight, r_out)) Some((weight, r_out))
@ -368,19 +378,22 @@ impl RealisticCamera {
} }
pub fn lens_rear_z(&self) -> Float { pub fn lens_rear_z(&self) -> Float {
self.element_interface.last().unwrap().thickness let last_interface = unsafe { self.element_interfaces.add(self.n_elements - 1) };
last_interface.thickness
} }
pub fn lens_front_z(&self) -> Float { pub fn lens_front_z(&self) -> Float {
let mut z_sum = 0.; let mut z_sum = 0.;
for element in &self.element_interface { for i in 0..self.n_elements {
let element = unsafe { self.element_interfaces.add(i) };
z_sum += element.thickness; z_sum += element.thickness;
} }
z_sum z_sum
} }
pub fn rear_element_radius(&self) -> Float { pub fn rear_element_radius(&self) -> Float {
self.element_interface.last().unwrap().aperture_radius let last_interface = unsafe { self.element_interfaces.add(self.n_elements - 1) };
last_interface.aperture_radius
} }
} }
@ -406,7 +419,7 @@ impl CameraTrait for RealisticCamera {
let eps = self.sample_exit_pupil(Point2f::new(p_film.x(), p_film.y()), sample.p_lens)?; let eps = self.sample_exit_pupil(Point2f::new(p_film.x(), p_film.y()), sample.p_lens)?;
let p_pupil = Point3f::new(0., 0., 0.); let p_pupil = Point3f::new(0., 0., 0.);
let r_film = Ray::new(p_film, p_pupil - p_film, None, None); let r_film = Ray::new(p_film, p_pupil - p_film, None, &Ptr::null());
let (weight, mut ray) = self.trace_lenses_from_film(&r_film)?; let (weight, mut ray) = self.trace_lenses_from_film(&r_film)?;
if weight == 0. { if weight == 0. {
return None; return None;

View file

@ -53,7 +53,7 @@ impl CameraTrait for SphericalCamera {
Point3f::new(0., 0., 0.), Point3f::new(0., 0., 0.),
dir, dir,
Some(self.sample_time(sample.time)), Some(self.sample_time(sample.time)),
self.base().medium.clone(), &self.base().medium,
); );
Some(CameraRay { Some(CameraRay {
ray: self.render_from_camera(&ray, &mut None), ray: self.render_from_camera(&ray, &mut None),

View file

@ -2,17 +2,17 @@ use crate::Float;
use crate::core::bxdf::{BSDFSample, BxDF, BxDFFlags, BxDFTrait, FArgs, TransportMode}; use crate::core::bxdf::{BSDFSample, BxDF, BxDFFlags, BxDFTrait, FArgs, TransportMode};
use crate::core::geometry::{Frame, Normal3f, Point2f, Vector3f, VectorLike}; use crate::core::geometry::{Frame, Normal3f, Point2f, Vector3f, VectorLike};
use crate::spectra::SampledSpectrum; use crate::spectra::SampledSpectrum;
use crate::utils::DevicePtr; use crate::utils::Ptr;
#[repr(C)] #[repr(C)]
#[derive(Copy, Debug, Default)] #[derive(Copy, Clone, Debug, Default)]
pub struct BSDF { pub struct BSDF {
bxdf: DevicePtr<BxDF>, bxdf: Ptr<BxDF>,
shading_frame: Frame, shading_frame: Frame,
} }
impl BSDF { impl BSDF {
pub fn new(ns: Normal3f, dpdus: Vector3f, bxdf: DevicePtr<BxDF>) -> Self { pub fn new(ns: Normal3f, dpdus: Vector3f, bxdf: Ptr<BxDF>) -> Self {
Self { Self {
bxdf, bxdf,
shading_frame: Frame::new(dpdus.normalize(), Vector3f::from(ns)), shading_frame: Frame::new(dpdus.normalize(), Vector3f::from(ns)),
@ -66,7 +66,7 @@ impl BSDF {
u2: Point2f, u2: Point2f,
f_args: FArgs, f_args: FArgs,
) -> Option<BSDFSample> { ) -> Option<BSDFSample> {
let bxdf = self.bxdf.as_ref()?; let bxdf = unsafe { self.bxdf.as_ref() };
let sampling_flags = BxDFFlags::from_bits_truncate(f_args.sample_flags.bits()); let sampling_flags = BxDFFlags::from_bits_truncate(f_args.sample_flags.bits());
let wo = self.render_to_local(wo_render); let wo = self.render_to_local(wo_render);
@ -119,7 +119,8 @@ impl BSDF {
pub fn regularize(&mut self) { pub fn regularize(&mut self) {
if !self.bxdf.is_null() { if !self.bxdf.is_null() {
unsafe { self.bxdf.as_mut().regularize() } let mut bxdf = unsafe { *self.bxdf.as_raw() };
bxdf.regularize();
} }
} }
} }

View file

@ -1,4 +1,5 @@
use crate::core::bxdf::{BSDF, NormalizedFresnelBxDF}; use crate::bxdfs::NormalizedFresnelBxDF;
use crate::core::bsdf::BSDF;
use crate::core::geometry::{Frame, Normal3f, Point2f, Point3f, Point3fi, Vector3f}; use crate::core::geometry::{Frame, Normal3f, Point2f, Point3f, Point3fi, Vector3f};
use crate::core::interaction::{InteractionBase, ShadingGeom, SurfaceInteraction}; use crate::core::interaction::{InteractionBase, ShadingGeom, SurfaceInteraction};
use crate::core::shape::Shape; use crate::core::shape::Shape;
@ -6,7 +7,6 @@ use crate::spectra::{N_SPECTRUM_SAMPLES, SampledSpectrum};
use crate::utils::Ptr; use crate::utils::Ptr;
use crate::utils::math::{catmull_rom_weights, square}; use crate::utils::math::{catmull_rom_weights, square};
use crate::utils::sampling::sample_catmull_rom_2d; use crate::utils::sampling::sample_catmull_rom_2d;
use crate::utils::{Ptr, ptr::Slice};
use crate::{Float, PI}; use crate::{Float, PI};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use std::sync::Arc; use std::sync::Arc;
@ -105,30 +105,35 @@ pub struct BSSRDFTable {
impl BSSRDFTable { impl BSSRDFTable {
pub fn get_rho(&self) -> &[Float] { pub fn get_rho(&self) -> &[Float] {
unsafe { core::slice::from_raw_parts(self.rho_samples.0, self.n_rho_samples as usize) } unsafe {
core::slice::from_raw_parts(self.rho_samples.as_ref(), self.n_rho_samples as usize)
}
} }
pub fn get_radius(&self) -> &[Float] { pub fn get_radius(&self) -> &[Float] {
unsafe { unsafe {
core::slice::from_raw_parts(self.radius_samples.0, self.n_radius_samples as usize) core::slice::from_raw_parts(
self.radius_samples.as_ref(),
self.n_radius_samples as usize,
)
} }
} }
pub fn get_profile(&self) -> &[Float] { pub fn get_profile(&self) -> &[Float] {
let n_profile = (self.n_rho_samples * self.n_radius_samples) as usize; let n_profile = (self.n_rho_samples * self.n_radius_samples) as usize;
unsafe { core::slice::from_raw_parts(self.profile.0, n_profile) } unsafe { core::slice::from_raw_parts(self.profile.as_ref(), n_profile) }
} }
pub fn get_cdf(&self) -> &[Float] { pub fn get_cdf(&self) -> &[Float] {
let n_profile = (self.n_rho_samples * self.n_radius_samples) as usize; let n_profile = (self.n_rho_samples * self.n_radius_samples) as usize;
unsafe { core::slice::from_raw_parts(self.profile_cdf.0, n_profile) } unsafe { core::slice::from_raw_parts(self.profile_cdf.as_ref(), n_profile) }
} }
pub fn eval_profile(&self, rho_index: u32, radius_index: u32) -> Float { pub fn eval_profile(&self, rho_index: u32, radius_index: u32) -> Float {
debug_assert!(rho_index < self.n_rho_samples); debug_assert!(rho_index < self.n_rho_samples);
debug_assert!(radius_index < self.n_radius_samples); debug_assert!(radius_index < self.n_radius_samples);
let idx = (rho_index * self.n_radius_samples + radius_index) as usize; let idx = (rho_index * self.n_radius_samples + radius_index) as usize;
unsafe { *self.profile.0.add(idx) } unsafe { *self.profile.add(idx) }
} }
} }

View file

@ -10,7 +10,7 @@ use crate::core::pbrt::Float;
use crate::core::sampler::CameraSample; use crate::core::sampler::CameraSample;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::math::lerp; use crate::utils::math::lerp;
use crate::utils::ptr::DevicePtr; use crate::utils::ptr::Ptr;
use crate::utils::transform::{AnimatedTransform, Transform}; use crate::utils::transform::{AnimatedTransform, Transform};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
@ -113,8 +113,8 @@ pub struct CameraBase {
pub min_pos_differential_y: Vector3f, pub min_pos_differential_y: Vector3f,
pub min_dir_differential_x: Vector3f, pub min_dir_differential_x: Vector3f,
pub min_dir_differential_y: Vector3f, pub min_dir_differential_y: Vector3f,
pub film: DevicePtr<Film>, pub film: Ptr<Film>,
pub medium: DevicePtr<Medium>, pub medium: Ptr<Medium>,
} }
#[enum_dispatch(CameraTrait)] #[enum_dispatch(CameraTrait)]
@ -163,9 +163,6 @@ pub trait CameraTrait {
sample: CameraSample, sample: CameraSample,
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
) -> Option<CameraRay> { ) -> Option<CameraRay> {
match self {
Camera::Orthographic(c) => c.generate_ray_differential(sample, lambda),
_ => {
let mut central_cam_ray = self.generate_ray(sample, lambda)?; let mut central_cam_ray = self.generate_ray(sample, lambda)?;
let mut rd = RayDifferential::default(); let mut rd = RayDifferential::default();
let mut rx_found = false; let mut rx_found = false;
@ -176,10 +173,10 @@ pub trait CameraTrait {
s_shift.p_film[0] += eps; s_shift.p_film[0] += eps;
if let Some(rx_cam_ray) = self.generate_ray(s_shift, lambda) { if let Some(rx_cam_ray) = self.generate_ray(s_shift, lambda) {
rd.rx_origin = central_cam_ray.ray.o rd.rx_origin =
+ (rx_cam_ray.ray.o - central_cam_ray.ray.o) / eps; central_cam_ray.ray.o + (rx_cam_ray.ray.o - central_cam_ray.ray.o) / eps;
rd.rx_direction = central_cam_ray.ray.d rd.rx_direction =
+ (rx_cam_ray.ray.d - central_cam_ray.ray.d) / eps; central_cam_ray.ray.d + (rx_cam_ray.ray.d - central_cam_ray.ray.d) / eps;
rx_found = true; rx_found = true;
break; break;
} }
@ -190,10 +187,10 @@ pub trait CameraTrait {
s_shift.p_film[1] += eps; s_shift.p_film[1] += eps;
if let Some(ry_cam_ray) = self.generate_ray(s_shift, lambda) { if let Some(ry_cam_ray) = self.generate_ray(s_shift, lambda) {
rd.ry_origin = central_cam_ray.ray.o rd.ry_origin =
+ (ry_cam_ray.ray.o - central_cam_ray.ray.o) / eps; central_cam_ray.ray.o + (ry_cam_ray.ray.o - central_cam_ray.ray.o) / eps;
rd.ry_direction = central_cam_ray.ray.d rd.ry_direction =
+ (ry_cam_ray.ray.d - central_cam_ray.ray.d) / eps; central_cam_ray.ray.d + (ry_cam_ray.ray.d - central_cam_ray.ray.d) / eps;
ry_found = true; ry_found = true;
break; break;
} }
@ -205,8 +202,6 @@ pub trait CameraTrait {
Some(central_cam_ray) Some(central_cam_ray)
} }
}
}
fn approximate_dp_dxy( fn approximate_dp_dxy(
&self, &self,
@ -232,13 +227,13 @@ pub trait CameraTrait {
Point3f::new(0., 0., 0.) + self.base().min_pos_differential_x, Point3f::new(0., 0., 0.) + self.base().min_pos_differential_x,
Vector3f::new(0., 0., 1.) + self.base().min_dir_differential_x, Vector3f::new(0., 0., 1.) + self.base().min_dir_differential_x,
None, None,
&DevicePtr::default(), &Ptr::default(),
); );
let y_ray = Ray::new( let y_ray = Ray::new(
Point3f::new(0., 0., 0.) + self.base().min_pos_differential_y, Point3f::new(0., 0., 0.) + self.base().min_pos_differential_y,
Vector3f::new(0., 0., 1.) + self.base().min_dir_differential_y, Vector3f::new(0., 0., 1.) + self.base().min_dir_differential_y,
None, None,
&DevicePtr::default(), &Ptr::default(),
); );
let n_down = Vector3f::from(n_down_z); let n_down = Vector3f::from(n_down_z);
let tx = -(n_down.dot(y_ray.o.into())) / n_down.dot(x_ray.d); let tx = -(n_down.dot(y_ray.o.into())) / n_down.dot(x_ray.d);

View file

@ -27,8 +27,8 @@ impl From<(Float, Float, Float)> for XYZ {
} }
impl From<[Float; 3]> for XYZ { impl From<[Float; 3]> for XYZ {
fn from(triplet: (Float, Float, Float)) -> Self { fn from(triplet: [Float; 3]) -> Self {
XYZ::new(triplet.0, triplet.1, triplet.2) XYZ::new(triplet[0], triplet[1], triplet[2])
} }
} }
@ -336,6 +336,30 @@ impl Index<u32> for RGB {
} }
} }
impl Index<i32> for RGB {
type Output = Float;
fn index(&self, index: i32) -> &Self::Output {
debug_assert!(index < 3);
match index {
0 => &self.r,
1 => &self.g,
_ => &self.b,
}
}
}
impl Index<usize> for RGB {
type Output = Float;
fn index(&self, index: usize) -> &Self::Output {
debug_assert!(index < 3);
match index {
0 => &self.r,
1 => &self.g,
_ => &self.b,
}
}
}
impl IndexMut<u32> for RGB { impl IndexMut<u32> for RGB {
fn index_mut(&mut self, index: u32) -> &mut Self::Output { fn index_mut(&mut self, index: u32) -> &mut Self::Output {
debug_assert!(index < 3); debug_assert!(index < 3);
@ -347,6 +371,28 @@ impl IndexMut<u32> for RGB {
} }
} }
impl IndexMut<i32> for RGB {
fn index_mut(&mut self, index: i32) -> &mut Self::Output {
debug_assert!(index < 3);
match index {
0 => &mut self.r,
1 => &mut self.g,
_ => &mut self.b,
}
}
}
impl IndexMut<usize> for RGB {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
debug_assert!(index < 3);
match index {
0 => &mut self.r,
1 => &mut self.g,
_ => &mut self.b,
}
}
}
impl Neg for RGB { impl Neg for RGB {
type Output = Self; type Output = Self;
fn neg(self) -> Self { fn neg(self) -> Self {
@ -667,7 +713,7 @@ impl ColorEncodingTrait for SRGBEncoding {
fn to_linear(&self, vin: &[u8], vout: &mut [Float]) { fn to_linear(&self, vin: &[u8], vout: &mut [Float]) {
for (i, &v) in vin.iter().enumerate() { for (i, &v) in vin.iter().enumerate() {
vout[i] = SRGB_TO_LINEAR_LUT[v as u32]; vout[i] = SRGB_TO_LINEAR_LUT[v as usize];
} }
} }
@ -992,6 +1038,18 @@ impl Add for Coeffs {
} }
} }
impl Sub for Coeffs {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: Self) -> Self {
Self {
c0: self.c0 - rhs.c0,
c1: self.c1 - rhs.c1,
c2: self.c2 - rhs.c2,
}
}
}
impl Mul<Float> for Coeffs { impl Mul<Float> for Coeffs {
type Output = Self; type Output = Self;
#[inline(always)] #[inline(always)]
@ -1025,7 +1083,7 @@ impl RGBToSpectrumTable {
let m = rgb.max_component_value(); let m = rgb.max_component_value();
let min_val = rgb.min_component_value(); let min_val = rgb.min_component_value();
if m - min_val < 1e-4 { if m - min_val < 1e-4 {
let x = clamp(rgb[0], 1e-4, 0.9999); let x: Float = clamp(rgb[0], 1e-4, 0.9999);
let c2 = (0.5 - x) / (x * (1.0 - x)).sqrt(); let c2 = (0.5 - x) / (x * (1.0 - x)).sqrt();
return RGBSigmoidPolynomial::new(0.0, 0.0, c2); return RGBSigmoidPolynomial::new(0.0, 0.0, c2);
} }

View file

@ -13,16 +13,15 @@ use crate::spectra::{
ConstantSpectrum, DenselySampledSpectrum, LAMBDA_MAX, LAMBDA_MIN, N_SPECTRUM_SAMPLES, ConstantSpectrum, DenselySampledSpectrum, LAMBDA_MAX, LAMBDA_MIN, N_SPECTRUM_SAMPLES,
PiecewiseLinearSpectrum, RGBColorSpace, SampledSpectrum, SampledWavelengths, colorspace, PiecewiseLinearSpectrum, RGBColorSpace, SampledSpectrum, SampledWavelengths, colorspace,
}; };
use crate::utils::AtomicFloat;
use crate::utils::containers::Array2D; use crate::utils::containers::Array2D;
use crate::utils::math::linear_least_squares; use crate::utils::math::linear_least_squares;
use crate::utils::math::{SquareMatrix, wrap_equal_area_square}; use crate::utils::math::{SquareMatrix, wrap_equal_area_square};
use crate::utils::ptr::DevicePtr;
use crate::utils::sampling::VarianceEstimator; use crate::utils::sampling::VarianceEstimator;
use crate::utils::transform::AnimatedTransform; use crate::utils::transform::AnimatedTransform;
use crate::utils::{AtomicFloat, Ptr};
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Debug)]
pub struct RGBFilm { pub struct RGBFilm {
pub base: FilmBase, pub base: FilmBase,
pub max_component_value: Float, pub max_component_value: Float,
@ -33,7 +32,7 @@ pub struct RGBFilm {
} }
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct RGBPixel { pub struct RGBPixel {
rgb_sum: [AtomicFloat; 3], rgb_sum: [AtomicFloat; 3],
weight_sum: AtomicFloat, weight_sum: AtomicFloat,
@ -108,7 +107,7 @@ impl RGBFilm {
_vi: Option<&VisibleSurface>, _vi: Option<&VisibleSurface>,
weight: Float, weight: Float,
) { ) {
let sensor = unsafe { self.get_sensor() }; let sensor = self.get_sensor();
let mut rgb = sensor.to_sensor_rgb(l, lambda); let mut rgb = sensor.to_sensor_rgb(l, lambda);
let m = rgb.into_iter().copied().fold(f32::NEG_INFINITY, f32::max); let m = rgb.into_iter().copied().fold(f32::NEG_INFINITY, f32::max);
if m > self.max_component_value { if m > self.max_component_value {
@ -117,13 +116,13 @@ impl RGBFilm {
let pixel = &self.pixels[p_film]; let pixel = &self.pixels[p_film];
for c in 0..3 { for c in 0..3 {
pixel.rgb_sum[c].add((weight * rgb[c]) as f64); pixel.rgb_sum[c].add((weight * rgb[c as u32]) as f32);
} }
pixel.weight_sum.add(weight as f64); pixel.weight_sum.add(weight as f32);
} }
pub fn add_splat(&mut self, p: Point2f, l: SampledSpectrum, lambda: &SampledWavelengths) { pub fn add_splat(&mut self, p: Point2f, l: SampledSpectrum, lambda: &SampledWavelengths) {
let sensor = unsafe { self.get_sensor() }; let sensor = self.get_sensor();
let mut rgb = sensor.to_sensor_rgb(l, lambda); let mut rgb = sensor.to_sensor_rgb(l, lambda);
let m = rgb.into_iter().copied().fold(f32::NEG_INFINITY, f32::max); let m = rgb.into_iter().copied().fold(f32::NEG_INFINITY, f32::max);
if m > self.max_component_value { if m > self.max_component_value {
@ -148,32 +147,32 @@ impl RGBFilm {
if wt != 0. { if wt != 0. {
let pixel = &self.pixels[*pi]; let pixel = &self.pixels[*pi];
for i in 0..3 { for i in 0..3 {
pixel.rgb_splat[i].add((wt * rgb[i]) as f64); pixel.rgb_splat[i].add((wt * rgb[i as u32]) as f32);
} }
} }
} }
} }
pub fn get_pixel_rgb(&self, p: Point2i, splat_scale: Option<Float>) -> RGB { pub fn get_pixel_rgb(&self, p: Point2i, splat_scale: Option<Float>) -> RGB {
let pixel = unsafe { &self.pixels.get(p) }; let pixel = &self.pixels.get(p);
let mut rgb = RGB::new( let mut rgb = RGB::new(
pixel.rgb_sum[0].load() as Float, pixel.rgb_sum[0].get() as Float,
pixel.rgb_sum[1].load() as Float, pixel.rgb_sum[1].get() as Float,
pixel.rgb_sum[2].load() as Float, pixel.rgb_sum[2].get() as Float,
); );
let weight_sum = pixel.weight_sum.load(); let weight_sum = pixel.weight_sum.get();
if weight_sum != 0. { if weight_sum != 0. {
rgb /= weight_sum as Float rgb /= weight_sum as Float
} }
if let Some(splat) = splat_scale { if let Some(splat) = splat_scale {
for c in 0..3 { for c in 0..3 {
let splat_val = pixel.rgb_splat[c].load(); let splat_val = pixel.rgb_splat[c].get();
rgb[c] += splat * splat_val as Float / self.filter_integral; rgb[c] += splat * splat_val as Float / self.filter_integral;
} }
} else { } else {
for c in 0..3 { for c in 0..3 {
let splat_val = pixel.rgb_splat[c].load(); let splat_val = pixel.rgb_splat[c].get();
rgb[c] += splat_val as Float / self.filter_integral; rgb[c] += splat_val as Float / self.filter_integral;
} }
} }
@ -210,7 +209,7 @@ struct GBufferPixel {
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug)]
#[cfg_attr(target_os = "cuda", derive(Copy, Clone))] #[cfg_attr(target_os = "cuda", derive(Copy, Clone))]
pub struct GBufferFilm { pub struct GBufferFilm {
pub base: FilmBase, pub base: FilmBase,
@ -224,40 +223,6 @@ pub struct GBufferFilm {
output_rgbf_from_sensor_rgb: SquareMatrix<Float, 3>, output_rgbf_from_sensor_rgb: SquareMatrix<Float, 3>,
} }
#[cfg(not(target_os = "cuda"))]
impl GBufferFilm {
pub fn new(
base: &FilmBase,
output_from_render: &AnimatedTransform,
apply_inverse: bool,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
assert!(!base.pixel_bounds.is_empty());
let sensor_ptr = base.sensor;
if sensor_ptr.is_null() {
panic!("Film must have a sensor");
}
let sensor = unsafe { &*sensor_ptr };
let output_rgbf_from_sensor_rgb = colorspace.rgb_from_xyz * sensor.xyz_from_sensor_rgb;
let filter_integral = base.filter.integral();
let pixels = Array2D::new(base.pixel_bounds);
Self {
base: base.clone(),
output_from_render: output_from_render.clone(),
apply_inverse,
pixels,
colorspace: colorspace.clone(),
max_component_value,
write_fp16,
filter_integral,
output_rgbf_from_sensor_rgb,
}
}
}
impl GBufferFilm { impl GBufferFilm {
pub fn base(&self) -> &FilmBase { pub fn base(&self) -> &FilmBase {
&self.base &self.base
@ -279,8 +244,19 @@ impl GBufferFilm {
unsafe { &*self.base.sensor } unsafe { &*self.base.sensor }
} }
pub fn add_sample(
&mut self,
_p_film: Point2i,
_l: SampledSpectrum,
_lambda: &SampledWavelengths,
_visible_surface: Option<&VisibleSurface>,
_weight: Float,
) {
todo!()
}
pub fn add_splat(&mut self, p: Point2f, l: SampledSpectrum, lambda: &SampledWavelengths) { pub fn add_splat(&mut self, p: Point2f, l: SampledSpectrum, lambda: &SampledWavelengths) {
let sensor = unsafe { self.get_sensor() }; let sensor = self.get_sensor();
let mut rgb = sensor.to_sensor_rgb(l, lambda); let mut rgb = sensor.to_sensor_rgb(l, lambda);
let m = rgb.into_iter().copied().fold(f32::NEG_INFINITY, f32::max); let m = rgb.into_iter().copied().fold(f32::NEG_INFINITY, f32::max);
if m > self.max_component_value { if m > self.max_component_value {
@ -305,7 +281,7 @@ impl GBufferFilm {
if wt != 0. { if wt != 0. {
let pixel = &self.pixels[*pi]; let pixel = &self.pixels[*pi];
for i in 0..3 { for i in 0..3 {
pixel.rgb_splat[i].add((wt * rgb[i]) as f64); pixel.rgb_splat[i].add((wt * rgb[i]) as f32);
} }
} }
} }
@ -318,25 +294,25 @@ impl GBufferFilm {
} }
pub fn get_pixel_rgb(&self, p: Point2i, splat_scale: Option<Float>) -> RGB { pub fn get_pixel_rgb(&self, p: Point2i, splat_scale: Option<Float>) -> RGB {
let pixel = unsafe { &self.pixels.get(p) }; let pixel = &self.pixels.get(p);
let mut rgb = RGB::new( let mut rgb = RGB::new(
pixel.rgb_sum[0].load() as Float, pixel.rgb_sum[0].get() as Float,
pixel.rgb_sum[1].load() as Float, pixel.rgb_sum[1].get() as Float,
pixel.rgb_sum[2].load() as Float, pixel.rgb_sum[2].get() as Float,
); );
let weight_sum = pixel.weight_sum.load(); let weight_sum = pixel.weight_sum.get();
if weight_sum != 0. { if weight_sum != 0. {
rgb /= weight_sum as Float rgb /= weight_sum as Float
} }
if let Some(splat) = splat_scale { if let Some(splat) = splat_scale {
for c in 0..3 { for c in 0..3 {
let splat_val = pixel.rgb_splat[c].load(); let splat_val = pixel.rgb_splat[c].get();
rgb[c] += splat * splat_val as Float / self.filter_integral; rgb[c] += splat * splat_val as Float / self.filter_integral;
} }
} else { } else {
for c in 0..3 { for c in 0..3 {
let splat_val = pixel.rgb_splat[c].load(); let splat_val = pixel.rgb_splat[c].get();
rgb[c] += splat_val as Float / self.filter_integral; rgb[c] += splat_val as Float / self.filter_integral;
} }
} }
@ -359,7 +335,7 @@ pub struct SpectralPixel {
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Default)] #[derive(Debug)]
#[cfg_attr(target_os = "cuda", derive(Copy, Clone))] #[cfg_attr(target_os = "cuda", derive(Copy, Clone))]
pub struct SpectralFilm { pub struct SpectralFilm {
pub base: FilmBase, pub base: FilmBase,
@ -389,6 +365,21 @@ impl SpectralFilm {
fn uses_visible_surface(&self) -> bool { fn uses_visible_surface(&self) -> bool {
true true
} }
pub fn add_sample(
&mut self,
_p_film: Point2i,
_l: SampledSpectrum,
_lambda: &SampledWavelengths,
_visible_surface: Option<&VisibleSurface>,
_weight: Float,
) {
todo!()
}
pub fn add_splat(&mut self, _p: Point2f, _v: SampledSpectrum, _lambda: &SampledWavelengths) {
todo!()
}
} }
#[repr(C)] #[repr(C)]
@ -402,102 +393,6 @@ pub struct PixelSensor {
} }
impl PixelSensor { impl PixelSensor {
const N_SWATCH_REFLECTANCES: usize = 24;
#[cfg(not(target_os = "cuda"))]
pub fn new(
r: Spectrum,
g: Spectrum,
b: Spectrum,
output_colorspace: RGBColorSpace,
sensor_illum: &Spectrum,
imaging_ratio: Float,
spectra: *const StandardSpectra,
swatches: &[Spectrum; 24],
) -> Self {
// As seen in usages of this constructos, sensor_illum can be null
// Going with the colorspace's own illuminant, but this might not be the right choice
// TODO: Test this
let illum: &Spectrum = match sensor_illum {
Some(arc_illum) => &**arc_illum,
None => &output_colorspace.illuminant,
};
let r_bar = DenselySampledSpectrum::from_spectrum(&r);
let g_bar = DenselySampledSpectrum::from_spectrum(&g);
let b_bar = DenselySampledSpectrum::from_spectrum(&b);
let mut rgb_camera = [[0.; 3]; Self::N_SWATCH_REFLECTANCES];
let swatches = Self::get_swatches();
for i in 0..Self::N_SWATCH_REFLECTANCES {
let rgb = Self::project_reflectance::<RGB>(
&swatches[i],
illum,
&Spectrum::DenselySampled(r_bar.clone()),
&Spectrum::DenselySampled(g_bar.clone()),
&Spectrum::DenselySampled(b_bar.clone()),
);
for c in 0..3 {
rgb_camera[i][c] = rgb[c];
}
}
let mut xyz_output = [[0.; 3]; Self::N_SWATCH_REFLECTANCES];
let sensor_white_g = illum.inner_product(&Spectrum::DenselySampled(g_bar.clone()));
let sensor_white_y = illum.inner_product(spectra.y);
for i in 0..Self::N_SWATCH_REFLECTANCES {
let s = swatches[i].clone();
let xyz = Self::project_reflectance::<XYZ>(
&s,
&output_colorspace.illuminant,
spectra.x,
spectra.y,
spectra.z,
) * (sensor_white_y / sensor_white_g);
for c in 0..3 {
xyz_output[i][c] = xyz[c];
}
}
let xyz_from_sensor_rgb = linear_least_squares(rgb_camera, xyz_output)?;
Ok(Self {
xyz_from_sensor_rgb,
r_bar,
g_bar,
b_bar,
imaging_ratio,
})
}
pub fn new_with_white_balance(
output_colorspace: &RGBColorSpace,
sensor_illum: DevicePtr<Spectrum>,
imaging_ratio: Float,
spectra: *const StandardSpectra,
) -> Self {
let r_bar = DenselySampledSpectrum::from_spectrum(spectra.x);
let g_bar = DenselySampledSpectrum::from_spectrum(spectra.y);
let b_bar = DenselySampledSpectrum::from_spectrum(spectra.z);
let xyz_from_sensor_rgb: SquareMatrix<Float, 3>;
if let Some(illum) = sensor_illum {
let source_white = illum.to_xyz(spectra).xy();
let target_white = output_colorspace.w;
xyz_from_sensor_rgb = white_balance(source_white, target_white);
} else {
xyz_from_sensor_rgb = SquareMatrix::<Float, 3>::default();
}
Self {
xyz_from_sensor_rgb,
r_bar,
g_bar,
b_bar,
imaging_ratio,
}
}
pub fn project_reflectance<T>( pub fn project_reflectance<T>(
refl: &Spectrum, refl: &Spectrum,
illum: &Spectrum, illum: &Spectrum,
@ -529,7 +424,7 @@ impl PixelSensor {
result[2] *= inv_g; result[2] *= inv_g;
} }
T::from((result[0], result[1], result[2])) T::from([result[0], result[1], result[2]])
} }
} }
@ -609,7 +504,7 @@ impl Film {
} }
pub fn add_sample( pub fn add_sample(
&self, &mut self,
p_film: Point2i, p_film: Point2i,
l: SampledSpectrum, l: SampledSpectrum,
lambda: &SampledWavelengths, lambda: &SampledWavelengths,

View file

@ -20,33 +20,6 @@ pub struct FilterSampler {
} }
impl FilterSampler { impl FilterSampler {
#[cfg(not(target_os = "cuda"))]
pub fn new<F>(radius: Vector2f, func: F) -> Self
where
F: Fn(Point2f) -> Float,
{
let domain = Bounds2f::from_points(
Point2f::new(-radius.x(), -radius.y()),
Point2f::new(radius.x(), radius.y()),
);
let nx = (32.0 * radius.x()) as usize;
let ny = (32.0 * radius.y()) as usize;
let mut f = Array2D::new_with_dims(nx, ny);
for y in 0..f.y_size() {
for x in 0..f.x_size() {
let p = domain.lerp(Point2f::new(
(x as Float + 0.5) / f.x_size() as Float,
(y as Float + 0.5) / f.y_size() as Float,
));
f[(x as i32, y as i32)] = func(p);
}
}
let distrib = DevicePiecewiseConstant2D::new_with_bounds(&f, domain);
Self { domain, f, distrib }
}
pub fn sample(&self, u: Point2f) -> FilterSample { pub fn sample(&self, u: Point2f) -> FilterSample {
let (p, pdf, pi) = self.distrib.sample(u); let (p, pdf, pi) = self.distrib.sample(u);
@ -54,7 +27,8 @@ impl FilterSampler {
return FilterSample { p, weight: 0.0 }; return FilterSample { p, weight: 0.0 };
} }
let weight = *self.f.get_linear(pi.x() as u32 + self.f.x_size()) / pdf; let idx = pi.x() as u32 + self.f.x_size();
let weight = *self.f.get_linear(idx as usize) / pdf;
FilterSample { p, weight } FilterSample { p, weight }
} }
} }

View file

@ -2,7 +2,7 @@ use super::{Normal3f, Point3f, Point3fi, Vector3f, VectorLike};
use crate::core::medium::Medium; use crate::core::medium::Medium;
use crate::core::pbrt::Float; use crate::core::pbrt::Float;
use crate::utils::math::{next_float_down, next_float_up}; use crate::utils::math::{next_float_down, next_float_up};
use crate::utils::ptr::DevicePtr; use crate::utils::ptr::Ptr;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -10,7 +10,7 @@ pub struct Ray {
pub o: Point3f, pub o: Point3f,
pub d: Vector3f, pub d: Vector3f,
pub time: Float, pub time: Float,
pub medium: DevicePtr<Medium>, pub medium: Ptr<Medium>,
// We do this instead of creating a trait for Rayable or some gnarly thing like that // We do this instead of creating a trait for Rayable or some gnarly thing like that
pub has_differentials: bool, pub has_differentials: bool,
pub differential: RayDifferential, pub differential: RayDifferential,
@ -21,7 +21,7 @@ impl Default for Ray {
Self { Self {
o: Point3f::new(0.0, 0.0, 0.0), o: Point3f::new(0.0, 0.0, 0.0),
d: Vector3f::new(0.0, 0.0, 0.0), d: Vector3f::new(0.0, 0.0, 0.0),
medium: DevicePtr::null(), medium: Ptr::null(),
time: 0.0, time: 0.0,
has_differentials: false, has_differentials: false,
differential: RayDifferential::default(), differential: RayDifferential::default(),
@ -35,7 +35,7 @@ impl Ray {
o, o,
d, d,
time: time.unwrap_or_else(|| Self::default().time), time: time.unwrap_or_else(|| Self::default().time),
medium: DevicePtr::from(medium), medium: Ptr::from(medium),
..Self::default() ..Self::default()
} }
} }
@ -71,7 +71,7 @@ impl Ray {
o: origin, o: origin,
d, d,
time, time,
medium: DevicePtr::null(), medium: Ptr::null(),
has_differentials: false, has_differentials: false,
differential: RayDifferential::default(), differential: RayDifferential::default(),
} }
@ -99,7 +99,7 @@ impl Ray {
o: pf, o: pf,
d, d,
time, time,
medium: DevicePtr::null(), medium: Ptr::null(),
has_differentials: false, has_differentials: false,
differential: RayDifferential::default(), differential: RayDifferential::default(),
} }

View file

@ -35,6 +35,16 @@ pub enum PixelFormat {
F32, F32,
} }
impl std::fmt::Display for PixelFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PixelFormat::U8 => write!(f, "U256"),
PixelFormat::F16 => write!(f, "Half"),
PixelFormat::F32 => write!(f, "Float"),
}
}
}
impl PixelFormat { impl PixelFormat {
pub fn is_8bit(&self) -> bool { pub fn is_8bit(&self) -> bool {
matches!(self, PixelFormat::U8) matches!(self, PixelFormat::U8)

View file

@ -1,6 +1,8 @@
use crate::Float; use crate::Float;
use crate::bxdfs::DiffuseBxDF;
use crate::core::bsdf::BSDF;
use crate::core::bssrdf::BSSRDF; use crate::core::bssrdf::BSSRDF;
use crate::core::bxdf::{BSDF, BxDF, BxDFFlags, DiffuseBxDF}; use crate::core::bxdf::{BxDF, BxDFFlags};
use crate::core::camera::{Camera, CameraTrait}; use crate::core::camera::{Camera, CameraTrait};
use crate::core::geometry::{ use crate::core::geometry::{
Normal3f, Point2f, Point3f, Point3fi, Ray, RayDifferential, Vector3f, VectorLike, Normal3f, Point2f, Point3f, Point3fi, Ray, RayDifferential, Vector3f, VectorLike,
@ -250,8 +252,8 @@ impl SurfaceInteraction {
} }
pub fn compute_differentials(&mut self, r: &Ray, camera: &Camera, samples_per_pixel: i32) { pub fn compute_differentials(&mut self, r: &Ray, camera: &Camera, samples_per_pixel: i32) {
let computed = if !r.differential.is_null() { let computed = if !r.has_differentials {
let diff = unsafe { &*r.differential }; let diff = r.differential;
let dot_rx = self.common.n.dot(diff.rx_direction.into()); let dot_rx = self.common.n.dot(diff.rx_direction.into());
let dot_ry = self.common.n.dot(diff.ry_direction.into()); let dot_ry = self.common.n.dot(diff.ry_direction.into());
@ -338,8 +340,8 @@ impl SurfaceInteraction {
let new_ray = Ray::spawn(&self.pi(), &self.n(), ray.time, ray.d); let new_ray = Ray::spawn(&self.pi(), &self.n(), ray.time, ray.d);
ray.o = new_ray.o; ray.o = new_ray.o;
// Skipping other variables, since they should not change when passing through surface // Skipping other variables, since they should not change when passing through surface
if !ray.differential.is_null() { if !ray.has_differentials {
let diff = unsafe { &mut *ray.differential }; let mut diff = ray.differential;
diff.rx_origin += diff.rx_direction * t; diff.rx_origin += diff.rx_direction * t;
diff.ry_origin += diff.ry_direction * t; diff.ry_origin += diff.ry_direction * t;
} }
@ -357,12 +359,12 @@ impl SurfaceInteraction {
let material = { let material = {
let root_mat = self.material; let root_mat = self.material;
let mut active_mat: &Material = *root_mat; let mut active_mat: &Material = &*root_mat;
let tex_eval = UniversalTextureEvaluator; let tex_eval = UniversalTextureEvaluator;
while let Material::Mix(mix) = active_mat { while let Material::Mix(mix) = active_mat {
// We need a context to evaluate the 'amount' texture // We need a context to evaluate the 'amount' texture
let ctx = MaterialEvalContext::from(&*self); let ctx = MaterialEvalContext::from(&*self);
active_mat = mix.choose_material(&tex_eval, &ctx); active_mat = mix.choose_material(&tex_eval, &ctx)?;
} }
active_mat.clone() active_mat.clone()
}; };
@ -370,8 +372,8 @@ impl SurfaceInteraction {
let ctx = MaterialEvalContext::from(&*self); let ctx = MaterialEvalContext::from(&*self);
let tex_eval = UniversalTextureEvaluator; let tex_eval = UniversalTextureEvaluator;
let displacement = material.get_displacement(); let displacement = material.get_displacement();
let normal_map = material.get_normal_map(); let normal_map = Ptr::from(material.get_normal_map().unwrap());
if displacement.is_some() || normal_map.is_some() { if !displacement.is_null() || !normal_map.is_null() {
// This calls the function defined above // This calls the function defined above
self.compute_bump_geom(&tex_eval, displacement, normal_map); self.compute_bump_geom(&tex_eval, displacement, normal_map);
} }
@ -380,7 +382,7 @@ impl SurfaceInteraction {
if get_options().force_diffuse { if get_options().force_diffuse {
let r = bsdf.rho_wo(self.common.wo, &[sampler.get1d()], &[sampler.get2d()]); let r = bsdf.rho_wo(self.common.wo, &[sampler.get1d()], &[sampler.get2d()]);
let diff_bxdf = BxDF::Diffuse(DiffuseBxDF::new(r)); let diff_bxdf = BxDF::Diffuse(DiffuseBxDF::new(r));
bsdf = BSDF::new(self.shading.n, self.shading.dpdu, Some(diff_bxdf)); bsdf = BSDF::new(self.shading.n, self.shading.dpdu, Ptr::from(&diff_bxdf));
} }
Some(bsdf) Some(bsdf)
} }
@ -393,13 +395,12 @@ impl SurfaceInteraction {
_camera: &Camera, _camera: &Camera,
) -> Option<BSSRDF> { ) -> Option<BSSRDF> {
let material = { let material = {
let root_mat = self.material.as_deref()?; let mut active_mat = unsafe { self.material.as_ref() };
let mut active_mat: &Material = root_mat;
let tex_eval = UniversalTextureEvaluator; let tex_eval = UniversalTextureEvaluator;
while let Material::Mix(mix) = active_mat { while let Material::Mix(mix) = active_mat {
// We need a context to evaluate the 'amount' texture // We need a context to evaluate the 'amount' texture
let ctx = MaterialEvalContext::from(self); let ctx = MaterialEvalContext::from(self);
active_mat = mix.choose_material(&tex_eval, &ctx); active_mat = mix.choose_material(&tex_eval, &ctx)?;
} }
active_mat.clone() active_mat.clone()
}; };
@ -418,8 +419,9 @@ impl SurfaceInteraction {
let ctx = NormalBumpEvalContext::from(&*self); let ctx = NormalBumpEvalContext::from(&*self);
let (dpdu, dpdv) = if !displacement.is_null() { let (dpdu, dpdv) = if !displacement.is_null() {
bump_map(tex_eval, &displacement, &ctx) bump_map(tex_eval, &displacement, &ctx)
} else if let Some(map) = normal_image { } else if !normal_image.is_null() {
normal_map(map.as_ref(), &ctx) let map = unsafe { normal_image.as_ref() };
normal_map(map, &ctx)
} else { } else {
(self.shading.dpdu, self.shading.dpdv) (self.shading.dpdu, self.shading.dpdv)
}; };
@ -441,7 +443,8 @@ impl SurfaceInteraction {
) -> Ray { ) -> Ray {
let mut rd = self.spawn_ray(wi); let mut rd = self.spawn_ray(wi);
if let Some(diff_i) = &ray_i.differential { if ray_i.has_differentials {
let diff_i = ray_i.differential;
let mut n = self.shading.n; let mut n = self.shading.n;
let mut dndx = self.shading.dndu * self.dudx + self.shading.dndv * self.dvdx; let mut dndx = self.shading.dndu * self.dudx + self.shading.dndv * self.dvdx;

View file

@ -17,7 +17,6 @@ use crate::spectra::{
}; };
use crate::utils::Transform; use crate::utils::Transform;
use crate::utils::math::{equal_area_sphere_to_square, radians, safe_sqrt, smooth_step, square}; use crate::utils::math::{equal_area_sphere_to_square, radians, safe_sqrt, smooth_step, square};
use crate::utils::ptr::{DevicePtr, Ptr};
use crate::utils::sampling::DevicePiecewiseConstant2D; use crate::utils::sampling::DevicePiecewiseConstant2D;
use crate::{Float, PI}; use crate::{Float, PI};
use bitflags::bitflags; use bitflags::bitflags;

View file

@ -19,7 +19,7 @@ use crate::core::texture::{
}; };
use crate::materials::*; use crate::materials::*;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::DevicePtr; use crate::utils::Ptr;
use crate::utils::hash::hash_float; use crate::utils::hash::hash_float;
use crate::utils::math::clamp; use crate::utils::math::clamp;
@ -125,7 +125,7 @@ pub fn bump_map<T: TextureEvaluator>(
displacement: &GPUFloatTexture, displacement: &GPUFloatTexture,
ctx: &NormalBumpEvalContext, ctx: &NormalBumpEvalContext,
) -> (Vector3f, Vector3f) { ) -> (Vector3f, Vector3f) {
debug_assert!(tex_eval.can_evaluate(&[DevicePtr::from(displacement)], &[])); debug_assert!(tex_eval.can_evaluate(&[Ptr::from(displacement)], &[]));
let mut du = 0.5 * (ctx.dudx.abs() + ctx.dudy.abs()); let mut du = 0.5 * (ctx.dudx.abs() + ctx.dudy.abs());
if du == 0.0 { if du == 0.0 {
du = 0.0005; du = 0.0005;
@ -174,7 +174,7 @@ pub trait MaterialTrait {
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool; fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool;
fn get_normal_map(&self) -> Option<&DeviceImage>; fn get_normal_map(&self) -> Option<&DeviceImage>;
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture>; fn get_displacement(&self) -> Ptr<GPUFloatTexture>;
fn has_subsurface_scattering(&self) -> bool; fn has_subsurface_scattering(&self) -> bool;
} }

View file

@ -12,7 +12,7 @@ use crate::spectra::{
}; };
use crate::utils::containers::SampledGrid; use crate::utils::containers::SampledGrid;
use crate::utils::math::{clamp, square}; use crate::utils::math::{clamp, square};
use crate::utils::ptr::DevicePtr; use crate::utils::ptr::Ptr;
use crate::utils::rng::Rng; use crate::utils::rng::Rng;
use crate::utils::transform::Transform; use crate::utils::transform::Transform;
@ -94,22 +94,26 @@ impl PhaseFunctionTrait for HGPhaseFunction {
pub struct MajorantGrid { pub struct MajorantGrid {
pub bounds: Bounds3f, pub bounds: Bounds3f,
pub res: Point3i, pub res: Point3i,
pub voxels: *const Float, pub voxels: *mut Float,
pub n_voxels: u32,
} }
unsafe impl Send for MajorantGrid {} unsafe impl Send for MajorantGrid {}
unsafe impl Sync for MajorantGrid {} unsafe impl Sync for MajorantGrid {}
impl MajorantGrid { impl MajorantGrid {
#[cfg(not(target_os = "cuda"))] // #[cfg(not(target_os = "cuda"))]
pub fn new(bounds: Bounds3f, res: Point3i) -> Self { // pub fn new(bounds: Bounds3f, res: Point3i) -> Self {
Self { // let n_voxels = (res.x() * res.y() * res.z()) as usize;
bounds, // let voxels = Vec::with_capacity(n_voxels);
res, // Self {
voxels: Vec::with_capacity((res.x() * res.y() * res.z()) as usize), // bounds,
} // res,
} // voxels: voxels.as_ptr(),
// n_voxels: n_voxels as u32,
// }
// }
//
#[inline(always)] #[inline(always)]
fn is_valid(&self) -> bool { fn is_valid(&self) -> bool {
!self.voxels.is_null() !self.voxels.is_null()
@ -123,7 +127,7 @@ impl MajorantGrid {
let idx = z * self.res.x() * self.res.y() + y * self.res.x() + x; let idx = z * self.res.x() * self.res.y() + y * self.res.x() + x;
if idx >= 0 && (idx as usize) < self.voxels.len() { if idx >= 0 && (idx as u32) < self.n_voxels {
unsafe { *self.voxels.add(idx as usize) } unsafe { *self.voxels.add(idx as usize) }
} else { } else {
0.0 0.0
@ -131,7 +135,7 @@ impl MajorantGrid {
} }
#[inline(always)] #[inline(always)]
pub fn set(&self, x: i32, y: i32, z: i32, v: Float) { pub fn set(&mut self, x: i32, y: i32, z: i32, v: Float) {
if !self.is_valid() { if !self.is_valid() {
return; return;
} }
@ -264,7 +268,7 @@ impl DDAMajorantIterator {
let p_grid_start = grid.bounds.offset(&ray.at(t_min)); let p_grid_start = grid.bounds.offset(&ray.at(t_min));
let grid_intersect = Vector3f::from(p_grid_start); let grid_intersect = Vector3f::from(p_grid_start);
let res = [grid.res.x, grid.res.y, grid.res.z]; let res = [grid.res.x(), grid.res.y(), grid.res.z()];
for axis in 0..3 { for axis in 0..3 {
iter.voxel[axis] = clamp( iter.voxel[axis] = clamp(
@ -449,36 +453,10 @@ pub enum Medium {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct HomogeneousMedium { pub struct HomogeneousMedium {
sigma_a_spec: DenselySampledSpectrum, pub sigma_a_spec: DenselySampledSpectrum,
sigma_s_spec: DenselySampledSpectrum, pub sigma_s_spec: DenselySampledSpectrum,
le_spec: DenselySampledSpectrum, pub le_spec: DenselySampledSpectrum,
phase: HGPhaseFunction, pub phase: HGPhaseFunction,
}
impl HomogeneousMedium {
pub fn new(
sigma_a: Spectrum,
sigma_s: Spectrum,
sigma_scale: Float,
le: Spectrum,
le_scale: Float,
g: Float,
) -> Self {
let mut sigma_a_spec = DenselySampledSpectrum::from_spectrum(&sigma_a);
let mut sigma_s_spec = DenselySampledSpectrum::from_spectrum(&sigma_s);
let mut le_spec = DenselySampledSpectrum::from_spectrum(&le);
sigma_a_spec.scale(sigma_scale);
sigma_s_spec.scale(sigma_scale);
le_spec.scale(le_scale);
Self {
sigma_a_spec,
sigma_s_spec,
le_spec,
phase: HGPhaseFunction::new(g),
}
}
} }
impl MediumTrait for HomogeneousMedium { impl MediumTrait for HomogeneousMedium {
@ -517,70 +495,17 @@ impl MediumTrait for HomogeneousMedium {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct GridMedium { pub struct GridMedium {
bounds: Bounds3f, pub bounds: Bounds3f,
render_from_medium: Transform, pub render_from_medium: Transform,
sigma_a_spec: DenselySampledSpectrum, pub sigma_a_spec: DenselySampledSpectrum,
sigma_s_spec: DenselySampledSpectrum, pub sigma_s_spec: DenselySampledSpectrum,
density_grid: SampledGrid<Float>, pub density_grid: SampledGrid<Float>,
phase: HGPhaseFunction, pub phase: HGPhaseFunction,
temperature_grid: SampledGrid<Float>, pub temperature_grid: SampledGrid<Float>,
le_spec: DenselySampledSpectrum, pub le_spec: DenselySampledSpectrum,
le_scale: SampledGrid<Float>, pub le_scale: SampledGrid<Float>,
is_emissive: bool, pub is_emissive: bool,
majorant_grid: MajorantGrid, pub majorant_grid: MajorantGrid,
}
impl GridMedium {
#[allow(clippy::too_many_arguments)]
#[cfg(not(target_os = "cuda"))]
pub fn new(
bounds: &Bounds3f,
render_from_medium: &Transform,
sigma_a: &Spectrum,
sigma_s: &Spectrum,
sigma_scale: Float,
g: Float,
density_grid: SampledGrid<Float>,
temperature_grid: SampledGrid<Float>,
le: &Spectrum,
le_scale: SampledGrid<Float>,
) -> Self {
let mut sigma_a_spec = DenselySampledSpectrum::from_spectrum(sigma_a);
let mut sigma_s_spec = DenselySampledSpectrum::from_spectrum(sigma_s);
let le_spec = DenselySampledSpectrum::from_spectrum(le);
sigma_a_spec.scale(sigma_scale);
sigma_s_spec.scale(sigma_scale);
let mut majorant_grid = MajorantGrid::new(*bounds, Point3i::new(16, 16, 16));
let is_emissive = if temperature_grid.is_some() {
true
} else {
le_spec.max_value() > 0.
};
for z in 0..majorant_grid.res.z() {
for y in 0..majorant_grid.res.y() {
for x in 0..majorant_grid.res.x() {
let bounds = majorant_grid.voxel_bounds(x, y, z);
majorant_grid.set(x, y, z, density_grid.max_value(bounds));
}
}
}
Self {
bounds: *bounds,
render_from_medium: *render_from_medium,
sigma_a_spec,
sigma_s_spec,
density_grid,
phase: HGPhaseFunction::new(g),
temperature_grid,
le_spec,
le_scale,
is_emissive,
majorant_grid,
}
}
} }
impl MediumTrait for GridMedium { impl MediumTrait for GridMedium {
@ -603,12 +528,11 @@ impl MediumTrait for GridMedium {
}; };
let le = if scale > 0.0 { let le = if scale > 0.0 {
let raw_emission = match &self.temperature_grid { let raw_emission = if self.temperature_grid.is_valid() {
Some(grid) => { let temp = self.temperature_grid.lookup(p);
let temp = grid.lookup(p);
BlackbodySpectrum::new(temp).sample(lambda) BlackbodySpectrum::new(temp).sample(lambda)
} } else {
None => self.le_spec.sample(lambda), self.le_spec.sample(lambda)
}; };
raw_emission * scale raw_emission * scale
@ -664,59 +588,15 @@ impl MediumTrait for GridMedium {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct RGBGridMedium { pub struct RGBGridMedium {
bounds: Bounds3f, pub bounds: Bounds3f,
render_from_medium: Transform, pub render_from_medium: Transform,
phase: HGPhaseFunction, pub phase: HGPhaseFunction,
le_scale: Float, pub le_scale: Float,
sigma_scale: Float, pub sigma_scale: Float,
sigma_a_grid: SampledGrid<RGBUnboundedSpectrum>, pub sigma_a_grid: SampledGrid<RGBUnboundedSpectrum>,
sigma_s_grid: SampledGrid<RGBUnboundedSpectrum>, pub sigma_s_grid: SampledGrid<RGBUnboundedSpectrum>,
le_grid: SampledGrid<RGBIlluminantSpectrum>, pub le_grid: SampledGrid<RGBIlluminantSpectrum>,
majorant_grid: MajorantGrid, pub majorant_grid: MajorantGrid,
}
impl RGBGridMedium {
#[allow(clippy::too_many_arguments)]
#[cfg(not(target_os = "cuda"))]
pub fn new(
bounds: &Bounds3f,
render_from_medium: &Transform,
g: Float,
sigma_a_grid: SampledGrid<RGBUnboundedSpectrum>,
sigma_s_grid: SampledGrid<RGBUnboundedSpectrum>,
sigma_scale: Float,
le_grid: SampledGrid<RGBIlluminantSpectrum>,
le_scale: Float,
) -> Self {
let mut majorant_grid = MajorantGrid::new(*bounds, Point3i::new(16, 16, 16));
for z in 0..majorant_grid.res.x() {
for y in 0..majorant_grid.res.y() {
for x in 0..majorant_grid.res.x() {
let bounds = majorant_grid.voxel_bounds(x, y, z);
let convert = |s: &RGBUnboundedSpectrum| s.max_value();
let max_sigma_t = sigma_a_grid
.as_ref()
.map_or(1.0, |g| g.max_value_convert(bounds, convert))
+ sigma_s_grid
.as_ref()
.map_or(1.0, |g| g.max_value_convert(bounds, convert));
majorant_grid.set(x, y, z, sigma_scale * max_sigma_t);
}
}
}
Self {
bounds: *bounds,
render_from_medium: *render_from_medium,
le_grid,
le_scale,
phase: HGPhaseFunction::new(g),
sigma_a_grid,
sigma_s_grid,
sigma_scale,
majorant_grid,
}
}
} }
impl MediumTrait for RGBGridMedium { impl MediumTrait for RGBGridMedium {
@ -789,7 +669,8 @@ impl MediumTrait for RGBGridMedium {
} }
} }
#[derive(Debug, Clone)] #[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct CloudMedium; pub struct CloudMedium;
impl MediumTrait for CloudMedium { impl MediumTrait for CloudMedium {
fn is_emissive(&self) -> bool { fn is_emissive(&self) -> bool {
@ -807,7 +688,9 @@ impl MediumTrait for CloudMedium {
todo!() todo!()
} }
} }
#[derive(Debug, Clone)]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct NanoVDBMedium; pub struct NanoVDBMedium;
impl MediumTrait for NanoVDBMedium { impl MediumTrait for NanoVDBMedium {
fn is_emissive(&self) -> bool { fn is_emissive(&self) -> bool {
@ -829,8 +712,8 @@ impl MediumTrait for NanoVDBMedium {
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct MediumInterface { pub struct MediumInterface {
pub inside: DevicePtr<Medium>, pub inside: Ptr<Medium>,
pub outside: DevicePtr<Medium>, pub outside: Ptr<Medium>,
} }
unsafe impl Send for MediumInterface {} unsafe impl Send for MediumInterface {}
@ -839,8 +722,8 @@ unsafe impl Sync for MediumInterface {}
impl Default for MediumInterface { impl Default for MediumInterface {
fn default() -> Self { fn default() -> Self {
Self { Self {
inside: DevicePtr::null(), inside: Ptr::null(),
outside: DevicePtr::null(), outside: Ptr::null(),
} }
} }
} }
@ -848,8 +731,8 @@ impl Default for MediumInterface {
impl From<Medium> for MediumInterface { impl From<Medium> for MediumInterface {
fn from(medium: Medium) -> Self { fn from(medium: Medium) -> Self {
Self { Self {
inside: DevicePtr::from(&medium), inside: Ptr::from(&medium),
outside: DevicePtr::from(&medium), outside: Ptr::from(&medium),
} }
} }
} }
@ -863,8 +746,8 @@ impl From<&Medium> for MediumInterface {
impl MediumInterface { impl MediumInterface {
pub fn new(inside: &Medium, outside: &Medium) -> Self { pub fn new(inside: &Medium, outside: &Medium) -> Self {
Self { Self {
inside: DevicePtr::from(inside), inside: Ptr::from(inside),
outside: DevicePtr::from(outside), outside: Ptr::from(outside),
} }
} }
@ -873,6 +756,6 @@ impl MediumInterface {
} }
pub fn is_medium_transition(&self) -> bool { pub fn is_medium_transition(&self) -> bool {
self.inside.0 != self.outside.0 self.inside != self.outside
} }
} }

View file

@ -1,4 +1,3 @@
use crate::core::aggregates::LinearBVHNode;
use crate::core::geometry::{Bounds3f, Ray}; use crate::core::geometry::{Bounds3f, Ray};
use crate::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction}; use crate::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction};
use crate::core::light::Light; use crate::core::light::Light;
@ -24,11 +23,11 @@ pub trait PrimitiveTrait {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct GeometricPrimitive { pub struct GeometricPrimitive {
shape: *const Shape, shape: Ptr<Shape>,
material: *const Material, material: Ptr<Material>,
area_light: *const Light, area_light: Ptr<Light>,
medium_interface: MediumInterface, medium_interface: MediumInterface,
alpha: *const GPUFloatTexture, alpha: Ptr<GPUFloatTexture>,
} }
unsafe impl Send for GeometricPrimitive {} unsafe impl Send for GeometricPrimitive {}
@ -41,7 +40,8 @@ impl PrimitiveTrait for GeometricPrimitive {
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> { fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
let mut si = self.shape.intersect(r, t_max)?; let mut si = self.shape.intersect(r, t_max)?;
if let Some(ref alpha) = self.alpha { if !self.alpha.is_null() {
let alpha = unsafe { &self.alpha.as_ref() };
let ctx = TextureEvalContext::from(&si.intr); let ctx = TextureEvalContext::from(&si.intr);
let a = alpha.evaluate(&ctx); let a = alpha.evaluate(&ctx);
if a < 1.0 { if a < 1.0 {
@ -66,18 +66,21 @@ impl PrimitiveTrait for GeometricPrimitive {
} }
} }
if r.medium.is_null() {
return None;
}
si.set_intersection_properties( si.set_intersection_properties(
self.material.clone(), self.material,
self.area_light.clone(), self.area_light,
Some(self.medium_interface.clone()), self.medium_interface.clone(),
Some(r.medium.clone().expect("Medium not set")), r.medium,
); );
Some(si) Some(si)
} }
fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool { fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool {
if self.alpha.is_some() { if !self.alpha.is_null() {
self.intersect(r, t_max).is_some() self.intersect(r, t_max).is_some()
} else { } else {
self.shape.intersect_p(r, t_max) self.shape.intersect_p(r, t_max)
@ -160,32 +163,38 @@ impl PrimitiveTrait for AnimatedPrimitive {
} }
} }
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct LinearBVHNode {
bounds: Bounds3f,
}
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct BVHAggregatePrimitive { pub struct BVHAggregatePrimitive {
max_prims_in_node: u32, max_prims_in_node: u32,
primitives: *const Ptr<Primitive>, primitives: *const Ptr<Primitive>,
nodes: *const LinearBVHNode, nodes: Ptr<LinearBVHNode>,
} }
impl PrimitiveTrait for BVHAggregatePrimitive { impl PrimitiveTrait for BVHAggregatePrimitive {
fn bounds(&self) -> Bounds3f { fn bounds(&self) -> Bounds3f {
if !self.nodes.is_empty() { if !self.nodes.is_null() {
self.nodes[0].bounds self.nodes.bounds
} else { } else {
Bounds3f::default() Bounds3f::default()
} }
} }
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> { fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
if self.nodes.is_empty() { if !self.nodes.is_null() {
return None; return None;
} }
self.intersect(r, t_max) self.intersect(r, t_max)
} }
fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool { fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool {
if self.nodes.is_empty() { if !self.nodes.is_null() {
return false; return false;
} }
self.intersect_p(r, t_max) self.intersect_p(r, t_max)

View file

@ -6,10 +6,9 @@ use crate::utils::Ptr;
use crate::utils::containers::Array2D; use crate::utils::containers::Array2D;
use crate::utils::math::{ use crate::utils::math::{
BinaryPermuteScrambler, DigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler, BinaryPermuteScrambler, DigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler,
PRIME_TABLE_SIZE, Scrambler, clamp, compute_radical_inverse_permutations, encode_morton_2, PRIME_TABLE_SIZE, Scrambler, clamp, encode_morton_2, inverse_radical_inverse, lerp, log2_int,
inverse_radical_inverse, lerp, log2_int, owen_scrambled_radical_inverse, permutation_element, owen_scrambled_radical_inverse, permutation_element, radical_inverse, round_up_pow2,
radical_inverse, round_up_pow2, scrambled_radical_inverse, sobol_interval_to_index, scrambled_radical_inverse, sobol_interval_to_index, sobol_sample,
sobol_sample,
}; };
use crate::utils::rng::Rng; use crate::utils::rng::Rng;
use crate::utils::sobol::N_SOBOL_DIMENSIONS; use crate::utils::sobol::N_SOBOL_DIMENSIONS;
@ -107,62 +106,59 @@ pub struct HaltonSampler {
} }
impl HaltonSampler { impl HaltonSampler {
pub fn new( // pub fn new(
samples_per_pixel: u32, // samples_per_pixel: u32,
full_res: Point2i, // full_res: Point2i,
randomize: RandomizeStrategy, // randomize: RandomizeStrategy,
seed: u64, // seed: u64,
) -> Self { // ) -> Self {
let digit_permutations = compute_radical_inverse_permutations(seed); // let digit_permutations = compute_radical_inverse_permutations(seed);
let mut base_scales = [0u64; 2]; // let mut base_scales = [0u64; 2];
let mut base_exponents = [0u64; 2]; // let mut base_exponents = [0u64; 2];
let bases = [2, 3]; // let bases = [2, 3];
let res_coords = [full_res.x(), full_res.y()]; // let res_coords = [full_res.x(), full_res.y()];
//
for i in 0..2 { // for i in 0..2 {
let base = bases[i] as u64; // let base = bases[i] as u64;
let mut scale = 1u64; // let mut scale = 1u64;
let mut exp = 0u64; // let mut exp = 0u64;
//
let limit = std::cmp::min(res_coords[i], MAX_HALTON_RESOLUTION) as u64; // let limit = std::cmp::min(res_coords[i], MAX_HALTON_RESOLUTION) as u64;
//
while scale < limit { // while scale < limit {
scale *= base; // scale *= base;
exp += 1; // exp += 1;
} // }
//
base_scales[i] = scale; // base_scales[i] = scale;
base_exponents[i] = exp; // base_exponents[i] = exp;
} // }
//
let mut mult_inverse = [0u64; 2]; // let mut mult_inverse = [0u64; 2];
//
mult_inverse[0] = // mult_inverse[0] =
Self::multiplicative_inverse(base_scales[0] as i64, base_scales[0] as i64); // Self::multiplicative_inverse(base_scales[0] as i64, base_scales[0] as i64);
mult_inverse[1] = // mult_inverse[1] =
Self::multiplicative_inverse(base_scales[1] as i64, base_scales[1] as i64); // Self::multiplicative_inverse(base_scales[1] as i64, base_scales[1] as i64);
//
Self { // Self {
samples_per_pixel, // samples_per_pixel,
randomize, // randomize,
digit_permutations, // digit_permutations,
base_scales, // base_scales,
base_exponents, // base_exponents,
mult_inverse, // mult_inverse,
halton_index: 0, // halton_index: 0,
dim: 0, // dim: 0,
} // }
} // }
fn sample_dimension(&self, dimension: u32) -> Float { fn sample_dimension(&self, dimension: u32) -> Float {
if self.randomize == RandomizeStrategy::None { if self.randomize == RandomizeStrategy::None {
radical_inverse(dimension, self.halton_index) radical_inverse(dimension, self.halton_index)
} else if self.randomize == RandomizeStrategy::PermuteDigits { } else if self.randomize == RandomizeStrategy::PermuteDigits {
scrambled_radical_inverse( let digit_perm = unsafe { &*self.digit_permutations.add(dimension as usize) };
dimension, scrambled_radical_inverse(dimension, self.halton_index, digit_perm)
self.halton_index,
&self.digit_permutations[dimension as usize],
)
} else { } else {
owen_scrambled_radical_inverse( owen_scrambled_radical_inverse(
dimension, dimension,
@ -418,13 +414,13 @@ impl SamplerTrait for PaddedSobolSampler {
self.dim as u64, self.dim as u64,
self.seed, self.seed,
]; ];
let hash = hash_buffer(&hash_input, 0) as u32; let hash = hash_buffer(&hash_input, 0);
let index = permutation_element( let index = permutation_element(
self.sample_index as u32, self.sample_index as u32,
self.samples_per_pixel as u32, self.samples_per_pixel as u32,
hash, hash as u32,
); );
self.sample_dimension(0, index, hash >> 32) self.sample_dimension(0, index, (hash >> 32) as u32)
} }
fn get2d(&mut self) -> Point2f { fn get2d(&mut self) -> Point2f {
let hash_input = [ let hash_input = [
@ -433,16 +429,16 @@ impl SamplerTrait for PaddedSobolSampler {
self.dim as u64, self.dim as u64,
self.seed, self.seed,
]; ];
let hash = hash_buffer(&hash_input, 0) as u32; let hash = hash_buffer(&hash_input, 0);
let index = permutation_element( let index = permutation_element(
self.sample_index as u32, self.sample_index as u32,
self.samples_per_pixel as u32, self.samples_per_pixel as u32,
hash, hash as u32,
); );
self.dim += 2; self.dim += 2;
Point2f::new( Point2f::new(
self.sample_dimension(0, index, hash), self.sample_dimension(0, index, hash as u32),
self.sample_dimension(1, index, hash >> 32), self.sample_dimension(1, index, (hash >> 32) as u32),
) )
} }
@ -630,7 +626,7 @@ impl ZSobolSampler {
let mix_input = higher_digits ^ (0x55555555 * self.dim as u64); let mix_input = higher_digits ^ (0x55555555 * self.dim as u64);
let p = (mix_bits(mix_input) >> 24) % 24; let p = (mix_bits(mix_input) >> 24) % 24;
digit = PERMUTATIONS[p as u32][digit as u32] as u64; digit = PERMUTATIONS[p as usize][digit as usize] as u64;
sample_index |= digit << digit_shift; sample_index |= digit << digit_shift;
} }

View file

@ -1,6 +1,6 @@
use crate::core::geometry::{ use crate::core::geometry::{
Bounds3f, DirectionCone, Normal3f, Point2f, Point3f, Point3fi, Ray, Vector2f, Vector3f, Bounds3f, DirectionCone, Normal3f, Point2f, Point3f, Point3fi, Ray, Vector2f, Vector3f,
Vector3fi, VectorLike, Vector3fi, VectorLike, ray,
}; };
use crate::core::interaction::{ use crate::core::interaction::{
Interaction, InteractionTrait, MediumInteraction, SurfaceInteraction, Interaction, InteractionTrait, MediumInteraction, SurfaceInteraction,
@ -10,7 +10,7 @@ use crate::core::material::Material;
use crate::core::medium::{Medium, MediumInterface}; use crate::core::medium::{Medium, MediumInterface};
use crate::shapes::*; use crate::shapes::*;
use crate::utils::math::{next_float_down, next_float_up}; use crate::utils::math::{next_float_down, next_float_up};
use crate::utils::{DevicePtr, Transform}; use crate::utils::{Ptr, Transform};
use crate::{Float, PI}; use crate::{Float, PI};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
@ -37,13 +37,13 @@ impl ShapeIntersection {
pub fn set_intersection_properties( pub fn set_intersection_properties(
&mut self, &mut self,
mtl: &Material, mtl: Ptr<Material>,
area: &Light, area: Ptr<Light>,
prim_medium_interface: MediumInterface, prim_medium_interface: MediumInterface,
ray_medium: &Medium, ray_medium: Ptr<Medium>,
) { ) {
self.intr self.intr
.set_intersection_properties(mtl, area, ray_medium, prim_medium_interface); .set_intersection_properties(&mtl, &area, &ray_medium, prim_medium_interface);
} }
} }
@ -118,12 +118,7 @@ impl ShapeSampleContext {
} }
pub fn spawn_ray(&self, w: Vector3f) -> Ray { pub fn spawn_ray(&self, w: Vector3f) -> Ray {
Ray::new( Ray::new(self.offset_ray_origin(w), w, Some(self.time), &Ptr::null())
self.offset_ray_origin(w),
w,
Some(self.time),
&DevicePtr::null(),
)
} }
} }

View file

@ -1,8 +1,9 @@
use crate::Float; use crate::Float;
use crate::core::color::{RGB, XYZ}; use crate::core::color::{RGB, XYZ};
use crate::spectra::*;
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
pub use crate::spectra::*;
#[enum_dispatch] #[enum_dispatch]
pub trait SpectrumTrait: Copy { pub trait SpectrumTrait: Copy {
fn evaluate(&self, lambda: Float) -> Float; fn evaluate(&self, lambda: Float) -> Float;

View file

@ -8,13 +8,15 @@ use crate::spectra::{
RGBAlbedoSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum, RGBAlbedoSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum,
SampledWavelengths, SampledWavelengths,
}; };
use crate::textures::*;
use crate::utils::DevicePtr; use crate::utils::Ptr;
use crate::utils::Transform; use crate::utils::Transform;
use crate::utils::math::square; use crate::utils::math::square;
use crate::{Float, INV_2_PI, INV_PI, PI}; use crate::{Float, INV_2_PI, INV_PI, PI};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
pub use crate::textures::*;
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, Copy)] #[derive(Clone, Debug, Copy)]
pub struct TexCoord2D { pub struct TexCoord2D {
@ -428,8 +430,8 @@ pub trait TextureEvaluator: Send + Sync {
fn can_evaluate( fn can_evaluate(
&self, &self,
_ftex: &[DevicePtr<GPUFloatTexture>], _ftex: &[Ptr<GPUFloatTexture>],
_stex: &[DevicePtr<GPUSpectrumTexture>], _stex: &[Ptr<GPUSpectrumTexture>],
) -> bool; ) -> bool;
} }
@ -453,8 +455,8 @@ impl TextureEvaluator for UniversalTextureEvaluator {
fn can_evaluate( fn can_evaluate(
&self, &self,
_float_textures: &[DevicePtr<GPUFloatTexture>], _float_textures: &[Ptr<GPUFloatTexture>],
_spectrum_textures: &[DevicePtr<GPUSpectrumTexture>], _spectrum_textures: &[Ptr<GPUSpectrumTexture>],
) -> bool { ) -> bool {
true true
} }

View file

@ -13,27 +13,6 @@ pub struct GaussianFilter {
pub sampler: FilterSampler, pub sampler: FilterSampler,
} }
impl GaussianFilter {
pub fn new(radius: Vector2f, sigma: Float) -> Self {
let exp_x = gaussian(radius.x(), 0., sigma);
let exp_y = gaussian(radius.y(), 0., sigma);
let sampler = FilterSampler::new(radius, move |p: Point2f| {
let gx = (gaussian(p.x(), 0., sigma) - exp_x).max(0.0);
let gy = (gaussian(p.y(), 0., sigma) - exp_y).max(0.0);
gx * gy
});
Self {
radius,
sigma,
exp_x: gaussian(radius.x(), 0., sigma),
exp_y: gaussian(radius.y(), 0., sigma),
sampler,
}
}
}
impl FilterTrait for GaussianFilter { impl FilterTrait for GaussianFilter {
fn radius(&self) -> Vector2f { fn radius(&self) -> Vector2f {
self.radius self.radius

View file

@ -12,20 +12,6 @@ pub struct LanczosSincFilter {
pub sampler: FilterSampler, pub sampler: FilterSampler,
} }
impl LanczosSincFilter {
pub fn new(radius: Vector2f, tau: Float) -> Self {
let sampler = FilterSampler::new(radius, move |p: Point2f| {
windowed_sinc(p.x(), radius.x(), tau) * windowed_sinc(p.y(), radius.y(), tau)
});
Self {
radius,
tau,
sampler,
}
}
}
impl FilterTrait for LanczosSincFilter { impl FilterTrait for LanczosSincFilter {
fn radius(&self) -> Vector2f { fn radius(&self) -> Vector2f {
self.radius self.radius

View file

@ -12,22 +12,7 @@ pub struct MitchellFilter {
} }
impl MitchellFilter { impl MitchellFilter {
pub fn new(radius: Vector2f, b: Float, c: Float) -> Self { pub fn mitchell_1d_eval(b: Float, c: Float, x: Float) -> Float {
let sampler = FilterSampler::new(radius, move |p: Point2f| {
let nx = 2.0 * p.x() / radius.x();
let ny = 2.0 * p.y() / radius.y();
Self::mitchell_1d_eval(b, c, nx) * Self::mitchell_1d_eval(b, c, ny)
});
Self {
radius,
b,
c,
sampler,
}
}
fn mitchell_1d_eval(b: Float, c: Float, x: Float) -> Float {
let x = x.abs(); let x = x.abs();
if x <= 1.0 { if x <= 1.0 {
((12.0 - 9.0 * b - 6.0 * c) * x.powi(3) ((12.0 - 9.0 * b - 6.0 * c) * x.powi(3)

View file

@ -125,10 +125,8 @@ impl LightTrait for DiffuseAreaLight {
rgb[c] = self.image.bilerp_channel(uv, c as i32); rgb[c] = self.image.bilerp_channel(uv, c as i32);
} }
let spec = RGBIlluminantSpectrum::new( let cs_ref = unsafe { self.colorspace.as_ref() };
self.image_color_space.as_ref().unwrap(), let spec = RGBIlluminantSpectrum::new(cs_ref, rgb.clamp_zero());
rgb.clamp_zero(),
);
self.scale * spec.sample(lambda) self.scale * spec.sample(lambda)
} else { } else {
@ -150,11 +148,9 @@ impl LightTrait for DiffuseAreaLight {
for c in 0..3 { for c in 0..3 {
rgb[c] = self.image.get_channel(Point2i::new(x, y), c as i32); rgb[c] = self.image.get_channel(Point2i::new(x, y), c as i32);
} }
l += RGBIlluminantSpectrum::new(
self.image_color_space.as_ref().unwrap(), let cs_ref = unsafe { self.colorspace.as_ref() };
rgb.clamp_zero(), l += RGBIlluminantSpectrum::new(cs_ref, rgb.clamp_zero()).sample(&lambda);
)
.sample(&lambda);
} }
} }
l *= self.scale / (self.image.resolution().x() * self.image.resolution().y()) as Float; l *= self.scale / (self.image.resolution().x() * self.image.resolution().y()) as Float;

View file

@ -214,8 +214,8 @@ impl LightTrait for ImageInfiniteLight {
#[cfg(not(target_os = "cuda"))] #[cfg(not(target_os = "cuda"))]
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum { fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
let mut sum_l = SampledSpectrum::new(0.); let mut sum_l = SampledSpectrum::new(0.);
let width = self.image.resolution.x(); let width = self.image.resolution().x();
let height = self.image.resolution.y(); let height = self.image.resolution().y();
for v in 0..height { for v in 0..height {
for u in 0..width { for u in 0..width {
let mut rgb = RGB::default(); let mut rgb = RGB::default();

View file

@ -3,7 +3,7 @@ use crate::core::color::RGB;
use crate::core::geometry::{ use crate::core::geometry::{
Bounds2f, Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f, VectorLike, cos_theta, Bounds2f, Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f, VectorLike, cos_theta,
}; };
use crate::core::image::DeviceImage; use crate::core::image::{DeviceImage, ImageAccess};
use crate::core::light::{ use crate::core::light::{
LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait, LightType, LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait, LightType,
}; };
@ -91,11 +91,12 @@ impl LightTrait for ProjectionLight {
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum { fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
let mut sum = SampledSpectrum::new(0.); let mut sum = SampledSpectrum::new(0.);
for y in 0..self.image.resolution.y() { let res = self.image.resolution();
for x in 0..self.image.resolution.x() { for y in 0..res.y() {
for x in 0..res.x() {
let ps = self.screen_bounds.lerp(Point2f::new( let ps = self.screen_bounds.lerp(Point2f::new(
(x as Float + 0.5) / self.image.resolution.x() as Float, (x as Float + 0.5) / res.x() as Float,
(y as Float + 0.5) / self.image.resolution.y() as Float, (y as Float + 0.5) / res.y() as Float,
)); ));
let w_raw = Vector3f::from(self.light_from_screen.apply_to_point(Point3f::new( let w_raw = Vector3f::from(self.light_from_screen.apply_to_point(Point3f::new(
ps.x(), ps.x(),
@ -113,7 +114,7 @@ impl LightTrait for ProjectionLight {
sum += s.sample(&lambda) * dwda; sum += s.sample(&lambda) * dwda;
} }
} }
self.scale * self.a * sum / (self.image.resolution.x() * self.image.resolution.y()) as Float self.scale * self.a * sum / (res.x() * res.y()) as Float
} }
fn preprocess(&mut self, _scene_bounds: &Bounds3f) { fn preprocess(&mut self, _scene_bounds: &Bounds3f) {

View file

@ -6,7 +6,7 @@ use crate::core::light::{LightBounds, LightSampleContext};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::math::{clamp, lerp, sample_discrete}; use crate::utils::math::{clamp, lerp, sample_discrete};
use crate::utils::math::{safe_sqrt, square}; use crate::utils::math::{safe_sqrt, square};
use crate::utils::ptr::{DevicePtr, Slice}; use crate::utils::ptr::Ptr;
use crate::utils::sampling::AliasTable; use crate::utils::sampling::AliasTable;
use crate::{Float, ONE_MINUS_EPSILON, PI}; use crate::{Float, ONE_MINUS_EPSILON, PI};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
@ -154,14 +154,14 @@ impl CompactLightBounds {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SampledLight { pub struct SampledLight {
pub light: DevicePtr<Light>, pub light: Ptr<Light>,
pub p: Float, pub p: Float,
} }
impl SampledLight { impl SampledLight {
pub fn new(light: Light, p: Float) -> Self { pub fn new(light: Light, p: Float) -> Self {
Self { Self {
light: DevicePtr::from(&light), light: Ptr::from(&light),
p, p,
} }
} }
@ -214,7 +214,7 @@ impl LightSamplerTrait for UniformLightSampler {
let light_index = (u as u32 * self.lights_len).min(self.lights_len - 1) as usize; let light_index = (u as u32 * self.lights_len).min(self.lights_len - 1) as usize;
Some(SampledLight { Some(SampledLight {
light: DevicePtr::from(&self.light(light_index)), light: Ptr::from(&self.light(light_index)),
p: 1. / self.lights_len as Float, p: 1. / self.lights_len as Float,
}) })
} }
@ -236,7 +236,7 @@ pub struct Alias {
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, Copy)] #[derive(Clone, Debug, Copy)]
pub struct PowerLightSampler { pub struct PowerLightSampler {
pub lights: Slice<Light>, pub lights: Ptr<Light>,
pub lights_len: u32, pub lights_len: u32,
pub alias_table: AliasTable, pub alias_table: AliasTable,
} }
@ -260,28 +260,24 @@ impl LightSamplerTrait for PowerLightSampler {
let (light_index, pmf, _) = self.alias_table.sample(u); let (light_index, pmf, _) = self.alias_table.sample(u);
let light_ref = &self.lights[light_index as usize]; let light_ref = unsafe { self.lights.add(light_index as usize) };
Some(SampledLight { Some(SampledLight {
light: DevicePtr::from(light_ref), light: light_ref,
p: pmf, p: pmf,
}) })
} }
fn pmf(&self, light: &Light) -> Float { fn pmf(&self, light: &Light) -> Float {
if self.lights_len == 0 { let array_start = self.lights.as_raw();
return 0.0; let target = light as *const Light as *mut Light;
}
let light_ptr = light as *const Light; unsafe {
let start = self.lights.as_ptr(); let index = target.offset_from(array_start);
let end = unsafe { start.add(self.lights.len as usize) }; if index >= 0 && index < self.lights_len as isize {
if light_ptr >= start && light_ptr < end {
let index = unsafe { light_ptr.offset_from(start) };
return self.alias_table.pmf(index as u32); return self.alias_table.pmf(index as u32);
} }
}
0. 0.
} }
} }

View file

@ -25,38 +25,37 @@ pub struct CoatedDiffuseMaterial {
pub thickness: Ptr<GPUFloatTexture>, pub thickness: Ptr<GPUFloatTexture>,
pub g: Ptr<GPUFloatTexture>, pub g: Ptr<GPUFloatTexture>,
pub eta: Ptr<Spectrum>, pub eta: Ptr<Spectrum>,
pub max_depth: u32,
pub n_samples: u32,
pub remap_roughness: bool, pub remap_roughness: bool,
pub max_depth: usize,
pub n_samples: usize,
} }
impl CoatedDiffuseMaterial { impl CoatedDiffuseMaterial {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[cfg(not(target_os = "cuda"))]
pub fn new( pub fn new(
reflectance: &GPUSpectrumTexture, reflectance: Ptr<GPUSpectrumTexture>,
u_roughness: &GPUFloatTexture, u_roughness: Ptr<GPUFloatTexture>,
v_roughness: &GPUFloatTexture, v_roughness: Ptr<GPUFloatTexture>,
thickness: &GPUFloatTexture, thickness: Ptr<GPUFloatTexture>,
albedo: &GPUSpectrumTexture, albedo: Ptr<GPUSpectrumTexture>,
g: &GPUFloatTexture, g: Ptr<GPUFloatTexture>,
eta: &Spectrum, eta: Ptr<Spectrum>,
displacement: &GPUFloatTexture, displacement: Ptr<GPUFloatTexture>,
normal_map: &DeviceImage, normal_map: Ptr<DeviceImage>,
remap_roughness: bool, remap_roughness: bool,
max_depth: usize, max_depth: u32,
n_samples: usize, n_samples: u32,
) -> Self { ) -> Self {
Self { Self {
displacement: Ptr::from(displacement), displacement,
normal_map: Ptr::from(normal_map), normal_map,
reflectance: Ptr::from(reflectance), reflectance,
albedo: Ptr::from(albedo), albedo,
u_roughness: Ptr::from(u_roughness), u_roughness,
v_roughness: Ptr::from(v_roughness), v_roughness,
thickness: Ptr::from(thickness), thickness,
g: Ptr::from(g), g,
eta: Ptr::from(eta), eta,
remap_roughness, remap_roughness,
max_depth, max_depth,
n_samples, n_samples,
@ -163,46 +162,45 @@ pub struct CoatedConductorMaterial {
conductor_eta: Ptr<GPUSpectrumTexture>, conductor_eta: Ptr<GPUSpectrumTexture>,
k: Ptr<GPUSpectrumTexture>, k: Ptr<GPUSpectrumTexture>,
reflectance: Ptr<GPUSpectrumTexture>, reflectance: Ptr<GPUSpectrumTexture>,
remap_roughness: bool,
max_depth: u32, max_depth: u32,
n_samples: u32, n_samples: u32,
remap_roughness: bool,
} }
impl CoatedConductorMaterial { impl CoatedConductorMaterial {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[cfg(not(target_os = "cuda"))]
pub fn new( pub fn new(
normal_map: &DeviceImage, normal_map: Ptr<DeviceImage>,
displacement: &GPUFloatTexture, displacement: Ptr<GPUFloatTexture>,
interface_uroughness: &GPUFloatTexture, interface_uroughness: Ptr<GPUFloatTexture>,
interface_vroughness: &GPUFloatTexture, interface_vroughness: Ptr<GPUFloatTexture>,
thickness: &GPUFloatTexture, thickness: Ptr<GPUFloatTexture>,
interface_eta: &Spectrum, interface_eta: Ptr<Spectrum>,
g: &GPUFloatTexture, g: Ptr<GPUFloatTexture>,
albedo: &GPUSpectrumTexture, albedo: Ptr<GPUSpectrumTexture>,
conductor_uroughness: &GPUFloatTexture, conductor_uroughness: Ptr<GPUFloatTexture>,
conductor_vroughness: &GPUFloatTexture, conductor_vroughness: Ptr<GPUFloatTexture>,
conductor_eta: &GPUSpectrumTexture, conductor_eta: Ptr<GPUSpectrumTexture>,
k: &GPUSpectrumTexture, k: Ptr<GPUSpectrumTexture>,
reflectance: &GPUSpectrumTexture, reflectance: Ptr<GPUSpectrumTexture>,
remap_roughness: bool,
max_depth: u32, max_depth: u32,
n_samples: u32, n_samples: u32,
remap_roughness: bool,
) -> Self { ) -> Self {
Self { Self {
displacement: Ptr::from(displacement), displacement,
normal_map: Ptr::from(normal_map), normal_map,
interface_uroughness: Ptr::from(interface_uroughness), interface_uroughness,
interface_vroughness: Ptr::from(interface_vroughness), interface_vroughness,
thickness: Ptr::from(thickness), thickness,
interface_eta: Ptr::from(interface_eta), interface_eta,
g: Ptr::from(g), g,
albedo: Ptr::from(albedo), albedo,
conductor_uroughness: Ptr::from(conductor_uroughness), conductor_uroughness,
conductor_vroughness: Ptr::from(conductor_vroughness), conductor_vroughness,
conductor_eta: Ptr::from(conductor_eta), conductor_eta,
k: Ptr::from(k), k,
reflectance: Ptr::from(reflectance), reflectance,
remap_roughness, remap_roughness,
max_depth, max_depth,
n_samples, n_samples,
@ -238,12 +236,9 @@ impl MaterialTrait for CoatedConductorMaterial {
} }
let (mut ce, mut ck) = if !self.conductor_eta.is_null() { let (mut ce, mut ck) = if !self.conductor_eta.is_null() {
let k_tex = self let k_tex = self.k;
.k
.as_ref()
.expect("CoatedConductor: 'k' must be provided if 'conductor_eta' is present");
let ce = tex_eval.evaluate_spectrum(&self.conductor_eta, ctx, lambda); let ce = tex_eval.evaluate_spectrum(&self.conductor_eta, ctx, lambda);
let ck = tex_eval.evaluate_spectrum(k_tex, ctx, lambda); let ck = tex_eval.evaluate_spectrum(unsafe { k_tex.as_ref() }, ctx, lambda);
(ce, ck) (ce, ck)
} else { } else {
let r = SampledSpectrum::clamp( let r = SampledSpectrum::clamp(
@ -282,8 +277,8 @@ impl MaterialTrait for CoatedConductorMaterial {
thick, thick,
a, a,
gg, gg,
self.max_depth as usize, self.max_depth,
self.n_samples as usize, self.n_samples,
)); ));
BSDF::new(ctx.ns, ctx.dpdus, Ptr::from(&bxdf)) BSDF::new(ctx.ns, ctx.dpdus, Ptr::from(&bxdf))
} }

View file

@ -13,33 +13,33 @@ use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::textures::GPUSpectrumMixTexture; use crate::textures::GPUSpectrumMixTexture;
use crate::utils::DevicePtr; use crate::utils::Ptr;
use crate::utils::math::clamp; use crate::utils::math::clamp;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct HairMaterial { pub struct HairMaterial {
pub sigma_a: DevicePtr<GPUSpectrumTexture>, pub sigma_a: Ptr<GPUSpectrumTexture>,
pub color: DevicePtr<GPUSpectrumTexture>, pub color: Ptr<GPUSpectrumTexture>,
pub eumelanin: DevicePtr<GPUFloatTexture>, pub eumelanin: Ptr<GPUFloatTexture>,
pub pheomelanin: DevicePtr<GPUFloatTexture>, pub pheomelanin: Ptr<GPUFloatTexture>,
pub eta: DevicePtr<GPUFloatTexture>, pub eta: Ptr<GPUFloatTexture>,
pub beta_m: DevicePtr<GPUFloatTexture>, pub beta_m: Ptr<GPUFloatTexture>,
pub beta_n: DevicePtr<GPUFloatTexture>, pub beta_n: Ptr<GPUFloatTexture>,
pub alpha: DevicePtr<GPUFloatTexture>, pub alpha: Ptr<GPUFloatTexture>,
} }
impl HairMaterial { impl HairMaterial {
#[cfg(not(target_os = "cuda"))] #[cfg(not(target_os = "cuda"))]
pub fn new( pub fn new(
sigma_a: DevicePtr<GPUSpectrumTexture>, sigma_a: Ptr<GPUSpectrumTexture>,
color: DevicePtr<GPUSpectrumTexture>, color: Ptr<GPUSpectrumTexture>,
eumelanin: DevicePtr<GPUFloatTexture>, eumelanin: Ptr<GPUFloatTexture>,
pheomelanin: DevicePtr<GPUFloatTexture>, pheomelanin: Ptr<GPUFloatTexture>,
eta: DevicePtr<GPUFloatTexture>, eta: Ptr<GPUFloatTexture>,
beta_m: DevicePtr<GPUFloatTexture>, beta_m: Ptr<GPUFloatTexture>,
beta_n: DevicePtr<GPUFloatTexture>, beta_n: Ptr<GPUFloatTexture>,
alpha: DevicePtr<GPUFloatTexture>, alpha: Ptr<GPUFloatTexture>,
) -> Self { ) -> Self {
Self { Self {
sigma_a, sigma_a,
@ -80,8 +80,8 @@ impl MaterialTrait for HairMaterial {
todo!() todo!()
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
DevicePtr::null() Ptr::null()
} }
fn has_subsurface_scattering(&self) -> bool { fn has_subsurface_scattering(&self) -> bool {
@ -92,9 +92,9 @@ impl MaterialTrait for HairMaterial {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct MeasuredMaterial { pub struct MeasuredMaterial {
pub displacement: DevicePtr<GPUFloatTexture>, pub displacement: Ptr<GPUFloatTexture>,
pub normal_map: DevicePtr<DeviceImage>, pub normal_map: Ptr<DeviceImage>,
pub brdf: DevicePtr<MeasuredBxDFData>, pub brdf: Ptr<MeasuredBxDFData>,
} }
impl MaterialTrait for MeasuredMaterial { impl MaterialTrait for MeasuredMaterial {
@ -125,7 +125,7 @@ impl MaterialTrait for MeasuredMaterial {
Some(&*self.normal_map) Some(&*self.normal_map)
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
self.displacement self.displacement
} }
@ -137,16 +137,16 @@ impl MaterialTrait for MeasuredMaterial {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SubsurfaceMaterial { pub struct SubsurfaceMaterial {
pub normal_map: DevicePtr<DeviceImage>, pub normal_map: Ptr<DeviceImage>,
pub displacement: DevicePtr<GPUFloatTexture>, pub displacement: Ptr<GPUFloatTexture>,
pub sigma_a: DevicePtr<GPUSpectrumTexture>, pub sigma_a: Ptr<GPUSpectrumTexture>,
pub sigma_s: DevicePtr<GPUSpectrumMixTexture>, pub sigma_s: Ptr<GPUSpectrumMixTexture>,
pub reflectance: DevicePtr<GPUSpectrumMixTexture>, pub reflectance: Ptr<GPUSpectrumMixTexture>,
pub mfp: DevicePtr<GPUSpectrumMixTexture>, pub mfp: Ptr<GPUSpectrumMixTexture>,
pub eta: Float, pub eta: Float,
pub scale: Float, pub scale: Float,
pub u_roughness: DevicePtr<GPUFloatTexture>, pub u_roughness: Ptr<GPUFloatTexture>,
pub v_roughness: DevicePtr<GPUFloatTexture>, pub v_roughness: Ptr<GPUFloatTexture>,
pub remap_roughness: bool, pub remap_roughness: bool,
pub table: BSSRDFTable, pub table: BSSRDFTable,
} }
@ -177,7 +177,7 @@ impl MaterialTrait for SubsurfaceMaterial {
todo!() todo!()
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
todo!() todo!()
} }

View file

@ -10,17 +10,17 @@ use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::DevicePtr; use crate::utils::Ptr;
use crate::utils::math::clamp; use crate::utils::math::clamp;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct DielectricMaterial { pub struct DielectricMaterial {
normal_map: DevicePtr<DeviceImage>, normal_map: Ptr<DeviceImage>,
displacement: DevicePtr<GPUFloatTexture>, displacement: Ptr<GPUFloatTexture>,
u_roughness: DevicePtr<GPUFloatTexture>, u_roughness: Ptr<GPUFloatTexture>,
v_roughness: DevicePtr<GPUFloatTexture>, v_roughness: Ptr<GPUFloatTexture>,
eta: DevicePtr<Spectrum>, eta: Ptr<Spectrum>,
remap_roughness: bool, remap_roughness: bool,
} }
@ -51,7 +51,7 @@ impl MaterialTrait for DielectricMaterial {
let distrib = TrowbridgeReitzDistribution::new(u_rough, v_rough); let distrib = TrowbridgeReitzDistribution::new(u_rough, v_rough);
let bxdf = BxDF::Dielectric(DielectricBxDF::new(sampled_eta, distrib)); let bxdf = BxDF::Dielectric(DielectricBxDF::new(sampled_eta, distrib));
BSDF::new(ctx.ns, ctx.dpdus, DevicePtr::from(&bxdf)) BSDF::new(ctx.ns, ctx.dpdus, Ptr::from(&bxdf))
} }
fn get_bssrdf<T>( fn get_bssrdf<T>(
@ -71,7 +71,7 @@ impl MaterialTrait for DielectricMaterial {
Some(&*self.normal_map) Some(&*self.normal_map)
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
self.displacement self.displacement
} }
@ -83,9 +83,9 @@ impl MaterialTrait for DielectricMaterial {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct ThinDielectricMaterial { pub struct ThinDielectricMaterial {
pub displacement: DevicePtr<GPUFloatTexture>, pub displacement: Ptr<GPUFloatTexture>,
pub normal_map: DevicePtr<DeviceImage>, pub normal_map: Ptr<DeviceImage>,
pub eta: DevicePtr<Spectrum>, pub eta: Ptr<Spectrum>,
} }
impl MaterialTrait for ThinDielectricMaterial { impl MaterialTrait for ThinDielectricMaterial {
fn get_bsdf<T: TextureEvaluator>( fn get_bsdf<T: TextureEvaluator>(
@ -113,7 +113,7 @@ impl MaterialTrait for ThinDielectricMaterial {
Some(&*self.normal_map) Some(&*self.normal_map)
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
self.displacement self.displacement
} }

View file

@ -11,15 +11,15 @@ use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::DevicePtr; use crate::utils::Ptr;
use crate::utils::math::clamp; use crate::utils::math::clamp;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct DiffuseMaterial { pub struct DiffuseMaterial {
pub normal_map: DevicePtr<DeviceImage>, pub normal_map: Ptr<DeviceImage>,
pub displacement: DevicePtr<GPUFloatTexture>, pub displacement: Ptr<GPUFloatTexture>,
pub reflectance: DevicePtr<GPUSpectrumTexture>, pub reflectance: Ptr<GPUSpectrumTexture>,
} }
impl MaterialTrait for DiffuseMaterial { impl MaterialTrait for DiffuseMaterial {
@ -31,7 +31,7 @@ impl MaterialTrait for DiffuseMaterial {
) -> BSDF { ) -> BSDF {
let r = tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda); let r = tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda);
let bxdf = BxDF::Diffuse(DiffuseBxDF::new(r)); let bxdf = BxDF::Diffuse(DiffuseBxDF::new(r));
BSDF::new(ctx.ns, ctx.dpdus, DevicePtr::from(&bxdf)) BSDF::new(ctx.ns, ctx.dpdus, Ptr::from(&bxdf))
} }
fn get_bssrdf<T>( fn get_bssrdf<T>(
@ -51,7 +51,7 @@ impl MaterialTrait for DiffuseMaterial {
Some(&*self.normal_map) Some(&*self.normal_map)
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
self.displacement self.displacement
} }
@ -63,10 +63,10 @@ impl MaterialTrait for DiffuseMaterial {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct DiffuseTransmissionMaterial { pub struct DiffuseTransmissionMaterial {
pub image: DevicePtr<DeviceImage>, pub image: Ptr<DeviceImage>,
pub displacement: DevicePtr<GPUFloatTexture>, pub displacement: Ptr<GPUFloatTexture>,
pub reflectance: DevicePtr<GPUFloatTexture>, pub reflectance: Ptr<GPUFloatTexture>,
pub transmittance: DevicePtr<GPUFloatTexture>, pub transmittance: Ptr<GPUFloatTexture>,
pub scale: Float, pub scale: Float,
} }
@ -96,7 +96,7 @@ impl MaterialTrait for DiffuseTransmissionMaterial {
Some(&*self.image) Some(&*self.image)
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
self.displacement self.displacement
} }

View file

@ -10,14 +10,14 @@ use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::Ptr;
use crate::utils::hash::hash_float; use crate::utils::hash::hash_float;
use crate::utils::math::clamp; use crate::utils::math::clamp;
use crate::utils::{DevicePtr, Ptr};
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct MixMaterial { pub struct MixMaterial {
pub amount: DevicePtr<GPUFloatTexture>, pub amount: Ptr<GPUFloatTexture>,
pub materials: [Ptr<Material>; 2], pub materials: [Ptr<Material>; 2],
} }
@ -73,7 +73,7 @@ impl MaterialTrait for MixMaterial {
None None
} }
fn get_displacement(&self) -> DevicePtr<GPUFloatTexture> { fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
panic!( panic!(
"MixMaterial::get_displacement() shouldn't be called. \ "MixMaterial::get_displacement() shouldn't be called. \
Displacement is not supported on Mix materials directly." Displacement is not supported on Mix materials directly."

View file

@ -61,11 +61,7 @@ impl BilinearPatchShape {
#[inline(always)] #[inline(always)]
fn get_vertex_indices(&self) -> [usize; 4] { fn get_vertex_indices(&self) -> [usize; 4] {
unsafe { unsafe {
let base_ptr = self let base_ptr = self.mesh.vertex_indices.add((self.blp_index as usize) * 4);
.mesh
.vertex_indices
.0
.add((self.blp_index as usize) * 4);
[ [
*base_ptr.add(0) as usize, *base_ptr.add(0) as usize,
*base_ptr.add(1) as usize, *base_ptr.add(1) as usize,
@ -80,10 +76,10 @@ impl BilinearPatchShape {
let [v0, v1, v2, v3] = self.get_vertex_indices(); let [v0, v1, v2, v3] = self.get_vertex_indices();
unsafe { unsafe {
[ [
*self.mesh.p.0.add(v0), *self.mesh.p.add(v0),
*self.mesh.p.0.add(v1), *self.mesh.p.add(v1),
*self.mesh.p.0.add(v2), *self.mesh.p.add(v2),
*self.mesh.p.0.add(v3), *self.mesh.p.add(v3),
] ]
} }
} }
@ -96,10 +92,10 @@ impl BilinearPatchShape {
let [v0, v1, v2, v3] = self.get_vertex_indices(); let [v0, v1, v2, v3] = self.get_vertex_indices();
unsafe { unsafe {
Some([ Some([
*self.mesh.uv.0.add(v0), *self.mesh.uv.add(v0),
*self.mesh.uv.0.add(v1), *self.mesh.uv.add(v1),
*self.mesh.uv.0.add(v2), *self.mesh.uv.add(v2),
*self.mesh.uv.0.add(v3), *self.mesh.uv.add(v3),
]) ])
} }
} }
@ -112,10 +108,10 @@ impl BilinearPatchShape {
let [v0, v1, v2, v3] = self.get_vertex_indices(); let [v0, v1, v2, v3] = self.get_vertex_indices();
unsafe { unsafe {
Some([ Some([
*self.mesh.n.0.add(v0), *self.mesh.n.add(v0),
*self.mesh.n.0.add(v1), *self.mesh.n.add(v1),
*self.mesh.n.0.add(v2), *self.mesh.n.add(v2),
*self.mesh.n.0.add(v3), *self.mesh.n.add(v3),
]) ])
} }
} }

View file

@ -45,11 +45,7 @@ impl TriangleShape {
#[inline(always)] #[inline(always)]
fn get_vertex_indices(&self) -> [usize; 3] { fn get_vertex_indices(&self) -> [usize; 3] {
unsafe { unsafe {
let base_ptr = self let base_ptr = self.mesh.vertex_indices.add((self.tri_index as usize) * 3);
.mesh
.vertex_indices
.0
.add((self.tri_index as usize) * 3);
[ [
*base_ptr.add(0) as usize, *base_ptr.add(0) as usize,
*base_ptr.add(1) as usize, *base_ptr.add(1) as usize,
@ -63,9 +59,9 @@ impl TriangleShape {
let [v0, v1, v2] = self.get_vertex_indices(); let [v0, v1, v2] = self.get_vertex_indices();
unsafe { unsafe {
[ [
*self.mesh.p.0.add(v0), *self.mesh.p.add(v0),
*self.mesh.p.0.add(v1), *self.mesh.p.add(v1),
*self.mesh.p.0.add(v2), *self.mesh.p.add(v2),
] ]
} }
} }
@ -78,9 +74,9 @@ impl TriangleShape {
let [v0, v1, v2] = self.get_vertex_indices(); let [v0, v1, v2] = self.get_vertex_indices();
unsafe { unsafe {
Some([ Some([
*self.mesh.uv.0.add(v0), *self.mesh.uv.add(v0),
*self.mesh.uv.0.add(v1), *self.mesh.uv.add(v1),
*self.mesh.uv.0.add(v2), *self.mesh.uv.add(v2),
]) ])
} }
} }
@ -93,9 +89,9 @@ impl TriangleShape {
let [v0, v1, v2] = self.get_vertex_indices(); let [v0, v1, v2] = self.get_vertex_indices();
unsafe { unsafe {
Some([ Some([
*self.mesh.s.0.add(v0), *self.mesh.s.add(v0),
*self.mesh.s.0.add(v1), *self.mesh.s.add(v1),
*self.mesh.s.0.add(v2), *self.mesh.s.add(v2),
]) ])
} }
} }
@ -108,9 +104,9 @@ impl TriangleShape {
let [v0, v1, v2] = self.get_vertex_indices(); let [v0, v1, v2] = self.get_vertex_indices();
unsafe { unsafe {
Some([ Some([
*self.mesh.n.0.add(v0), *self.mesh.n.add(v0),
*self.mesh.n.0.add(v1), *self.mesh.n.add(v1),
*self.mesh.n.0.add(v2), *self.mesh.n.add(v2),
]) ])
} }
} }
@ -213,7 +209,7 @@ impl TriangleShape {
); );
isect.face_index = if !self.mesh.face_indices.is_null() { isect.face_index = if !self.mesh.face_indices.is_null() {
unsafe { *self.mesh.face_indices.0.add(self.tri_index as usize) } unsafe { *self.mesh.face_indices.add(self.tri_index as usize) }
} else { } else {
0 0
}; };

View file

@ -3,17 +3,17 @@ use crate::core::geometry::Point2f;
use crate::core::pbrt::Float; use crate::core::pbrt::Float;
use crate::spectra::{DenselySampledSpectrum, SampledSpectrum}; use crate::spectra::{DenselySampledSpectrum, SampledSpectrum};
use crate::utils::math::SquareMatrix3f; use crate::utils::math::SquareMatrix3f;
use crate::utils::ptr::DevicePtr; use crate::utils::ptr::Ptr;
use std::cmp::{Eq, PartialEq}; use std::cmp::{Eq, PartialEq};
#[repr(C)] #[repr(C)]
#[derive(Copy, Debug, Clone)] #[derive(Copy, Debug, Clone)]
pub struct StandardColorSpaces { pub struct StandardColorSpaces {
pub srgb: DevicePtr<RGBColorSpace>, pub srgb: Ptr<RGBColorSpace>,
pub dci_p3: DevicePtr<RGBColorSpace>, pub dci_p3: Ptr<RGBColorSpace>,
pub rec2020: DevicePtr<RGBColorSpace>, pub rec2020: Ptr<RGBColorSpace>,
pub aces2065_1: DevicePtr<RGBColorSpace>, pub aces2065_1: Ptr<RGBColorSpace>,
} }
#[repr(C)] #[repr(C)]
@ -24,7 +24,7 @@ pub struct RGBColorSpace {
pub b: Point2f, pub b: Point2f,
pub w: Point2f, pub w: Point2f,
pub illuminant: DenselySampledSpectrum, pub illuminant: DenselySampledSpectrum,
pub rgb_to_spectrum_table: DevicePtr<RGBToSpectrumTable>, pub rgb_to_spectrum_table: Ptr<RGBToSpectrumTable>,
pub xyz_from_rgb: SquareMatrix3f, pub xyz_from_rgb: SquareMatrix3f,
pub rgb_from_xyz: SquareMatrix3f, pub rgb_from_xyz: SquareMatrix3f,
} }
@ -42,7 +42,7 @@ impl RGBColorSpace {
} }
pub fn to_rgb_coeffs(&self, rgb: RGB) -> RGBSigmoidPolynomial { pub fn to_rgb_coeffs(&self, rgb: RGB) -> RGBSigmoidPolynomial {
self.rgb_to_spectrum_table.to_polynomial(rgb) self.rgb_to_spectrum_table.evaluate(rgb)
} }
pub fn convert_colorspace(&self, other: &RGBColorSpace) -> SquareMatrix3f { pub fn convert_colorspace(&self, other: &RGBColorSpace) -> SquareMatrix3f {

View file

@ -4,7 +4,7 @@ use super::{
}; };
use crate::core::color::{RGB, RGBSigmoidPolynomial, XYZ}; use crate::core::color::{RGB, RGBSigmoidPolynomial, XYZ};
use crate::core::spectrum::SpectrumTrait; use crate::core::spectrum::SpectrumTrait;
use crate::utils::DevicePtr; use crate::utils::Ptr;
use crate::Float; use crate::Float;
@ -69,7 +69,7 @@ impl SpectrumTrait for UnboundedRGBSpectrum {
pub struct RGBIlluminantSpectrum { pub struct RGBIlluminantSpectrum {
pub scale: Float, pub scale: Float,
pub rsp: RGBSigmoidPolynomial, pub rsp: RGBSigmoidPolynomial,
pub illuminant: DevicePtr<DenselySampledSpectrum>, pub illuminant: Ptr<DenselySampledSpectrum>,
} }
impl RGBIlluminantSpectrum { impl RGBIlluminantSpectrum {
@ -85,7 +85,7 @@ impl RGBIlluminantSpectrum {
Self { Self {
scale, scale,
rsp, rsp,
illuminant: DevicePtr::from(&illuminant), illuminant: Ptr::from(&illuminant),
} }
} }
} }

View file

@ -4,7 +4,7 @@ use crate::Float;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::spectra::{N_SPECTRUM_SAMPLES, SampledSpectrum, SampledWavelengths}; use crate::spectra::{N_SPECTRUM_SAMPLES, SampledSpectrum, SampledWavelengths};
use crate::utils::find_interval; use crate::utils::find_interval;
use crate::utils::ptr::DevicePtr; use crate::utils::ptr::Ptr;
use core::slice; use core::slice;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::sync::LazyLock; use std::sync::LazyLock;
@ -36,7 +36,7 @@ impl SpectrumTrait for ConstantSpectrum {
pub struct DenselySampledSpectrum { pub struct DenselySampledSpectrum {
pub lambda_min: i32, pub lambda_min: i32,
pub lambda_max: i32, pub lambda_max: i32,
pub values: DevicePtr<Float>, pub values: Ptr<Float>,
} }
unsafe impl Send for DenselySampledSpectrum {} unsafe impl Send for DenselySampledSpectrum {}
@ -54,7 +54,7 @@ impl DenselySampledSpectrum {
#[inline(always)] #[inline(always)]
fn get(&self, idx: u32) -> Float { fn get(&self, idx: u32) -> Float {
unsafe { *self.values.0.add(idx as usize) } unsafe { *self.values.add(idx as usize) }
} }
} }
@ -62,7 +62,7 @@ impl PartialEq for DenselySampledSpectrum {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.lambda_min == other.lambda_min self.lambda_min == other.lambda_min
&& self.lambda_max == other.lambda_max && self.lambda_max == other.lambda_max
&& self.values.0 == other.values.0 && self.values == other.values
} }
} }
@ -91,7 +91,7 @@ impl SpectrumTrait for DenselySampledSpectrum {
s[i] = 0.0; s[i] = 0.0;
} else { } else {
unsafe { unsafe {
s[i] = *self.values.0.add(offset as usize); s[i] = *self.values.add(offset as usize);
} }
} }
} }
@ -104,7 +104,7 @@ impl SpectrumTrait for DenselySampledSpectrum {
if offset < 0 || offset >= n { if offset < 0 || offset >= n {
0.0 0.0
} else { } else {
unsafe { *self.values.0.add(offset as usize) } unsafe { *self.values.add(offset as usize) }
} }
} }
@ -118,7 +118,7 @@ impl SpectrumTrait for DenselySampledSpectrum {
for i in 0..n { for i in 0..n {
unsafe { unsafe {
let val = *self.values.0.add(i); let val = *self.values.add(i);
if val > max_val { if val > max_val {
max_val = val; max_val = val;
} }
@ -131,20 +131,20 @@ impl SpectrumTrait for DenselySampledSpectrum {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct PiecewiseLinearSpectrum { pub struct PiecewiseLinearSpectrum {
pub lambdas: DevicePtr<Float>, pub lambdas: Ptr<Float>,
pub values: DevicePtr<Float>, pub values: Ptr<Float>,
pub count: u32, pub count: u32,
} }
impl PiecewiseLinearSpectrum { impl PiecewiseLinearSpectrum {
#[inline(always)] #[inline(always)]
fn lambda(&self, i: u32) -> Float { fn lambda(&self, i: u32) -> Float {
unsafe { *self.lambdas.0.add(i as usize) } unsafe { *self.lambdas.add(i as usize) }
} }
#[inline(always)] #[inline(always)]
fn value(&self, i: u32) -> Float { fn value(&self, i: u32) -> Float {
unsafe { *self.values.0.add(i as usize) } unsafe { *self.values.add(i as usize) }
} }
} }
@ -186,7 +186,7 @@ impl SpectrumTrait for PiecewiseLinearSpectrum {
for i in 0..n { for i in 0..n {
unsafe { unsafe {
let val = *self.values.0.add(i as usize); let val = *self.values.add(i as usize);
if val > max_val { if val > max_val {
max_val = val; max_val = val;
} }

View file

@ -3,7 +3,7 @@ use crate::core::spectrum::Spectrum;
use crate::core::spectrum::SpectrumTrait; use crate::core::spectrum::SpectrumTrait;
use crate::core::texture::{TextureEvalContext, TextureMapping2D}; use crate::core::texture::{TextureEvalContext, TextureMapping2D};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::{DevicePtr, Transform}; use crate::utils::{Ptr, Transform};
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -48,19 +48,19 @@ impl FloatBilerpTexture {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SpectrumBilerpTexture { pub struct SpectrumBilerpTexture {
pub mapping: TextureMapping2D, pub mapping: TextureMapping2D,
pub v00: DevicePtr<Spectrum>, pub v00: Ptr<Spectrum>,
pub v01: DevicePtr<Spectrum>, pub v01: Ptr<Spectrum>,
pub v10: DevicePtr<Spectrum>, pub v10: Ptr<Spectrum>,
pub v11: DevicePtr<Spectrum>, pub v11: Ptr<Spectrum>,
} }
impl SpectrumBilerpTexture { impl SpectrumBilerpTexture {
pub fn new( pub fn new(
mapping: TextureMapping2D, mapping: TextureMapping2D,
v00: DevicePtr<Spectrum>, v00: Ptr<Spectrum>,
v01: DevicePtr<Spectrum>, v01: Ptr<Spectrum>,
v10: DevicePtr<Spectrum>, v10: Ptr<Spectrum>,
v11: DevicePtr<Spectrum>, v11: Ptr<Spectrum>,
) -> Self { ) -> Self {
Self { Self {
mapping, mapping,

View file

@ -4,12 +4,12 @@ use crate::core::texture::{
TextureMapping3DTrait, TextureMapping3DTrait,
}; };
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::{DevicePtr, Ptr, math::square}; use crate::utils::{Ptr, math::square};
fn checkerboard( fn checkerboard(
ctx: &TextureEvalContext, ctx: &TextureEvalContext,
map2d: DevicePtr<TextureMapping2D>, map2d: Ptr<TextureMapping2D>,
map3d: DevicePtr<TextureMapping3D>, map3d: Ptr<TextureMapping3D>,
) -> Float { ) -> Float {
let d = |x: Float| -> Float { let d = |x: Float| -> Float {
let y = x / 2. - (x / 2.).floor() - 0.5; let y = x / 2. - (x / 2.).floor() - 0.5;
@ -43,8 +43,8 @@ fn checkerboard(
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct FloatCheckerboardTexture { pub struct FloatCheckerboardTexture {
pub map2d: DevicePtr<TextureMapping2D>, pub map2d: Ptr<TextureMapping2D>,
pub map3d: DevicePtr<TextureMapping3D>, pub map3d: Ptr<TextureMapping3D>,
pub tex: [Ptr<GPUFloatTexture>; 2], pub tex: [Ptr<GPUFloatTexture>; 2],
} }
@ -74,8 +74,8 @@ impl FloatCheckerboardTexture {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SpectrumCheckerboardTexture { pub struct SpectrumCheckerboardTexture {
pub map2d: DevicePtr<TextureMapping2D>, pub map2d: Ptr<TextureMapping2D>,
pub map3d: DevicePtr<TextureMapping3D>, pub map3d: Ptr<TextureMapping3D>,
pub tex: [Ptr<GPUSpectrumTexture>; 2], pub tex: [Ptr<GPUSpectrumTexture>; 2],
} }

View file

@ -4,7 +4,7 @@ use crate::core::texture::{
GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext, TextureMapping2D, GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext, TextureMapping2D,
}; };
use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths}; use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths};
use crate::utils::DevicePtr; use crate::utils::Ptr;
use crate::utils::math::square; use crate::utils::math::square;
use crate::utils::noise::noise_2d; use crate::utils::noise::noise_2d;
@ -28,8 +28,8 @@ fn inside_polka_dot(st: Point2f) -> bool {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct FloatDotsTexture { pub struct FloatDotsTexture {
pub mapping: TextureMapping2D, pub mapping: TextureMapping2D,
pub outside_dot: DevicePtr<GPUFloatTexture>, pub outside_dot: Ptr<GPUFloatTexture>,
pub inside_dot: DevicePtr<GPUFloatTexture>, pub inside_dot: Ptr<GPUFloatTexture>,
} }
impl FloatDotsTexture { impl FloatDotsTexture {
@ -53,8 +53,8 @@ impl FloatDotsTexture {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SpectrumDotsTexture { pub struct SpectrumDotsTexture {
pub mapping: TextureMapping2D, pub mapping: TextureMapping2D,
pub outside_dot: DevicePtr<GPUSpectrumTexture>, pub outside_dot: Ptr<GPUSpectrumTexture>,
pub inside_dot: DevicePtr<GPUSpectrumTexture>, pub inside_dot: Ptr<GPUSpectrumTexture>,
} }
impl SpectrumDotsTexture { impl SpectrumDotsTexture {

View file

@ -23,6 +23,7 @@ pub struct GPUSpectrumImageTexture {
} }
impl GPUSpectrumImageTexture { impl GPUSpectrumImageTexture {
#[allow(unused)]
pub fn evaluate( pub fn evaluate(
&self, &self,
ctx: &TextureEvalContext, ctx: &TextureEvalContext,
@ -44,12 +45,14 @@ impl GPUSpectrumImageTexture {
let d_p_dy = [c.dsdy, c.dtdy]; let d_p_dy = [c.dsdy, c.dtdy];
let tex_color = if self.is_single_channel { let tex_color = if self.is_single_channel {
let val: Float = let val = 0.;
unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) }; // let val: Float =
// unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
RGB::new(val, val, val) RGB::new(val, val, val)
} else { } else {
let val: [Float; 4] = let val = [0., 0., 0., 0.];
unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) }; // let val: [Float; 4] =
// unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
RGB::new(val[0], val[1], val[2]) RGB::new(val[0], val[1], val[2])
}; };
@ -86,6 +89,7 @@ impl GPUFloatImageTexture {
return 0.; return 0.;
} }
#[cfg(feature = "cuda")] #[cfg(feature = "cuda")]
#[allow(unused)]
{ {
use cuda_std::intrinsics; use cuda_std::intrinsics;
let c = self.mapping.map(ctx); let c = self.mapping.map(ctx);
@ -93,10 +97,12 @@ impl GPUFloatImageTexture {
let v = 1.0 - c.st.y(); let v = 1.0 - c.st.y();
let d_p_dx = [c.dsdx, c.dtdx]; let d_p_dx = [c.dsdx, c.dtdx];
let d_p_dy = [c.dsdy, c.dtdy]; let d_p_dy = [c.dsdy, c.dtdy];
let val: Float = unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) }; // let val: Float = unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
let val: Float = 0.;
let result = if self.invert { let result = if self.invert {
(1.0 - val).max(0.0) // Invert the pixel intensity // Invert the pixel intensity
(1.0 - val).max(0.0)
} else { } else {
val val
}; };

View file

@ -6,7 +6,7 @@ use crate::core::texture::{TextureEvalContext, TextureMapping3D};
use crate::spectra::{RGBAlbedoSpectrum, RGBColorSpace, SampledSpectrum, SampledWavelengths}; use crate::spectra::{RGBAlbedoSpectrum, RGBColorSpace, SampledSpectrum, SampledWavelengths};
use crate::utils::math::clamp; use crate::utils::math::clamp;
use crate::utils::noise::fbm; use crate::utils::noise::fbm;
use crate::utils::ptr::DevicePtr; use crate::utils::ptr::Ptr;
use crate::utils::splines::evaluate_cubic_bezier; use crate::utils::splines::evaluate_cubic_bezier;
#[repr(C)] #[repr(C)]
@ -18,7 +18,7 @@ pub struct MarbleTexture {
pub scale: Float, pub scale: Float,
pub variation: Float, pub variation: Float,
// TODO: DO not forget to pass StandardColorSpace here!! // TODO: DO not forget to pass StandardColorSpace here!!
pub colorspace: DevicePtr<RGBColorSpace>, pub colorspace: Ptr<RGBColorSpace>,
} }
unsafe impl Send for MarbleTexture {} unsafe impl Send for MarbleTexture {}

View file

@ -6,7 +6,7 @@ use crate::spectra::{
RGBAlbedoSpectrum, RGBColorSpace, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum, RGBAlbedoSpectrum, RGBColorSpace, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum,
SampledWavelengths, StandardColorSpaces, SampledWavelengths, StandardColorSpaces,
}; };
use crate::utils::ptr::{DevicePtr, Slice}; use crate::utils::Ptr;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -23,7 +23,7 @@ impl GPUFloatPtexTexture {
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, Copy)] #[derive(Clone, Debug, Copy)]
pub struct GPUSpectrumPtexTexture { pub struct GPUSpectrumPtexTexture {
pub face_values: Slice<RGB>, pub face_values: *const RGB,
pub n_faces: u32, pub n_faces: u32,
pub spectrum_type: SpectrumType, pub spectrum_type: SpectrumType,
pub colorspaces: StandardColorSpaces, pub colorspaces: StandardColorSpaces,
@ -36,16 +36,16 @@ impl GPUSpectrumPtexTexture {
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
) -> SampledSpectrum { ) -> SampledSpectrum {
let index = ctx.face_index.clamp(0, self.n_faces.saturating_sub(1)); let index = ctx.face_index.clamp(0, self.n_faces.saturating_sub(1));
let rgb = self.face_values[index as usize]; let rgb = unsafe { &*self.face_values.add(index as usize) };
let s_rgb = self.colorspaces.srgb; let s_rgb = self.colorspaces.srgb;
match self.spectrum_type { match self.spectrum_type {
SpectrumType::Unbounded => RGBUnboundedSpectrum::new(&s_rgb, rgb).sample(lambda), SpectrumType::Unbounded => RGBUnboundedSpectrum::new(&s_rgb, *rgb).sample(lambda),
SpectrumType::Albedo => { SpectrumType::Albedo => {
let clamped_rgb = rgb.clamp(0.0, 1.0); let clamped_rgb = rgb.clamp(0.0, 1.0);
RGBAlbedoSpectrum::new(&s_rgb, clamped_rgb).sample(lambda) RGBAlbedoSpectrum::new(&s_rgb, clamped_rgb).sample(lambda)
} }
SpectrumType::Illuminant => RGBIlluminantSpectrum::new(&s_rgb, rgb).sample(lambda), SpectrumType::Illuminant => RGBIlluminantSpectrum::new(&s_rgb, *rgb).sample(lambda),
} }
} }
} }

View file

@ -1,4 +1,8 @@
use crate::core::geometry::{
Bounds2i, Bounds3f, Bounds3i, Point2i, Point3f, Point3i, Vector2i, Vector3f, Vector3i,
};
use crate::core::pbrt::Float; use crate::core::pbrt::Float;
use crate::utils::Ptr;
use crate::utils::math::lerp; use crate::utils::math::lerp;
use std::collections::HashSet; use std::collections::HashSet;
use std::collections::hash_map::RandomState; use std::collections::hash_map::RandomState;
@ -6,10 +10,6 @@ use std::hash::{BuildHasher, Hash, Hasher};
use std::ops::{Add, Index, IndexMut, Mul, Sub}; use std::ops::{Add, Index, IndexMut, Mul, Sub};
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use crate::core::geometry::{
Bounds2i, Bounds3f, Bounds3i, Point2i, Point3f, Point3i, Vector2i, Vector3f, Vector3i,
};
pub trait Interpolatable: pub trait Interpolatable:
Copy + Default + Add<Output = Self> + Sub<Output = Self> + Mul<Float, Output = Self> Copy + Default + Add<Output = Self> + Sub<Output = Self> + Mul<Float, Output = Self>
{ {
@ -120,7 +120,7 @@ impl<T> IndexMut<(i32, i32)> for Array2D<T> {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct SampledGrid<T> { pub struct SampledGrid<T> {
pub values: *const T, pub values: Ptr<T>,
pub values_len: u32, pub values_len: u32,
pub nx: i32, pub nx: i32,
pub ny: i32, pub ny: i32,
@ -135,7 +135,7 @@ impl<T> SampledGrid<T> {
pub fn new(slice: &[T], nx: i32, ny: i32, nz: i32) -> Self { pub fn new(slice: &[T], nx: i32, ny: i32, nz: i32) -> Self {
assert_eq!(slice.len(), (nx * ny * nz) as usize); assert_eq!(slice.len(), (nx * ny * nz) as usize);
Self { Self {
values: slice.as_ptr(), values: Ptr::from(slice),
values_len: (nx * ny * nz) as u32, values_len: (nx * ny * nz) as u32,
nx, nx,
ny, ny,
@ -145,7 +145,7 @@ impl<T> SampledGrid<T> {
pub fn empty() -> Self { pub fn empty() -> Self {
Self { Self {
values: core::ptr::null(), values: Ptr::null(),
values_len: 0, values_len: 0,
nx: 0, nx: 0,
ny: 0, ny: 0,

View file

@ -1,12 +1,14 @@
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
#[derive(Error, Debug)] #[derive(Debug)]
pub enum LlsError { pub enum LlsError {
SingularMatrix, SingularMatrix,
} }
#[derive(Error, Debug, Clone, PartialEq, Eq)] impl std::error::Error for LlsError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InversionError { pub enum InversionError {
SingularMatrix, SingularMatrix,
EmptyMatrix, EmptyMatrix,
@ -30,3 +32,5 @@ impl fmt::Display for InversionError {
} }
} }
} }
impl std::error::Error for InversionError {}

View file

@ -5,7 +5,7 @@ use crate::core::pbrt::{Float, FloatBitOps, FloatBits, ONE_MINUS_EPSILON, PI, PI
use crate::utils::hash::{hash_buffer, mix_bits}; use crate::utils::hash::{hash_buffer, mix_bits};
use crate::utils::sobol::{SOBOL_MATRICES_32, VDC_SOBOL_MATRICES, VDC_SOBOL_MATRICES_INV}; use crate::utils::sobol::{SOBOL_MATRICES_32, VDC_SOBOL_MATRICES, VDC_SOBOL_MATRICES_INV};
use crate::utils::DevicePtr; use crate::utils::Ptr;
use half::f16; use half::f16;
use num_traits::{Float as NumFloat, Num, One, Signed, Zero}; use num_traits::{Float as NumFloat, Num, One, Signed, Zero};
use std::error::Error; use std::error::Error;
@ -647,7 +647,7 @@ pub fn round_up_pow2(mut n: i32) -> i32 {
pub const PRIME_TABLE_SIZE: usize = 1000; pub const PRIME_TABLE_SIZE: usize = 1000;
const PRIMES: [i32; PRIME_TABLE_SIZE] = [ pub const PRIMES: [i32; PRIME_TABLE_SIZE] = [
2, 3, 5, 7, 11, // Subsequent prime numbers 2, 3, 5, 7, 11, // Subsequent prime numbers
13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107,
109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
@ -753,14 +753,15 @@ pub fn inverse_radical_inverse(mut inverse: u64, base: u64, n_digits: u64) -> u6
pub struct DigitPermutation { pub struct DigitPermutation {
pub base: u32, pub base: u32,
pub n_digits: u32, pub n_digits: u32,
pub permutations: DevicePtr<u16>, pub permutations: Ptr<u16>,
} }
impl DigitPermutation { impl DigitPermutation {
#[inline(always)] #[inline(always)]
pub fn permute(&self, digit_index: i32, digit_value: i32) -> i32 { pub fn permute(&self, digit_index: i32, digit_value: i32) -> i32 {
let idx = (digit_index * self.base as i32 + digit_value) as usize; let idx = (digit_index * self.base as i32 + digit_value) as usize;
self.permutations[idx] as i32 let permutation = unsafe { *self.permutations.add(idx.into()) };
permutation as i32
} }
} }

View file

@ -1,5 +1,3 @@
use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
pub mod containers; pub mod containers;
pub mod error; pub mod error;
pub mod hash; pub mod hash;
@ -15,9 +13,12 @@ pub mod sobol;
pub mod splines; pub mod splines;
pub mod transform; pub mod transform;
pub use ptr::{DevicePtr, Ptr}; pub use ptr::Ptr;
pub use transform::{AnimatedTransform, Transform, TransformGeneric}; pub use transform::{AnimatedTransform, Transform, TransformGeneric};
use crate::Float;
use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
#[inline] #[inline]
pub fn find_interval<F>(sz: u32, pred: F) -> u32 pub fn find_interval<F>(sz: u32, pred: F) -> u32
where where
@ -57,6 +58,8 @@ where
i i
} }
#[repr(C)]
#[derive(Debug, Default)]
pub struct AtomicFloat { pub struct AtomicFloat {
bits: AtomicU32, bits: AtomicU32,
} }
@ -68,11 +71,11 @@ impl AtomicFloat {
} }
} }
pub fn get(&self) -> f32 { pub fn get(&self) -> Float {
f32::from_bits(self.bits.load(Ordering::Relaxed)) Float::from_bits(self.bits.load(Ordering::Relaxed))
} }
pub fn set(&self, val: f32) { pub fn set(&self, val: Float) {
self.bits.store(val.to_bits(), Ordering::Relaxed); self.bits.store(val.to_bits(), Ordering::Relaxed);
} }

View file

@ -14,7 +14,14 @@ impl<T: ?Sized> Clone for Ptr<T> {
} }
impl<T: ?Sized> Copy for Ptr<T> {} impl<T: ?Sized> Copy for Ptr<T> {}
// Ptr is just a pointer - Send/Sync depends on T impl<T: ?Sized> PartialEq for Ptr<T> {
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<T: ?Sized> Eq for Ptr<T> {}
unsafe impl<T: ?Sized + Send> Send for Ptr<T> {} unsafe impl<T: ?Sized + Send> Send for Ptr<T> {}
unsafe impl<T: ?Sized + Sync> Sync for Ptr<T> {} unsafe impl<T: ?Sized + Sync> Sync for Ptr<T> {}

View file

@ -722,6 +722,27 @@ impl DevicePiecewiseConstant1D {
self.n self.n
} }
fn find_interval(&self, u: Float) -> usize {
let mut size = self.n as usize;
let mut first = 0;
while size > 0 {
let half = size >> 1;
let middle = first + half;
let cdf_val = unsafe { *self.cdf.add(middle) };
if cdf_val <= u {
first = middle + 1;
size -= half + 1;
} else {
size = half;
}
}
(first - 1).clamp(0, self.n as usize - 1)
}
pub fn sample(&self, u: Float) -> (Float, Float, usize) { pub fn sample(&self, u: Float) -> (Float, Float, usize) {
// Find offset via binary search on CDF // Find offset via binary search on CDF
let offset = self.find_interval(u); let offset = self.find_interval(u);
@ -766,12 +787,12 @@ impl DevicePiecewiseConstant2D {
// } // }
pub fn integral(&self) -> f32 { pub fn integral(&self) -> f32 {
self.p_marginal.integral() self.marginal.integral()
} }
pub fn sample(&self, u: Point2f) -> (Point2f, f32, Point2i) { pub fn sample(&self, u: Point2f) -> (Point2f, f32, Point2i) {
let (d1, pdf1, off_y) = self.p_marginal.sample(u.y()); let (d1, pdf1, off_y) = self.marginal.sample(u.y());
let (d0, pdf0, off_x) = self.p_conditional_v[off_y].sample(u.x()); let (d0, pdf0, off_x) = (unsafe { &*self.conditional.add(off_y) }).sample(u.x());
let pdf = pdf0 * pdf1; let pdf = pdf0 * pdf1;
let offset = Point2i::new(off_x as i32, off_y as i32); let offset = Point2i::new(off_x as i32, off_y as i32);
(Point2f::new(d0, d1), pdf, offset) (Point2f::new(d0, d1), pdf, offset)
@ -779,13 +800,13 @@ impl DevicePiecewiseConstant2D {
pub fn pdf(&self, p: Point2f) -> Float { pub fn pdf(&self, p: Point2f) -> Float {
// Find which row // Find which row
let delta_v = 1.0 / self.n_v as Float; // let delta_v = 1.0 / self.n_v as Float;
let v_offset = ((p.y() * self.n_v as Float) as usize).min(self.n_v 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.conditional.add(v_offset) }; let conditional = unsafe { &*self.conditional.add(v_offset) };
// Find which column // Find which column
let delta_u = 1.0 / self.n_u as Float; // let delta_u = 1.0 / self.n_u as Float;
let u_offset = ((p.x() * self.n_u as Float) as usize).min(self.n_u as usize - 1); let u_offset = ((p.x() * self.n_u as Float) as usize).min(self.n_u as usize - 1);
let func_val = unsafe { *conditional.func.add(u_offset) }; let func_val = unsafe { *conditional.func.add(u_offset) };
@ -1279,7 +1300,7 @@ impl<const N: usize> PiecewiseLinear2D<N> {
#[inline(always)] #[inline(always)]
fn get_param_value(&self, dim: usize, idx: usize) -> Float { fn get_param_value(&self, dim: usize, idx: usize) -> Float {
// Safety: Bounds checking against param_size ensures this is valid // Safety: Bounds checking against param_size ensures this is valid
unsafe { *self.param_values[dim].0.add(idx) } unsafe { *self.param_values[dim].add(idx) }
} }
fn get_slice_info(&self, params: [Float; N]) -> (u32, [(Float, Float); N]) { fn get_slice_info(&self, params: [Float; N]) -> (u32, [(Float, Float); N]) {
@ -1341,7 +1362,7 @@ impl<const N: usize> PiecewiseLinear2D<N> {
current_mask >>= 1; current_mask >>= 1;
} }
let idx = (i0 + offset) as usize; let idx = (i0 + offset) as usize;
let val = unsafe { *data.0.add(idx) }; let val = unsafe { *data.add(idx) };
result += weight * val; result += weight * val;
} }
result result

View file

@ -1,11 +1,10 @@
use crate::Float;
use crate::core::geometry::{Bounds3f, Point3f, Ray, Vector3f};
use crate::core::primitive::PrimitiveTrait; use crate::core::primitive::PrimitiveTrait;
use crate::core::shape::ShapeIntersection;
use crate::utils::math::encode_morton_3;
use crate::utils::math::next_float_down;
use crate::utils::{find_interval, partition_slice};
use rayon::prelude::*; use rayon::prelude::*;
use shared::Float;
use shared::core::geometry::{Bounds3f, Point3f, Ray, Vector3f};
use shared::core::shape::ShapeIntersection;
use shared::utils::math::encode_morton_3;
use shared::utils::{find_interval, partition_slice};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};

View file

@ -88,6 +88,7 @@ pub trait CameraFactory {
medium: Medium, medium: Medium,
film: Arc<Film>, film: Arc<Film>,
loc: &FileLoc, loc: &FileLoc,
arena: &mut Arena,
) -> Result<Self, String>; ) -> Result<Self, String>;
} }

View file

@ -1,4 +1,10 @@
use shared::film::{Film, FilmBase, GBufferFilm, PixelSensor, RGBFilm, SpectralFilm}; use shared::Float;
use shared::core::spectrum::Spectrum;
use shared::film::{Film, FilmBase, GBufferFilm, PixelSensor, PixelSensor, RGBFilm, SpectralFilm};
use shared::spectra::{PiecewiseLinearSpectrum, RGBColorSpace};
use crate::spectra::DenselySampledSpectrumBuffer;
use crate::utils::{FileLoc, ParameterDictionary};
const N_SWATCH_REFLECTANCES: usize = 24; const N_SWATCH_REFLECTANCES: usize = 24;
const SWATCH_REFLECTANCES: Lazy<[Spectrum; N_SWATCH_REFLECTANCES]> = Lazy::new(|| { const SWATCH_REFLECTANCES: Lazy<[Spectrum; N_SWATCH_REFLECTANCES]> = Lazy::new(|| {
@ -10,7 +16,7 @@ const SWATCH_REFLECTANCES: Lazy<[Spectrum; N_SWATCH_REFLECTANCES]> = Lazy::new(|
}); });
pub trait PixelSensorHost { pub trait PixelSensorHost {
pub fn get_swatches() -> &[Spectrum; N_SWATCH_REFLECTANCES] { pub fn get_swatches() -> &'static [Spectrum; N_SWATCH_REFLECTANCES] {
&*SWATCH_REFLECTANCES &*SWATCH_REFLECTANCES
} }
@ -29,9 +35,9 @@ pub trait PixelSensorHost {
let imaging_ratio = exposure_time * iso / 100.; let imaging_ratio = exposure_time * iso / 100.;
let d_illum = if white_balance_temp == 0. { let d_illum = if white_balance_temp == 0. {
generate_cie_d(6500.) DenselySampledSpectrumBuffer::generate_cie_d(6500.)
} else { } else {
generate_cie_d(white_balance_temp) DenselySampledSpectrumBuffer::generate_cie_d(white_balance_temp)
}; };
let sensor_illum: Option<Arc<Spectrum>> = if white_balance_temp != 0. { let sensor_illum: Option<Arc<Spectrum>> = if white_balance_temp != 0. {
@ -73,7 +79,103 @@ pub trait PixelSensorHost {
.map_err(|e| e.to_string()); .map_err(|e| e.to_string());
} }
} }
fn new(
r: Spectrum,
g: Spectrum,
b: Spectrum,
output_colorspace: RGBColorSpace,
sensor_illum: &Spectrum,
imaging_ratio: Float,
spectra: *const StandardSpectra,
swatches: &[Spectrum; 24],
) -> Self {
// As seen in usages of this constructos, sensor_illum can be null
// Going with the colorspace's own illuminant, but this might not be the right choice
// TODO: Test this
let illum: &Spectrum = match sensor_illum {
Some(arc_illum) => &**arc_illum,
None => &output_colorspace.illuminant,
};
let r_bar = DenselySampledSpectrum::from_spectrum(&r);
let g_bar = DenselySampledSpectrum::from_spectrum(&g);
let b_bar = DenselySampledSpectrum::from_spectrum(&b);
let mut rgb_camera = [[0.; 3]; Self::N_SWATCH_REFLECTANCES];
let swatches = Self::get_swatches();
for i in 0..Self::N_SWATCH_REFLECTANCES {
let rgb = Self::project_reflectance::<RGB>(
&swatches[i],
illum,
&Spectrum::Dense(r_bar.clone()),
&Spectrum::Dense(g_bar.clone()),
&Spectrum::Dense(b_bar.clone()),
);
for c in 0..3 {
rgb_camera[i][c] = rgb[c];
} }
}
let mut xyz_output = [[0.; 3]; Self::N_SWATCH_REFLECTANCES];
let sensor_white_g = illum.inner_product(&Spectrum::Dense(g_bar.clone()));
let sensor_white_y = illum.inner_product(spectra.y);
for i in 0..Self::N_SWATCH_REFLECTANCES {
let s = swatches[i].clone();
let xyz = Self::project_reflectance::<XYZ>(
&s,
&Spectrum::Dense(output_colorspace.illuminant),
spectra.x,
spectra.y,
spectra.z,
) * (sensor_white_y / sensor_white_g);
for c in 0..3 {
xyz_output[i][c] = xyz[c];
}
}
let xyz_from_sensor_rgb = linear_least_squares(rgb_camera, xyz_output)?;
Ok(Self {
xyz_from_sensor_rgb,
r_bar,
g_bar,
b_bar,
imaging_ratio,
})
}
fn new_with_white_balance(
output_colorspace: &RGBColorSpace,
sensor_illum: &Spectrum,
imaging_ratio: Float,
spectra: *const StandardSpectra,
) -> Self {
let r_bar = DenselySampledSpectrumBuffer::from_spectrum(spectra.x);
let g_bar = DenselySampledSpectrumBuffer::from_spectrum(spectra.y);
let b_bar = DenselySampledSpectrumBuffer::from_spectrum(spectra.z);
let xyz_from_sensor_rgb: SquareMatrix<Float, 3>;
if let Some(illum) = sensor_illum {
let source_white = illum.to_xyz(spectra).xy();
let target_white = output_colorspace.w;
xyz_from_sensor_rgb = white_balance(source_white, target_white);
} else {
xyz_from_sensor_rgb = SquareMatrix::<Float, 3>::default();
}
Self {
xyz_from_sensor_rgb,
r_bar,
g_bar,
b_bar,
imaging_ratio,
}
}
}
impl PixelSensorHost for PixelSensor {}
struct SpectralFilmStorage { struct SpectralFilmStorage {
pixels: Array2D<SpectralPixel>, pixels: Array2D<SpectralPixel>,
@ -164,6 +266,39 @@ impl SpectralFilmHost {
} }
} }
impl GBufferFilmHost {
pub fn new(
base: &FilmBase,
output_from_render: &AnimatedTransform,
apply_inverse: bool,
colorspace: &RGBColorSpace,
max_component_value: Float,
write_fp16: bool,
) -> Self {
assert!(!base.pixel_bounds.is_empty());
let sensor_ptr = base.sensor;
if sensor_ptr.is_null() {
panic!("Film must have a sensor");
}
let sensor = unsafe { &*sensor_ptr };
let output_rgbf_from_sensor_rgb = colorspace.rgb_from_xyz * sensor.xyz_from_sensor_rgb;
let filter_integral = base.filter.integral();
let pixels = Array2D::new(base.pixel_bounds);
Self {
base: base.clone(),
output_from_render: output_from_render.clone(),
apply_inverse,
pixels,
colorspace: colorspace.clone(),
max_component_value,
write_fp16,
filter_integral,
output_rgbf_from_sensor_rgb,
}
}
}
pub trait FilmBaseHost { pub trait FilmBaseHost {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,

View file

@ -1,3 +1,5 @@
use shared::core::filter::FilterSampler;
use shared::core::geometry::Point2f;
use shared::filter::Filter; use shared::filter::Filter;
use shared::filters::*; use shared::filters::*;
@ -46,3 +48,37 @@ impl FilterFactory for Filter {
} }
} }
} }
pub trait CreateFilterSampler {
fn new<F>(radius: Vector2f, func: F) -> Self
where
F: Fn(Point2f) -> Float;
}
impl CreateFilterSampler for FilterSampler {
fn new<F>(radius: Vector2f, func: F) -> Self
where
F: Fn(Point2f) -> Float,
{
let domain = Bounds2f::from_points(
Point2f::new(-radius.x(), -radius.y()),
Point2f::new(radius.x(), radius.y()),
);
let nx = (32.0 * radius.x()) as usize;
let ny = (32.0 * radius.y()) as usize;
let mut f = Array2D::new_with_dims(nx, ny);
for y in 0..f.y_size() {
for x in 0..f.x_size() {
let p = domain.lerp(Point2f::new(
(x as Float + 0.5) / f.x_size() as Float,
(y as Float + 0.5) / f.y_size() as Float,
));
f[(x as i32, y as i32)] = func(p);
}
}
let distrib = DevicePiecewiseConstant2D::new_with_bounds(&f, domain);
Self { domain, f, distrib }
}
}

View file

@ -1,12 +1,11 @@
use super::{Image, ImageAndMetadata}; use super::{Image, ImageAndMetadata};
use crate::core::image::PixelStorage;
use crate::utils::error::ImageError; use crate::utils::error::ImageError;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use exr::prelude::{read_first_rgba_layer_from_file, write_rgba_file}; use exr::prelude::{read_first_rgba_layer_from_file, write_rgba_file};
use image_rs::ImageReader; use image_rs::{DynamicImage, ImageReader};
use image_rs::{DynamicImage, ImageBuffer, Rgb, Rgba};
use shared::Float; use shared::Float;
use shared::core::color::{ColorEncoding, LINEAR, SRGB}; use shared::core::color::{ColorEncoding, LINEAR, SRGB};
use shared::core::image::DeviceImage;
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Read, Write}; use std::io::{BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path; use std::path::Path;
@ -182,12 +181,12 @@ impl ImageIO for Image {
fn to_u8_buffer(&self) -> Vec<u8> { fn to_u8_buffer(&self) -> Vec<u8> {
match &self.pixels { match &self.pixels {
PixelData::U8(data) => data.clone(), PixelStorage::U8(data) => data.clone(),
PixelData::F16(data) => data PixelStorage::F16(data) => data
.iter() .iter()
.map(|v| (v.to_f32().clamp(0.0, 1.0) * 255.0 + 0.5) as u8) .map(|v| (v.to_f32().clamp(0.0, 1.0) * 255.0 + 0.5) as u8)
.collect(), .collect(),
PixelData::F32(data) => data PixelStorage::F32(data) => data
.iter() .iter()
.map(|v| (v.clamp(0.0, 1.0) * 255.0 + 0.5) as u8) .map(|v| (v.clamp(0.0, 1.0) * 255.0 + 0.5) as u8)
.collect(), .collect(),
@ -205,41 +204,27 @@ fn read_generic(path: &Path, encoding: Option<ColorEncoding>) -> Result<ImageAnd
let res = Point2i::new(w, h); let res = Point2i::new(w, h);
// Check if it was loaded as high precision or standard // Check if it was loaded as high precision or standard
let rgb_names = || vec!["R".to_string(), "G".to_string(), "B".to_string()];
let rgba_names = || {
vec![
"R".to_string(),
"G".to_string(),
"B".to_string(),
"A".to_string(),
]
};
let image = match dyn_img { let image = match dyn_img {
DynamicImage::ImageRgb32F(buf) => Image { DynamicImage::ImageRgb32F(buf) => Image::from_f32(buf.into_raw(), res, rgb_names()),
format: PixelFormat::F32, DynamicImage::ImageRgba32F(buf) => Image::from_f32(buf.into_raw(), res, rgba_names()),
resolution: res,
channel_names: vec!["R".into(), "G".into(), "B".into()],
encoding: LINEAR,
pixels: PixelData::F32(buf.into_raw()),
},
DynamicImage::ImageRgba32F(buf) => Image {
format: PixelFormat::F32,
resolution: res,
channel_names: vec!["R".into(), "G".into(), "B".into(), "A".into()],
encoding: LINEAR,
pixels: PixelData::F32(buf.into_raw()),
},
_ => { _ => {
// Default to RGB8 for everything else // Default to RGB8 for everything else
let enc = encoding.unwrap_or(ColorEncoding::sRGB);
if dyn_img.color().has_alpha() { if dyn_img.color().has_alpha() {
let buf = dyn_img.to_rgba8(); let buf = dyn_img.to_rgba8();
Image { Image::from_u8(buf.into_raw(), res, rgba_names(), enc)
format: PixelFormat::U8,
resolution: res,
channel_names: vec!["R".into(), "G".into(), "B".into(), "A".into()],
encoding: encoding.unwrap_or(SRGB),
pixels: PixelData::U8(buf.into_raw()),
}
} else { } else {
let buf = dyn_img.to_rgb8(); let buf = dyn_img.to_rgb8();
Image { Image::from_u8(buf.into_raw(), res, rgb_names(), enc)
format: PixelFormat::U8,
resolution: res,
channel_names: vec!["R".into(), "G".into(), "B".into()],
encoding: encoding.unwrap_or(SRGB),
pixels: PixelData::U8(buf.into_raw()),
}
} }
} }
}; };
@ -275,7 +260,7 @@ fn read_exr(path: &Path) -> Result<ImageAndMetadata> {
resolution: Point2i::new(w, h), resolution: Point2i::new(w, h),
channel_names: vec!["R".into(), "G".into(), "B".into(), "A".into()], channel_names: vec!["R".into(), "G".into(), "B".into(), "A".into()],
encoding: LINEAR, encoding: LINEAR,
pixels: PixelData::F32(image.layer_data.channel_data.pixels), pixels: PixelStorage::F32(image.layer_data.channel_data.pixels),
}; };
let metadata = ImageMetadata::default(); let metadata = ImageMetadata::default();
@ -360,7 +345,7 @@ fn read_pfm(path: &Path) -> Result<ImageAndMetadata> {
resolution: Point2i::new(w, h), resolution: Point2i::new(w, h),
channel_names: names, channel_names: names,
encoding: LINEAR, encoding: LINEAR,
pixels: PixelData::F32(pixels), pixels: PixelStorage::F32(pixels),
}; };
let metadata = ImageMetadata::default(); let metadata = ImageMetadata::default();

View file

@ -1,11 +1,11 @@
use crate::core::geometry::{Bounds2i, Point2i}; use shared::Float;
use crate::core::pbrt::Float; use shared::core::geometry::{Bounds2i, Point2i};
use crate::spectra::colorspace::RGBColorSpace; use shared::spectra::RGBColorSpace;
use crate::utils::math::SquareMatrix; use shared::utils::math::SquareMatrix;
use smallvec::SmallVec;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Deref, DerefMut}; // use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct ImageChannelDesc { pub struct ImageChannelDesc {
pub offset: Vec<usize>, pub offset: Vec<usize>,

View file

@ -1,6 +1,7 @@
use half::f16;
use shared::core::geometry::Point2i; use shared::core::geometry::Point2i;
use shared::core::image::{DeviceImage, ImageAccess, ImageBase, PixelFormat, WrapMode}; use shared::core::image::{DeviceImage, ImageAccess, ImageBase, PixelFormat, WrapMode};
use shared::utils::math::f16_to_f32; use smallvec::smallvec;
use std::ops::Deref; use std::ops::Deref;
pub mod io; pub mod io;
@ -11,16 +12,6 @@ pub mod pixel;
pub use io::ImageIO; pub use io::ImageIO;
pub use metadata::*; pub use metadata::*;
impl std::fmt::Display for PixelFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PixelFormat::U8 => write!(f, "U256"),
PixelFormat::F16 => write!(f, "Half"),
PixelFormat::F32 => write!(f, "Float"),
}
}
}
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct ImageChannelValues(pub SmallVec<[Float; 4]>); pub struct ImageChannelValues(pub SmallVec<[Float; 4]>);

View file

@ -1,5 +1,5 @@
// use rayon::prelude::*;
use super::Image; use super::Image;
use crate::core::image::PixelStorage;
use rayon::prelude::*; use rayon::prelude::*;
use shared::Float; use shared::Float;
use shared::core::geometry::{Bounds2i, Point2i}; use shared::core::geometry::{Bounds2i, Point2i};
@ -19,9 +19,9 @@ impl Image {
let nc = self.n_channels(); let nc = self.n_channels();
match &mut self.pixels { match &mut self.pixels {
PixelData::U8(d) => flip_y_kernel(d, res, nc), PixelStorage::U8(d) => flip_y_kernel(d, res, nc),
PixelData::F16(d) => flip_y_kernel(d, res, nc), PixelStorage::F16(d) => flip_y_kernel(d, res, nc),
PixelData::F32(d) => flip_y_kernel(d, res, nc), PixelStorage::F32(d) => flip_y_kernel(d, res, nc),
} }
} }
@ -39,13 +39,13 @@ impl Image {
); );
match (&self.pixels, &mut new_image.pixels) { match (&self.pixels, &mut new_image.pixels) {
(PixelData::U8(src), PixelData::U8(dst)) => { (PixelStorage::U8(src), PixelStorage::U8(dst)) => {
crop_kernel(src, dst, self.resolution, bounds, self.n_channels()) crop_kernel(src, dst, self.resolution, bounds, self.n_channels())
} }
(PixelData::F16(src), PixelData::F16(dst)) => { (PixelStorage::F16(src), PixelStorage::F16(dst)) => {
crop_kernel(src, dst, self.resolution, bounds, self.n_channels()) crop_kernel(src, dst, self.resolution, bounds, self.n_channels())
} }
(PixelData::F32(src), PixelData::F32(dst)) => { (PixelStorage::F32(src), PixelStorage::F32(dst)) => {
crop_kernel(src, dst, self.resolution, bounds, self.n_channels()) crop_kernel(src, dst, self.resolution, bounds, self.n_channels())
} }
_ => panic!("Format mismatch in crop"), _ => panic!("Format mismatch in crop"),
@ -56,9 +56,9 @@ impl Image {
pub fn copy_rect_out(&self, extent: Bounds2i, buf: &mut [Float], wrap: WrapMode2D) { pub fn copy_rect_out(&self, extent: Bounds2i, buf: &mut [Float], wrap: WrapMode2D) {
match &self.pixels { match &self.pixels {
PixelData::U8(d) => copy_rect_out_kernel(d, self, extent, buf, wrap), PixelStorage::U8(d) => copy_rect_out_kernel(d, self, extent, buf, wrap),
PixelData::F16(d) => copy_rect_out_kernel(d, self, extent, buf, wrap), PixelStorage::F16(d) => copy_rect_out_kernel(d, self, extent, buf, wrap),
PixelData::F32(d) => copy_rect_out_kernel(d, self, extent, buf, wrap), PixelStorage::F32(d) => copy_rect_out_kernel(d, self, extent, buf, wrap),
} }
} }
@ -68,13 +68,13 @@ impl Image {
let encoding = self.encoding; let encoding = self.encoding;
match &mut self.pixels { match &mut self.pixels {
PixelData::U8(d) => { PixelStorage::U8(d) => {
copy_rect_in_kernel(d, resolution, n_channels, encoding, extent, buf) copy_rect_in_kernel(d, resolution, n_channels, encoding, extent, buf)
} }
PixelData::F16(d) => { PixelStorage::F16(d) => {
copy_rect_in_kernel(d, resolution, n_channels, encoding, extent, buf) copy_rect_in_kernel(d, resolution, n_channels, encoding, extent, buf)
} }
PixelData::F32(d) => { PixelStorage::F32(d) => {
copy_rect_in_kernel(d, resolution, n_channels, encoding, extent, buf) copy_rect_in_kernel(d, resolution, n_channels, encoding, extent, buf)
} }
} }
@ -154,9 +154,9 @@ impl Image {
); );
match &mut next.pixels { match &mut next.pixels {
PixelData::U8(d) => downsample_kernel(d, new_res, prev, internal_wrap), PixelStorage::U8(d) => downsample_kernel(d, new_res, prev, internal_wrap),
PixelData::F16(d) => downsample_kernel(d, new_res, prev, internal_wrap), PixelStorage::F16(d) => downsample_kernel(d, new_res, prev, internal_wrap),
PixelData::F32(d) => downsample_kernel(d, new_res, prev, internal_wrap), PixelStorage::F32(d) => downsample_kernel(d, new_res, prev, internal_wrap),
} }
levels.push(next); levels.push(next);
} }

View file

@ -1,16 +1,16 @@
use crate::core::spectrum::{SPECTRUM_CACHE, spectrum_to_photometric}; use crate::core::spectrum::SPECTRUM_CACHE;
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::lights::*; use crate::lights::*;
use crate::utils::containers::InternCache; use crate::utils::containers::InternCache;
use crate::utils::{Arena, FileLoc, ParameterDictionary, Upload, resolve_filename}; use crate::utils::{Arena, FileLoc, ParameterDictionary};
use log::error;
use shared::core::camera::CameraTransform; use shared::core::camera::CameraTransform;
use shared::core::light::Light; use shared::core::light::Light;
use shared::core::medium::Medium; use shared::core::medium::Medium;
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;
use shared::core::texture::SpectrumType;
use shared::lights::*; use shared::lights::*;
use shared::spectra::{DenselySampledSpectrum, RGBColorSpace}; use shared::spectra::{DenselySampledSpectrum, RGBColorSpace};
use shared::utils::{Ptr, Transform}; use shared::utils::Transform;
pub fn lookup_spectrum(s: &Spectrum) -> DenselySampledSpectrum { pub fn lookup_spectrum(s: &Spectrum) -> DenselySampledSpectrum {
let cache = SPECTRUM_CACHE.get_or_init(InternCache::new); let cache = SPECTRUM_CACHE.get_or_init(InternCache::new);
@ -120,7 +120,7 @@ impl LightFactory for Light {
alpha_tex, alpha_tex,
colorspace, colorspace,
)?, )?,
"infinite" => infinite::create( "infinite" => crate::lights::infinite::create(
arena, arena,
render_from_light, render_from_light,
medium, medium,

View file

@ -1,6 +1,7 @@
use crate::Arena;
use crate::core::image::Image; use crate::core::image::Image;
use crate::utils::TextureParameterDictionary;
use crate::utils::error::FileLoc; use crate::utils::error::FileLoc;
use crate::utils::parameters::ParameterDictionary;
use shared::core::material::Material; use shared::core::material::Material;
use shared::materials::*; use shared::materials::*;
use std::collections::HashMap; use std::collections::HashMap;
@ -11,6 +12,7 @@ pub trait CreateMaterial: Sized {
normal_map: Option<Ptr<Image>>, normal_map: Option<Ptr<Image>>,
named_materials: &HashMap<String, Material>, named_materials: &HashMap<String, Material>,
loc: &FileLoc, loc: &FileLoc,
arena: &mut Arena,
) -> Result<Self, Error>; ) -> Result<Self, Error>;
} }
@ -38,6 +40,7 @@ pub trait MaterialFactory {
normal_map: Ptr<Image>, normal_map: Ptr<Image>,
named_materials: HashMap<String, Material>, named_materials: HashMap<String, Material>,
loc: &FileLoc, loc: &FileLoc,
arena: &mut Arena,
) -> Result<Self, Error>; ) -> Result<Self, Error>;
} }
@ -48,7 +51,8 @@ impl MaterialFactory for Material {
normal_map: Option<Arc<Image>>, normal_map: Option<Arc<Image>>,
named_materials: &HashMap<String, Material>, named_materials: &HashMap<String, Material>,
loc: &FileLoc, loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
make_material_factory!( make_material_factory!(
name, params, normal_map, named_materials, loc; name, params, normal_map, named_materials, loc;

View file

@ -7,6 +7,7 @@ pub mod filter;
pub mod image; pub mod image;
pub mod light; pub mod light;
pub mod material; pub mod material;
pub mod medium;
pub mod sampler; pub mod sampler;
pub mod sampler; pub mod sampler;
pub mod scene; pub mod scene;

View file

@ -1,12 +1,24 @@
use shared::core::sampler::Sampler; use shared::core::sampler::Sampler;
use crate::Arena;
pub trait CreateSampler {
fn create(
params: &ParameterDictionary,
full_res: Point2i,
loc: &FileLoc,
arena: &mut Arena,
) -> Result<Self, Error>;
}
pub trait SamplerFactory { pub trait SamplerFactory {
fn create( fn create(
name: &str, name: &str,
params: &ParameterDictionary, params: &ParameterDictionary,
full_res: Point2i, full_res: Point2i,
loc: &FileLoc, loc: &FileLoc,
) -> Result<Self, String>; arena: &mut Arena,
) -> Result<Self, Error>;
} }
impl SamplerFactory for Sampler { impl SamplerFactory for Sampler {
@ -15,30 +27,31 @@ impl SamplerFactory for Sampler {
params: &ParameterDictionary, params: &ParameterDictionary,
full_res: Point2i, full_res: Point2i,
loc: &FileLoc, loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
match name { match name {
"zsobol" => { "zsobol" => {
let sampler = ZSobolSampler::create(params, full_res, loc)?; let sampler = ZSobolSampler::create(params, full_res, loc, arena)?;
Ok(Sampler::ZSobol(sampler)) Ok(Sampler::ZSobol(sampler))
} }
"paddedsobol" => { "paddedsobol" => {
let sampler = PaddedSobolSampler::create(params, full_res, loc)?; let sampler = PaddedSobolSampler::create(params, full_res, loc, arena)?;
Ok(Sampler::PaddedSobol(sampler)) Ok(Sampler::PaddedSobol(sampler))
} }
"halton" => { "halton" => {
let sampler = HaltonSampler::create(params, full_res, loc)?; let sampler = HaltonSampler::create(params, full_res, loc, arena)?;
Ok(Sampler::Halton(sampler)) Ok(Sampler::Halton(sampler))
} }
"sobol" => { "sobol" => {
let sampler = SobolSampler::create(params, full_res, loc)?; let sampler = SobolSampler::create(params, full_res, loc, arena)?;
Ok(Sampler::Sobol(sampler)) Ok(Sampler::Sobol(sampler))
} }
"Independent" => { "Independent" => {
let sampler = IndependentSampler::create(params, full_res, loc)?; let sampler = IndependentSampler::create(params, full_res, loc, arena)?;
Ok(Sampler::Independent(sampler)) Ok(Sampler::Independent(sampler))
} }
"stratified" => { "stratified" => {
let sampler = StratifiedSampler::create(params, full_res, loc)?; let sampler = StratifiedSampler::create(params, full_res, loc, arena)?;
Ok(Sampler::Stratified(sampler)) Ok(Sampler::Stratified(sampler))
} }
_ => Err(format!("Film type '{}' unknown at {}", name, loc)), _ => Err(format!("Film type '{}' unknown at {}", name, loc)),

View file

@ -12,27 +12,27 @@ use image_rs::Primitive;
use parking_lot::Mutex; use parking_lot::Mutex;
use shared::Float; use shared::Float;
use shared::core::camera::{Camera, CameraTransform}; use shared::core::camera::{Camera, CameraTransform};
use shared::core::color::LINEAR; // use shared::core::color::LINEAR;
use shared::core::film::{Film, FilmTrait}; use shared::core::film::{Film, FilmTrait};
use shared::core::filter::Filter; use shared::core::filter::Filter;
use shared::core::geometry::{Point3f, Vector3f}; use shared::core::geometry::Vector3f;
use shared::core::lights::Light; use shared::core::lights::Light;
use shared::core::material::Material; use shared::core::material::Material;
use shared::core::medium::{Medium, MediumInterface}; use shared::core::medium::{Medium, MediumInterface};
use shared::core::options::RenderingCoordinateSystem; use shared::core::options::RenderingCoordinateSystem;
use shared::core::primitive::{Primitive, PrimitiveTrait}; use shared::core::primitive::PrimitiveTrait;
use shared::core::sampler::Sampler; use shared::core::sampler::Sampler;
use shared::core::spectrum::{Spectrum, SpectrumType}; use shared::core::spectrum::SpectrumType;
use shared::core::texture::{FloatTexture, SpectrumTexture}; use shared::core::texture::{FloatTexture, SpectrumTexture};
use shared::images::Image; use shared::images::Image;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::error::FileLoc; use shared::utils::error::FileLoc;
use shared::utils::math::SquareMatrix; // use shared::utils::math::SquareMatrix;
use shared::utils::transform::{AnimatedTransform, Transform, look_at}; use shared::utils::transform::{AnimatedTransform, Transform, look_at};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ops::{Index as IndexTrait, IndexMut as IndexMutTrait}; use std::ops::{Index as IndexTrait, IndexMut as IndexMutTrait};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicI32, Ordering}; // use std::sync::atomic::{AtomicI32, Ordering};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum MaterialRef { pub enum MaterialRef {
@ -1000,6 +1000,7 @@ struct GraphicsState {
pub current_inside_medium: String, pub current_inside_medium: String,
pub current_outside_medium: String, pub current_outside_medium: String,
pub current_material_name: String, pub current_material_name: String,
pub current_material_index: Option<usize>,
pub area_light_name: String, pub area_light_name: String,
pub area_light_params: ParsedParameterVector, pub area_light_params: ParsedParameterVector,
pub area_light_loc: FileLoc, pub area_light_loc: FileLoc,
@ -1064,6 +1065,7 @@ impl BasicSceneBuilder {
named_coordinate_systems: HashMap::new(), named_coordinate_systems: HashMap::new(),
active_instance_definition: None, active_instance_definition: None,
shapes: Vec::new(), shapes: Vec::new(),
animated_shapes: Vec::new(),
named_material_names: HashSet::new(), named_material_names: HashSet::new(),
medium_names: HashSet::new(), medium_names: HashSet::new(),
@ -1526,8 +1528,9 @@ impl ParserTarget for BasicSceneBuilder {
} }
} }
fn material(&mut self, _name: &str, _params: &ParsedParameterVector, _loc: FileLoc) { fn material(&mut self, _name: &str, _params: &ParsedParameterVector, loc: FileLoc) {
todo!() self.verify_world("material", loc);
self.graphics_state.current_material_name = self.scene.add_material(name, material)
} }
fn make_named_material(&mut self, _name: &str, _params: &ParsedParameterVector, _loc: FileLoc) { fn make_named_material(&mut self, _name: &str, _params: &ParsedParameterVector, _loc: FileLoc) {
todo!() todo!()

View file

@ -1,16 +1,15 @@
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::shapes::TriQuadMesh; use crate::shapes::{BilinearPatchMeshHost, TriQuadMesh, TriangleMeshHost};
use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename}; use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename};
use shared::core::options::get_options; use shared::core::options::get_options;
use shared::core::shape::*; use shared::core::shape::*;
use shared::shapes::*; use shared::shapes::*;
use shared::spectra::*; // use shared::spectra::*;
use shared::utils::Transform; use shared::utils::Transform;
use shared::utils::mesh::{BilinearPatchMesh, TriangleMesh};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
pub static ALL_TRIANGLE_MESHES: Mutex<Vec<Arc<TriangleMeshHost>>> = Mutex::new(Vec::new()); pub static ALL_TRIANGLE_MESHES: Mutex<Vec<Arc<TriangleMeshHost>>> = Mutex::new(Vec::new());
pub static ALL_TRIANGLE_MESHES: Mutex<Vec<Arc<BilinearPatchMeshHost>>> = Mutex::new(Vec::new()); pub static ALL_BILINEAR_MESHES: Mutex<Vec<Arc<BilinearPatchMeshHost>>> = Mutex::new(Vec::new());
pub trait CreateShape { pub trait CreateShape {
fn create( fn create(

View file

@ -2,7 +2,6 @@ use crate::core::light::LightBaseTrait;
use crate::spectra::cie_y; use crate::spectra::cie_y;
use crate::utils::containers::InternCache; use crate::utils::containers::InternCache;
use shared::Float; use shared::Float;
use shared::core::light::LightBase;
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;
pub static SPECTRUM_CACHE: Lazy<Mutex<HashMap<String, Spectrum>>> = pub static SPECTRUM_CACHE: Lazy<Mutex<HashMap<String, Spectrum>>> =

View file

@ -1,7 +1,7 @@
use crate::textures::*; use crate::textures::*;
use crate::utils::FileLoc;
use crate::utils::mipmap::MIPMapFilterOptions; use crate::utils::mipmap::MIPMapFilterOptions;
use crate::utils::{FileLoc, TextureParameterDictionary}; use crate::utils::{Arena, FileLoc, TextureParameterDictionary};
use enum_dispatch::enum_dispatch;
use shared::textures::*; use shared::textures::*;
use shared::utils::Transform; use shared::utils::Transform;
use std::sync::{Arc, Mutex, OnceLock}; use std::sync::{Arc, Mutex, OnceLock};
@ -29,19 +29,25 @@ impl FloatTexture {
render_from_texture: &Transform, render_from_texture: &Transform,
params: &TextureParameterDictionary, params: &TextureParameterDictionary,
loc: &FileLoc, loc: &FileLoc,
arena: &mut Arena,
) -> Result<Self, String> { ) -> Result<Self, String> {
match name { match name {
"constant" => { "constant" => {
let tex = FloatConstantTexture::create(render_from_texture, params, loc); let tex = FloatConstantTexture::create(render_from_texture, params, loc);
Ok(FloatTexture::Constant(tex)) Ok(FloatTexture::Constant(tex))
} }
"scale" => Ok(FloatScaledTexture::create(render_from_texture, params, loc)), "scale" => Ok(FloatScaledTexture::create(
render_from_texture,
params,
loc,
arena,
)),
"mix" => { "mix" => {
let tex = FloatMixTexture::create(render_from_texture, params, loc); let tex = FloatMixTexture::create(render_from_texture, params, loc, arena);
Ok(FloatTexture::Mix(tex)) Ok(FloatTexture::Mix(tex))
} }
"directionmix" => { "directionmix" => {
let tex = FloatDirectionMixTexture::create(render_from_texture, params, loc); let tex = FloatDirectionMixTexture::create(render_from_texture, params, loc, arena);
Ok(FloatTexture::DirectionMix(tex)) Ok(FloatTexture::DirectionMix(tex))
} }
"bilerp" => { "bilerp" => {
@ -50,7 +56,7 @@ impl FloatTexture {
} }
"imagemap" => { "imagemap" => {
let tex = FloatImageTexture::create(render_from_texture, params, loc); let tex = FloatImageTexture::create(render_from_texture, params, loc);
Ok(loatTexture::Image(tex)) Ok(FloatTexture::Image(tex))
} }
"checkerboard" => { "checkerboard" => {
let tex = FloatCheckerboardTexture::create(render_from_texture, params, loc); let tex = FloatCheckerboardTexture::create(render_from_texture, params, loc);
@ -143,10 +149,11 @@ pub static TEXTURE_CACHE: OnceLock<Mutex<HashMap<TexInfo, Arc<MIPMap>>>> = OnceL
pub fn get_texture_cache() -> &'static Mutex<HashMap<TexInfo, Arc<MIPMap>>> { pub fn get_texture_cache() -> &'static Mutex<HashMap<TexInfo, Arc<MIPMap>>> {
TEXTURE_CACHE.get_or_init(|| Mutex::new(HashMap::new())) TEXTURE_CACHE.get_or_init(|| Mutex::new(HashMap::new()))
} }
#[derive(Debug, Hash, PartialEq, Eq, Clone)] #[derive(Debug, Hash, PartialEq, Eq, Clone)]
struct TexInfo { pub struct TexInfo {
filename: String, pub filename: String,
filter_options: MIPMapFilterOptions, pub filter_options: MIPMapFilterOptions,
wrap_mode: WrapMode, pub wrap_mode: WrapMode,
encoding: ColorEncoding, pub encoding: ColorEncoding,
} }

View file

@ -1,9 +1,7 @@
mod pipeline; mod pipeline;
use pipeline::*;
use shared::core::bssrdf::{BSSRDFTrait, SubsurfaceInteraction}; use shared::core::bssrdf::{BSSRDFTrait, SubsurfaceInteraction};
use shared::core::bxdf::{BSDF, BxDFFlags, BxDFReflTransFlags, BxDFTrait, FArgs, TransportMode}; use shared::core::bxdf::{BSDF, BxDFFlags, BxDFTrait, FArgs, TransportMode};
use shared::core::camera::Camera; use shared::core::camera::Camera;
use shared::core::film::VisibleSurface; use shared::core::film::VisibleSurface;
use shared::core::geometry::{Bounds2i, Point2f, Point2i, Point3fi, Ray, Vector3f, VectorLike}; use shared::core::geometry::{Bounds2i, Point2f, Point2i, Point3fi, Ray, Vector3f, VectorLike};
@ -15,7 +13,7 @@ use shared::core::medium::{MediumTrait, PhaseFunctionTrait};
use shared::core::options::get_options; use shared::core::options::get_options;
use shared::core::pbrt::{Float, SHADOW_EPSILON}; use shared::core::pbrt::{Float, SHADOW_EPSILON};
use shared::core::primitive::{Primitive, PrimitiveTrait}; use shared::core::primitive::{Primitive, PrimitiveTrait};
use shared::core::sampler::{CameraSample, Sampler, SamplerTrait}; use shared::core::sampler::{Sampler, SamplerTrait};
use shared::lights::sampler::LightSamplerTrait; use shared::lights::sampler::LightSamplerTrait;
use shared::lights::sampler::{LightSampler, UniformLightSampler}; use shared::lights::sampler::{LightSampler, UniformLightSampler};
use shared::shapes::ShapeIntersection; use shared::shapes::ShapeIntersection;
@ -30,6 +28,8 @@ use shared::utils::sampling::{
use std::sync::Arc; use std::sync::Arc;
use crate::Arena;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct IntegratorBase { pub struct IntegratorBase {
pub aggregate: Arc<Primitive>, pub aggregate: Arc<Primitive>,
@ -70,7 +70,13 @@ pub trait IntegratorTrait {
} }
pub trait RayIntegratorTrait { pub trait RayIntegratorTrait {
fn evaluate_pixel_sample(&self, p_pixel: Point2i, sample_ind: usize, sampler: &mut Sampler); fn evaluate_pixel_sample(
&self,
p_pixel: Point2i,
sample_ind: usize,
sampler: &mut Sampler,
arena: &mut Arena,
);
fn li( fn li(
&self, &self,
@ -78,6 +84,7 @@ pub trait RayIntegratorTrait {
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
visible_surface: bool, visible_surface: bool,
arena: &mut Arena,
) -> (SampledSpectrum, Option<VisibleSurface>); ) -> (SampledSpectrum, Option<VisibleSurface>);
} }
@ -201,8 +208,21 @@ impl SimplePathIntegrator {
} }
impl RayIntegratorTrait for SimplePathIntegrator { impl RayIntegratorTrait for SimplePathIntegrator {
fn evaluate_pixel_sample(&self, p_pixel: Point2i, sample_ind: usize, sampler: &mut Sampler) { fn evaluate_pixel_sample(
pipeline::evaluate_pixel_sample(self, self.camera.as_ref(), sampler, p_pixel, sample_ind); &self,
p_pixel: Point2i,
sample_ind: usize,
sampler: &mut Sampler,
arena: &mut Arena,
) {
pipeline::evaluate_pixel_sample(
self,
self.camera.as_ref(),
sampler,
p_pixel,
sample_ind,
arena,
);
} }
fn li( fn li(
@ -211,6 +231,7 @@ impl RayIntegratorTrait for SimplePathIntegrator {
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
_visible_surface: bool, _visible_surface: bool,
arena: &mut Arena,
) -> (SampledSpectrum, Option<VisibleSurface>) { ) -> (SampledSpectrum, Option<VisibleSurface>) {
let mut l = SampledSpectrum::new(0.0); let mut l = SampledSpectrum::new(0.0);
let mut beta = SampledSpectrum::new(1.0); let mut beta = SampledSpectrum::new(1.0);
@ -333,7 +354,7 @@ impl RayIntegratorTrait for PathIntegrator {
p_pixel: Point2i, p_pixel: Point2i,
sample_ind: usize, sample_ind: usize,
sampler: &mut Sampler, sampler: &mut Sampler,
scratch: &Bump, arena: &mut Arena,
) { ) {
pipeline::evaluate_pixel_sample( pipeline::evaluate_pixel_sample(
self, self,
@ -341,7 +362,7 @@ impl RayIntegratorTrait for PathIntegrator {
sampler, sampler,
p_pixel, p_pixel,
sample_ind, sample_ind,
scratch, arena,
); );
} }
@ -350,8 +371,8 @@ impl RayIntegratorTrait for PathIntegrator {
mut ray: Ray, mut ray: Ray,
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
_scratch: &Bump,
visible_surface: bool, visible_surface: bool,
_arena: &mut Arena,
) -> (SampledSpectrum, Option<VisibleSurface>) { ) -> (SampledSpectrum, Option<VisibleSurface>) {
let mut l = SampledSpectrum::new(0.0); let mut l = SampledSpectrum::new(0.0);
let mut beta = SampledSpectrum::new(1.0); let mut beta = SampledSpectrum::new(1.0);
@ -508,7 +529,7 @@ impl RayIntegratorTrait for SimpleVolPathIntegrator {
p_pixel: Point2i, p_pixel: Point2i,
sample_ind: usize, sample_ind: usize,
sampler: &mut Sampler, sampler: &mut Sampler,
scratch: &Bump, arena: &mut Arena,
) { ) {
pipeline::evaluate_pixel_sample( pipeline::evaluate_pixel_sample(
self, self,
@ -516,7 +537,7 @@ impl RayIntegratorTrait for SimpleVolPathIntegrator {
sampler, sampler,
p_pixel, p_pixel,
sample_ind, sample_ind,
scratch, arena,
); );
} }
@ -525,8 +546,8 @@ impl RayIntegratorTrait for SimpleVolPathIntegrator {
mut ray: Ray, mut ray: Ray,
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
_scratch: &Bump,
_visible_surface: bool, _visible_surface: bool,
_arena: &mut Arena,
) -> (SampledSpectrum, Option<VisibleSurface>) { ) -> (SampledSpectrum, Option<VisibleSurface>) {
let mut l = SampledSpectrum::new(0.); let mut l = SampledSpectrum::new(0.);
let mut beta = 1.; let mut beta = 1.;
@ -786,7 +807,7 @@ impl RayIntegratorTrait for VolPathIntegrator {
p_pixel: Point2i, p_pixel: Point2i,
sample_ind: usize, sample_ind: usize,
sampler: &mut Sampler, sampler: &mut Sampler,
scratch: &Bump, arena: &mut Arena,
) { ) {
pipeline::evaluate_pixel_sample( pipeline::evaluate_pixel_sample(
self, self,
@ -803,8 +824,8 @@ impl RayIntegratorTrait for VolPathIntegrator {
mut ray: Ray, mut ray: Ray,
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
scratch: &Bump,
visible_surface: bool, visible_surface: bool,
arena: &mut Arena,
) -> (SampledSpectrum, Option<VisibleSurface>) { ) -> (SampledSpectrum, Option<VisibleSurface>) {
let mut l = SampledSpectrum::new(0.); let mut l = SampledSpectrum::new(0.);
let mut beta = SampledSpectrum::new(1.); let mut beta = SampledSpectrum::new(1.);

View file

@ -1,5 +1,6 @@
use crate::core::image::Image; use crate::core::image::Image;
use crate::core::{options::PBRTOptions, sampler::get_camera_sample}; use crate::core::{options::PBRTOptions, sampler::get_camera_sample};
use crate::spectra::get_spectra_context;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
@ -66,6 +67,7 @@ pub fn render<T>(
_base: &IntegratorBase, _base: &IntegratorBase,
camera: &Camera, camera: &Camera,
sampler_prototype: &Sampler, sampler_prototype: &Sampler,
arena: &mut Arena,
) where ) where
T: RayIntegratorTrait, T: RayIntegratorTrait,
{ {
@ -76,7 +78,14 @@ pub fn render<T>(
tile_sampler.start_pixel_sample(p_pixel, s_index, None); tile_sampler.start_pixel_sample(p_pixel, s_index, None);
evaluate_pixel_sample(integrator, camera, &mut tile_sampler, p_pixel, s_index); evaluate_pixel_sample(
integrator,
camera,
&mut tile_sampler,
p_pixel,
s_index,
arena,
);
return; return;
} }
@ -142,7 +151,14 @@ pub fn render<T>(
for p_pixel in tile_bounds { for p_pixel in tile_bounds {
for sample_index in wave_start..wave_end { for sample_index in wave_start..wave_end {
sampler.start_pixel_sample(*p_pixel, sample_index, None); sampler.start_pixel_sample(*p_pixel, sample_index, None);
evaluate_pixel_sample(integrator, camera, &mut sampler, *p_pixel, sample_index); evaluate_pixel_sample(
integrator,
camera,
&mut sampler,
*p_pixel,
sample_index,
arena,
);
} }
} }
@ -202,6 +218,7 @@ pub fn evaluate_pixel_sample<T: RayIntegratorTrait>(
sampler: &mut Sampler, sampler: &mut Sampler,
pixel: Point2i, pixel: Point2i,
_sample_index: usize, _sample_index: usize,
arena: &mut Arena,
) { ) {
let mut lu = sampler.get1d(); let mut lu = sampler.get1d();
if get_options().disable_wavelength_jitter { if get_options().disable_wavelength_jitter {
@ -221,10 +238,11 @@ pub fn evaluate_pixel_sample<T: RayIntegratorTrait>(
let initialize_visible_surface = film.uses_visible_surface(); let initialize_visible_surface = film.uses_visible_surface();
let (mut l, visible_surface) = let (mut l, visible_surface) =
integrator.li(camera_ray.ray, &lambda, sampler, initialize_visible_surface); integrator.li(camera_ray.ray, &lambda, sampler, initialize_visible_surface, arena);
l *= camera_ray.weight; l *= camera_ray.weight;
if l.has_nans() || l.y(&lambda).is_infinite() { let std_spectra = get_spectra_context();
if l.has_nans() || l.y(&lambda, std_spectra).is_infinite() {
l = SampledSpectrum::new(0.); l = SampledSpectrum::new(0.);
} }

View file

@ -1,5 +1,7 @@
pub mod core; pub mod core;
pub mod filters;
pub mod globals; pub mod globals;
pub mod gpu;
pub mod integrators; pub mod integrators;
pub mod lights; pub mod lights;
pub mod materials; pub mod materials;
@ -8,3 +10,5 @@ pub mod shapes;
pub mod spectra; pub mod spectra;
pub mod textures; pub mod textures;
pub mod utils; pub mod utils;
pub use utils::arena::Arena;

View file

@ -1,22 +1,19 @@
use crate::core::image::{Image, ImageIO};
use crate::core::light::{CreateLight, lookup_spectrum};
use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::FloatTexture;
use crate::utils::{Arena, FileLoc, ParameterDictionary, Upload, resolve_filename};
use log::error;
use shared::Float; use shared::Float;
use shared::core::ligh::{Light, LightBase, LightType}; use shared::core::ligh::{Light, LightBase, LightType};
use shared::core::medium::MediumInterface; use shared::core::medium::MediumInterface;
use shared::core::shape::Shape; use shared::core::shape::Shape;
use shared::core::spectrum::{Spectrum, SpectrumTrait}; use shared::core::spectrum::{Spectrum, SpectrumTrait};
use shared::core::texture::SpectrumType; use shared::core::texture::SpectrumType;
use shared::core::texture::{FloatTextureTrait, TextureEvalContext};
use shared::lights::DiffuseAreaLight; use shared::lights::DiffuseAreaLight;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::Transform; use shared::utils::{Ptr, Transform};
use std::sync::Arc;
use crate::core::image::{Image, ImageIO};
use crate::core::light::{CreateLight, lookup_spectrum};
use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::{
FloatTexture, FloatTextureTrait, TextureEvalContext, TextureEvaluator,
UniversalTextureEvaluator,
};
use crate::utils::{Arena, FileLoc, ParameterDictionary, Upload, resolve_filename};
pub trait CreateDiffuseLight { pub trait CreateDiffuseLight {
fn new( fn new(
@ -59,7 +56,7 @@ impl CreateDiffuseLight for DiffuseAreaLight {
let base = LightBase::new(light_type, &render_from_light, &medium_interface); let base = LightBase::new(light_type, &render_from_light, &medium_interface);
let lemit = LightBase::lookup_spectrum(&le); let lemit = lookup_spectrum(&le);
if let Some(im) = &image { if let Some(im) = &image {
let desc = im let desc = im
.get_channel_desc(&["R", "G", "B"]) .get_channel_desc(&["R", "G", "B"])

View file

@ -2,13 +2,13 @@ use crate::core::light::{CreateLight, lookup_spectrum};
use crate::core::spectrum::spectrum_to_photometric; use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::utils::{Arena, FileLoc, ParameterDictionary}; use crate::utils::{Arena, FileLoc, ParameterDictionary};
use shared::core::geometry::{Vector3f, VectorLike}; use shared::core::geometry::{Point3f, Vector3f, VectorLike};
use shared::core::light::{Light, LightBase}; use shared::core::light::{Light, LightBase};
use shared::core::medium::{Medium, MediumInterface}; use shared::core::medium::{Medium, MediumInterface};
use shared::core::shape::Shape; use shared::core::shape::Shape;
use shared::lights::DistantLight; use shared::lights::DistantLight;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::{Ptr, Transform}; use shared::utils::Transform;
pub trait CreateDistantLight { pub trait CreateDistantLight {
fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self; fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self;
@ -53,7 +53,7 @@ impl CreateLight for DistantLight {
let mut scale = parameters.get_one_float("scale", 1); let mut scale = parameters.get_one_float("scale", 1);
let from = parameters.get_one_point3f("from", Point3f::new(0., 0., 0.)); let from = parameters.get_one_point3f("from", Point3f::new(0., 0., 0.));
let to = parameters.get_one_point3f("to", Point3f(0., 0., 1.)); let to = parameters.get_one_point3f("to", Point3f::new(0., 0., 1.));
let w = (from - to).normalize(); let w = (from - to).normalize();
let (v1, v2) = w.coordinate_system(); let (v1, v2) = w.coordinate_system();
let m: [Float; 16] = [ let m: [Float; 16] = [

View file

@ -1,19 +1,18 @@
use crate::core::image::{Image, ImageIO, ImageMetadata}; use crate::core::image::{Image, ImageIO};
use crate::core::light::{CreateLight, lookup_spectrum}; use crate::core::light::{CreateLight, lookup_spectrum};
use crate::core::spectrum::spectrum_to_photometric; use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::lights::distant::CreateDistantLight; use crate::lights::distant::CreateDistantLight;
use crate::utils::sampling::PiecewiseConstant2D; use crate::utils::sampling::PiecewiseConstant2D;
use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename}; use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename};
use log::error;
use shared::Float; use shared::Float;
use shared::core::image::ImageBase;
use shared::core::light::{Light, LightBase, LightType}; use shared::core::light::{Light, LightBase, LightType};
use shared::core::medium::{Medium, MediumInterface}; use shared::core::medium::{Medium, MediumInterface};
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;
use shared::core::texture::SpectrumType; use shared::core::texture::SpectrumType;
use shared::lights::GoniometricLight; use shared::lights::GoniometricLight;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::containers::Array2D;
use shared::utils::{Ptr, Transform}; use shared::utils::{Ptr, Transform};
pub trait CreateGoniometricLight { pub trait CreateGoniometricLight {

View file

@ -1,5 +1,6 @@
use log::error;
use shared::Float; use shared::Float;
use shared::core::geometry::{Bounds3f, Point2f}; use shared::core::geometry::Point2f;
use shared::core::light::{CreateLight, Light, LightBase, LightType}; use shared::core::light::{CreateLight, Light, LightBase, LightType};
use shared::core::medium::MediumInterface; use shared::core::medium::MediumInterface;
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;

View file

@ -2,7 +2,6 @@ use crate::core::light::{CreateLight, LightBaseTrait, lookup_spectrum};
use crate::core::spectrum::spectrum_to_photometric; use crate::core::spectrum::spectrum_to_photometric;
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::utils::{Arena, FileLoc, ParameterDictionary}; use crate::utils::{Arena, FileLoc, ParameterDictionary};
use shared::core::geometry::VectorLike;
use shared::core::light::{Light, LightBase, LightType}; use shared::core::light::{Light, LightBase, LightType};
use shared::core::medium::{Medium, MediumInterface}; use shared::core::medium::{Medium, MediumInterface};
use shared::core::shape::Shape; use shared::core::shape::Shape;

View file

@ -1,8 +1,9 @@
use crate::core::image::{Image, ImageIO, ImageMetadata}; use crate::core::image::{Image, ImageIO};
use crate::core::light::CreateLight; use crate::core::light::CreateLight;
use crate::core::spectrum::spectrum_to_photometric; use crate::core::spectrum::spectrum_to_photometric;
use crate::spectra::colorspace::new; use crate::spectra::colorspace::new;
use crate::utils::{Arena, ParameterDictionary, Ptr, Upload, resolve_filename}; use crate::utils::{Arena, ParameterDictionary, Upload, resolve_filename};
use log::error;
use shared::Float; use shared::Float;
use shared::core::geometry::{Bounds2f, VectorLike}; use shared::core::geometry::{Bounds2f, VectorLike};
use shared::core::image::ImageAccess; use shared::core::image::ImageAccess;

View file

@ -1,18 +1,16 @@
use crate::core::image::{Image, ImageIO, ImageMetadata}; // use crate::core::image::{Image, ImageIO, ImageMetadata};
use crate::core::light::CreateLight; use crate::core::light::CreateLight;
use crate::core::spectrum::spectrum_to_photometric; use crate::core::spectrum::spectrum_to_photometric;
use crate::spectra::colorspace::new; use crate::utils::{Arena, ParameterDictionary};
use crate::utils::{Arena, ParameterDictionary, Ptr, Upload, resolve_filename}; use shared::core::geometry::{Frame, VectorLike};
use shared::core::geometry::{Bounds2f, Frame, VectorLike};
use shared::core::image::ImageAccess;
use shared::core::light::{Light, LightBase, LightType}; use shared::core::light::{Light, LightBase, LightType};
use shared::core::medium::MediumInterface; use shared::core::medium::MediumInterface;
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;
use shared::core::texture::SpectrumType; use shared::core::texture::SpectrumType;
use shared::lights::{ProjectionLight, SpotLight}; use shared::lights::SpotLight;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::math::{radians, square}; use shared::utils::Transformk
use shared::utils::{Ptr, Transform}; use shared::utils::math::radians;
use shared::{Float, PI}; use shared::{Float, PI};
pub trait CreateSpotLight { pub trait CreateSpotLight {
@ -32,7 +30,6 @@ impl CreateSpotLight for SpotLight {
medium_interface: MediumInterface, medium_interface: MediumInterface,
le: Spectrum, le: Spectrum,
scale: shared::Float, scale: shared::Float,
image: Ptr<Image>,
cos_falloff_start: Float, cos_falloff_start: Float,
total_width: Float, total_width: Float,
) -> Self { ) -> Self {
@ -98,6 +95,7 @@ impl CreateLight for SpotLight {
coneangle, coneangle,
coneangle - conedelta, coneangle - conedelta,
); );
arena.alloc(specific);
Ok(Light::Spot(specific)) Ok(Light::Spot(specific))
} }
} }

View file

@ -1,11 +1,14 @@
use crate::core::image::Image; use crate::core::image::Image;
use crate::core::material::CreateMaterial; use crate::core::material::CreateMaterial;
use crate::utils::{Arena, ParameterDictionary}; use crate::core::texture::SpectrumTexture;
use crate::utils::{Arena, FileLoc, TextureParameterDictionary, Upload};
use shared::core::material::Material;
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;
use shared::core::texture::SpectrumType; use shared::core::texture::SpectrumType;
use shared::materials::coated::*; use shared::materials::coated::*;
use shared::spectra::ConstantSpectrum; use shared::spectra::ConstantSpectrum;
use shared::textures::SpectrumConstantTexture; use shared::textures::SpectrumConstantTexture;
use std::collections::HashMap;
impl CreateMaterial for CoatedDiffuseMaterial { impl CreateMaterial for CoatedDiffuseMaterial {
fn create( fn create(
@ -13,17 +16,17 @@ impl CreateMaterial for CoatedDiffuseMaterial {
normal_map: Option<Arc<Image>>, normal_map: Option<Arc<Image>>,
named_materials: &HashMap<String, Material>, named_materials: &HashMap<String, Material>,
loc: &FileLoc, loc: &FileLoc,
area: &mut Arena, arena: &mut Arena,
) -> Self { ) -> Result<Material, Error> {
let reflectance = parameters let reflectance = parameters
.get_spectrum_texture("reflectance", None, SpectrumType::Albedo) .get_spectrum_texture("reflectance", None, SpectrumType::Albedo)
.unwrap_or(SpectrumConstantTexture::new(Spectrum::Constant( .unwrap_or(Arc::new(SpectrumTexture::Constant(
ConstantSpectrum::new(0.5), SpectrumConstantTexture::new(Spectrum::Constant(ConstantSpectrum::new(0.5))),
))); )));
let u_roughness = parameters let u_roughness = parameters
.get_float_texture_or_null("uroughness") .get_float_texture_or_null("uroughness")
.unwrap_or_else(|| parameters.get_float_texture("roughness", 0.5)); .or_else(|| parameters.get_float_texture("roughness", 0.5));
let v_roughness = parameters let v_roughness = parameters
.get_float_texture_or_null("vroughness") .get_float_texture_or_null("vroughness")
.unwap_or_else(|| parameters.get_float("roughness", 0.5)); .unwap_or_else(|| parameters.get_float("roughness", 0.5));
@ -42,24 +45,27 @@ impl CreateMaterial for CoatedDiffuseMaterial {
let albedo = parameters let albedo = parameters
.get_spectrum_texture("albedo", None, SpectrumType::Albedo) .get_spectrum_texture("albedo", None, SpectrumType::Albedo)
.unwrap_or_else(|| { .unwrap_or_else(|| {
SpectrumConstantTexture::new(Spectrum::Constant(ConstantSpectrum::new(0.))) let default_spectrum = Spectrum::Constant(ConstantSpectrum::new(0.));
SpectrumTexture::Constant(SpectrumConstantTexture::new(default_spectrum))
}); });
let displacement = parameters.get_float_texture("displacement"); let displacement = parameters.get_float_texture("displacement", 0.);
let remap_roughness = parameters.get_one_bool("remaproughness", true); let remap_roughness = parameters.get_one_bool("remaproughness", true);
arena.alloc(Self::new( let specific = CoatedDiffuseMaterial::new(
reflectance, reflectance.upload(arena),
u_roughness, u_roughness.upload(arena),
v_roughness, v_roughness.upload(arena),
thickness, thickness.upload(arena),
albedo, albedo.upload(arena),
g, g.upload(arena),
eta, eta,
displacement, displacement.upload(arena),
normal_map, normal_map.upload(arena),
remap_roughness, remap_roughness,
max_depth, max_depth,
n_samples, n_samples,
)); );
Ok(Material::CoatedDiffuse(specific));
} }
} }
@ -73,7 +79,7 @@ impl CreateMaterial for CoatedConductorMaterial {
) -> Result<Self, String> { ) -> Result<Self, String> {
let interface_u_roughness = parameters let interface_u_roughness = parameters
.get_float_texture_or_null("interface.uroughness") .get_float_texture_or_null("interface.uroughness")
.unwrap_or_else(|| parameters.get_float_texture("interface.roughness", 0.)); .r_else(|| parameters.get_float_texture("interface.roughness", 0.));
let interface_v_roughness = parameters let interface_v_roughness = parameters
.GetFloatTextureOrNull("interface.vroughness") .GetFloatTextureOrNull("interface.vroughness")
.unwrap_or_else(|| parameters.get_float_texture("interface.vroughness", 0.)); .unwrap_or_else(|| parameters.get_float_texture("interface.vroughness", 0.));
@ -123,8 +129,8 @@ impl CreateMaterial for CoatedConductorMaterial {
let displacement = parameters.get_float_texture_or_null("displacement"); let displacement = parameters.get_float_texture_or_null("displacement");
let remap_roughness = parameters.get_one_bool("remaproughness", true); let remap_roughness = parameters.get_one_bool("remaproughness", true);
let material = Self::new( let material = Self::new(
displacement, displacement.upload(arena),
normal_map, normal_map.upload(arena),
interface_u_roughness, interface_u_roughness,
interface_v_roughness, interface_v_roughness,
thickness, thickness,

View file

@ -1,76 +1,52 @@
use crate::core::material::CreateMaterial; use crate::core::material::CreateMaterial;
use crate::utils::{Arena, FileLoc, TextureParameterDictionary}; use crate::utils::{Arena, FileLoc, TextureParameterDictionary, Upload};
use shared::core::bxdf::HairBxDF; use shared::bxdfs::HairBxDF;
use shared::core::material::Material;
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;
use shared::core::texture::{GPUFloatTexture, GPUSpectrumTexture}; use shared::core::texture::GPUFloatTexture;
use shared::materials::complex::*; use shared::materials::complex::*;
impl CreateMaterial for HairMaterial { impl CreateMaterial for HairMaterial {
fn create( fn create(
parameters: &TextureParameterDictionary, parameters: &TextureParameterDictionary,
normal_map: Option<Arc<ImageBuffer>>, normal_map: Option<Arc<ImageBuffer>>,
named_materials: &HashMap<String, Material>, _named_materials: &HashMap<String, Material>,
loc: &FileLoc, loc: &FileLoc,
arena: &mut Arena, arena: &mut Arena,
) -> Result<Self, String> { ) -> Result<Material, Error> {
let sigma_a = parameters.get_spectrum_texture_or_null("sigma_a", SpectrumType::Unbounded); let sigma_a = parameters.get_spectrum_texture_or_null("sigma_a", SpectrumType::Unbounded);
let reflectance = parameters let reflectance = parameters
.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo) .get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo)
.or_else(|| parameters.get_spectrum_texture_or_null("color", SpectrumType::Albedo)); .or_else(|| parameters.get_spectrum_texture_or_null("color", SpectrumType::Albedo));
let eumelanin = parameters.get_float_texture_or_null("eumelanin"); let eumelanin = parameters.get_float_texture_or_null("eumelanin");
let pheomelanin = parameters.get_float_texture_or_null("pheomelanin"); let pheomelanin = parameters.get_float_texture_or_null("pheomelanin");
let sigma_a = match ( let has_melanin = eumelanin.is_some() || pheomelanin.is_some();
sigma_a,
reflectance,
eumelanin.is_some() || pheomelanin.is_some(),
) {
(Some(s), Some(_), _) => {
warn(
loc,
r#"Ignoring "reflectance" parameter since "sigma_a" was provided."#,
);
Some(s)
}
(Some(s), _, true) => {
warn(
loc,
r#"Ignoring "eumelanin"/"pheomelanin" parameter since "sigma_a" was provided."#,
);
Some(s)
}
(Some(s), None, false) => Some(s),
(None, Some(r), true) => { // Default distribution if nothing is spceified
warn( let sigma_a = if sigma_a.is_none() && color.is_none() && !has_melanin {
loc, let default_rgb = HairBxDF::sigma_a_from_concentration(1.3, 0.0);
r#"Ignoring "eumelanin"/"pheomelanin" parameter since "reflectance" was provided."#, Some(Arc::new(SpectrumConstantTexture::new(
); Spectrum::RGBUnbounded(RGBUnboundedSpectrum::new(default_rgb)),
Some(r) )))
} } else {
(None, Some(r), false) => Some(r), sigma_a
(None, None, true) => None, // eumelanin/pheomelanin will be used
(None, None, false) => Some(SpectrumConstantTexture::new(Spectrum::RGBUnbounded(
RGBUnboundedSpectrum::new(HairBxDF::sigma_a_from_concentration(1.3, 0.0)),
))),
}; };
let eta = parameters.get_flot_texture("eta", 1.55); let eta = parameters.get_flot_texture("eta", 1.55);
let beta_m = parameters.get_float_texture("beta_m", 0.3); let beta_m = parameters.get_float_texture("beta_m", 0.3);
let beta_n = parameters.get_float_texture("beta_n", 0.3); let beta_n = parameters.get_float_texture("beta_n", 0.3);
let alpha = parameters.get_float_texture("alpha", 2.); let alpha = parameters.get_float_texture("alpha", 2.);
let material = HairMaterial::new( let material = HairMaterial::new(
sigma_a, sigma_a.upload(arena),
reflectance, reflectance.upload(arena),
eumelanin, eumelanin.upload(arena),
pheomelanin, pheomelanin.upload(arena),
eta, eta.upload(arena),
beta_m, beta_m.upload(arena),
beta_n, beta_n.upload(arena),
alpha, alpha.upload(arena),
); );
arena.alloc(material);
return material; return material;
} }
} }

View file

@ -1,16 +1,11 @@
use crate::core::bssrdf::BSSRDF;
use crate::core::bxdf::{
BSDF, BxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF,
HairBxDF,
};
use crate::core::image::Image; use crate::core::image::Image;
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
use crate::core::scattering::TrowbridgeReitzDistribution; use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use shared::core::bsdf::BSDF;
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use shared::core::bssrdf::BSSRDF;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use shared::core::material::{MaterialEvalContext, MaterialTrait};
use crate::utils::Ptr; use shared::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
use crate::utils::math::clamp; use shared::spectra::SampledWavelengths;
use shared::utils::Ptr;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -22,7 +17,7 @@ pub struct ConductorMaterial {
pub u_roughness: Ptr<GPUFloatTexture>, pub u_roughness: Ptr<GPUFloatTexture>,
pub v_roughness: Ptr<GPUFloatTexture>, pub v_roughness: Ptr<GPUFloatTexture>,
pub remap_roughness: bool, pub remap_roughness: bool,
pub normal_map: *const Image, pub normal_map: Ptr<Image>,
} }
impl MaterialTrait for ConductorMaterial { impl MaterialTrait for ConductorMaterial {

View file

@ -1,15 +1,12 @@
use crate::core::bssrdf::BSSRDF;
use crate::core::bxdf::{
BSDF, BxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF,
HairBxDF,
};
use crate::core::image::Image; use crate::core::image::Image;
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
use crate::core::scattering::TrowbridgeReitzDistribution; use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use shared::core::bsdf::BSDF;
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use shared::core::bssrdf::BSSRDF;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use shared::core::bxdf::BxDF;
use crate::utils::math::clamp; use shared::core::material::{MaterialEvalContext, MaterialTrait};
use shared::core::spectrum::{Spectrum, SpectrumTrait};
use shared::core::texture::{GPUFloatTexture, TextureEvaluator};
use shared::spectra::SampledWavelengths;
use shared::utils::Ptr; use shared::utils::Ptr;
#[repr(C)] #[repr(C)]

View file

@ -1,16 +1,12 @@
use crate::core::bssrdf::BSSRDF;
use crate::core::bxdf::{
BSDF, BxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF,
HairBxDF,
};
use crate::core::image::Image; use crate::core::image::Image;
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
use crate::core::scattering::TrowbridgeReitzDistribution; use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use shared::core::bsdf::BSDF;
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use shared::core::bssrdf::BSSRDF;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use shared::core::bxdf::BxDF;
use crate::utils::Ptr; use shared::core::material::{MaterialEvalContext, MaterialTrait};
use crate::utils::math::clamp; use shared::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
use shared::spectra::SampledWavelengths;
use shared::utils::Ptr;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]

View file

@ -1,17 +1,12 @@
use crate::core::bssrdf::BSSRDF;
use crate::core::bxdf::{
BSDF, BxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF,
HairBxDF,
};
use crate::core::image::Image; use crate::core::image::Image;
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
use crate::core::scattering::TrowbridgeReitzDistribution; use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use shared::core::bsdf::BSDF;
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator}; use shared::core::bssrdf::BSSRDF;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use shared::core::material::{Material, MaterialEvalContext, MaterialTrait};
use crate::utils::Ptr; use shared::core::texture::{GPUFloatTexture, TextureEvaluator};
use crate::utils::hash::hash_float; use shared::spectra::SampledWavelengths;
use crate::utils::math::clamp; use shared::utils::Ptr;
use shared::utils::hash::hash_float;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]

View file

@ -1,14 +1,15 @@
use crate::core::sampler::SamplerFactory; use crate::core::sampler::CreateSampler;
use crate::utils::{FileLoc, ParameterDictionary}; use crate::utils::{FileLoc, ParameterDictionary};
use shared::core::geometry::Point2i; use shared::core::geometry::Point2i;
use shared::core::sampler::{HaltonSampler, RandomizeStrategy}; use shared::core::sampler::{HaltonSampler, RandomizeStrategy};
impl SamplerFactory for HaltonSampler { impl CreateSampler for HaltonSampler {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,
full_res: Point2i, full_res: Point2i,
loc: &FileLoc, loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
let options = get_options(); let options = get_options();
let nsamp = options let nsamp = options
.quick_render .quick_render
@ -32,6 +33,8 @@ impl SamplerFactory for HaltonSampler {
} }
}; };
Ok(HaltonSampler::new(nsamp as u32, full_res, s, seed as u64)) let sampler = HaltonSampler::new(nsamp as u32, full_res, s, seed as u64);
arena.alloc(sampler);
Ok(sampler)
} }
} }

View file

@ -1,14 +1,15 @@
use crate::core::sampler::SamplerFactory; use crate::core::sampler::CreateSampler;
use crate::utils::{FileLoc, ParameterDictionary}; use crate::utils::{FileLoc, ParameterDictionary};
use shared::core::geometry::Point2i; use shared::core::geometry::Point2i;
use shared::core::sampler::IndependentSampler; use shared::core::sampler::IndependentSampler;
impl SamplerFactory for IndependentSampler { impl CreateSampler for IndependentSampler {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,
_full_res: Point2i, _full_res: Point2i,
_loc: &FileLoc, _loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
let options = get_options(); let options = get_options();
let nsamp = options let nsamp = options
.quick_render .quick_render
@ -16,6 +17,8 @@ impl SamplerFactory for IndependentSampler {
.or(options.pixel_samples) .or(options.pixel_samples)
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16)); .unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
let seed = params.get_one_int("seed", options.seed); let seed = params.get_one_int("seed", options.seed);
Ok(Self::new(nsamp as usize, seed as u64)) let sampler = Self::new(nsamp as usize, seed as u64);
arena.alloc(sampler);
Ok(sampler)
} }
} }

View file

@ -1,14 +1,15 @@
use crate::core::sampler::SamplerFactory; use crate::core::sampler::CreateSampler;
use crate::utils::{FileLoc, ParameterDictionary}; use crate::utils::{FileLoc, ParameterDictionary};
use shared::core::geometry::Point2i; use shared::core::geometry::Point2i;
use shared::core::sampler::{PaddedSobolSampler, RandomizeStrategy, SobolSampler, ZSobolSampler}; use shared::core::sampler::{PaddedSobolSampler, RandomizeStrategy, SobolSampler, ZSobolSampler};
impl SamplerFactory for SobolSampler { impl CreateSampler for SobolSampler {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,
full_res: Point2i, full_res: Point2i,
loc: &FileLoc, loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
let options = get_options(); let options = get_options();
let nsamp = options let nsamp = options
.quick_render .quick_render
@ -26,16 +27,19 @@ impl SamplerFactory for SobolSampler {
} }
}; };
Ok(Self::new(nsamp as usize, full_res, s, Some(seed as u64))) let sampler = Self::new(nsamp as usize, full_res, s, Some(seed as u64));
arena.alloc(sampler);
Ok(sampler)
} }
} }
impl SamplerFactory for PaddedSobolSampler { impl CreateSampler for PaddedSobolSampler {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,
_full_res: Point2i, _full_res: Point2i,
loc: &FileLoc, loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
let options = get_options(); let options = get_options();
let nsamp = options let nsamp = options
.quick_render .quick_render
@ -56,16 +60,19 @@ impl SamplerFactory for PaddedSobolSampler {
} }
}; };
Ok(Self::new(nsamp as u32, s, Some(seed as u64))) let sampler = Self::new(nsamp as u32, s, Some(seed as u64));
arena.alloc(sampler);
Ok(sampler)
} }
} }
impl SamplerFactory for ZSobolSampler { impl CreateSampler for ZSobolSampler {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,
full_res: Point2i, full_res: Point2i,
loc: &FileLoc, loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
let options = get_options(); let options = get_options();
let nsamp = options let nsamp = options
.quick_render .quick_render
@ -86,11 +93,8 @@ impl SamplerFactory for ZSobolSampler {
} }
}; };
Ok(ZSobolSampler::new( let sampler = ZSobolSampler::new(nsamp as u32, full_res, s, Some(seed as u64));
nsamp as u32, arena.alloc(sampler);
full_res, Ok(sampler)
s,
Some(seed as u64),
))
} }
} }

View file

@ -1,14 +1,16 @@
use crate::core::sampler::SamplerFactory; use crate::Arena;
use crate::core::sampler::CreateSampler;
use crate::utils::{FileLoc, ParameterDictionary}; use crate::utils::{FileLoc, ParameterDictionary};
use shared::core::geometry::{FileLoc, ParameterDictionary}; use shared::core::geometry::{FileLoc, ParameterDictionary};
use shared::core::sampler::StratifiedSampler; use shared::core::sampler::StratifiedSampler;
impl SamplerFactory for StratifiedSampler { impl CreateSampler for StratifiedSampler {
fn create( fn create(
params: &ParameterDictionary, params: &ParameterDictionary,
_full_res: Point2i, _full_res: Point2i,
_loc: &FileLoc, _loc: &FileLoc,
) -> Result<Self, String> { arena: &mut Arena,
) -> Result<Self, Error> {
let options = get_options(); let options = get_options();
let jitter = params.get_one_bool("jitter", true); let jitter = params.get_one_bool("jitter", true);
let (x_samples, y_samples) = if options.quick_render { let (x_samples, y_samples) = if options.quick_render {
@ -25,11 +27,14 @@ impl SamplerFactory for StratifiedSampler {
) )
}; };
let seed = params.get_one_int("seed", options.seed); let seed = params.get_one_int("seed", options.seed);
Ok(Self::new( let sampler = Self::new(
x_samples as u32, x_samples as u32,
y_samples as u32, y_samples as u32,
Some(seed as u64), Some(seed as u64),
jitter, jitter,
)) );
arena.aloc(sampler);
Ok(sampler)
} }
} }

View file

@ -1,8 +1,9 @@
use crate::core::shape::{ALL_BILINEAR_MESHES, CreateMesh, CreateShape}; use crate::core::shape::{ALL_BILINEAR_MESHES, CreateMesh};
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::shapes::mesh::Mesh;
use crate::utils::{Arena, FileLoc, ParameterDictionary}; use crate::utils::{Arena, FileLoc, ParameterDictionary};
use log::warn;
use shared::shapes::BilinearPatchShape; use shared::shapes::BilinearPatchShape;
use shared::shapes::mesh::Mesh;
use shared::utils::Transform; use shared::utils::Transform;
use std::collections::HashMap; use std::collections::HashMap;

View file

@ -1,13 +1,15 @@
use crate::Arena;
use crate::core::shape::CreateShape; use crate::core::shape::CreateShape;
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::utils::{FileLoc, ParameterDictionary}; use crate::utils::{FileLoc, ParameterDictionary};
use rayon::iter::split;
use shared::core::geometry::Normal3f; use shared::core::geometry::Normal3f;
use shared::shapes::{CurveCommon, CurveShape, CurveType, CylinderShape}; use shared::shapes::{CurveCommon, CurveShape, CurveType};
use shared::utils::Transform; use shared::utils::Transform;
use shared::utils::splines::{ use shared::utils::splines::{
cubic_bspline_to_bezier, elevate_quadratic_bezier_to_cubic, quadratic_bspline_to_bezier, cubic_bspline_to_bezier, elevate_quadratic_bezier_to_cubic, quadratic_bspline_to_bezier,
}; };
use log::warn;
use std::collections::HashMap; use std::collections::HashMap;
pub fn create_curve( pub fn create_curve(
@ -58,6 +60,7 @@ impl CreateShape for CurveShape {
parameters: ParameterDictionary, parameters: ParameterDictionary,
float_textures: HashMap<String, FloatTexture>, float_textures: HashMap<String, FloatTexture>,
loc: FileLoc, loc: FileLoc,
arena: &mut Arena,
) -> Result<Vec<Shape>, String> { ) -> Result<Vec<Shape>, String> {
let width = parameters.get_one_float("width", 1.0); let width = parameters.get_one_float("width", 1.0);
let width0 = parameters.get_one_float("width0", width); let width0 = parameters.get_one_float("width0", width);

View file

@ -1,10 +1,9 @@
use crate::utils::FileLoc; use anyhow::{Context, Result as AnyResult, bail};
use ply_rs::parser::Parser; use ply_rs::parser::Parser;
use ply_rs::ply::{DefaultElement, Property}; use ply_rs::ply::{DefaultElement, Property};
use shared::utils::Transform; use shared::utils::Transform;
use shared::utils::mesh::{BilinearPatchMesh, TriangleMesh}; use shared::utils::mesh::{BilinearPatchMesh, TriangleMesh};
use shared::utils::sampling::DevicePiecewiseConstant2D; use shared::utils::sampling::DevicePiecewiseConstant2D;
use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
@ -18,7 +17,7 @@ pub struct TriQuadMesh {
pub quad_indices: Vec<u32>, pub quad_indices: Vec<u32>,
} }
fn get_float(elem: &DefaultElement, key: &str) -> Result<f32> { fn get_float(elem: &DefaultElement, key: &str) -> AnyResult<f32> {
match elem.get(key) { match elem.get(key) {
Some(Property::Float(v)) => Ok(*v), Some(Property::Float(v)) => Ok(*v),
Some(Property::Double(v)) => Ok(*v as f32), Some(Property::Double(v)) => Ok(*v as f32),
@ -27,7 +26,7 @@ fn get_float(elem: &DefaultElement, key: &str) -> Result<f32> {
} }
} }
fn get_int(elem: &DefaultElement, key: &str) -> Result<i32> { fn get_int(elem: &DefaultElement, key: &str) -> AnyResult<i32> {
match elem.get(key) { match elem.get(key) {
Some(Property::Int(v)) => Ok(*v), Some(Property::Int(v)) => Ok(*v),
Some(Property::UInt(v)) => Ok(*v as i32), Some(Property::UInt(v)) => Ok(*v as i32),
@ -48,7 +47,7 @@ fn get_float_any(elem: &DefaultElement, keys: &[&str]) -> Option<f32> {
None None
} }
fn get_list_uint(elem: &DefaultElement, key: &str) -> Result<Vec<u32>> { fn get_list_uint(elem: &DefaultElement, key: &str) -> AnyResult<Vec<u32>> {
match elem.get(key) { match elem.get(key) {
Some(Property::List_Int(vec)) => Ok(vec.iter().map(|&x| x as u32).collect()), Some(Property::List_Int(vec)) => Ok(vec.iter().map(|&x| x as u32).collect()),
Some(Property::List_UInt(vec)) => Ok(vec.clone()), Some(Property::List_UInt(vec)) => Ok(vec.clone()),
@ -59,10 +58,14 @@ fn get_list_uint(elem: &DefaultElement, key: &str) -> Result<Vec<u32>> {
} }
impl TriQuadMesh { impl TriQuadMesh {
pub fn read_ply<P: AsRef<Path>>(filename: P) -> Result<Self> { pub fn read_ply<P: AsRef<Path>>(filename: P) -> AnyResult<Self> {
let filename_display = filename.as_ref().display().to_string(); let path = filename.as_ref();
let filename_display = path.display().to_string();
let mut f = File::open(&filename) let mut f = File::open(&filename)
.with_context(|| format!("Couldn't open PLY file \"{}\"", filename_display))?; .with_context(|| format!("Couldn't open PLY file \"{}\"", filename_display))?;
// Going to ply-rs
let p = Parser::<DefaultElement>::new(); let p = Parser::<DefaultElement>::new();
let ply = p let ply = p
.read_ply(&mut f) .read_ply(&mut f)
@ -78,13 +81,13 @@ impl TriQuadMesh {
let has_normal = let has_normal =
first.contains_key("nx") && first.contains_key("ny") && first.contains_key("nz"); first.contains_key("nx") && first.contains_key("ny") && first.contains_key("nz");
for v_elem in vertices { for v_elem in vertices {
// Read Position (Required) // Read Position
let x = get_float(v_elem, "x")?; let x = get_float(v_elem, "x")?;
let y = get_float(v_elem, "y")?; let y = get_float(v_elem, "y")?;
let z = get_float(v_elem, "z")?; let z = get_float(v_elem, "z")?;
mesh.p.push([x, y, z]); mesh.p.push([x, y, z]);
// Read Normal (Optional) // Read Normal
if has_normal { if has_normal {
let nx = get_float(v_elem, "nx").unwrap_or(0.0); let nx = get_float(v_elem, "nx").unwrap_or(0.0);
let ny = get_float(v_elem, "ny").unwrap_or(0.0); let ny = get_float(v_elem, "ny").unwrap_or(0.0);
@ -343,6 +346,12 @@ pub struct BilinearPatchMeshHost {
_storage: Box<BilinearMeshStorage>, _storage: Box<BilinearMeshStorage>,
} }
#[derive(Debug, Clone, Copy)]
pub struct TriangleMeshHost {
pub view: BilinearPatchMesh,
_storage: Box<BilinearMeshStorage>,
}
impl Deref for TriangleMeshHost { impl Deref for TriangleMeshHost {
type Target = TriangleMesh; type Target = TriangleMesh;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {

View file

@ -7,7 +7,7 @@ pub mod mesh;
pub mod sphere; pub mod sphere;
pub mod triangle; pub mod triangle;
pub use bilinear::*; // pub use bilinear::*;
pub use mesh::*; pub use mesh::*;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};

View file

@ -2,6 +2,7 @@ use crate::core::shape::{ALL_TRIANGLE_MESHES, CreateShape};
use crate::core::texture::FloatTexture; use crate::core::texture::FloatTexture;
use crate::shapes::mesh::TriangleMeshHost; use crate::shapes::mesh::TriangleMeshHost;
use crate::utils::{Arena, FileLoc, ParameterDictionary}; use crate::utils::{Arena, FileLoc, ParameterDictionary};
use log::warn;
use shared::shapes::TriangleShape; use shared::shapes::TriangleShape;
use shared::utils::Transform; use shared::utils::Transform;
@ -9,8 +10,10 @@ impl CreateShape for TriangleShape {
fn create( fn create(
name: &str, name: &str,
render_from_object: Transform, render_from_object: Transform,
_object_from_render: Transform,
reverse_orientation: bool, reverse_orientation: bool,
parameters: ParameterDictionary, parameters: ParameterDictionary,
_float_texture: HashMap<String, FloatTexture>,
loc: FileLoc, loc: FileLoc,
arena: &mut Arena, arena: &mut Arena,
) -> Result<Mesh, String> { ) -> Result<Mesh, String> {

View file

@ -1,18 +1,20 @@
use super::DenselySampledSpectrumBuffer; use super::DenselySampledSpectrumBuffer;
use shared::core::color::RGBToSpectrumTable;
use shared::core::geometry::Point2f; use shared::core::geometry::Point2f;
use shared::spectra::{RGBColorSpace, RGBToSpectrumTable}; use shared::spectra::RGBColorSpace;
use shared::utils::SquareMatrix; use shared::utils::math::SquareMatrix;
pub struct RGBColorSpaceData { pub struct RGBColorSpaceData {
_illuminant: DenselySampledBuffer, _illuminant: DenselySampledSpectrumBuffer,
pub view: RGBColorSpace, pub view: RGBColorSpace,
} }
impl RGBColorSpaceData {
pub fn new( pub fn new(
r: Point2f, r: Point2f,
g: Point2f, g: Point2f,
b: Point2f, b: Point2f,
illuminant: DenselySampledBuffer, illuminant: DenselySampledSpectrumBuffer,
rgb_to_spectrum_table: *const RGBToSpectrumTable, rgb_to_spectrum_table: *const RGBToSpectrumTable,
) -> Self { ) -> Self {
let w_xyz: XYZ = illuminant.to_xyz(); let w_xyz: XYZ = illuminant.to_xyz();
@ -46,6 +48,7 @@ pub fn new(
view, view,
} }
} }
}
pub fn get_named(name: &str) -> Result<Arc<RGBColorSpace>, String> { pub fn get_named(name: &str) -> Result<Arc<RGBColorSpace>, String> {
match name.to_lowercase().as_str() { match name.to_lowercase().as_str() {

View file

@ -1,16 +1,9 @@
use crate::spectra::{DenselySampledSpectrumBuffer, SpectrumData}; use crate::spectra::DenselySampledSpectrumBuffer;
use shared::Float; use shared::Float;
use shared::core::cie::{CIE_S_LAMBDA, CIE_S0, CIE_S1, CIE_S2, CIE_X, CIE_Y, CIE_Z, N_CIES}; use shared::core::spectrum::Spectrum;
use shared::spectra::cie::{CIE_S_LAMBDA, CIE_S0, CIE_S1, CIE_S2, N_CIES}; use shared::spectra::PiecewiseLinearSpectrum;
use shared::spectra::{
BlackbodySpectrum, DenselySampledSpectrum, LAMBDA_MAX, LAMBDA_MIN, PiecewiseLinearSpectrum,
Spectrum,
};
use shared::utils::math::square;
use once_cell::sync::Lazy; pub fn create_cie_buffer(data: &[Float]) -> Spectrum {
fn create_cie_buffer(data: &[Float]) -> Spectrum {
let buffer = PiecewiseLinearSpectrum::from_interleaved(data, false); let buffer = PiecewiseLinearSpectrum::from_interleaved(data, false);
let spec = Spectrum::Piecewise(buffer.view); let spec = Spectrum::Piecewise(buffer.view);
DenselySampledSpectrumBuffer::from_spectrum(spec) DenselySampledSpectrumBuffer::from_spectrum(spec)

View file

@ -1,15 +1,15 @@
use crate::core::pbrt::Float; use shared::Float;
use shared::spectra::{DenselySampledSpectrum, SampledSpectrum}; use shared::spectra::{DenselySampledSpectrum, SampledSpectrum};
pub struct DenselySampledSpectrumBuffer { pub struct DenselySampledSpectrumBuffer {
pub view: DenselySampledSpectrum, pub device: DenselySampledSpectrum,
_storage: Vec<Float>, _storage: Vec<Float>,
} }
impl std::ops::Deref for DenselySampledSpectrumBuffer { impl std::ops::Deref for DenselySampledSpectrumBuffer {
type Target = DenselySampledSpectrum; type Target = DenselySampledSpectrum;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.view &self.device
} }
} }
@ -21,7 +21,7 @@ impl DenselySampledSpectrumBuffer {
values: values.as_ptr(), values: values.as_ptr(),
}; };
Self { Self {
view, device: view,
_storage: values, _storage: values,
} }
} }

Some files were not shown because too many files have changed in this diff Show more