Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include "redner.h"
- #include "vector.h"
- #include "intersection.h"
- #include "buffer.h"
- #include "ptr.h"
- #include "texture.h"
- #include <tuple>
- struct Material {
- Material() {}
- Material(Texture3 diffuse_reflectance,
- Texture3 specular_reflectance,
- Texture1 roughness,
- Texture3 normal_map,
- bool two_sided)
- : diffuse_reflectance(diffuse_reflectance),
- specular_reflectance(specular_reflectance),
- roughness(roughness),
- normal_map(normal_map),
- two_sided(two_sided) {}
- inline std::tuple<int, int, int> get_diffuse_size() const {
- return std::make_tuple(
- diffuse_reflectance.width,
- diffuse_reflectance.height,
- diffuse_reflectance.num_levels);
- }
- inline std::tuple<int, int, int> get_specular_size() const {
- return std::make_tuple(
- specular_reflectance.width,
- specular_reflectance.height,
- specular_reflectance.num_levels);
- }
- inline std::tuple<int, int, int> get_roughness_size() const {
- return std::make_tuple(
- roughness.width,
- roughness.height,
- roughness.num_levels);
- }
- inline std::tuple<int, int, int> get_normal_map_size() const {
- return std::make_tuple(
- normal_map.width,
- normal_map.height,
- normal_map.num_levels);
- }
- Texture3 diffuse_reflectance;
- Texture3 specular_reflectance;
- Texture1 roughness;
- Texture3 normal_map;
- bool two_sided;
- };
- struct DMaterial {
- Texture3 diffuse_reflectance;
- Texture3 specular_reflectance;
- Texture1 roughness;
- Texture3 normal_map;
- };
- template <typename T>
- struct TBSDFSample {
- TVector2<T> uv;
- T w;
- };
- using BSDFSample = TBSDFSample<Real>;
- DEVICE
- inline Vector3 get_diffuse_reflectance(const Material &material,
- const SurfacePoint &shading_point) {
- return get_texture_value(material.diffuse_reflectance,
- shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
- }
- DEVICE
- inline void d_get_diffuse_reflectance(const Material &material,
- const SurfacePoint &shading_point,
- const Vector3 &d_output,
- Texture3 &d_texture,
- SurfacePoint &d_shading_point) {
- d_get_texture_value(material.diffuse_reflectance,
- shading_point.uv,
- shading_point.du_dxy,
- shading_point.dv_dxy,
- d_output,
- d_texture,
- d_shading_point.uv,
- d_shading_point.du_dxy,
- d_shading_point.dv_dxy);
- }
- DEVICE
- inline Vector3 get_specular_reflectance(const Material &material,
- const SurfacePoint &shading_point) {
- return get_texture_value(material.specular_reflectance,
- shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
- }
- DEVICE
- inline void d_get_specular_reflectance(const Material &material,
- const SurfacePoint &shading_point,
- const Vector3 &d_output,
- Texture3 &d_texture,
- SurfacePoint &d_shading_point) {
- d_get_texture_value(material.specular_reflectance,
- shading_point.uv,
- shading_point.du_dxy,
- shading_point.dv_dxy,
- d_output,
- d_texture,
- d_shading_point.uv,
- d_shading_point.du_dxy,
- d_shading_point.dv_dxy);
- }
- DEVICE
- inline Real get_roughness(const Material &material,
- const SurfacePoint &shading_point) {
- return get_texture_value(material.roughness,
- shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
- }
- DEVICE
- inline void d_get_roughness(const Material &material,
- const SurfacePoint &shading_point,
- const Real d_output,
- Texture1 &d_texture,
- SurfacePoint &d_shading_point) {
- d_get_texture_value(material.roughness,
- shading_point.uv,
- shading_point.du_dxy,
- shading_point.dv_dxy,
- d_output,
- d_texture,
- d_shading_point.uv,
- d_shading_point.du_dxy,
- d_shading_point.dv_dxy);
- }
- DEVICE
- inline bool has_normal_map(const Material &material) {
- return material.normal_map.texels != nullptr;
- }
- DEVICE
- inline Vector3 get_normal(const Material &material,
- const SurfacePoint &shading_point) {
- return get_texture_value(material.normal_map,
- shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
- }
- DEVICE
- inline void d_get_normal(const Material &material,
- const SurfacePoint &shading_point,
- const Vector3 &d_output,
- Texture3 &d_texture,
- SurfacePoint &d_shading_point) {
- d_get_texture_value(material.normal_map,
- shading_point.uv,
- shading_point.du_dxy,
- shading_point.dv_dxy,
- d_output,
- d_texture,
- d_shading_point.uv,
- d_shading_point.du_dxy,
- d_shading_point.dv_dxy);
- }
- // y = 2 / x - 2
- // y + 2 = 2 / x
- // x = 2 / (y + 2)
- DEVICE
- inline Real roughness_to_phong(Real roughness) {
- return max(2.f / roughness - 2.f, Real(0));
- }
- DEVICE
- inline Real d_roughness_to_phong(Real roughness, Real d_exponent) {
- return (roughness > 0 && roughness <= 1.f) ?
- -2.f * d_exponent / square(roughness) : 0.f;
- }
- DEVICE
- inline Frame perturb_shading_frame(const Material &material,
- const SurfacePoint &shading_point) {
- auto n = 2 * get_normal(material, shading_point) - 1;
- auto perturb_n = normalize(to_world(shading_point.shading_frame, n));
- auto perturb_x = normalize(
- shading_point.dpdu - perturb_n * dot(perturb_n, shading_point.dpdu));
- auto perturb_y = cross(perturb_n, perturb_x);
- return Frame(perturb_x, perturb_y, perturb_n);
- }
- DEVICE
- inline void d_perturb_shading_frame(const Material &material,
- const SurfacePoint &shading_point,
- const Frame &d_frame,
- DMaterial &d_material,
- SurfacePoint &d_shading_point) {
- // Perturb shading frame
- auto n = 2 * get_normal(material, shading_point) - 1;
- auto npn = to_world(shading_point.shading_frame, n);
- auto perturb_n = normalize(npn);
- auto dot_pn_dpdu = dot(perturb_n, shading_point.dpdu);
- auto npx = shading_point.dpdu - perturb_n * dot_pn_dpdu;
- auto perturb_x = normalize(npx);
- // perturb_y = cross(perturb_n, perturb_x)
- // return Frame(perturb_x, perturb_y, perturb_n)
- auto d_perturb_n = Vector3{0, 0, 0};
- auto d_perturb_x = Vector3{0, 0, 0};
- d_cross(perturb_n, perturb_x, d_frame[1], d_perturb_n, d_perturb_x);
- // perturb_x = normalize(npx)
- auto d_npx = d_normalize(npx, d_perturb_x);
- // npx = shading_point.dpdu - perturb_n * dot(perturb_n, shading_point.dpdu)
- d_shading_point.dpdu += d_npx;
- d_perturb_n -= d_npx * dot_pn_dpdu;
- auto d_dot_pn_dpdu = -d_npx * dot_pn_dpdu;
- // dot_pn_dpdu = dot(perturb_n, shading_point.dpdu)
- d_perturb_n += dot_pn_dpdu * shading_point.dpdu;
- d_shading_point.dpdu += d_dot_pn_dpdu * perturb_n;
- // perturb_n = normalize(npn)
- auto d_npn = d_normalize(npn, d_perturb_n);
- // npn = to_world(shading_point.shading_frame, n)
- auto d_normal_map_n = Vector3{0, 0, 0};
- d_to_world(shading_point.shading_frame, n, d_npn,
- d_shading_point.shading_frame, d_normal_map_n);
- // n = 2 * get_normal(material, shading_point) - 1
- d_get_normal(material,
- shading_point,
- 2 * d_normal_map_n,
- d_material.normal_map,
- d_shading_point);
- }
- // Specialized version
- DEVICE
- inline void d_perturb_shading_frame(const Material &material,
- const SurfacePoint &shading_point,
- const Vector3 &d_n,
- DMaterial &d_material,
- SurfacePoint &d_shading_point) {
- // Perturb shading frame
- auto n = get_normal(material, shading_point);
- auto npn = to_world(shading_point.shading_frame, n);
- // perturb_n = normalize(npn)
- auto d_npn = d_normalize(npn, d_n);
- auto d_normal_map_n = Vector3{0, 0, 0};
- d_to_world(shading_point.shading_frame, n, d_npn,
- d_shading_point.shading_frame, d_normal_map_n);
- // n = 2 * get_normal(material, shading_point) - 1
- d_get_normal(material,
- shading_point,
- 2 * d_normal_map_n,
- d_material.normal_map,
- d_shading_point);
- }
- // TODO: update
- const Real ior = 1.5f;
- const bool sampleVisibleArea = true;
- const Real etaA = 1.0f;
- const Real etaB = 1.5f;
- DEVICE
- inline
- Real Clamp(Real val, Real low, Real high) {
- if (val < low) val = low;
- if (val > high) val = high;
- return val;
- }
- // BSDF Inline Functions
- DEVICE
- inline
- Real CosTheta(const Vector3 &w) { return w.z; }
- Vector3 d_CosTheta(const Vector3 &w) { return }
- DEVICE
- inline
- Real Cos2Theta(const Vector3 &w) { return w.z * w.z; }
- DEVICE
- inline
- Real d_Cos2Theta(const Vector3 &w) { return 2.f * CosTheta(w) * -SinTheta(w); }
- DEVICE
- inline
- Real AbsCosTheta(const Vector3 &w) { return fabs(w.z); }
- DEVICE
- inline
- Real Sin2Theta(const Vector3 &w) {
- return max(Real(0), Real(1) - Cos2Theta(w));
- }
- DEVICE
- inline
- Real d_Sin2Theta(const Vector3 &w) { return 2.f * SinTheta(w) * CosTheta(w); }
- DEVICE
- inline
- Real SinTheta(const Vector3 &w) { return sqrt(Sin2Theta(w)); }
- DEVICE
- inline
- Real SecTheta(const Vector3 &w) { return 1.f / CosTheta(w); }
- DEVICE
- inline
- Real Sec2Theta(const Vector3 &w) { return SecTheta(w) * SecTheta(w); }
- DEVICE
- inline
- Real TanTheta(const Vector3 &w) { return SinTheta(w) / CosTheta(w); }
- DEVICE
- inline
- Real d_TanTheta(const Vector3 &w) { return Sec2Theta(w); }
- DEVICE
- inline
- Real Tan2Theta(const Vector3 &w) {
- return Sin2Theta(w) / Cos2Theta(w);
- }
- DEVICE
- inline
- Real d_Tan2Theta(const Vector3 &w) {
- return 2.f * TanTheta(w) * d_TanTheta(w);
- }
- DEVICE
- inline
- Real CosPhi(const Vector3 &w) {
- Real sinTheta = SinTheta(w);
- return (sinTheta == 0) ? 1 : Clamp(w.x / sinTheta, -1, 1);
- }
- DEVICE
- inline
- Real SinPhi(const Vector3 &w) {
- Real sinTheta = SinTheta(w);
- return (sinTheta == 0) ? 0 : Clamp(w.y / sinTheta, -1, 1);
- }
- DEVICE
- inline
- Real Cos2Phi(const Vector3 &w) { return CosPhi(w) * CosPhi(w); }
- DEVICE
- inline
- Real d_Cos2Phi(const Vector3 &w) { return 2.f * CosPhi(w) * -SinPhi(w); }
- DEVICE
- inline
- Real Sin2Phi(const Vector3 &w) { return SinPhi(w) * SinPhi(w); }
- DEVICE
- inline
- Real d_Sin2Phi(const Vector3 &w) { return 2.f * SinPhi(w) * CosPhi(w); }
- DEVICE
- inline
- Real RoughnessToAlpha(Real roughness) {
- auto x = log(roughness);
- return 1.62142f + 0.819955f * x + 0.1734f * x * x +
- 0.0171201f * x * x * x + 0.000640711f * x * x * x * x;
- }
- DEVICE
- inline
- Real d_RoughnessToAlpha(Real roughness) {
- auto x = log(roughness);
- auto d_log_d_x = 1.f / roughness;
- return 0.819955f * d_log_d_x
- + 0.1734f * 2.f * x * d_log_d_x
- + 0.0171201f * 3.f * x * x * d_log_d_x
- + 0.000640711f * 4.f * x * x * x * d_log_d_x;
- }
- DEVICE
- inline
- Real Lambda(const Vector3 &w, Real roughness) {
- Real absTanTheta = std::abs(TanTheta(w));
- if (std::isinf(absTanTheta)) return 0.;
- Real alphax = RoughnessToAlpha(roughness);
- Real alphay = alphax;
- // Compute _alpha_ for direction _w_
- Real alpha = sqrt(Cos2Phi(w) * alphax * alphax + Sin2Phi(w) * alphay * alphay);
- Real alpha2Tan2Theta = (alpha * absTanTheta) * (alpha * absTanTheta);
- return (-1 + sqrt(1.f + alpha2Tan2Theta)) / 2;
- }
- DEVICE
- inline
- void d_Lambda(const Vector3 &w, Real roughness, Vector3 &d_lambda_d_w, Real &d_lambda_d_roughness) {
- Real absTanTheta = std::abs(TanTheta(w));
- if (std::isinf(absTanTheta)) return 0.;
- Real d_absTanTheta_d_w = ((TanTheta(w) < 0.f) ? -1.f : 1.f) * d_TanTheta(w);
- Real alphax = RoughnessToAlpha(roughness);
- Real alphay = alphax;
- /* Derivatives of anisotropic alphas w.r.t. roughness. */
- Real d_alphax_d_roughness = d_RoughnessToAlpha(roughness);
- Real d_alphay_d_roughness = d_alphax;
- // Compute _alpha_ for direction _w_
- Real alpha = sqrt(Cos2Phi(w) * alphax * alphax + Sin2Phi(w) * alphay * alphay);
- /* Derivative of alpha w.r.t. roughness. */
- Real d_alpha_d_roughness = 0.5f/alpha * (2.f * Cos2Phi(w) * alphax * d_alphax_d_roughness
- + 2.f * Sin2Phi(w) * alphay * d_alphay_d_roughness);
- /* Derivative of alpha w.r.t. w. */
- Real d_alpha_d_w = 0.5f/alpha * (alphax * alphax * d_Cos2Phi(w) + alphay * alphay * d_Sin2Phi(w));
- Real alpha2Tan2Theta = (alpha * absTanTheta) * (alpha * absTanTheta);
- /* Derivative of alpha2Tan2Theta w.r.t. roughness. */
- Real d_alpha2Tan2Theta_d_roughness = 2.f * (alpha * absTanTheta) * d_alpha_d_roughness;
- /* Derivative of alpha2Tan2Theta w.r.t. w. */
- Real d_alpha2Tan2Theta_d_roughness = 2.f * (alpha * absTanTheta) * (d_alpha_d_w * absTanTheta + alpha * d_absTanTheta_d_w);
- /* LAMBDA: return (-1 + sqrt(1.f + alpha2Tan2Theta)) / 2; */
- /* Derivative of lambda w.r.t. roughness. */
- d_lambda_d_roughness = 0.5f * ((0.5f / sqrt(1 + alpha2Tan2Theta)) * d_alpha2Tan2Theta_d_roughness);
- /* Derivative of lambda w.r.t. w. */
- d_lambda_d_w = 0.5f * ((0.5f / sqrt(1 + alpha2Tan2Theta)) * d_alpha2Tan2Theta_d_w);
- }
- DEVICE
- inline
- Real FrDielectric(Real cosThetaI, Real etaI, Real etaT) {
- cosThetaI = Clamp(cosThetaI, -1, 1);
- // Potentially swap indices of refraction
- bool entering = cosThetaI > 0.f;
- if (!entering) {
- Real temp = etaT;
- etaT = etaI;
- etaI = temp;
- cosThetaI = fabs(cosThetaI);
- }
- // Compute _cosThetaT_ using Snell's law
- Real sinThetaI = sqrt(max(Real(0), 1 - cosThetaI * cosThetaI));
- Real sinThetaT = etaI / etaT * sinThetaI;
- // Handle total internal reflection
- if (sinThetaT >= 1) return 1;
- Real cosThetaT = sqrt(max(Real(0), 1 - sinThetaT * sinThetaT));
- Real Rparl = ((etaT * cosThetaI) - (etaI * cosThetaT)) /
- ((etaT * cosThetaI) + (etaI * cosThetaT));
- Real Rperp = ((etaI * cosThetaI) - (etaT * cosThetaT)) /
- ((etaI * cosThetaI) + (etaT * cosThetaT));
- return (Rparl * Rparl + Rperp * Rperp) / 2;
- }
- DEVICE
- inline
- void d_FrDielectric(Real cosThetaI, Real etaI, Real etaT, Vector3 &d_FrDielectric_d_cosThetaI) {
- cosThetaI = Clamp(cosThetaI, -1, 1);
- // Potentially swap indices of refraction
- bool entering = cosThetaI > 0.f;
- if (!entering) {
- Real temp = etaT;
- etaT = etaI;
- etaI = temp;
- cosThetaI = fabs(cosThetaI);
- }
- /* Derivative of absolute value of cosThetaI w.r.t. cosThetaI. */
- d_absCosThetaI_d_cosThetaI = (entering) ? 1 : -1;
- // Compute _cosThetaT_ using Snell's law
- Real sinThetaI = sqrt(max(Real(0), 1 - cosThetaI * cosThetaI));
- /* Derivative of sinThetaI w.r.t. cosThetaI. */
- Real d_sinThetaI_d_cosThetaI = (0.5 / max(Real(0), 1 - cosThetaI * cosThetaI))
- * -2 * cosThetaI * d_absCosThetaI_d_cosThetaI;
- Real sinThetaT = etaI / etaT * sinThetaI;
- /* Derivative of sinThetaT w.r.t. cosThetaI. */
- Real d_sinThetaT_d_cosThetaI = (etaI / etaT) * d_sinThetaI_d_cosThetaI;
- // Handle total internal reflection
- if (sinThetaT >= 1) {
- d_FrDielectric_d_cosThetaI = Vector3(0, 0, 0);
- return;
- }
- Real cosThetaT = sqrt(max(Real(0), 1 - sinThetaT * sinThetaT));
- /* Derivative of cosThetaT w.r.t. cosThetaI. */
- Real d_cosThetaT_d_cosThetaI = (0.5 / max(Real(0), 1 - sinThetaT * sinThetaT))
- * -2 * sinThetaT * d_sinThetaT_d_cosThetaI;
- Real Rparl = ((etaT * cosThetaI) - (etaI * cosThetaT)) /
- ((etaT * cosThetaI) + (etaI * cosThetaT));
- /* Derivative of Rparl w.r.t. cosThetaI. */
- Real d_Rparl_d_cosThetaI = ((etaT - etaI * d_cosThetaT_d_cosThetaI) / ((etaT * cosThetaI) + (etaI * cosThetaT)))
- + ((etaT * cosThetaI) - (etaI * cosThetaT))
- * -1 * pow((etaT * cosThetaI) + (etaI * cosThetaT), -2) * (etaT + etaI * d_cosThetaT_d_cosThetaI);
- Real Rperp = ((etaI * cosThetaI) - (etaT * cosThetaT)) /
- ((etaI * cosThetaI) + (etaT * cosThetaT));
- /* Derivative of Rperp w.r.t. cosThetaI. */
- Real d_Rperp_d_cosThetaI = ((etaI - etaT * d_cosThetaT_d_cosThetaI) / ((etaI * cosThetaI) + (etaT * cosThetaT)))
- + ((etaI * cosThetaI) - (etaT * cosThetaT))
- * -1 * pow((etaI * cosThetaI) + (etaT * cosThetaT), -2) * (etaI + etaT * d_cosThetaT_d_cosThetaI);
- /* Derivative of output w.r.t. cosThetaI. */
- /* return (Rparl * Rparl + Rperp * Rperp) / 2 */
- d_FrDielectric_d_cosThetaI = Rparl * d_Rparl_d_cosThetaI + Rperp * d_Rperp_d_cosThetaI;
- }
- DEVICE
- inline
- Vector3 schlick(Vector3 specular_reflectance, Real cos_theta_d) {
- return specular_reflectance * FrDielectric(cos_theta_d, etaA, etaB);
- }
- DEVICE
- inline
- void d_schlick(Real cos_theta_d, Vector3 &d_schlick_d_cos_theta_d) {
- d_FrDielectric(cos_theta_d, etaA, etaB, d_schlick_d_cos_theta_d);
- }
- // Trowbridge Distribution
- DEVICE
- inline
- Real D(Real roughness, const Vector3 &wh) {
- Real alphax = RoughnessToAlpha(roughness);
- Real alphay = alphax;
- Real tan2Theta = Tan2Theta(wh);
- if (std::isinf(tan2Theta)) return 0.;
- const Real cos4Theta = Cos2Theta(wh) * Cos2Theta(wh);
- Real e =
- (Cos2Phi(wh) / (alphax * alphax) + Sin2Phi(wh) / (alphay * alphay)) *
- tan2Theta;
- return 1.0 / (M_PI * alphax * alphay * cos4Theta * (1 + e) * (1 + e));
- }
- DEVICE
- inline
- void d_D(Real roughness, const Vector3 &wh, Real &d_D_d_roughness, Vector3 &d_D_d_wh) {
- Real alphax = RoughnessToAlpha(roughness);
- Real alphay = alphax;
- /* Derivatives of anisotropic alphas w.r.t. roughness. */
- Real d_alphax_d_roughness = d_RoughnessToAlpha(roughness);
- Real d_alphay_d_roughness = d_alphax_d_roughness;
- Real tan2Theta = Tan2Theta(wh);
- /* Derivative of tan2Theta w.r.t. wh. */
- Real d_Tan2Theta_d_wh = d_Tan2Theta(wh);
- if (std::isinf(tan2Theta)) return 0.;
- const Real cos4Theta = Cos2Theta(wh) * Cos2Theta(wh);
- Real d_cos4Theta_d_wh = -4 * SinTheta(wh) * CosTheta(wh) * CosTheta(wh) * CosTheta(wh);
- Real e = (Cos2Phi(wh) / (alphax * alphax) + Sin2Phi(wh) / (alphay * alphay)) * tan2Theta;
- /* Derivative of e w.r.t. roughness. */
- Real d_e_d_roughness = -2 * (Cos2Phi(wh) / (alphax * alphax * alphax) + Sin2Phi(wh) / (alphay * alphay * alphay)) * tan2Theta;
- /* Derivative of e w.r.t. wh. */
- Real d_e_d_wh = (d_Cos2Phi(wh) / (alphax * alphax) + d_Sin2Phi(wh) / (alphay * alphay)) * tan2Theta +
- (Cos2Phi(wh) / (alphax * alphax) + Sin2Phi(wh) / (alphay * alphay)) * d_Tan2Theta_d_wh;
- /* return 1.0 / (M_PI * alphax * alphay * cos4Theta * (1 + e) * (1 + e)); */
- Real denom = (M_PI * alphax * alphay * cos4Theta * (1 + e) * (1 + e));
- Real d_D_d_denom = -1.f / (denom * denom);
- d_D_d_roughness = d_D_d_denom * (M_PI * cos4Theta
- * (
- d_alphax_d_roughness * alphay * ((1 + e) * (1 + e))
- + alphax * d_alphay_d_roughness * ((1 + e) * (1 + e))
- + alphax * alphay * (2 * (1 + e))
- ));
- d_D_d_wh = d_D_d_denom * (M_PI * alphax * alphay
- * (
- d_cos4Theta_d_wh * ((1 + e) * (1 + e))
- + cos4Theta * (2 * (1 + e))
- ));
- }
- DEVICE
- inline
- Real G(const Vector3 &wo, const Vector3 &wi, Real roughness) {
- return 1.0 / (1.0 + Lambda(wo, roughness) + Lambda(wi, roughness));
- }
- DEVICE
- inline
- void d_G(const Vector3 &wo, const Vector3 &wi, Real roughness, Vector3 &d_G_d_wo, Vector3 &d_G_d_wi, Real &d_G_d_roughness) {
- /* return 1.0 / (1.0 + Lambda(wo, roughness) + Lambda(wi, roughness)); */
- /* Derivative of lambda w.r.t wo. */
- Vector3 d_Lambda_d_wo;
- /* Derivative of lambda w.r.t roughness given wo. */
- Real d_Lambda_d_roughness_wo;
- d_Lambda(wo, roughness, d_Lambda_d_wo, d_Lambda_d_roughness_wo);
- /* Derivative of lambda w.r.t wi. */
- Vector3 d_Lambda_d_wi;
- /* Derivative of lambda w.r.t roughness given wi. */
- Real d_Lambda_d_roughness_wi;
- d_Lambda(wi, roughness, d_Lambda_d_wi, d_Lambda_d_roughness_wi);
- auto denom = (1.0 + Lambda(wo, roughness) + Lambda(wi, roughness));
- auto d_G_d_denom = -1.f / (denom * denom);
- /* Derivative of G w.r.t wo. */
- d_G_d_wo = d_G_d_denom * d_Lambda_d_wo;
- /* Derivative of G w.r.t wi. */
- d_G_d_wi = d_G_d_denom * d_Lambda_d_wi;
- /* Derivative of G w.r.t roughness. */
- d_G_d_roughness = d_G_d_denom * (d_Lambda_d_roughness_wo + d_Lambda_d_roughness_wi);
- }
- DEVICE
- inline bool SameHemisphere(const Vector3 &w, const Vector3 &wp) {
- return w.z * wp.z > 0;
- }
- DEVICE
- inline Real G1(const Vector3 &w, Real roughness) {
- // if (Dot(w, wh) * CosTheta(w) < 0.) return 0.;
- return 1 / (1 + Lambda(w, roughness));
- }
- DEVICE
- inline void d_G1(const Vector3 &w, Real roughness, Vector3 &d_G1_d_w, Real &d_G1_d_roughness) {
- // if (Dot(w, wh) * CosTheta(w) < 0.) return 0.;
- /* return 1 / (1 + Lambda(w, roughness)); */
- /* Derivative of Lambda w.r.t. w. */
- Vector3 d_Lambda_d_w;
- /* Derivative of Lambda w.r.t. roughness. */
- Real d_Lambda_d_roughness;
- d_Lambda(w, roughness, d_Lambda_d_w, d_Lambda_d_roughness);
- auto denom = (1.0 + Lambda(w, roughness));
- auto d_G_d_denom = -1.f / (denom * denom);
- /* Derivative of G1 w.r.t. w. */
- d_G1_d_w = d_G_d_denom * d_Lambda_d_w;
- /* Derivative of G1 w.r.t. roughness. */
- d_G_d_roughness = d_G_d_denom * d_Lambda_d_roughness;
- }
- DEVICE
- inline Real Pdf(Real roughness, const Vector3 &wo, const Vector3 &wh) {
- if (sampleVisibleArea)
- return D(roughness, wh) * G1(wo, roughness) * fabs(dot(wo, wh)) / fabs(CosTheta(wo));
- else
- return D(roughness, wh) * fabs(CosTheta(wh));
- }
- DEVICE
- inline void d_Pdf(Real roughness, const Vector3 &wo, const Vector3 &wh, Real &d_Pdf_d_roughness, Vector3 &d_Pdf_d_wo, Vector3 &d_Pdf_d_wh) {
- if (sampleVisibleArea) {
- /* return D(roughness, wh) * G1(wo, roughness) * fabs(dot(wo, wh)) / fabs(CosTheta(wo)); */
- Real d_D_d_roughness;
- Vector3 d_D_d_wh;
- d_D(roughness, wh, d_D_d_roughness, d_D_d_wh);
- Vector3 d_G1_d_wo;
- Real d_G1_d_roughness;
- d_G1(wo, roughness, d_G1_d_wo, d_G1_d_roughness);
- /* Derivative of PDF w.r.t. roughness. */
- d_Pdf_d_roughness = fabs(dot(wo, wh)) / fabs(CosTheta(wo)) * ( d_D_d_roughness * G1(wo, roughness) + d_G1_d_wo * D(roughness, wh));
- /* Derivative of PDF w.r.t. wh. */
- d_Pdf_d_wh = (G1(wo, roughness) / fabs(CosTheta(wo))) * (d_D_d_wh * fabs(dot(wo, wh)) + ((dot(wo, wh) < 0) ? -1 : 1) * (wo) * D(roughness, wh));
- /* Derivative of PDF w.r.t. wo */
- d_Pdf_d_wo = D(roughness, wh) * (
- ((dot(wo, wh) < 0) ? -1 : 1) * wh * G1(wo, roughness) / fabs(CosTheta(wo)) +
- fabs(dot(wo, wh)) * d_G1_d_wo / fabs(CosTheta(wo)) +
- G1(wo, roughness) * fabs(dot(wo, wh)) * ((CosTheta(wo) < 0) ? -1 : 1) * (-1 / Cos2Theta(wo))
- );
- }
- else {
- /* return D(roughness, wh) * fabs(CosTheta(wh)); */
- }
- }
- DEVICE
- inline bool Refract(const Vector3 &wi, const Vector3 &n, Real eta, Vector3 &wt) {
- // Compute $\cos \theta_\roman{t}$ using Snell's law
- Real cosThetaI = dot(n, wi);
- Real sin2ThetaI = max(Real(0), Real(1 - cosThetaI * cosThetaI));
- Real sin2ThetaT = eta * eta * sin2ThetaI;
- // Handle total internal reflection for transmission
- if (sin2ThetaT >= 1) return false;
- Real cosThetaT = sqrt(1 - sin2ThetaT);
- wt = eta * -wi + (eta * cosThetaI - cosThetaT) * n;
- return true;
- }
- DEVICE
- inline void TrowbridgeReitzSample11(Real cosTheta, Real U1, Real U2,
- Real &slope_x, Real &slope_y) {
- // special case (normal incidence)
- if (cosTheta > .9999) {
- Real r = sqrt(U1 / (1 - U1));
- Real phi = 6.28318530718 * U2;
- slope_x = r * cos(phi);
- slope_y = r * sin(phi);
- return;
- }
- Real sinTheta = sqrt(max(Real(0), Real(1) - cosTheta * cosTheta));
- Real tanTheta = sinTheta / cosTheta;
- Real a = 1 / tanTheta;
- Real G1 = 2 / (1 + sqrt(1.f + 1.f / (a * a)));
- // sample slope_x
- Real A = 2 * U1 / G1 - 1;
- Real tmp = 1.f / (A * A - 1.f);
- if (tmp > 1e10) tmp = 1e10;
- Real B = tanTheta;
- Real D = sqrt(max(Real(B * B * tmp * tmp - (A * A - B * B) * tmp), Real(0)));
- Real slope_x_1 = B * tmp - D;
- Real slope_x_2 = B * tmp + D;
- slope_x = (A < 0 || slope_x_2 > 1.f / tanTheta) ? slope_x_1 : slope_x_2;
- // sample slope_y
- Real S;
- if (U2 > 0.5f) {
- S = 1.f;
- U2 = 2.f * (U2 - .5f);
- } else {
- S = -1.f;
- U2 = 2.f * (.5f - U2);
- }
- Real z =
- (U2 * (U2 * (U2 * 0.27385f - 0.73369f) + 0.46341f)) /
- (U2 * (U2 * (U2 * 0.093073f + 0.309420f) - 1.000000f) + 0.597999f);
- slope_y = S * z * sqrt(1.f + slope_x * slope_x);
- }
- DEVICE
- inline Vector3 TrowbridgeReitzSample(const Vector3 &wi, Real alpha_x,
- Real alpha_y, Real U1, Real U2) {
- // 1. stretch wi
- Vector3 wiStretched = normalize(Vector3(alpha_x * wi.x, alpha_y * wi.y, wi.z));
- // 2. simulate P22_{wi}(x_slope, y_slope, 1, 1)
- Real slope_x, slope_y;
- TrowbridgeReitzSample11(CosTheta(wiStretched), U1, U2, slope_x, slope_y);
- // 3. rotate
- Real tmp = CosPhi(wiStretched) * slope_x - SinPhi(wiStretched) * slope_y;
- slope_y = SinPhi(wiStretched) * slope_x + CosPhi(wiStretched) * slope_y;
- slope_x = tmp;
- // 4. unstretch
- slope_x = alpha_x * slope_x;
- slope_y = alpha_y * slope_y;
- // 5. compute normal
- return normalize(Vector3(-slope_x, -slope_y, 1.));
- }
- DEVICE
- inline Vector3 SphericalDirection(Real sinTheta, Real cosTheta, Real phi) {
- return Vector3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
- }
- DEVICE
- inline Vector3 Sample_wh(const Vector3 &wo, const Vector2 &uv, Real roughness) {
- Real alphax = RoughnessToAlpha(roughness);
- Real alphay = alphax;
- Vector3 wh;
- if (!sampleVisibleArea) {
- Real cosTheta = 0, phi = (2 * M_PI) * uv[1];
- if (alphax == alphay) {
- Real tanTheta2 = alphax * alphax * uv[0] / (1.0f - uv[0]);
- cosTheta = 1 / sqrt(1 + tanTheta2);
- } else {
- phi = atan(alphay / alphax * tan(2 * M_PI * uv[1] + .5f * M_PI));
- if (uv[1] > .5f) phi += M_PI;
- Real sinPhi = sin(phi), cosPhi = cos(phi);
- const Real alphax2 = alphax * alphax, alphay2 = alphay * alphay;
- const Real alpha2 = 1 / (cosPhi * cosPhi / alphax2 + sinPhi * sinPhi / alphay2);
- Real tanTheta2 = alpha2 * uv[0] / (1 - uv[0]);
- cosTheta = 1 / sqrt(1 + tanTheta2);
- }
- Real sinTheta = sqrt(max((Real)0., (Real)1. - cosTheta * cosTheta));
- wh = SphericalDirection(sinTheta, cosTheta, phi);
- if (!SameHemisphere(wo, wh)) wh = -wh;
- } else {
- bool flip = wo.z < 0;
- wh = TrowbridgeReitzSample(flip ? -wo : wo, alphax, alphay, uv[0], uv[1]);
- if (flip) wh = -wh;
- }
- return wh;
- }
- DEVICE
- inline
- Vector3 bsdf(const Material &material,
- const SurfacePoint &shading_point,
- Vector3 wi,
- Vector3 wo,
- const Real min_roughness) {
- auto shading_frame = shading_point.shading_frame;
- if (has_normal_map(material)) {
- // Perturb shading frame
- shading_frame = perturb_shading_frame(material, shading_point);
- }
- auto n = normalize(to_local(shading_frame, shading_frame.n));
- wi = normalize(to_local(shading_frame, wi));
- wo = normalize(to_local(shading_frame, wo));
- auto cosThetaO = dot(wo, n);
- auto cosThetaI = dot(wi, n);
- if (fabs(cosThetaO) < 1e-3f || fabs(cosThetaI) < 1e-3f) {
- return {0, 0, 0};
- }
- Real eta = CosTheta(wo) > 0 ? (etaB / etaA) : (etaA / etaB);
- auto wh = normalize(wo + wi * eta);
- if (wh.z < 0) {
- wh = -wh;
- }
- auto specular_reflectance = get_specular_reflectance(material, shading_point);
- auto F = schlick(specular_reflectance, dot(wo, wh));
- auto sqrtDenom = fabs(dot(wo, wh)) + eta * fabs(dot(wi, wh));
- auto roughness = max(get_roughness(material, shading_point), min_roughness);
- cosThetaI = fabs(cosThetaI);
- cosThetaO = fabs(cosThetaO);
- auto res = (Vector3(1, 1, 1) - F) * fabs(D(roughness, wh) * G(wo, wi, roughness) * eta * eta * fabs(dot(wi, wh)) * fabs(dot(wo, wh))) /
- (cosThetaI * cosThetaO * sqrtDenom * sqrtDenom);
- return res;
- }
- DEVICE
- inline
- void d_bsdf(const Material &material,
- const SurfacePoint &shading_point,
- const Vector3 &wi,
- const Vector3 &wo,
- const Real min_roughness,
- const Vector3 &d_output,
- DMaterial &d_material,
- SurfacePoint &d_shading_point,
- Vector3 &d_wi,
- Vector3 &d_wo) {
- auto shading_frame = shading_point.shading_frame;
- if (has_normal_map(material)) {
- // Perturb shading frame
- shading_frame = perturb_shading_frame(material, shading_point);
- }
- /* Derivatives of tangent space representations of n, wi, and wo w.r.t. their
- * world space representations. */
- auto d_n_local_d_n = d_normalize(to_local(shading_frame, shading_frame.n)) * d_to_local(shading_frame, shading_frame.n);
- auto d_wi_local_d_wi = d_normalize(to_local(shading_frame, wi)) * d_to_local(shading_frame, wi);
- auto d_wo_local_d_wo = d_normalize(to_local(shading_frame, wo)) * d_to_local(shading_frame, wo);
- auto n_local = normalize(to_local(shading_frame, shading_frame.n));
- wi_local = normalize(to_local(shading_frame, wi));
- wo_local = normalize(to_local(shading_frame, wo));
- auto cosThetaO = dot(wo_local, n);
- auto cosThetaI = dot(wi_local, n);
- if (fabs(cosThetaO) < 1e-3f || fabs(cosThetaI) < 1e-3f) {
- return;
- }
- Real eta = CosTheta(wo_local) > 0 ? (etaB / etaA) : (etaA / etaB);
- auto wh_local = normalize(wo_local + wi_local * eta);
- /* Derivative of wh w.r.t. wo. */
- d_wh_d_wo = d_normalize(wo_local + wi_local * eta) * d_wo_local_d_wo;
- /* Derivative of wh w.r.t. wi. */
- d_wh_d_wi = d_normalize(wo_local + wi_local * eta) * eta * d_wi_local_d_wi;
- if (wh_local.z < 0) {
- wh_local = -wh_local;
- /* diFfeREnTIaTioN iS liNEAr */
- d_wh_d_wo = -d_wh_d_wo;
- d_wh_d_wi = -d_wh_d_wi;
- }
- /* Get specular reflectance from reflectance map. */
- auto specular_reflectance = get_specular_reflectance(material, shading_point);
- /* Derivatives of specular reflectance will be 1, since we assume uniform specular
- * reflectance. */
- Real wo_local_dot_wh_local = dot(wo_local, wh_local);
- auto F = schlick(specular_reflectance, wo_local_dot_wh_local);
- /* Derivative of F w.r.t. dot(wo_local, wh_local). */
- Vector3 d_F_d_wo_local_dot_wh_local;
- d_schlick(specular_reflectance, wo_local_dot_wh_local, d_F_d_wo_local_dot_wh_local);
- /* Derivative of dot(wo_local, wh_local) w.r.t wo */
- Vector3 d_wo_local_dot_wh_local_d_wo = wh + wo * d_wh_d_wo;
- /* Derivative of F w.r.t. wo. */
- Vector3 d_F_d_wo = d_F_d_wo_local_dot_wh_local * d_wo_local_dot_wh_local_d_wo;
- /* Derivative of F w.r.t. wi. */
- Vector3 d_F_d_wi = wh * d_wh_d_wi * d_F_d_wo_local_dot_wh_local;
- auto sqrtDenom = fabs(dot(wo_local, wh_local)) + eta * fabs(dot(wi_local, wh_local));
- /* Derivative of sqrtDenom w.r.t. wo. */
- Vector3 d_sqrtDenom_d_wo = ((dot(wo_local, wh_local) > 0) ? 1 : -1) * d_wo_local_dot_wh_local_d_wo + eta * ((dot(wi_local, wh_local) > 0) ? 1 : -1) * ;
- auto roughness = max(get_roughness(material, shading_point), min_roughness);
- cosThetaI = fabs(cosThetaI);
- cosThetaO = fabs(cosThetaO);
- auto res = (Vector3(1, 1, 1) - F) * fabs(D(roughness, wh_local) * G(wo_local, wi, roughness) * eta * eta * fabs(dot(wi_local, wh_local)) * fabs(dot(wo_local, wh_local))) /
- (cosThetaI * cosThetaO * sqrtDenom * sqrtDenom);
- return res;
- }
- DEVICE
- inline
- Vector3 bsdf_sample(const Material &material,
- const SurfacePoint &shading_point,
- Vector3 wi,
- const BSDFSample &bsdf_sample,
- const Real min_roughness,
- const RayDifferential &wi_differential,
- RayDifferential &wo_differential,
- Real *next_min_roughness = nullptr) {
- auto shading_frame = shading_point.shading_frame;
- if (has_normal_map(material)) {
- // Perturb shading frame
- shading_frame = perturb_shading_frame(material, shading_point);
- }
- auto n_local = Vector3{0, 0, 1};
- auto n = to_world(shading_frame, n_local);
- // metal/glass:
- auto refl = 2.f * dot(wi, n) * n - wi;
- wi = normalize(to_local(shading_frame, normalize(wi)));
- if (wi.z == 0) return {0, 0, 0};
- auto roughness = max(get_roughness(material, shading_point), min_roughness);
- Vector3 wh = Sample_wh(wi, bsdf_sample.uv, roughness);
- auto eta = CosTheta(wi) > 0 ? (etaA / etaB) : (etaB / etaA);
- Vector3 wo;
- if (!Refract(wi, wh, eta, wo)) {
- return refl;
- }
- wo = normalize(to_world(shading_frame, wo));
- return wo;
- /*
- // Propagate ray differentials
- // HACK: we approximate the directional derivative dn_dx using dn_dx * n_local[2]
- // i.e. we ignore the derivatives on the tangent plane
- auto dn_dx = shading_point.dn_dx * n_local[2];
- auto dn_dy = shading_point.dn_dy * n_local[2];
- auto wi_dx = -wi_differential.dir_dx;
- auto wi_dy = -wi_differential.dir_dy;
- // Igehy 1999, Equation 15
- auto widotn_dx = sum(wi_dx * n) + sum(wi * dn_dx);
- auto widotn_dy = sum(wi_dy * n) + sum(wi * dn_dy);
- if (radicand < 0) {
- // Reflection
- // Igehy 1999, Equation 14
- wo_differential.org_dx = wi_differential.org_dx;
- wo_differential.org_dy = wi_differential.org_dy;
- wo_differential.dir_dx = 2 * (dot(wi, n) * dn_dx + widotn_dx * n) - wi_dx;
- wo_differential.dir_dy = 2 * (dot(wi, n) * dn_dy + widotn_dy * n) - wi_dy;
- //return refl;
- }
- else {
- if (bsdf_sample.uv[0] < Rtheta) {
- // Reflection
- // Igehy 1999, Equation 14
- wo_differential.org_dx = wi_differential.org_dx;
- wo_differential.org_dy = wi_differential.org_dy;
- wo_differential.dir_dx = 2 * (dot(wi, n) * dn_dx + widotn_dx * n) - wi_dx;
- wo_differential.dir_dy = 2 * (dot(wi, n) * dn_dy + widotn_dy * n) - wi_dy;
- return refl;
- }
- // Refraction
- auto T = refr;
- auto D = -wi;
- auto N = n_oriented;
- // Igehy 1999, Equation 17
- auto mu = eta*dot(D,N) - dot(T,N);
- auto TN = -sqrtf(1-eta*eta*(1-dot(D,N)*dot(D,N)));
- // Igehy 1999, Equation 19
- auto dmu_dx = (eta - (eta*eta*dot(D,N))/TN)*widotn_dx;
- auto dmu_dy = (eta - (eta*eta*dot(D,N))/TN)*widotn_dy;
- // Igehy 1999, Equation 18
- wo_differential.org_dx = wi_differential.org_dx;
- wo_differential.org_dy = wi_differential.org_dy;
- wo_differential.dir_dx = eta * wi_dx - (mu * dn_dx + dmu_dx * N);
- wo_differential.dir_dy = eta * wi_dy - (mu * dn_dy + dmu_dy * N);
- }
- return Vector3 {0, 0, 0};
- */
- }
- DEVICE
- inline
- void d_bsdf_sample(const Material &material,
- const SurfacePoint &shading_point,
- Vector3 wi,
- const BSDFSample &bsdf_sample,
- const Real min_roughness,
- const RayDifferential &wi_differential,
- const Vector3 &d_wo,
- const RayDifferential &d_wo_differential,
- DMaterial &d_material,
- SurfacePoint &d_shading_point,
- Vector3 &d_wi,
- RayDifferential &d_wi_differential) {
- auto shading_frame = shading_point.shading_frame;
- if (has_normal_map(material)) {
- // Perturb shading frame
- shading_frame = perturb_shading_frame(material, shading_point);
- }
- bool inward = false;
- auto geom_wi = dot(shading_point.geom_normal, wi);
- auto n_local = Vector3{0, 0, 1};
- auto n = to_world(shading_frame, n_local);
- if (material.two_sided && geom_wi < 0.f) {
- shading_frame = -shading_frame;
- geom_wi = -geom_wi;
- inward = true;
- }
- if (geom_wi <= 0.f) {
- return;
- }
- // local normal
- //auto n_local = to_local(shading_frame, n);
- auto d_shading_frame = Frame{ Vector3{0, 0, 0},
- Vector3{0, 0, 0},
- Vector3{0, 0, 0} };
- // Propagate ray differentials
- // HACK: we approximate the directional derivative dmdx using dndx * n_local[2]
- // i.e. we ignore the derivatives on the tangent plane
- auto dn_dx = shading_point.dn_dx * n_local[2];
- auto dn_dy = shading_point.dn_dy * n_local[2];
- auto wi_dx = -wi_differential.dir_dx;
- auto wi_dy = -wi_differential.dir_dy;
- // Igehy 1999, Equation 15
- auto widotn_dx = sum(wi_dx * n) + sum(wi * dn_dx);
- auto widotn_dy = sum(wi_dy * n) + sum(wi * dn_dy);
- d_wi_differential.org_dx += d_wo_differential.org_dx;
- d_wi_differential.org_dy += d_wo_differential.org_dy;
- d_wi_differential.dir_dx += d_wo_differential.dir_dx;
- d_wi_differential.dir_dy += d_wo_differential.dir_dy;
- auto d_dot_wi_n = 2 * sum(d_wo_differential.dir_dx * dn_dx) + 2 * sum(d_wo_differential.dir_dy * dn_dy);
- auto d_dndx = d_wo_differential.dir_dx * 2 * dot(wi, n);
- auto d_dndy = d_wo_differential.dir_dy * 2 * dot(wi, n);
- auto d_widotn_dx = 2 * sum(d_wo_differential.dir_dx * n);
- auto d_widotn_dy = 2 * sum(d_wo_differential.dir_dy * n);
- auto d_n = d_wo_differential.dir_dx * 2 * widotn_dx + d_wo_differential.dir_dy * 2 * widotn_dy;
- // widotm_dx = sum(wi_dx * n) + sum(wi * dn_dx)
- auto d_wi_dx = d_widotn_dx * n;
- d_n += d_widotn_dx * wi_dx;
- d_wi += d_widotn_dx * dn_dx;
- d_dndx += d_widotn_dx * wi;
- // widotm_dy = sum(wi_dy * n) + sum(wi * dn_dy)
- auto d_wi_dy = d_widotn_dy * n;
- d_n += d_widotn_dy * wi_dy;
- d_wi += d_widotn_dy * dn_dy;
- d_dndy += d_widotn_dy * wi;
- // wi_dx = -wi_differential.dir_dx
- // wi_dy = -wi_differential.dir_dy
- d_wi_differential.dir_dx -= d_wi_dx;
- d_wi_differential.dir_dy -= d_wi_dy;
- // dmdx = shading_point.dn_dx * n_local[2]
- // dmdy = shading_point.dn_dy * n_local[2]
- d_shading_point.dn_dx += d_dndx * n_local[2];
- d_shading_point.dn_dy += d_dndy * n_local[2];
- auto d_m_local = Vector3{ 0, 0, 0 };
- d_m_local[2] += sum(d_dndx * shading_point.dn_dx) + sum(d_dndy * shading_point.dn_dy);
- // wo = 2.f * dot(wi, m) * m - wi
- d_dot_wi_n += 2.f * sum(d_wo * n);
- d_n += d_wo * (2.f * dot(wi, n));
- d_wi += -d_wo;
- // dot_wi_m = dot(wi, m)
- d_wi += d_dot_wi_n * n;
- d_n += d_dot_wi_n * wi;
- // m = to_world(shading_frame, m_local)
- d_to_world(shading_frame, n_local, d_n, d_shading_frame, d_m_local);
- if (inward) {
- d_shading_frame = -d_shading_frame;
- }
- if (has_normal_map(material)) {
- d_perturb_shading_frame(material,
- shading_point,
- d_shading_frame,
- d_material,
- d_shading_point);
- }
- else {
- d_shading_point.shading_frame += d_shading_frame;
- }
- }
- DEVICE
- inline Real bsdf_pdf(const Material &material,
- const SurfacePoint &shading_point,
- Vector3 wi,
- Vector3 wo,
- const Real min_roughness) {
- auto shading_frame = shading_point.shading_frame;
- wi = normalize(to_local(shading_frame, wi));
- wo = normalize(to_local(shading_frame, wo));
- if (SameHemisphere(wo, wi)) return 0;
- // Compute $\wh$ from $\wo$ and $\wi$ for microfacet transmission
- auto eta = CosTheta(wo) > 0 ? (etaB / etaA) : (etaA / etaB);
- auto wh = normalize(wo + wi * eta);
- // Compute change of variables _dwh\_dwi_ for microfacet transmission
- auto sqrtDenom = fabs(dot(wo, wh)) + eta * fabs(dot(wi, wh));
- auto dwh_dwi = fabs((eta * eta * dot(wi, wh)) / (sqrtDenom * sqrtDenom));
- auto roughness = max(get_roughness(material, shading_point), min_roughness);
- auto pdf_val = Pdf(roughness, wo, wh) * dwh_dwi;
- return pdf_val;
- }
- DEVICE
- inline void d_bsdf_pdf(const Material &material,
- const SurfacePoint &shading_point,
- const Vector3 &wi,
- const Vector3 &wo,
- const Real min_roughness,
- const Real d_pdf,
- DMaterial &d_material,
- SurfacePoint &d_shading_point,
- Vector3 &d_wi,
- Vector3 &d_wo) {
- }
- void test_d_bsdf();
- void test_d_bsdf_sample();
- void test_d_bsdf_pdf();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement