Fixes
This commit is contained in:
parent
3b3f9eb155
commit
86c9a90f2e
114 changed files with 1548 additions and 2421 deletions
|
|
@ -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 }
|
||||||
|
|
|
||||||
|
|
@ -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};
|
if i < n as usize {
|
||||||
use cust::device::DeviceAttribute;
|
let ptr = unsafe { data.add(i) };
|
||||||
use cust::memory::{DeviceCopy, DeviceMemory};
|
unsafe {
|
||||||
use cust::prelude::*;
|
*ptr = *ptr * scale;
|
||||||
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];
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if let Err(e) =
|
|
||||||
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 {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
5
shared/build.rs
Normal 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\"))");
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,49 +163,44 @@ pub trait CameraTrait {
|
||||||
sample: CameraSample,
|
sample: CameraSample,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
) -> Option<CameraRay> {
|
) -> Option<CameraRay> {
|
||||||
match self {
|
let mut central_cam_ray = self.generate_ray(sample, lambda)?;
|
||||||
Camera::Orthographic(c) => c.generate_ray_differential(sample, lambda),
|
let mut rd = RayDifferential::default();
|
||||||
_ => {
|
let mut rx_found = false;
|
||||||
let mut central_cam_ray = self.generate_ray(sample, lambda)?;
|
let mut ry_found = false;
|
||||||
let mut rd = RayDifferential::default();
|
|
||||||
let mut rx_found = false;
|
|
||||||
let mut ry_found = false;
|
|
||||||
|
|
||||||
for eps in [0.05, -0.05] {
|
for eps in [0.05, -0.05] {
|
||||||
let mut s_shift = sample;
|
let mut s_shift = sample;
|
||||||
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;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for eps in [0.05, -0.05] {
|
|
||||||
let mut s_shift = sample;
|
|
||||||
s_shift.p_film[1] += eps;
|
|
||||||
|
|
||||||
if let Some(ry_cam_ray) = self.generate_ray(s_shift, lambda) {
|
|
||||||
rd.ry_origin = central_cam_ray.ray.o
|
|
||||||
+ (ry_cam_ray.ray.o - central_cam_ray.ray.o) / eps;
|
|
||||||
rd.ry_direction = central_cam_ray.ray.d
|
|
||||||
+ (ry_cam_ray.ray.d - central_cam_ray.ray.d) / eps;
|
|
||||||
ry_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rx_found && ry_found {
|
|
||||||
central_cam_ray.ray.differential = rd;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(central_cam_ray)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for eps in [0.05, -0.05] {
|
||||||
|
let mut s_shift = sample;
|
||||||
|
s_shift.p_film[1] += eps;
|
||||||
|
|
||||||
|
if let Some(ry_cam_ray) = self.generate_ray(s_shift, lambda) {
|
||||||
|
rd.ry_origin =
|
||||||
|
central_cam_ray.ray.o + (ry_cam_ray.ray.o - central_cam_ray.ray.o) / eps;
|
||||||
|
rd.ry_direction =
|
||||||
|
central_cam_ray.ray.d + (ry_cam_ray.ray.d - central_cam_ray.ray.d) / eps;
|
||||||
|
ry_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rx_found && ry_found {
|
||||||
|
central_cam_ray.ray.differential = rd;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(central_cam_ray)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn approximate_dp_dxy(
|
fn approximate_dp_dxy(
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
}
|
self.le_spec.sample(lambda)
|
||||||
None => 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let index = target.offset_from(array_start);
|
||||||
|
|
||||||
|
if index >= 0 && index < self.lights_len as isize {
|
||||||
|
return self.alias_table.pmf(index as u32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let light_ptr = light as *const Light;
|
|
||||||
let start = self.lights.as_ptr();
|
|
||||||
|
|
||||||
let end = unsafe { start.add(self.lights.len as usize) };
|
|
||||||
|
|
||||||
if light_ptr >= start && light_ptr < end {
|
|
||||||
let index = unsafe { light_ptr.offset_from(start) };
|
|
||||||
return self.alias_table.pmf(index as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
0.
|
0.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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."
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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> {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
|
|
|
||||||
|
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
143
src/core/film.rs
143
src/core/film.rs
|
|
@ -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,8 +79,104 @@ 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>,
|
||||||
bucket_sums: Vec<f64>,
|
bucket_sums: Vec<f64>,
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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>,
|
||||||
|
|
|
||||||
|
|
@ -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]>);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)),
|
||||||
|
|
|
||||||
|
|
@ -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!()
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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>>> =
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.);
|
||||||
|
|
|
||||||
|
|
@ -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.);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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"])
|
||||||
|
|
|
||||||
|
|
@ -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] = [
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,52 @@
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
impl RGBColorSpaceData {
|
||||||
r: Point2f,
|
pub fn new(
|
||||||
g: Point2f,
|
r: Point2f,
|
||||||
b: Point2f,
|
g: Point2f,
|
||||||
illuminant: DenselySampledBuffer,
|
b: Point2f,
|
||||||
rgb_to_spectrum_table: *const RGBToSpectrumTable,
|
illuminant: DenselySampledSpectrumBuffer,
|
||||||
) -> Self {
|
rgb_to_spectrum_table: *const RGBToSpectrumTable,
|
||||||
let w_xyz: XYZ = illuminant.to_xyz();
|
) -> Self {
|
||||||
let w = w_xyz.xy();
|
let w_xyz: XYZ = illuminant.to_xyz();
|
||||||
let r_xyz = XYZ::from_xyy(r, Some(1.0));
|
let w = w_xyz.xy();
|
||||||
let g_xyz = XYZ::from_xyy(g, Some(1.0));
|
let r_xyz = XYZ::from_xyy(r, Some(1.0));
|
||||||
let b_xyz = XYZ::from_xyy(b, Some(1.0));
|
let g_xyz = XYZ::from_xyy(g, Some(1.0));
|
||||||
let rgb_values = [
|
let b_xyz = XYZ::from_xyy(b, Some(1.0));
|
||||||
[r_xyz.x(), g_xyz.x(), b_xyz.x()],
|
let rgb_values = [
|
||||||
[r_xyz.y(), g_xyz.y(), b_xyz.y()],
|
[r_xyz.x(), g_xyz.x(), b_xyz.x()],
|
||||||
[r_xyz.z(), g_xyz.z(), b_xyz.z()],
|
[r_xyz.y(), g_xyz.y(), b_xyz.y()],
|
||||||
];
|
[r_xyz.z(), g_xyz.z(), b_xyz.z()],
|
||||||
let rgb = SquareMatrix::new(rgb_values);
|
];
|
||||||
let c: RGB = rgb.inverse()? * w_xyz;
|
let rgb = SquareMatrix::new(rgb_values);
|
||||||
let xyz_from_rgb = rgb * SquareMatrix::diag(&[c.r, c.g, c.b]);
|
let c: RGB = rgb.inverse()? * w_xyz;
|
||||||
let rgb_from_xyz = xyz_from_rgb
|
let xyz_from_rgb = rgb * SquareMatrix::diag(&[c.r, c.g, c.b]);
|
||||||
.inverse()
|
let rgb_from_xyz = xyz_from_rgb
|
||||||
.expect("XYZ from RGB matrix is singular");
|
.inverse()
|
||||||
let view = RGBColorSpace {
|
.expect("XYZ from RGB matrix is singular");
|
||||||
r,
|
let view = RGBColorSpace {
|
||||||
g,
|
r,
|
||||||
b,
|
g,
|
||||||
w,
|
b,
|
||||||
illuminant: illuminant_buffer.view, // Extract view
|
w,
|
||||||
xyz_from_rgb,
|
illuminant: illuminant_buffer.view, // Extract view
|
||||||
rgb_from_xyz,
|
xyz_from_rgb,
|
||||||
rgb_to_spectrum_table: table_ptr,
|
rgb_from_xyz,
|
||||||
};
|
rgb_to_spectrum_table: table_ptr,
|
||||||
Self {
|
};
|
||||||
_illuminant: illuminant_buffer,
|
Self {
|
||||||
view,
|
_illuminant: illuminant_buffer,
|
||||||
|
view,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in a new issue