From a279b7f638346a1c3648b5b78fdbee9051ef95a2 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 6 Feb 2013 21:17:50 -0500 Subject: [PATCH] improved reliability of specular perturbations --- src/bsdfs/coating.cpp | 4 ++-- src/bsdfs/conductor.cpp | 4 ++-- src/bsdfs/dielectric.cpp | 8 ++++---- src/bsdfs/plastic.cpp | 4 ++-- src/bsdfs/thindielectric.cpp | 8 ++++---- src/libbidir/vertex.cpp | 8 +++++++- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/bsdfs/coating.cpp b/src/bsdfs/coating.cpp index ec37de9a..b9102474 100644 --- a/src/bsdfs/coating.cpp +++ b/src/bsdfs/coating.cpp @@ -225,7 +225,7 @@ public: && (bRec.component == -1 || bRec.component < (int) m_components.size()-1); if (measure == EDiscrete && sampleSpecular && - absDot(reflect(bRec.wi), bRec.wo) > 1-DeltaEpsilon) { + std::abs(dot(reflect(bRec.wi), bRec.wo)-1) < DeltaEpsilon) { return m_specularReflectance->eval(bRec.its) * fresnelDielectricExt(std::abs(Frame::cosTheta(bRec.wi)), m_eta); } else if (sampleNested) { @@ -274,7 +274,7 @@ public: (1-R12) * (1-m_specularSamplingWeight)); if (measure == EDiscrete && sampleSpecular && - absDot(reflect(bRec.wi), bRec.wo) > 1-DeltaEpsilon) { + std::abs(dot(reflect(bRec.wi), bRec.wo)-1) < DeltaEpsilon) { return sampleNested ? probSpecular : 1.0f; } else if (sampleNested) { Float R21; diff --git a/src/bsdfs/conductor.cpp b/src/bsdfs/conductor.cpp index d7042176..b2ff6d47 100644 --- a/src/bsdfs/conductor.cpp +++ b/src/bsdfs/conductor.cpp @@ -229,7 +229,7 @@ public: if (!sampleReflection || measure != EDiscrete || Frame::cosTheta(bRec.wi) <= 0 || Frame::cosTheta(bRec.wo) <= 0 || - absDot(reflect(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + std::abs(dot(reflect(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return Spectrum(0.0f); return m_specularReflectance->eval(bRec.its) * @@ -245,7 +245,7 @@ public: if (!sampleReflection || measure != EDiscrete || Frame::cosTheta(bRec.wi) <= 0 || Frame::cosTheta(bRec.wo) <= 0 || - absDot(reflect(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + std::abs(dot(reflect(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return 0.0f; return 1.0f; diff --git a/src/bsdfs/dielectric.cpp b/src/bsdfs/dielectric.cpp index afa6efce..d1edfb67 100644 --- a/src/bsdfs/dielectric.cpp +++ b/src/bsdfs/dielectric.cpp @@ -235,12 +235,12 @@ public: Float F = fresnelDielectricExt(Frame::cosTheta(bRec.wi), cosThetaT, m_eta); if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) >= 0) { - if (!sampleReflection || absDot(reflect(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + if (!sampleReflection || std::abs(dot(reflect(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return Spectrum(0.0f); return m_specularReflectance->eval(bRec.its) * F; } else { - if (!sampleTransmission || absDot(refract(bRec.wi, cosThetaT), bRec.wo) < 1-DeltaEpsilon) + if (!sampleTransmission || std::abs(dot(refract(bRec.wi, cosThetaT), bRec.wo)-1) > DeltaEpsilon) return Spectrum(0.0f); /* Radiance must be scaled to account for the solid angle compression @@ -262,12 +262,12 @@ public: Float F = fresnelDielectricExt(Frame::cosTheta(bRec.wi), cosThetaT, m_eta); if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) >= 0) { - if (!sampleReflection || absDot(reflect(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + if (!sampleReflection || std::abs(dot(reflect(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return 0.0f; return sampleTransmission ? F : 1.0f; } else { - if (!sampleTransmission || absDot(refract(bRec.wi, cosThetaT), bRec.wo) < 1-DeltaEpsilon) + if (!sampleTransmission || std::abs(dot(refract(bRec.wi, cosThetaT), bRec.wo)-1) > DeltaEpsilon) return 0.0f; return sampleReflection ? 1-F : 1.0f; diff --git a/src/bsdfs/plastic.cpp b/src/bsdfs/plastic.cpp index 5c1999f6..b5083021 100644 --- a/src/bsdfs/plastic.cpp +++ b/src/bsdfs/plastic.cpp @@ -255,7 +255,7 @@ public: if (hasSpecular) { /* Check if the provided direction pair matches an ideal specular reflection; tolerate some roundoff errors */ - if (absDot(reflect(bRec.wi), bRec.wo) > 1-DeltaEpsilon) + if (std::abs(dot(reflect(bRec.wi), bRec.wo)-1) < DeltaEpsilon) return m_specularReflectance->eval(bRec.its) * Fi; } else if (hasDiffuse) { Float Fo = fresnelDielectricExt(Frame::cosTheta(bRec.wo), m_eta); @@ -294,7 +294,7 @@ public: if (hasSpecular && measure == EDiscrete) { /* Check if the provided direction pair matches an ideal specular reflection; tolerate some roundoff errors */ - if (absDot(reflect(bRec.wi), bRec.wo) > 1-DeltaEpsilon) + if (std::abs(dot(reflect(bRec.wi), bRec.wo)-1) < DeltaEpsilon) return probSpecular; } else if (hasDiffuse && measure == ESolidAngle) { return Warp::squareToCosineHemispherePdf(bRec.wo) * (1-probSpecular); diff --git a/src/bsdfs/thindielectric.cpp b/src/bsdfs/thindielectric.cpp index f33edeb7..efafac12 100644 --- a/src/bsdfs/thindielectric.cpp +++ b/src/bsdfs/thindielectric.cpp @@ -163,12 +163,12 @@ public: R += T*T * R / (1-R*R); if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) >= 0) { - if (!sampleReflection || absDot(reflect(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + if (!sampleReflection || std::abs(dot(reflect(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return Spectrum(0.0f); return m_specularReflectance->eval(bRec.its) * R; } else { - if (!sampleTransmission || absDot(transmit(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + if (!sampleTransmission || std::abs(dot(transmit(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return Spectrum(0.0f); return m_specularTransmittance->eval(bRec.its) * (1 - R); @@ -188,12 +188,12 @@ public: R += T*T * R / (1-R*R); if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) >= 0) { - if (!sampleReflection || absDot(reflect(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + if (!sampleReflection || std::abs(dot(reflect(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return 0.0f; return sampleTransmission ? R : 1.0f; } else { - if (!sampleTransmission || absDot(transmit(bRec.wi), bRec.wo) < 1-DeltaEpsilon) + if (!sampleTransmission || std::abs(dot(transmit(bRec.wi), bRec.wo)-1) > DeltaEpsilon) return 0.0f; return sampleReflection ? 1-R : 1.0f; diff --git a/src/libbidir/vertex.cpp b/src/libbidir/vertex.cpp index 1729a1fe..61345836 100644 --- a/src/libbidir/vertex.cpp +++ b/src/libbidir/vertex.cpp @@ -710,7 +710,13 @@ bool PathVertex::propagatePerturbation(const Scene *scene, const PathVertex *pre bRec.typeMask = BSDF::EAll; Float prob = bsdf->pdf(bRec, EDiscrete); - weight[mode] = bsdf->eval(bRec, EDiscrete)/prob; + if (prob == 0) { + SLog(EWarn, "Unable to recreate specular vertex in perturbation (bsdf=%s)", + bsdf->toString().c_str()); + return false; + } + + weight[mode] = bsdf->eval(bRec, EDiscrete) / prob; pdf[mode] = prob; measure = EDiscrete; componentType = componentType_;