161 lines
5.3 KiB
Rust
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)
|
|
}
|
|
}
|