use bxdf::*;
use geometry::prelude::*;
use spectrum::{RGBSpectrumf, Spectrum};
use std::cmp;
use aren_alloc::Pointer;
pub struct Bsdf<'a> {
pub eta: Float,
ns: Vector3f,
ng: Vector3f,
ts: Vector3f,
bs: Vector3f,
sink: BsdfSink<'a>,
}
impl<'a> Bsdf<'a> {
#[inline]
pub fn new(si: &SurfaceInteraction, eta: Float) -> Bsdf<'a> {
let ts = si.shading_duv.dpdu.normalize();
let ns = si.shading_norm;
let bs = ns.cross(ts).normalize();
let ng = si.basic.norm;
Bsdf{
eta: eta, ns: ns, ng: ng, ts: ts, bs: bs, sink: Default::default(),
}
}
#[inline]
pub fn add(&mut self, bxdf: Pointer<'a, Bxdf>) {
self.sink.add(bxdf);
}
#[inline]
pub fn have_n(&self, kind: BxdfType) -> usize {
let mut count = 0;
for bxdf in self.sink.iter() {
if bxdf.is(kind) {
count += 1;
}
}
count
}
#[inline]
pub fn parent_to_local(&self, v: Vector3f) -> Vector3f {
Vector3f::new(v.dot(self.ts), v.dot(self.bs), v.dot(self.ns))
}
#[inline]
pub fn local_to_parent(&self, v: Vector3f) -> Vector3f {
Vector3f::new(
v.dot(Vector3f::new(self.ts.x, self.bs.x, self.ns.x)),
v.dot(Vector3f::new(self.ts.y, self.bs.y, self.ns.y)),
v.dot(Vector3f::new(self.ts.z, self.bs.z, self.ns.z))
)
}
pub fn evaluate(&self, wow: Vector3f, wiw: Vector3f, types: BxdfType) -> (RGBSpectrumf, BxdfType) {
let wo = self.parent_to_local(wow).normalize();
let wi = self.parent_to_local(wiw).normalize();
let is_reflection = wow.dot(self.ng) * wiw.dot(self.ng) > 0.0 as Float;
let mut ret = RGBSpectrumf::black();
let mut rettype = BxdfType::empty();
for bxdf in self.sink.iter() {
if bxdf.is(types) && (
(is_reflection && bxdf.kind().contains(BXDF_REFLECTION))
|| (!is_reflection && bxdf.kind().contains(BXDF_TRANSMISSION))
) {
ret += bxdf.evaluate(wo, wi);
rettype.insert(bxdf.kind() & types);
}
}
(ret, rettype)
}
pub fn evaluate_sampled(&self, wow: Vector3f, u: Point2f, types: BxdfType) -> (RGBSpectrumf, Vector3f, Float, BxdfType) {
let match_count = self.have_n(types);
let mut ret = (
RGBSpectrumf::black(),
Vector3f::new(0.0 as Float, 1.0 as Float, 0.0 as Float),
0.0 as Float,
BxdfType::empty(),
);
if match_count == 0 { return ret; }
let wo = self.parent_to_local(wow).normalize();
let idx = cmp::min((u.x * match_count as Float).floor() as usize, match_count-1);
let mut i = 0;
let mut is_specular = false;
for bxdf in self.sink.iter() {
if i == idx {
is_specular = bxdf.is(BXDF_SPECULAR);
let (f, wi, pdf, t) = bxdf.evaluate_sampled(wo, u);
if pdf == 0.0 as Float { return ret; }
ret = (f, wi, pdf, t & types);
}
if bxdf.is(types) { i += 1; }
}
let wi = ret.1;
ret.1 = self.local_to_parent(wi);
if ret.1.x.is_nan() || ret.1.y.is_nan() || ret.1.z.is_nan() {
warn!("Invalid wiw {:?}, wi {:?}, wow {:?}, wo {:?} bxdft {:?}", ret.1, wi, wow, wo, ret.3);
}
if match_count == 1 || is_specular { return ret; }
ret.0 = RGBSpectrumf::black();
let is_reflection = wow.dot(self.ng) * ret.1.dot(self.ng) > 0.0 as Float;
let mut pdfsum = 0.0 as Float;
for bxdf in self.sink.iter() {
if bxdf.is(ret.3) && (
(is_reflection && bxdf.is(BXDF_REFLECTION))
|| (!is_reflection && bxdf.is(BXDF_TRANSMISSION))
) {
ret.0 += bxdf.evaluate(wo, wi);
pdfsum += bxdf.pdf(wo, wi).max(0. as Float);
}
}
ret.2 = pdfsum / match_count as Float;
ret
}
pub fn evaluate_importance(&self, wow: Vector3f, wiw: Vector3f, types: BxdfType) -> (RGBSpectrumf, BxdfType) {
let wo = self.parent_to_local(wow);
let wi = self.parent_to_local(wiw);
let is_reflection = wow.dot(self.ng) * wiw.dot(self.ng) > 0.0 as Float;
let mut ret = RGBSpectrumf::black();
let mut rettype = BxdfType::empty();
for bxdf in self.sink.iter() {
if bxdf.is(types) && (
(is_reflection && (bxdf.kind() & BXDF_REFLECTION == BXDF_REFLECTION))
|| (!is_reflection && (bxdf.kind() & BXDF_TRANSMISSION == BXDF_TRANSMISSION))
) {
ret += bxdf.evaluate_importance(wo, wi);
rettype.insert(bxdf.kind() & types);
}
}
(ret, rettype)
}
pub fn evaluate_importance_sampled(&self, wow: Vector3f, u: Point2f, types: BxdfType)-> (RGBSpectrumf, Vector3f, Float, BxdfType) {
let match_count = self.have_n(types);
let mut ret = (
RGBSpectrumf::black(),
Vector3f::new(0.0 as Float, 1.0 as Float, 0.0 as Float),
0.0 as Float,
BxdfType::empty(),
);
if match_count == 0 { return ret; }
let wo = self.parent_to_local(wow);
let idx = cmp::min((u.x * match_count as Float).floor() as usize, match_count-1);
let mut i = 0;
for bxdf in self.sink.iter() {
if i == idx {
let (f, wi, pdf, t) = bxdf.evaluate_importance_sampled(wo, u);
if pdf == 0.0 as Float { return ret; }
ret = (f, wi, pdf, t & types);
}
if bxdf.is(types) { i += 1; }
}
let wi = ret.1;
ret.1 = self.local_to_parent(wi);
if match_count == 1 { return ret; }
let mut pdfsum = 0.0 as Float;
for bxdf in self.sink.iter() {
if bxdf.is(types) {
pdfsum += bxdf.pdf(wo, wi).max(0. as Float);
}
}
if match_count > 0 {
pdfsum /= match_count as Float;
}
ret.2 = pdfsum;
ret
}
pub fn pdf(&self, wow: Vector3f, wiw: Vector3f, types: BxdfType) -> Float {
let wo = self.parent_to_local(wow).normalize();
let wi = self.parent_to_local(wiw).normalize();
if wo.z == 0. as Float { return 0. as Float; }
let mut pdfsum = 0.0 as Float;
let mut match_count = 0;
for bxdf in self.sink.iter() {
if bxdf.is(types) {
match_count += 1;
pdfsum += bxdf.pdf(wo, wi).max(0. as Float);
}
}
if match_count == 0 {
pdfsum
} else {
pdfsum / match_count as Float
}
}
pub fn rho_hd(&self, wow: Vector3f, samples: &[Point2f]) -> RGBSpectrumf {
let wo = self.parent_to_local(wow);
let mut ret = RGBSpectrumf::black();
for bxdf in self.sink.iter() {
ret += bxdf.rho_hd(wo, samples);
}
ret
}
pub fn rho_hh(&self, samples0: &[Point2f], samples1: &[Point2f]) -> RGBSpectrumf {
let mut ret = RGBSpectrumf::black();
for bxdf in self.sink.iter() {
ret += bxdf.rho_hh(samples0, samples1);
}
ret
}
}
struct BsdfSink<'a> {
bxdfs: [Option<Pointer<'a, Bxdf>>; 8],
n: usize,
}
impl<'a> Default for BsdfSink<'a> {
fn default() -> BsdfSink<'a> {
BsdfSink{
bxdfs: [None, None, None, None, None, None, None, None],
n: 0,
}
}
}
impl<'a> BsdfSink<'a> {
#[inline]
fn add(&mut self, bxdf: Pointer<'a, Bxdf>) {
assert!(self.n < 8);
let n = self.n;
self.bxdfs[n] = Some(bxdf);
self.n += 1;
}
#[inline]
fn iter<'b>(&'b self) -> BsdfSinkIter<'b, 'a> {
BsdfSinkIter{
sink: self,
i: 0
}
}
}
struct BsdfSinkIter<'a, 'b: 'a> {
sink: &'a BsdfSink<'b>,
i: usize,
}
impl<'a, 'b: 'a> Iterator for BsdfSinkIter<'a, 'b> {
type Item = &'a Bxdf;
fn next(&mut self) -> Option<&'a Bxdf> {
if self.i >= self.sink.n {
None
} else {
let i = self.i;
let ret = unsafe {
self.sink.bxdfs.get_unchecked(i).as_ref().map(|p| {
let ret: *const Bxdf = &**p;
&*ret
})
};
self.i += 1;
ret
}
}
}