use super::*;
use sample;
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct DistantLight {
pub intensity: RGBSpectrumf,
dir: Vector3f,
world_center: Point3f,
world_radius: Float,
}
impl DistantLight {
#[inline]
pub fn new(intensity: RGBSpectrumf, dir: Vector3f) -> DistantLight {
let dir = dir.normalize();
DistantLight{
intensity: intensity,
dir: dir,
world_center: Point3f::new(0.0 as Float, 0.0 as Float, 0.0 as Float),
world_radius: float::infinity(),
}
}
#[inline]
pub fn set_direction(&mut self, towards: Vector3f) {
self.dir = towards.normalize();
}
#[inline]
pub fn set_world_bounds<C>(&mut self, components: &C)
where C: Composable
{
let (world_center, world_radius) = components.bbox_parent().bsphere();
self.world_radius = world_radius;
self.world_center = world_center;
}
}
impl Light for DistantLight {
#[inline]
fn flags(&self) -> LightFlag {
LIGHT_INFINITE
}
#[inline]
fn is_delta(&self) -> bool {
false
}
#[inline]
fn evaluate_sampled(&self, pos: Point3f, _sample: Point2f) -> LightSample {
let radiance = self.intensity;
let pfrom = pos + (-2.0 as Float * self.world_radius) * self.dir;
let pto = pos;
let pdf = 1.0 as Float;
LightSample{
radiance: radiance,
pfrom: pfrom,
pto: pto,
pdf: pdf,
}
}
fn generate_path(&self, samples: SampleInfo) -> PathInfo {
let (u, v) = normal::get_basis_from(self.dir);
let pdisk = sample::sample_concentric_disk(samples.pfilm);
let pdisk = self.world_center + self.world_radius*(pdisk.x * u + pdisk.y * v);
let pos = pdisk + self.dir * (-self.world_radius);
PathInfo{
ray: RawRay::from_od(pos, self.dir),
normal: self.dir,
pdfpos: 1. as Float / (self.world_radius * self.world_radius * float::pi()),
pdfdir: 1. as Float,
radiance: self.intensity,
}
}
#[inline]
fn pdf_path(&self, _pos: Point3f, _dir: Vector3f, _normal: Vector3f) -> (Float, Float) {
(
1. as Float / (self.world_radius * self.world_radius * float::pi()),
0. as Float
)
}
#[inline]
fn power(&self) -> RGBSpectrumf {
self.intensity * (self.world_radius * self.world_radius * float::pi())
}
}