Skip to content

Commit

Permalink
Fix orientation of wh in MicrofacetReflection::f
Browse files Browse the repository at this point in the history
Always orient wh to be on the same side of the surface as the normal; in turn, this means that the cos theta value passed to Fresnel::Evaluate() has the right sign.

This in particular fixes the handling of total internal reflection with this BxDF, both accounting for it when it should be and not incorrectly including it when there is none. (Rendered images may change due to this, especially noticeable in cases where TIR was incorrectly happening with non-transmissive surfaces, giving bright highlights.)

Fixes issues mmp#214 and mmp#254.
  • Loading branch information
mmp committed Oct 15, 2019
1 parent 4a77ece commit 478b2e6
Showing 1 changed file with 6 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/core/reflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ Spectrum MicrofacetReflection::f(const Vector3f &wo, const Vector3f &wi) const {
if (cosThetaI == 0 || cosThetaO == 0) return Spectrum(0.);
if (wh.x == 0 && wh.y == 0 && wh.z == 0) return Spectrum(0.);
wh = Normalize(wh);
Spectrum F = fresnel->Evaluate(Dot(wi, wh));
// For the Fresnel call, make sure that wh is in the same hemisphere
// as the surface normal, so that TIR is handled correctly.
Spectrum F = fresnel->Evaluate(Dot(wi, Faceforward(wh, Vector3f(0,0,1))));
return R * distribution->D(wh) * distribution->G(wo, wi) * F /
(4 * cosThetaI * cosThetaO);
}
Expand Down Expand Up @@ -408,6 +410,7 @@ Spectrum MicrofacetReflection::Sample_f(const Vector3f &wo, Vector3f *wi,
// Sample microfacet orientation $\wh$ and reflected direction $\wi$
if (wo.z == 0) return 0.;
Vector3f wh = distribution->Sample_wh(wo, u);
if (Dot(wo, wh) < 0) return 0.; // Should be rare
*wi = Reflect(wo, wh);
if (!SameHemisphere(wo, *wi)) return Spectrum(0.f);

Expand All @@ -427,6 +430,8 @@ Spectrum MicrofacetTransmission::Sample_f(const Vector3f &wo, Vector3f *wi,
BxDFType *sampledType) const {
if (wo.z == 0) return 0.;
Vector3f wh = distribution->Sample_wh(wo, u);
if (Dot(wo, wh) < 0) return 0.; // Should be rare

Float eta = CosTheta(wo) > 0 ? (etaA / etaB) : (etaB / etaA);
if (!Refract(wo, (Normal3f)wh, eta, wi)) return 0;
*pdf = Pdf(wo, *wi);
Expand Down

0 comments on commit 478b2e6

Please sign in to comment.