diff --git a/data/blender/mitsuba/matpreview/matpreview.xml b/data/blender/mitsuba/matpreview/matpreview.xml
index 1e5915ed..64a65c48 100644
--- a/data/blender/mitsuba/matpreview/matpreview.xml
+++ b/data/blender/mitsuba/matpreview/matpreview.xml
@@ -41,7 +41,7 @@
-
+
diff --git a/src/bsdfs/roughglass.cpp b/src/bsdfs/roughglass.cpp
index 63802bc5..af93c010 100644
--- a/src/bsdfs/roughglass.cpp
+++ b/src/bsdfs/roughglass.cpp
@@ -43,8 +43,6 @@ public:
m_type[0] = EGlossyReflection;
m_type[1] = EGlossyTransmission;
m_combinedType = m_type[0] | m_type[1];
- m_transmissionSamplingWeight = .5f;
- m_reflectionSamplingWeight = 1 - m_transmissionSamplingWeight;
m_usesRayDifferentials = false;
}
@@ -55,8 +53,6 @@ public:
m_alphaB = stream->readFloat();
m_intIOR = stream->readFloat();
m_extIOR = stream->readFloat();
- m_reflectionSamplingWeight = stream->readFloat();
- m_transmissionSamplingWeight = stream->readFloat();
m_componentCount = 2;
m_type = new unsigned int[m_componentCount];
@@ -78,9 +74,9 @@ public:
* Beckmann distribution function for gaussian random surfaces
* @param thetaM Tangent of the angle between M and N.
*/
- Float beckmannD(const Vector &m) const {
- Float ex = Frame::tanTheta(m) / m_alphaB;
- Float value = std::exp(-(ex*ex)) / (M_PI * m_alphaB*m_alphaB *
+ inline Float beckmannD(const Vector &m, Float alphaB) const {
+ Float ex = Frame::tanTheta(m) / alphaB;
+ Float value = std::exp(-(ex*ex)) / (M_PI * alphaB*alphaB *
std::pow(Frame::cosTheta(m), (Float) 4.0f));
if (value < Epsilon)
return 0;
@@ -91,8 +87,8 @@ public:
* Sample microsurface normals according to
* the Beckmann distribution
*/
- Normal sampleBeckmannD(Point2 sample) const {
- Float thetaM = std::atan(std::sqrt(-m_alphaB*m_alphaB
+ Normal sampleBeckmannD(Point2 sample, Float alphaB) const {
+ Float thetaM = std::atan(std::sqrt(-alphaB*alphaB
* std::log(1.0f - sample.x)));
Float phiM = (2.0f * M_PI) * sample.y;
return Normal(sphericalDirection(thetaM, phiM));
@@ -187,7 +183,7 @@ public:
Float F = fresnel(dot(bRec.wi, Hr), m_extIOR, m_intIOR);
/* Microsurface normal distribution */
- Float D = beckmannD(Hr);
+ Float D = beckmannD(Hr, m_alphaB);
/* Smith's shadow-masking function for the Beckmann distribution */
Float G = smithBeckmannG1(bRec.wi, Hr) * smithBeckmannG1(bRec.wo, Hr);
@@ -214,7 +210,7 @@ public:
Float F = 1.0f - fresnel(dot(bRec.wi, Ht), m_extIOR, m_intIOR);
/* Microsurface normal distribution */
- Float D = beckmannD(Ht);
+ Float D = beckmannD(Ht, m_alphaB);
/* Smith's shadow-masking function for the Beckmann distribution */
Float G;
@@ -257,7 +253,7 @@ public:
return result;
}
- inline Float pdfReflection(const BSDFQueryRecord &bRec) const {
+ inline Float pdfReflection(const BSDFQueryRecord &bRec, Float alphaB) const {
if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) < 0)
return 0.0f;
@@ -267,10 +263,10 @@ public:
/* Jacobian of the half-direction transform */
Float dwhr_dwo = 1.0f / (4.0f * absDot(bRec.wo, Hr));
- return beckmannD(Hr) * std::abs(Frame::cosTheta(Hr)) * dwhr_dwo;
+ return beckmannD(Hr, alphaB) * std::abs(Frame::cosTheta(Hr)) * dwhr_dwo;
}
- inline Float pdfTransmission(const BSDFQueryRecord &bRec) const {
+ inline Float pdfTransmission(const BSDFQueryRecord &bRec, Float alphaB) const {
Float etaI = m_extIOR, etaO = m_intIOR;
if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) >= 0)
@@ -285,7 +281,7 @@ public:
Float sqrtDenom = etaI * dot(bRec.wi, Ht) + etaO * dot(bRec.wo, Ht);
Float dwht_dwo = (etaO*etaO * absDot(bRec.wo, Ht)) / (sqrtDenom*sqrtDenom);
- return beckmannD(Ht) * std::abs(Frame::cosTheta(Ht)) * dwht_dwo;
+ return beckmannD(Ht, alphaB) * std::abs(Frame::cosTheta(Ht)) * dwht_dwo;
}
Float pdf(const BSDFQueryRecord &bRec) const {
@@ -294,21 +290,30 @@ public:
bool hasTransmission = (bRec.typeMask & EGlossyTransmission)
&& (bRec.component == -1 || bRec.component == 1);
+ /* Suggestion by Bruce walter: sample using a slightly different
+ value of alphaB. This in practice limits the weights to
+ values <= 4. See also \ref sample() */
+ Float alphaB = m_alphaB * (1.2f - 0.2f * std::sqrt(
+ std::abs(Frame::cosTheta(bRec.wi))));
+
if (hasReflection && hasTransmission) {
- return m_reflectionSamplingWeight * pdfReflection(bRec) +
- m_transmissionSamplingWeight * pdfTransmission(bRec);
+ Float fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR);
+ fr = std::min(std::max(fr, (Float) 0.05f), (Float) 0.95f);
+ return fr * pdfReflection(bRec, alphaB) +
+ (1-fr) * pdfTransmission(bRec, alphaB);
} else if (hasReflection) {
- return pdfReflection(bRec);
+ return pdfReflection(bRec, alphaB);
} else if (hasTransmission) {
- return pdfTransmission(bRec);
+ return pdfTransmission(bRec, alphaB);
}
return 0.0f;
}
-
- inline Spectrum sampleReflection(BSDFQueryRecord &bRec) const {
+
+ inline Spectrum sampleReflection(BSDFQueryRecord &bRec, Float alphaB) const {
/* Sample M, the microsurface normal */
- Normal m = sampleBeckmannD(bRec.sample);
+ Normal m = sampleBeckmannD(bRec.sample, alphaB);
+
/* Perfect specular reflection along the microsurface normal */
bRec.wo = reflect(bRec.wi, m);
@@ -322,13 +327,14 @@ public:
return f(bRec) / pdf(bRec);
}
- inline Spectrum sampleTransmission(BSDFQueryRecord &bRec) const {
+ inline Spectrum sampleTransmission(BSDFQueryRecord &bRec, Float alphaB) const {
/* Sample M, the microsurface normal */
- Frame mFrame(sampleBeckmannD(bRec.sample));
+ Frame mFrame(sampleBeckmannD(bRec.sample, alphaB));
/* Perfect specular reflection along the microsurface normal */
if (refract(mFrame.toLocal(bRec.wi), bRec.wo, bRec.quantity) == 0)
return Spectrum(0.0f);
+
bRec.wo = mFrame.toWorld(bRec.wo);
bRec.sampledComponent = 1;
@@ -346,19 +352,27 @@ public:
bool hasTransmission = (bRec.typeMask & EGlossyTransmission)
&& (bRec.component == -1 || bRec.component == 1);
+ /* Suggestion by Bruce walter: sample using a slightly different
+ value of alphaB. This in practice limits the weights to
+ values <= 4. The change is of course also accounted for
+ in \ref pdf(), hence no error is introduced. */
+ Float alphaB = m_alphaB * (1.2f - 0.2f * std::sqrt(
+ std::abs(Frame::cosTheta(bRec.wi))));
+
if (hasReflection && hasTransmission) {
- if (bRec.sample.x < m_reflectionSamplingWeight) {
- bRec.sample.x = bRec.sample.x / m_reflectionSamplingWeight;
- return sampleReflection(bRec);
+ Float fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR);
+ fr = std::min(std::max(fr, (Float) 0.05f), (Float) 0.95f);
+ if (bRec.sample.x < fr) {
+ bRec.sample.x /= fr;
+ return sampleReflection(bRec, alphaB);
} else {
- bRec.sample.x = (bRec.sample.x - m_reflectionSamplingWeight)
- / m_transmissionSamplingWeight;
- return sampleTransmission(bRec);
+ bRec.sample.x = (bRec.sample.x - fr) / (1-fr);
+ return sampleTransmission(bRec, alphaB);
}
} else if (hasReflection) {
- return sampleReflection(bRec);
+ return sampleReflection(bRec, alphaB);
} else if (hasTransmission) {
- return sampleTransmission(bRec);
+ return sampleTransmission(bRec, alphaB);
}
return Spectrum(0.0f);
@@ -372,8 +386,6 @@ public:
stream->writeFloat(m_alphaB);
stream->writeFloat(m_intIOR);
stream->writeFloat(m_extIOR);
- stream->writeFloat(m_reflectionSamplingWeight);
- stream->writeFloat(m_transmissionSamplingWeight);
}
std::string toString() const {
@@ -393,8 +405,6 @@ private:
Spectrum m_specularReflectance;
Spectrum m_specularTransmittance;
Float m_alphaB, m_intIOR, m_extIOR;
- Float m_reflectionSamplingWeight;
- Float m_transmissionSamplingWeight;
};
MTS_IMPLEMENT_CLASS_S(RoughGlass, false, BSDF)