pbrt/src/camera/spherical.rs

64 lines
2 KiB
Rust

use super::{CameraBase, CameraRay, CameraTrait};
use crate::core::film::FilmTrait;
use crate::core::pbrt::{Float, PI};
use crate::core::sampler::CameraSample;
use crate::geometry::{Bounds2f, Point2f, Point3f, Ray, Vector3f, spherical_direction};
use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::math::{equal_area_square_to_sphere, wrap_equal_area_square};
#[derive(PartialEq)]
pub struct EquiRectangularMapping;
#[derive(PartialEq)]
pub enum Mapping {
EquiRectangular(EquiRectangularMapping),
}
pub struct SphericalCamera {
pub base: CameraBase,
pub screen: Bounds2f,
pub lens_radius: Float,
pub focal_distance: Float,
pub mapping: Mapping,
}
impl CameraTrait for SphericalCamera {
fn base(&self) -> &CameraBase {
&self.base
}
fn generate_ray(
&self,
sample: CameraSample,
_lamdba: &SampledWavelengths,
) -> Option<CameraRay> {
// Compute spherical camera ray direction
let mut uv = Point2f::new(
sample.p_film.x() / self.base().film.full_resolution().x() as Float,
sample.p_film.y() / self.base().film.full_resolution().y() as Float,
);
let dir: Vector3f;
if self.mapping == Mapping::EquiRectangular(EquiRectangularMapping) {
// 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(),
})
}
}