pbrt/shared/src/cameras/orthographic.rs
2026-01-01 09:45:00 +00:00

161 lines
5.3 KiB
Rust

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<CameraRay> {
// 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<CameraRay> {
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)
}
}