use crate::core::camera::{CameraBase, CameraRay, CameraTrait, CameraTransform}; use crate::core::film::Film; use crate::core::geometry::{ Bounds2f, Point2f, Point3f, Ray, RayDifferential, Vector2f, Vector3f, VectorLike, }; use crate::core::medium::Medium; use crate::core::pbrt::Float; use crate::core::sampler::CameraSample; use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::utils::Transform; use crate::utils::sampling::sample_uniform_disk_concentric; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct OrthographicCamera { pub base: CameraBase, pub screen_from_camera: Transform, pub camera_from_raster: Transform, pub raster_from_screen: Transform, pub screen_from_raster: Transform, pub lens_radius: Float, pub focal_distance: Float, pub dx_camera: Vector3f, pub dy_camera: Vector3f, } #[cfg(not(target_os = "cuda"))] impl OrthographicCamera { pub fn new( base: CameraBase, screen_window: Bounds2f, lens_radius: Float, focal_distance: Float, ) -> Self { let ndc_from_screen: Transform = Transform::scale( 1. / (screen_window.p_max.x() - screen_window.p_min.x()), 1. / (screen_window.p_max.y() - screen_window.p_min.y()), 1., ) * Transform::translate(Vector3f::new( -screen_window.p_min.x(), -screen_window.p_max.y(), 0., )); let mut base_ortho = base; let film = base.film; if film.is_null() { panic!("Camera must have a film"); } let raster_from_ndc = Transform::scale( film.full_resolution().x() as Float, -film.full_resolution().y() as Float, 1., ); let raster_from_screen = raster_from_ndc * ndc_from_screen; let screen_from_raster = raster_from_screen.inverse(); let screen_from_camera = Transform::orthographic(0., 1.); let camera_from_raster = screen_from_camera.inverse() * screen_from_raster; let dx_camera = camera_from_raster.apply_to_vector(Vector3f::new(1., 0., 0.)); let dy_camera = camera_from_raster.apply_to_vector(Vector3f::new(0., 1., 0.)); base_ortho.min_dir_differential_x = Vector3f::new(0., 0., 0.); base_ortho.min_dir_differential_y = Vector3f::new(0., 0., 0.); base_ortho.min_pos_differential_x = dx_camera; base_ortho.min_pos_differential_y = dy_camera; Self { base: base_ortho, screen_from_camera, camera_from_raster, raster_from_screen, screen_from_raster, lens_radius, focal_distance, dx_camera, dy_camera, } } } impl CameraTrait for OrthographicCamera { fn base(&self) -> &CameraBase { &self.base } fn generate_ray( &self, sample: CameraSample, _lambda: &SampledWavelengths, ) -> Option { // Compute raster and camera sample positions let p_film = Point3f::new(sample.p_film.x(), sample.p_film.y(), 0.); let p_camera = self.camera_from_raster.apply_to_point(p_film); let mut ray = Ray::new( p_camera, Vector3f::new(0., 0., 1.), Some(self.sample_time(sample.time)), &*self.base().medium, ); if self.lens_radius > 0. { let p_lens_vec = self.lens_radius * Vector2f::from(sample_uniform_disk_concentric(sample.p_lens)); let p_lens = Point2f::from(p_lens_vec); let ft = self.focal_distance / ray.d.z(); let p_focus = ray.at(ft); ray.o = Point3f::new(p_lens.x(), p_lens.y(), 0.); ray.d = (p_focus - ray.o).normalize(); } let camera_ray = self.render_from_camera(&ray, &mut None); Some(CameraRay { ray: camera_ray, weight: SampledSpectrum::default(), }) } fn generate_ray_differential( &self, sample: CameraSample, lambda: &SampledWavelengths, ) -> Option { let mut central_cam_ray = self.generate_ray(sample, lambda)?; let mut rd = RayDifferential::default(); if self.lens_radius > 0.0 { let mut sample_x = sample; sample_x.p_film[0] += 1.0; let rx = self.generate_ray(sample_x, lambda)?; let mut sample_y = sample; sample_y.p_film[1] += 1.0; let ry = self.generate_ray(sample_y, lambda)?; rd.rx_origin = rx.ray.o; rd.ry_origin = ry.ray.o; rd.rx_direction = rx.ray.d; rd.ry_direction = ry.ray.d; } else { let time = self.sample_time(sample.time); let world_dx = self .base .camera_transform .render_from_camera_vector(self.dx_camera, time); let world_dy = self .base .camera_transform .render_from_camera_vector(self.dy_camera, time); rd.rx_origin = central_cam_ray.ray.o + world_dx; rd.ry_origin = central_cam_ray.ray.o + world_dy; rd.rx_direction = central_cam_ray.ray.d; rd.ry_direction = central_cam_ray.ray.d; } central_cam_ray.ray.differential = rd; Some(central_cam_ray) } }