123 lines
4.3 KiB
Rust
123 lines
4.3 KiB
Rust
use super::{CameraBase, CameraRay, CameraTrait};
|
|
use crate::camera;
|
|
use crate::core::film::FilmTrait;
|
|
use crate::core::filter::FilterTrait;
|
|
use crate::core::pbrt::Float;
|
|
use crate::core::sampler::CameraSample;
|
|
use crate::geometry::{
|
|
Bounds2f, Point2f, Point3f, Ray, RayDifferential, Vector2f, Vector3f, VectorLike,
|
|
};
|
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
|
use crate::utils::sampling::sample_uniform_disk_concentric;
|
|
use crate::utils::transform::Transform;
|
|
|
|
#[derive(Debug)]
|
|
pub struct PerspectiveCamera {
|
|
pub base: CameraBase,
|
|
pub screen_from_camera: Transform<Float>,
|
|
pub camera_from_raster: Transform<Float>,
|
|
pub raster_from_screen: Transform<Float>,
|
|
pub screen_from_raster: Transform<Float>,
|
|
pub lens_radius: Float,
|
|
pub focal_distance: Float,
|
|
pub dx_camera: Vector3f,
|
|
pub dy_camera: Vector3f,
|
|
pub cos_total_width: Float,
|
|
}
|
|
|
|
impl PerspectiveCamera {
|
|
pub fn new(
|
|
base: CameraBase,
|
|
screen_from_camera: &Transform<Float>,
|
|
screen_window: Bounds2f,
|
|
lens_radius: Float,
|
|
focal_distance: Float,
|
|
) -> Self {
|
|
let ndc_from_screen: Transform<Float> = 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 raster_from_ndc = Transform::scale(
|
|
base.film.full_resolution().x() as Float,
|
|
-base.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 camera_from_raster = screen_from_camera.inverse() * screen_from_raster;
|
|
let dx_camera = camera_from_raster.apply_to_point(Point3f::new(1., 0., 0.))
|
|
- camera_from_raster.apply_to_point(Point3f::new(0., 0., 0.));
|
|
let dy_camera = camera_from_raster.apply_to_point(Point3f::new(0., 1., 0.))
|
|
- camera_from_raster.apply_to_point(Point3f::new(0., 0., 0.));
|
|
let radius = base.film.get_filter().radius();
|
|
let p_corner = Point3f::new(-radius.x(), -radius.y(), 0.);
|
|
let w_corner_camera =
|
|
(camera_from_raster.apply_to_point(p_corner) - Point3f::new(0., 0., 0.)).normalize();
|
|
let cos_total_width = w_corner_camera.z();
|
|
Self {
|
|
base,
|
|
screen_from_camera: *screen_from_camera,
|
|
camera_from_raster,
|
|
raster_from_screen,
|
|
screen_from_raster,
|
|
lens_radius,
|
|
focal_distance,
|
|
dx_camera,
|
|
dy_camera,
|
|
cos_total_width,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CameraTrait for PerspectiveCamera {
|
|
fn base(&self) -> &CameraBase {
|
|
&self.base
|
|
}
|
|
|
|
fn init_metadata(&self, metadata: &mut crate::image::ImageMetadata) {
|
|
self.base.init_metadata(metadata)
|
|
}
|
|
|
|
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 p_vector = p_camera - Point3f::new(0., 0., 0.);
|
|
|
|
let mut r = Ray::new(
|
|
Point3f::new(0., 0., 0.),
|
|
p_vector.normalize(),
|
|
Some(self.sample_time(sample.time)),
|
|
self.base().medium.clone(),
|
|
);
|
|
// Modify ray for depth of field
|
|
if self.lens_radius > 0. {
|
|
// Sample point on lens
|
|
let p_lens =
|
|
self.lens_radius * Vector2f::from(sample_uniform_disk_concentric(sample.p_lens));
|
|
|
|
// Compute point on plane of focus
|
|
let ft = self.focal_distance / r.d.z();
|
|
let p_focus = r.at(ft);
|
|
|
|
// Update ray for effect of lens
|
|
r.o = Point3f::new(p_lens.x(), p_lens.y(), 0.);
|
|
r.d = (p_focus - r.o).normalize();
|
|
}
|
|
|
|
let ray = self.render_from_camera(&r, &mut None);
|
|
Some(CameraRay {
|
|
ray,
|
|
weight: SampledSpectrum::default(),
|
|
})
|
|
}
|
|
}
|