extended the chi2-tester with some extra checks for BSDF::pdf() and BSDF::eval()
parent
dacb6f96b6
commit
e22b47cc4a
|
@ -2,22 +2,6 @@
|
||||||
to be tested for consistency. This is done
|
to be tested for consistency. This is done
|
||||||
using the testcase 'test_chisquare' -->
|
using the testcase 'test_chisquare' -->
|
||||||
<scene>
|
<scene>
|
||||||
<!-- Test the rough dielectric model with the anisotropic
|
|
||||||
Ashikhmin-Shirley microfacet distribution -->
|
|
||||||
<bsdf type="roughdielectric">
|
|
||||||
<string name="distribution" value="as"/>
|
|
||||||
<float name="alphaU" value=".1"/>
|
|
||||||
<float name="alphaV" value=".3"/>
|
|
||||||
<float name="intIOR" value="1.5"/>
|
|
||||||
<float name="extIOR" value="1.0"/>
|
|
||||||
</bsdf>
|
|
||||||
|
|
||||||
<!-- Test the dielectric model -->
|
|
||||||
<bsdf type="dielectric">
|
|
||||||
<string name="intIOR" value="water"/>
|
|
||||||
<string name="extIOR" value="air"/>
|
|
||||||
</bsdf>
|
|
||||||
|
|
||||||
<!-- Test the diffuse model -->
|
<!-- Test the diffuse model -->
|
||||||
<bsdf type="diffuse"/>
|
<bsdf type="diffuse"/>
|
||||||
|
|
||||||
|
@ -40,6 +24,27 @@
|
||||||
<!-- Test the conductor model -->
|
<!-- Test the conductor model -->
|
||||||
<bsdf type="conductor"/>
|
<bsdf type="conductor"/>
|
||||||
|
|
||||||
|
<!-- Test the dielectric model -->
|
||||||
|
<bsdf type="dielectric">
|
||||||
|
<string name="intIOR" value="water"/>
|
||||||
|
<string name="extIOR" value="air"/>
|
||||||
|
</bsdf>
|
||||||
|
|
||||||
|
<!-- Test a mixture of degenerate materials -->
|
||||||
|
<bsdf type="mixture">
|
||||||
|
<string name="weights" value=".8 .2"/>
|
||||||
|
<bsdf type="dielectric"/>
|
||||||
|
<bsdf type="conductor"/>
|
||||||
|
</bsdf>
|
||||||
|
|
||||||
|
<!-- Test a mixture of degenerate and
|
||||||
|
non-degenerate materials -->
|
||||||
|
<bsdf type="mixture">
|
||||||
|
<string name="weights" value=".8 .2"/>
|
||||||
|
<bsdf type="dielectric"/>
|
||||||
|
<bsdf type="diffuse"/>
|
||||||
|
</bsdf>
|
||||||
|
|
||||||
<!-- Test the rough glass model with the
|
<!-- Test the rough glass model with the
|
||||||
Beckmann microfacet distribution -->
|
Beckmann microfacet distribution -->
|
||||||
<bsdf type="roughdielectric">
|
<bsdf type="roughdielectric">
|
||||||
|
|
|
@ -265,6 +265,7 @@ public:
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "SmoothConductor[" << endl
|
oss << "SmoothConductor[" << endl
|
||||||
|
<< " name = \"" << getName() << "\"," << endl
|
||||||
<< " eta = " << m_eta.toString() << "," << endl
|
<< " eta = " << m_eta.toString() << "," << endl
|
||||||
<< " k = " << m_k.toString() << "," << endl
|
<< " k = " << m_k.toString() << "," << endl
|
||||||
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << endl
|
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << endl
|
||||||
|
|
|
@ -477,6 +477,7 @@ public:
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "SmoothDielectric[" << endl
|
oss << "SmoothDielectric[" << endl
|
||||||
|
<< " name = \"" << getName() << "\"," << endl
|
||||||
<< " intIOR = " << m_intIOR << "," << endl
|
<< " intIOR = " << m_intIOR << "," << endl
|
||||||
<< " extIOR = " << m_extIOR << "," << endl
|
<< " extIOR = " << m_extIOR << "," << endl
|
||||||
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << "," << endl
|
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << "," << endl
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "DiffuseTransmitter[" << endl
|
oss << "DiffuseTransmitter[" << endl
|
||||||
|
<< " name = \"" << getName() << "\"," << endl
|
||||||
<< " transmittance = " << indent(m_transmittance->toString()) << endl
|
<< " transmittance = " << indent(m_transmittance->toString()) << endl
|
||||||
<< "]";
|
<< "]";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
|
|
|
@ -37,7 +37,6 @@ public:
|
||||||
Log(EError, "No weights were supplied!");
|
Log(EError, "No weights were supplied!");
|
||||||
m_weights.resize(weights.size());
|
m_weights.resize(weights.size());
|
||||||
|
|
||||||
Float totalWeight = 0;
|
|
||||||
char *end_ptr = NULL;
|
char *end_ptr = NULL;
|
||||||
for (size_t i=0; i<weights.size(); ++i) {
|
for (size_t i=0; i<weights.size(); ++i) {
|
||||||
Float weight = (Float) strtod(weights[i].c_str(), &end_ptr);
|
Float weight = (Float) strtod(weights[i].c_str(), &end_ptr);
|
||||||
|
@ -46,13 +45,7 @@ public:
|
||||||
if (weight < 0)
|
if (weight < 0)
|
||||||
SLog(EError, "Invalid BRDF weight!");
|
SLog(EError, "Invalid BRDF weight!");
|
||||||
m_weights[i] = weight;
|
m_weights[i] = weight;
|
||||||
totalWeight += weight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalWeight > 1)
|
|
||||||
Log(EWarn, "Energy conservation is violated!");
|
|
||||||
if (totalWeight == 0)
|
|
||||||
Log(EError, "Combined weight must be > 0!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MixtureBSDF(Stream *stream, InstanceManager *manager)
|
MixtureBSDF(Stream *stream, InstanceManager *manager)
|
||||||
|
@ -91,6 +84,27 @@ public:
|
||||||
Log(EError, "BSDF count mismatch: " SIZE_T_FMT " bsdfs, but specified " SIZE_T_FMT " weights",
|
Log(EError, "BSDF count mismatch: " SIZE_T_FMT " bsdfs, but specified " SIZE_T_FMT " weights",
|
||||||
m_bsdfs.size(), m_bsdfs.size());
|
m_bsdfs.size(), m_bsdfs.size());
|
||||||
|
|
||||||
|
Float totalWeight = 0;
|
||||||
|
for (size_t i=0; i<m_weights.size(); ++i)
|
||||||
|
totalWeight += m_weights[i];
|
||||||
|
|
||||||
|
if (totalWeight <= 0)
|
||||||
|
Log(EError, "The weights must sum to a value greater than zero!");
|
||||||
|
|
||||||
|
if (m_ensureEnergyConservation && totalWeight > 1) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
Float scale = 1.0f / totalWeight;
|
||||||
|
oss << "The BSDF" << endl << toString() << endl
|
||||||
|
<< "potentially violates energy conservation, since the weights "
|
||||||
|
<< "sum to " << totalWeight << ", which is greater than one! "
|
||||||
|
<< "They will be re-scaled to avoid potential issues. Specify "
|
||||||
|
<< "the parameter ensureEnergyConservation=false to prevent "
|
||||||
|
<< "this from happening.";
|
||||||
|
Log(EWarn, "%s", oss.str().c_str());
|
||||||
|
for (size_t i=0; i<m_weights.size(); ++i)
|
||||||
|
m_weights[i] *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i=0; i<m_bsdfs.size(); ++i)
|
for (size_t i=0; i<m_bsdfs.size(); ++i)
|
||||||
componentCount += m_bsdfs[i]->getComponentCount();
|
componentCount += m_bsdfs[i]->getComponentCount();
|
||||||
|
|
||||||
|
@ -239,6 +253,7 @@ public:
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "MixtureBSDF[" << endl
|
oss << "MixtureBSDF[" << endl
|
||||||
|
<< " name = \"" << getName() << "\"," << endl
|
||||||
<< " weights = {";
|
<< " weights = {";
|
||||||
for (size_t i=0; i<m_bsdfs.size(); ++i) {
|
for (size_t i=0; i<m_bsdfs.size(); ++i) {
|
||||||
oss << " " << m_weights[i];
|
oss << " " << m_weights[i];
|
||||||
|
|
|
@ -90,24 +90,26 @@ Texture *BSDF::ensureEnergyConservation(Texture *texture,
|
||||||
static std::string typeMaskToString(unsigned int typeMask) {
|
static std::string typeMaskToString(unsigned int typeMask) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "{ ";
|
oss << "{ ";
|
||||||
if (typeMask & BSDF::EAll) { oss << "all "; typeMask &= ~BSDF::EAll; }
|
#define isset(mask) (typeMask & mask) == mask
|
||||||
if (typeMask & BSDF::ESmooth) { oss << "smooth "; typeMask &= ~BSDF::ESmooth; }
|
if (isset(BSDF::EAll)) { oss << "all "; typeMask &= ~BSDF::EAll; }
|
||||||
if (typeMask & BSDF::EDiffuse) { oss << "diffuse "; typeMask &= ~BSDF::EDiffuse; }
|
if (isset(BSDF::ESmooth)) { oss << "smooth "; typeMask &= ~BSDF::ESmooth; }
|
||||||
if (typeMask & BSDF::EGlossy) { oss << "glossy "; typeMask &= ~BSDF::EGlossy; }
|
if (isset(BSDF::EDiffuse)) { oss << "diffuse "; typeMask &= ~BSDF::EDiffuse; }
|
||||||
if (typeMask & BSDF::EDelta) { oss << "delta"; typeMask &= ~BSDF::EDelta; }
|
if (isset(BSDF::EGlossy)) { oss << "glossy "; typeMask &= ~BSDF::EGlossy; }
|
||||||
if (typeMask & BSDF::EDelta1D) { oss << "delta1D "; typeMask &= ~BSDF::EDelta1D; }
|
if (isset(BSDF::EDelta)) { oss << "delta"; typeMask &= ~BSDF::EDelta; }
|
||||||
if (typeMask & BSDF::EDiffuseReflection) { oss << "diffuseReflection "; typeMask &= ~BSDF::EDiffuseReflection; }
|
if (isset(BSDF::EDelta1D)) { oss << "delta1D "; typeMask &= ~BSDF::EDelta1D; }
|
||||||
if (typeMask & BSDF::EDiffuseTransmission) { oss << "diffuseTransmission "; typeMask &= ~BSDF::EDiffuseTransmission; }
|
if (isset(BSDF::EDiffuseReflection)) { oss << "diffuseReflection "; typeMask &= ~BSDF::EDiffuseReflection; }
|
||||||
if (typeMask & BSDF::EGlossyReflection) { oss << "glossyReflection "; typeMask &= ~BSDF::EGlossyReflection; }
|
if (isset(BSDF::EDiffuseTransmission)) { oss << "diffuseTransmission "; typeMask &= ~BSDF::EDiffuseTransmission; }
|
||||||
if (typeMask & BSDF::EGlossyTransmission) { oss << "glossyTransmission "; typeMask &= ~BSDF::EGlossyTransmission; }
|
if (isset(BSDF::EGlossyReflection)) { oss << "glossyReflection "; typeMask &= ~BSDF::EGlossyReflection; }
|
||||||
if (typeMask & BSDF::EDeltaReflection) { oss << "deltaReflection "; typeMask &= ~BSDF::EDeltaReflection; }
|
if (isset(BSDF::EGlossyTransmission)) { oss << "glossyTransmission "; typeMask &= ~BSDF::EGlossyTransmission; }
|
||||||
if (typeMask & BSDF::EDeltaTransmission) { oss << "deltaTransmission "; typeMask &= ~BSDF::EDeltaTransmission; }
|
if (isset(BSDF::EDeltaReflection)) { oss << "deltaReflection "; typeMask &= ~BSDF::EDeltaReflection; }
|
||||||
if (typeMask & BSDF::EDelta1DReflection) { oss << "delta1DReflection "; typeMask &= ~BSDF::EDelta1DReflection; }
|
if (isset(BSDF::EDeltaTransmission)) { oss << "deltaTransmission "; typeMask &= ~BSDF::EDeltaTransmission; }
|
||||||
if (typeMask & BSDF::EDelta1DTransmission) { oss << "delta1DTransmission "; typeMask &= ~BSDF::EDelta1DTransmission; }
|
if (isset(BSDF::EDelta1DReflection)) { oss << "delta1DReflection "; typeMask &= ~BSDF::EDelta1DReflection; }
|
||||||
if (typeMask & BSDF::EAnisotropic) { oss << "anisotropic "; typeMask &= ~BSDF::EAnisotropic; }
|
if (isset(BSDF::EDelta1DTransmission)) { oss << "delta1DTransmission "; typeMask &= ~BSDF::EDelta1DTransmission; }
|
||||||
if (typeMask & BSDF::EFrontSide) { oss << "frontSide "; typeMask &= ~BSDF::EFrontSide; }
|
if (isset(BSDF::EAnisotropic)) { oss << "anisotropic "; typeMask &= ~BSDF::EAnisotropic; }
|
||||||
if (typeMask & BSDF::EBackSide) { oss << "backSide "; typeMask &= ~BSDF::EBackSide; }
|
if (isset(BSDF::EFrontSide)) { oss << "frontSide "; typeMask &= ~BSDF::EFrontSide; }
|
||||||
if (typeMask & BSDF::ECanUseSampler) { oss << "canUseSampler "; typeMask &= ~BSDF::ECanUseSampler; }
|
if (isset(BSDF::EBackSide)) { oss << "backSide "; typeMask &= ~BSDF::EBackSide; }
|
||||||
|
if (isset(BSDF::ECanUseSampler)) { oss << "canUseSampler "; typeMask &= ~BSDF::ECanUseSampler; }
|
||||||
|
#undef isset
|
||||||
oss << "}";
|
oss << "}";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ public:
|
||||||
enableFPExceptions();
|
enableFPExceptions();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Float pdfVal;
|
Float pdfVal, pdfVal2;
|
||||||
|
|
||||||
/* Only make the sampler available to the BSDF when requested
|
/* Only make the sampler available to the BSDF when requested
|
||||||
by the testcase. This allows testing both sampling variants
|
by the testcase. This allows testing both sampling variants
|
||||||
|
@ -123,42 +123,48 @@ public:
|
||||||
if (m_passSamplerToBSDF)
|
if (m_passSamplerToBSDF)
|
||||||
bRec.sampler = m_fakeSampler;
|
bRec.sampler = m_fakeSampler;
|
||||||
|
|
||||||
/* Check the various sampling routines for agreement amongst each other */
|
/* Check the various sampling routines for agreement
|
||||||
|
amongst each other */
|
||||||
m_fakeSampler->clear();
|
m_fakeSampler->clear();
|
||||||
Spectrum f = m_bsdf->sample(bRec, pdfVal, sample);
|
Spectrum f = m_bsdf->sample(bRec, pdfVal, sample);
|
||||||
m_fakeSampler->rewind();
|
m_fakeSampler->rewind();
|
||||||
Spectrum sampled = m_bsdf->sample(bRec, sample);
|
Spectrum sampled = m_bsdf->sample(bRec, sample);
|
||||||
|
EMeasure measure = ESolidAngle;
|
||||||
|
if (!f.isZero())
|
||||||
|
measure = BSDF::getMeasure(bRec.sampledType);
|
||||||
|
Spectrum f2 = m_bsdf->eval(bRec, measure);
|
||||||
|
pdfVal2 = m_bsdf->pdf(bRec, measure);
|
||||||
|
|
||||||
if (f.isZero() || pdfVal == 0) {
|
if (f.isZero() || pdfVal == 0 || pdfVal2 == 0) {
|
||||||
if (!sampled.isZero())
|
if (!sampled.isZero())
|
||||||
Log(EWarn, "Inconsistency (1): f=%s, pdf=%f, sampled f/pdf=%s, bRec=%s",
|
Log(EWarn, "Inconsistency (1): f=%s, f2=%s, pdf=%f, pdf2=%f, sampled f/pdf=%s, bRec=%s, measure=%i",
|
||||||
f.toString().c_str(), pdfVal, sampled.toString().c_str(), bRec.toString().c_str());
|
f.toString().c_str(), f2.toString().c_str(), pdfVal, pdfVal2, sampled.toString().c_str(), bRec.toString().c_str(), measure);
|
||||||
#if defined(MTS_DEBUG_FP)
|
#if defined(MTS_DEBUG_FP)
|
||||||
disableFPExceptions();
|
disableFPExceptions();
|
||||||
#endif
|
#endif
|
||||||
return boost::make_tuple(bRec.wo, 0.0f, ESolidAngle);
|
return boost::make_tuple(bRec.wo, 0.0f, ESolidAngle);
|
||||||
} else if (sampled.isZero()) {
|
} else if (sampled.isZero()) {
|
||||||
if (!f.isZero() && pdfVal != 0)
|
if ((!f.isZero() && pdfVal != 0) || (!f2.isZero() && pdfVal2 != 0))
|
||||||
Log(EWarn, "Inconsistency (2): f=%s, pdf=%f, sampled f/pdf=%s, bRec=%s",
|
Log(EWarn, "Inconsistency (2): f=%s, f2=%s, pdf=%f, pdf2=%f, sampled f/pdf=%s, bRec=%s, measure=%i",
|
||||||
f.toString().c_str(), pdfVal, sampled.toString().c_str(), bRec.toString().c_str());
|
f.toString().c_str(), f2.toString().c_str(), pdfVal, pdfVal2, sampled.toString().c_str(), bRec.toString().c_str(), measure);
|
||||||
#if defined(MTS_DEBUG_FP)
|
#if defined(MTS_DEBUG_FP)
|
||||||
disableFPExceptions();
|
disableFPExceptions();
|
||||||
#endif
|
#endif
|
||||||
return boost::make_tuple(bRec.wo, 0.0f, ESolidAngle);
|
return boost::make_tuple(bRec.wo, 0.0f, ESolidAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sampled2 = f/pdfVal;
|
Spectrum sampled2 = f/pdfVal, evaluated = f2/pdfVal2;
|
||||||
if (!sampled.isValid() || !sampled2.isValid()) {
|
if (!sampled.isValid() || !sampled2.isValid() || !evaluated.isValid()) {
|
||||||
Log(EWarn, "Ooops: f=%s, pdf=%f, sampled f/pdf=%s, bRec=%s",
|
Log(EWarn, "Ooops: f=%s, f2=%s, pdf=%f, pdf2=%f, sampled f/pdf=%s, bRec=%s, measure=%i",
|
||||||
f.toString().c_str(), pdfVal, sampled.toString().c_str(), bRec.toString().c_str());
|
f.toString().c_str(), f2.toString().c_str(), pdfVal, pdfVal2, sampled.toString().c_str(), bRec.toString().c_str(), measure);
|
||||||
return boost::make_tuple(bRec.wo, 0.0f, ESolidAngle);
|
return boost::make_tuple(bRec.wo, 0.0f, ESolidAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mismatch = false;
|
bool mismatch = false;
|
||||||
for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
|
for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
|
||||||
Float a = sampled[i], b = sampled2[i];
|
Float a = sampled[i], b = sampled2[i], c = evaluated[i];
|
||||||
Float min = std::min(a, b);
|
Float min = std::min(std::min(a, b), c);
|
||||||
Float err = std::abs(a - b);
|
Float err = std::max(std::max(std::abs(a - b), std::abs(a - c)), std::abs(b - c));
|
||||||
m_largestWeight = std::max(m_largestWeight, a);
|
m_largestWeight = std::max(m_largestWeight, a);
|
||||||
|
|
||||||
if (min < ERROR_REQ && err > ERROR_REQ) // absolute error threshold
|
if (min < ERROR_REQ && err > ERROR_REQ) // absolute error threshold
|
||||||
|
@ -168,15 +174,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mismatch)
|
if (mismatch)
|
||||||
Log(EWarn, "Potential inconsistency (3): f/pdf=%s, sampled f/pdf=%s",
|
Log(EWarn, "Potential inconsistency (3): f/pdf=%s (method 1), f/pdf=%s (methdod 2), sampled f/pdf=%s",
|
||||||
sampled2.toString().c_str(), sampled.toString().c_str());
|
sampled2.toString().c_str(), evaluated.toString().c_str(), sampled.toString().c_str());
|
||||||
|
|
||||||
#if defined(MTS_DEBUG_FP)
|
#if defined(MTS_DEBUG_FP)
|
||||||
disableFPExceptions();
|
disableFPExceptions();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return boost::make_tuple(bRec.wo, 1.0f,
|
return boost::make_tuple(bRec.wo, 1.0f, measure);
|
||||||
BSDF::getMeasure(bRec.sampledType));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Float pdf(const Vector &wo, EMeasure measure) {
|
Float pdf(const Vector &wo, EMeasure measure) {
|
||||||
|
|
Loading…
Reference in New Issue