#![allow(dead_code)]
use geometry::prelude::*;
use filming::prelude::*;
use lighting::prelude::*;
use material::prelude::*;
use spectrum::{Spectrum, RGBSpectrumf};
use bxdf::prelude::*;
use renderer::scene::Scene;
use std::ptr;
use std::mem;
use super::TransportMode;
#[derive(Copy, Clone)]
pub enum Node<'a> {
Camera{
camera: &'a Camera,
info: InteractInfo,
beta: RGBSpectrumf,
pdf: Float,
pdf_reversed: Float,
},
Light{
light: &'a Light,
info: InteractInfo,
beta: RGBSpectrumf,
pdf: Float,
pdf_reversed: Float,
},
Surface{
bsdf: &'a Bsdf<'a>,
si: SurfaceInteraction<'a>,
beta: RGBSpectrumf,
pdf: Float,
pdf_reversed: Float,
},
Medium{
info: InteractInfo,
beta: RGBSpectrumf,
pdf: Float,
pdf_reversed: Float,
},
}
impl<'a> Node<'a> {
#[inline]
pub fn info(&self) -> InteractInfo {
match *self {
Node::Camera{info, ..} => info,
Node::Light{info, ..} => info,
Node::Surface{ref si, ..} => si.basic,
Node::Medium{info, ..} => info,
}
}
#[inline(always)]
pub fn pos(&self) -> Point3f {
self.info().pos
}
#[inline(always)]
pub fn norm(&self) -> Vector3f {
self.info().norm
}
#[inline(always)]
pub fn shading_norm(&self) -> Vector3f {
match *self {
Node::Camera{ref info, ..} => info.norm,
Node::Light{ref info, ..} => info.norm,
Node::Surface{ref si, ..} => si.shading_norm,
Node::Medium{ref info, ..} => info.norm,
}
}
#[inline(always)]
pub fn on_surface(&self) -> bool {
self.norm() != Vector3f::zero()
}
#[inline(always)]
pub fn wo(&self) -> Vector3f {
self.info().wo
}
#[inline]
pub fn evaluate(&self, next: &Node, mode: TransportMode) -> RGBSpectrumf {
let wi = (next.pos() - self.pos()).normalize();
match *self {
Node::Surface{bsdf, ref si, ..} => {
if mode == TransportMode::Radiance {
bsdf.evaluate(si.basic.wo, wi, BXDF_ALL).0
} else {
bsdf.evaluate_importance(si.basic.wo, wi, BXDF_ALL).0
}
},
_ => RGBSpectrumf::black(),
}
}
#[inline]
pub fn is_connectible(&self) -> bool {
match *self {
Node::Light{light, ..} => light.flags().intersects(LIGHT_DDIR),
Node::Surface{bsdf, ..} => bsdf.have_n(BXDF_DIFFUSE|BXDF_GLOSSY|BXDF_REFLECTION|BXDF_TRANSMISSION) > 0,
_ => true,
}
}
#[inline(always)]
pub fn is_light(&self) -> bool {
match *self {
Node::Light{..} => true,
Node::Surface{ref si, ..} => si.is_emissive(),
_ => false,
}
}
#[inline(always)]
pub fn is_light_node(&self) -> bool {
match *self {
Node::Light{..} => true,
_ => false,
}
}
#[inline]
pub fn is_delta_light(&self) -> bool {
match *self {
Node::Light{light, ..} => light.is_delta(),
_ => false,
}
}
#[inline]
pub fn convert_density(&self, next: &Node, mut pdf: Float) -> Float {
let wi = next.pos() - self.pos();
let invdist2 = 1. as Float / wi.magnitude2();
let norm = next.norm();
if norm != Vector3f::new(0. as Float, 0. as Float, 0. as Float) {
pdf *= norm.dot(wi*invdist2.sqrt()).abs();
}
pdf * invdist2
}
#[inline]
pub fn pdf(&self, prev: Option<&Node>, next: &Node) -> Float {
let wp = if let Some(prev) = prev {
(prev.pos() - self.pos()).normalize()
} else {
Vector3f::new(0. as Float, 0. as Float, 0. as Float)
};
let wn = (next.pos() - self.pos()).normalize();
let pdf = match *self {
Node::Light{light, ref info, ..} => light.pdf(info.pos, wn, info.norm).1,
Node::Camera{camera, ref info, ..} => camera.pdf(info.pos, wn).1,
Node::Surface{bsdf, ..} => bsdf.pdf(wp, wn, BXDF_ALL),
_ => unimplemented!(),
};
self.convert_density(next, pdf)
}
pub fn pdf_light(&self, next: &Node) -> Float {
let wi = next.pos() - self.pos();
let invdist2 = 1. as Float / wi.magnitude2();
let wn = wi*invdist2.sqrt();
let mut pdf = match *self {
Node::Light{light, ref info, ..} => light.pdf(info.pos, wn, info.norm).1,
Node::Surface{ref si, ..} => {
if let Some(light) = si.primitive_hit {
light.pdf(si.basic.pos, wn, si.basic.norm).1
} else {
0. as Float
}
},
_ => 0. as Float,
};
let nnorm = next.norm();
if nnorm != Vector3f::new(0. as Float, 0. as Float, 0. as Float) {
pdf *= nnorm.dot(wn).abs();
}
pdf * invdist2
}
pub fn pdf_light_origin(&self, scene: &Scene, next: &Node) -> Float {
let wi = (next.pos() - self.pos()).normalize();
match *self {
Node::Light{light, ref info, ..} => {
let pdf_pos = light.pdf(info.pos, wi, info.norm).0;
let mut pdf_choice = 0. as Float;
for (i, l) in scene.lights.iter().enumerate() {
if ptr::eq(light, l.as_ref()) {
pdf_choice = scene.light_distribution.discrete_pdf(i);
break;
}
}
pdf_pos * pdf_choice
}
Node::Surface{ref si, ..} => {
if let Some(light) = si.primitive_hit {
let pdf_pos = light.pdf(si.basic.pos, wi, si.basic.norm).0;
let mut pdf_choice = 0. as Float;
pdf_pos * pdf_choice
} else {
0. as Float
}
},
_ => 0. as Float,
}
}
#[inline]
pub fn get_pdf_mut(&mut self) -> &mut Float {
match *self {
Node::Camera{ref mut pdf, ..} => pdf,
Node::Light{ref mut pdf, ..} => pdf,
Node::Surface{ref mut pdf, ..} => pdf,
Node::Medium{ref mut pdf, ..} => pdf,
}
}
#[inline]
pub fn get_pdf_rev_mut(&mut self) -> &mut Float {
match *self {
Node::Camera{ref mut pdf_reversed, ..} => pdf_reversed,
Node::Light{ref mut pdf_reversed, ..} => pdf_reversed,
Node::Surface{ref mut pdf_reversed, ..} => pdf_reversed,
Node::Medium{ref mut pdf_reversed, ..} => pdf_reversed,
}
}
#[inline]
pub fn get_pdf(&self) -> Float {
match *self {
Node::Camera{pdf, ..} => pdf,
Node::Light{pdf, ..} => pdf,
Node::Surface{pdf, ..} => pdf,
Node::Medium{pdf, ..} => pdf,
}
}
#[inline]
pub fn get_pdf_rev(&self) -> Float {
match *self {
Node::Camera{pdf_reversed, ..} => pdf_reversed,
Node::Light{pdf_reversed, ..} => pdf_reversed,
Node::Surface{pdf_reversed, ..} => pdf_reversed,
Node::Medium{pdf_reversed, ..} => pdf_reversed,
}
}
#[inline]
pub fn get_beta_mut(&mut self) -> &mut RGBSpectrumf {
match *self {
Node::Camera{ref mut beta, ..} => beta,
Node::Light{ref mut beta, ..} => beta,
Node::Surface{ref mut beta, ..} => beta,
Node::Medium{ref mut beta, ..} => beta,
}
}
#[inline]
pub fn get_beta(&self) -> RGBSpectrumf {
match *self {
Node::Camera{beta, ..} => beta,
Node::Light{beta, ..} => beta,
Node::Surface{beta, ..} => beta,
Node::Medium{beta, ..} => beta,
}
}
#[inline]
pub fn as_light(&self) -> Option<&Light> {
match *self {
Node::Light{light, ..} => Some(light),
Node::Surface{ref si, ..} => si.primitive_hit.map(|p| p.as_light()),
_ => None,
}
}
}
impl<'a> Default for Node<'a> {
fn default() -> Self {unsafe {
mem::uninitialized()
}}
}