use crate::core::camera::{CameraBase, CameraRay, CameraTransform}; use crate::core::film::Film; use crate::core::geometry::{Bounds2f, Point2f, Point3f, Ray, Vector3f, spherical_direction}; use crate::core::medium::Medium; use crate::core::pbrt::{Float, PI}; use crate::core::sampler::CameraSample; use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::utils::math::{equal_area_square_to_sphere, wrap_equal_area_square}; use std::sync::Arc; #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq)] pub enum Mapping { EquiRectangular, EqualArea, } #[derive(Debug, Copy, Clone)] pub struct SphericalCamera { pub mapping: Mapping, pub base: CameraBase, } #[cfg(not(target_os = "cuda"))] impl SphericalCamera { pub fn init_metadata(&self, metadata: &mut crate::image::ImageMetadata) { self.base.init_metadata(metadata) } } impl CameraTrait for SphericalCamera { fn base(&self) -> &CameraBase { &self.base } fn get_film(&self) -> &Film { #[cfg(not(target_os = "cuda"))] { if self.base.film.is_null() { panic!( "FilmBase error: PixelSensor pointer is null. This should have been checked during construction." ); } } unsafe { &*self.base.film } } fn generate_ray( &self, sample: CameraSample, _lamdba: &SampledWavelengths, ) -> Option { // Compute spherical camera ray direction let film = self.get_film(); let mut uv = Point2f::new( sample.p_film.x() / film.full_resolution().x() as Float, sample.p_film.y() / film.full_resolution().y() as Float, ); let dir: Vector3f; if self.mapping == Mapping::EquiRectangular { // Compute ray direction using equirectangular mapping let theta = PI * uv[1]; let phi = 2. * PI * uv[0]; dir = spherical_direction(theta.sin(), theta.cos(), phi); } else { // Compute ray direction using equal area mapping uv = wrap_equal_area_square(&mut uv); dir = equal_area_square_to_sphere(uv); } std::mem::swap(&mut dir.y(), &mut dir.z()); let ray = Ray::new( Point3f::new(0., 0., 0.), dir, Some(self.sample_time(sample.time)), self.base().medium.clone(), ); Some(CameraRay { ray: self.render_from_camera(&ray, &mut None), weight: SampledSpectrum::default(), }) } }