104 lines
3.4 KiB
Rust
104 lines
3.4 KiB
Rust
// use crate::core::image::{Image, ImageIO, ImageMetadata};
|
|
use crate::core::light::{CreateLight, lookup_spectrum};
|
|
use crate::core::spectrum::spectrum_to_photometric;
|
|
use crate::core::texture::FloatTexture;
|
|
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
|
use shared::core::geometry::{Frame, Point3f, VectorLike};
|
|
use shared::core::light::{Light, LightBase, LightType};
|
|
use shared::core::medium::{Medium, MediumInterface};
|
|
use shared::core::shape::Shape;
|
|
use shared::core::spectrum::Spectrum;
|
|
use shared::core::texture::SpectrumType;
|
|
use shared::lights::SpotLight;
|
|
use shared::spectra::RGBColorSpace;
|
|
use shared::utils::Transform;
|
|
use shared::utils::math::radians;
|
|
use shared::{Float, PI};
|
|
use std::fmt::Error;
|
|
|
|
pub trait CreateSpotLight {
|
|
fn new(
|
|
render_from_light: Transform,
|
|
medium_interface: MediumInterface,
|
|
le: Spectrum,
|
|
scale: shared::Float,
|
|
cos_falloff_start: Float,
|
|
total_width: Float,
|
|
) -> Self;
|
|
}
|
|
|
|
impl CreateSpotLight for SpotLight {
|
|
fn new(
|
|
render_from_light: Transform,
|
|
medium_interface: MediumInterface,
|
|
le: Spectrum,
|
|
scale: shared::Float,
|
|
cos_falloff_start: Float,
|
|
total_width: Float,
|
|
) -> Self {
|
|
let base = LightBase::new(
|
|
LightType::DeltaPosition,
|
|
render_from_light,
|
|
MediumInterface::empty(),
|
|
);
|
|
|
|
let iemit = Ptr::from(&lookup_spectrum(&le));
|
|
Self {
|
|
base,
|
|
iemit,
|
|
scale,
|
|
cos_falloff_end: radians(total_width).cos(),
|
|
cos_falloff_start: radians(cos_falloff_start).cos(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CreateLight for SpotLight {
|
|
fn create(
|
|
arena: &mut Arena,
|
|
render_from_light: Transform,
|
|
medium: Medium,
|
|
parameters: &ParameterDictionary,
|
|
_loc: &FileLoc,
|
|
_shape: &Shape,
|
|
_alpha_tex: &FloatTexture,
|
|
colorspace: Option<&RGBColorSpace>,
|
|
) -> Result<Light, Error> {
|
|
let i = parameters
|
|
.get_one_spectrum(
|
|
"I",
|
|
Some(Spectrum::Dense(colorspace.unwrap().illuminant)),
|
|
SpectrumType::Illuminant,
|
|
)
|
|
.expect("No spectrum");
|
|
let mut scale = parameters.get_one_float("scale", 1.);
|
|
let coneangle = parameters.get_one_float("coneangle", 30.);
|
|
let conedelta = parameters.get_one_float("conedelta", 5.);
|
|
let from = parameters.get_one_point3f("from", Point3f::zero());
|
|
let to = parameters.get_one_point3f("to", Point3f::new(0., 0., 1.));
|
|
let dir_to_z = Transform::from(Frame::from_z((to - from).normalize()));
|
|
let t = Transform::translate(from.into()) * dir_to_z.inverse();
|
|
let final_render = render_from_light * t;
|
|
scale /= spectrum_to_photometric(i);
|
|
|
|
let phi_v = parameters.get_one_float("power", -1.);
|
|
if phi_v > 0. {
|
|
let cos_falloff_end = radians(coneangle).cos();
|
|
let cos_falloff_start = radians(coneangle - conedelta).cos();
|
|
let k_e =
|
|
2. * PI * ((1. - cos_falloff_start) + (cos_falloff_start - cos_falloff_end) / 2.);
|
|
scale *= phi_v / k_e;
|
|
}
|
|
|
|
let specific = SpotLight::new(
|
|
final_render,
|
|
medium.into(),
|
|
i,
|
|
scale,
|
|
coneangle,
|
|
coneangle - conedelta,
|
|
);
|
|
arena.alloc(specific);
|
|
Ok(Light::Spot(specific))
|
|
}
|
|
}
|