use geometry::prelude::*;
use std::mem;
use spectrum::{Spectrum, RGBSpectrumf};
use super::*;
fn fresnel_dielectric(mut cos_theta_i: Float, mut etai: Float, mut etat: Float) -> Float {
if cos_theta_i < 0.0 as Float {
mem::swap(&mut etai, &mut etat);
cos_theta_i = -cos_theta_i;
}
let sin2_theta_i = (1.0 as Float - cos_theta_i * cos_theta_i).max(0. as Float);
let eta = etai / etat;
let sin2_theta_t = eta*eta*sin2_theta_i;
if sin2_theta_t >= 1.0 as Float {
return 1.0 as Float;
}
let cos_theta_t = (1.0 as Float - sin2_theta_t).sqrt();
let etci = etat * cos_theta_i;
let eict = etai * cos_theta_t;
let r_para = (etci - eict) / (etci + eict);
let eici = etai * cos_theta_i;
let etct = etat * cos_theta_t;
let r_perp = (eici - etct) / (eici + etct);
(r_para * r_para + r_perp * r_perp) * 0.5 as Float
}
fn fresnel_conductor(mut cos_theta_i: Float, mut etai: RGBSpectrumf, mut etat: RGBSpectrumf, k: RGBSpectrumf) -> RGBSpectrumf {
if cos_theta_i < 0.0 as Float {
mem::swap(&mut etai, &mut etat);
cos_theta_i = -cos_theta_i;
}
let sin_theta_i2 = 1.0 as Float - cos_theta_i * cos_theta_i;
let cos_theta_i2 = cos_theta_i * cos_theta_i;
let sin_theta_i4 = sin_theta_i2 * sin_theta_i2;
let sin_theta_i2 = RGBSpectrumf::grey_scale(sin_theta_i2);
let sin_theta_i4 = RGBSpectrumf::grey_scale(sin_theta_i4);
let cos_theta_i2 = RGBSpectrumf::grey_scale(cos_theta_i2);
let eta = etat/etai;
let eta2 = eta * eta;
let k2 = k * k;
let tmp0 = eta2 - k2 - sin_theta_i2;
let a2pb2 = (tmp0 * tmp0 + 4.0 as Float * eta2 * k2).sqrt();
let am2 = (a2pb2 * 2.0 as Float).sqrt();
let r_perp = (a2pb2 + cos_theta_i2 - am2 * cos_theta_i) / (a2pb2 + cos_theta_i2 + am2 * cos_theta_i);
let tmpa = a2pb2 * cos_theta_i2;
let tmpb = am2 * cos_theta_i * sin_theta_i2 + sin_theta_i4;
let r_para = r_perp * (tmpa - tmpb) / (tmpa + tmpb);
(r_para * r_para + r_perp * r_perp) * 0.5 as Float
}
pub trait Fresnel {
fn evaluate(&self, cos_theta_i: Float) -> RGBSpectrumf;
}
#[derive(Copy, Clone, Debug)]
pub struct Conductor {
pub etai: RGBSpectrumf,
pub etat: RGBSpectrumf,
pub k: RGBSpectrumf,
}
impl Conductor {
#[inline]
pub fn new(etai: RGBSpectrumf, etat: RGBSpectrumf, k: RGBSpectrumf) -> Conductor {
Conductor {
etai: etai, etat: etat, k: k
}
}
}
impl Fresnel for Conductor {
#[inline]
fn evaluate(&self, cos_theta_i: Float) -> RGBSpectrumf {
fresnel_conductor(cos_theta_i, self.etai, self.etat, self.k)
}
}
#[derive(Copy, Clone, Debug)]
pub struct Dielectric {
pub eta0: Float,
pub eta1: Float,
}
impl Dielectric {
#[inline]
pub fn new(etai: Float, etat: Float) -> Dielectric {
Dielectric{
eta0: etai, eta1: etat
}
}
}
impl Fresnel for Dielectric {
#[inline]
fn evaluate(&self, cos_theta_i: Float) -> RGBSpectrumf {
RGBSpectrumf::grey_scale(fresnel_dielectric(cos_theta_i, self.eta0, self.eta1))
}
}
pub struct Noop;
impl Fresnel for Noop {
#[inline]
fn evaluate(&self, _cos_theta_i: Float) -> RGBSpectrumf {
RGBSpectrumf::grey_scale(1.0 as Float)
}
}
#[derive(Copy, Clone, Debug)]
pub struct FresnelBxdf {
pub reflectance: RGBSpectrumf,
pub transmittance: RGBSpectrumf,
pub eta0: Float,
pub eta1: Float,
}
impl FresnelBxdf {
pub fn new(reflectance: RGBSpectrumf, transmittance: RGBSpectrumf, eta0: Float, eta1: Float) -> FresnelBxdf {
FresnelBxdf{
reflectance, transmittance, eta0, eta1
}
}
}
impl Bxdf for FresnelBxdf {
#[inline]
fn kind(&self) -> BxdfType {
BXDF_REFLECTION | BXDF_TRANSMISSION | BXDF_SPECULAR
}
#[inline]
fn evaluate(&self, _wo: Vector3f, _wi: Vector3f) -> RGBSpectrumf {
RGBSpectrumf::black()
}
fn evaluate_sampled(&self, wo: Vector3f, u: Point2f) -> (RGBSpectrumf, Vector3f, Float, BxdfType) {
let cos_theta = normal::cos_theta(wo);
let f = fresnel_dielectric(cos_theta, self.eta0, self.eta1);
if u.x < f {
let wi = Vector3f::new(-wo.x, -wo.y, wo.z);
let pdf = f;
debug_assert!(pdf <= 1. as Float);
debug_assert!(pdf > 0. as Float);
let f = pdf * self.reflectance / cos_theta.abs();
(f, wi, pdf, BXDF_REFLECTION | BXDF_SPECULAR)
} else {
let pdf = 1. as Float - f;
debug_assert!(pdf>= 0. as Float);
let (etai, etao, n) = if cos_theta > 0. as Float {
(self.eta0, self.eta1, Vector3f::new(0. as Float, 0., 1.))
} else {
(self.eta1, self.eta0, Vector3f::new(0. as Float, 0., -1.))
};
let eta = etai/etao;
let wt = normal::refract(wo, n, eta);
if let Some(wt) = wt {
let f = self.transmittance *eta * eta* pdf/wt.z.abs();
(f, wt, pdf, BXDF_TRANSMISSION | BXDF_SPECULAR)
} else {
(RGBSpectrumf::black(), Vector3f::zero(), pdf, BXDF_TRANSMISSION | BXDF_SPECULAR)
}
}
}
#[inline]
fn pdf(&self, _wo: Vector3f, _wi: Vector3f) -> Float {
0. as Float
}
}
#[derive(Copy, Clone, Debug)]
pub struct FresnelTBxdf {
pub transmittance: RGBSpectrumf,
pub eta0: Float,
pub eta1: Float,
}
impl Bxdf for FresnelTBxdf {
#[inline]
fn kind(&self) -> BxdfType {
BXDF_TRANSMISSION | BXDF_SPECULAR
}
#[inline]
fn evaluate(&self, _wo: Vector3f, _wi: Vector3f) -> RGBSpectrumf {
RGBSpectrumf::black()
}
fn evaluate_sampled(&self, wo: Vector3f, _u: Point2f) -> (RGBSpectrumf, Vector3f, Float, BxdfType) {
let (etai, etao, n) = if wo.z > 0. as Float {
(self.eta0, self.eta1, Vector3f::new(0. as Float, 0., 1.))
} else {
(self.eta1, self.eta0, Vector3f::new(0. as Float, 0., -1.))
};
let eta = etai/etao;
let wt = normal::refract(wo, n, eta);
if let Some(wt) = wt {
let f = self.transmittance *eta * eta*(
1. as Float - fresnel_dielectric(wo.z, self.eta0, self.eta1)
) /wt.z.abs();
(f, wt, 1. as Float, BXDF_TRANSMISSION | BXDF_SPECULAR)
} else {
(RGBSpectrumf::black(), Vector3f::zero(), 1. as Float, BXDF_TRANSMISSION | BXDF_SPECULAR)
}
}
#[inline]
fn pdf(&self, _wo: Vector3f, _wi: Vector3f) -> Float {
0. as Float
}
}