test_microfacet.cpp
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2014 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/core/plugin.h>
#include <mitsuba/core/statistics.h>
#include <mitsuba/core/chisquare.h>
#include <mitsuba/core/fresolver.h>
#include <mitsuba/render/testcase.h>
#include <boost/bind.hpp>
#include "../bsdfs/microfacet.h"
/* Statistical significance level of the test. Set to
1/4 percent by default -- we want there to be strong
evidence of an implementaiton error before failing
a test case */
#define SIGNIFICANCE_LEVEL 0.0025f
/* Relative bound on what is still accepted as roundoff
error -- be quite tolerant */
#if defined(SINGLE_PRECISION)
#define ERROR_REQ 1e-2f
#else
#define ERROR_REQ 1e-5
#endif
MTS_NAMESPACE_BEGIN
class TestChiSquare : public TestCase {
public:
MTS_BEGIN_TESTCASE()
MTS_DECLARE_TEST(test01_Microfacet)
MTS_DECLARE_TEST(test02_MicrofacetVisible)
MTS_END_TESTCASE()
class MicrofacetAdapter {
public:
MicrofacetAdapter(Sampler *sampler, const MicrofacetDistribution &distr, const Vector &wi = Vector(0.0f)) : m_sampler(sampler), m_distr(distr), m_wi(wi) { }
boost::tuple<Vector, Float, EMeasure> generateSample() {
Float pdf;
if (m_wi.lengthSquared() == 0) {
Normal m = m_distr.sampleAll(m_sampler->next2D(), pdf);
Float pdf_ref = m_distr.pdfAll(m);
SAssert(std::isfinite(pdf) && pdf > 0);
SAssert(std::isfinite(pdf_ref) && pdf_ref > 0);
SAssert(std::isfinite(m.x) && std::isfinite(m.y) && std::isfinite(m.z));
SAssert(std::abs(m.length() - 1) < 1e-4f);
SAssert(std::abs((pdf-pdf_ref)/pdf_ref) < 1e-4f);
return boost::make_tuple(m, 1.0f, ESolidAngle);
} else {
Normal m = m_distr.sampleVisible(m_wi, m_sampler->next2D());
SAssert(std::isfinite(m.x) && std::isfinite(m.y) && std::isfinite(m.z));
SAssert(std::abs(m.length() - 1) < 1e-4f);
return boost::make_tuple(m, 1.0f, ESolidAngle);
}
}
Float pdf(const Vector &d, EMeasure measure) const {
if (measure != ESolidAngle)
return 0.0f;
Float pdf = m_wi.lengthSquared() == 0 ? m_distr.pdfAll(d)
: m_distr.pdfVisible(m_wi, d);
SAssert(std::isfinite(pdf) && pdf >= 0);
return pdf;
}
private:
ref<Sampler> m_sampler;
MicrofacetDistribution m_distr;
Vector m_wi;
};
void test01_Microfacet() {
int thetaBins = 20;
std::vector<MicrofacetDistribution> distrs;
distrs.push_back(MicrofacetDistribution(MicrofacetDistribution::EBeckmann, 0.5f));
distrs.push_back(MicrofacetDistribution(MicrofacetDistribution::EBeckmann, 0.5f, 0.3f));
distrs.push_back(MicrofacetDistribution(MicrofacetDistribution::EGGX, 0.5f));
distrs.push_back(MicrofacetDistribution(MicrofacetDistribution::EGGX, 0.5f, 0.3f));
distrs.push_back(MicrofacetDistribution(MicrofacetDistribution::EPhong, 0.5f));
distrs.push_back(MicrofacetDistribution(MicrofacetDistribution::EPhong, 0.5f, 0.3f));
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(MTS_CLASS(Sampler), Properties("independent")));
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, (int) distrs.size());
chiSqr->setLogLevel(EDebug);
for (size_t i=0; i<distrs.size(); ++i) {
Log(EInfo, "Testing %s", distrs[i].toString().c_str());
// Initialize the tables used by the chi-square test
MicrofacetAdapter adapter(sampler, distrs[i]);
chiSqr->fill(
boost::bind(&MicrofacetAdapter::generateSample, &adapter),
boost::bind(&MicrofacetAdapter::pdf, &adapter, _1, _2)
);
// (the following assumes that the distribution has 1 parameter, e.g. exponent value)
ChiSquare::ETestResult result = chiSqr->runTest(SIGNIFICANCE_LEVEL);
if (result == ChiSquare::EReject) {
std::string filename = formatString("failure_%i.m", (int) i);
chiSqr->dumpTables(filename);
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
"issue. Dumped the contingency tables to '%s' for user analysis",
filename.c_str()));
} else {
//chiSqr->dumpTables(formatString("success_%i.m", (int) i));
succeed();
}
}
}
void test02_MicrofacetVisible() {
int thetaBins = 10;
std::vector<std::pair<MicrofacetDistribution, Vector> > distrs;
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(MTS_CLASS(Sampler), Properties("independent")));
for (int i=0; i<10; ++i) {
Vector wi = warp::squareToUniformHemisphere(sampler->next2D());
distrs.push_back(std::make_pair(MicrofacetDistribution(MicrofacetDistribution::EBeckmann, 0.3f), wi));
distrs.push_back(std::make_pair(MicrofacetDistribution(MicrofacetDistribution::EBeckmann, 0.5f, 0.3f), wi));
distrs.push_back(std::make_pair(MicrofacetDistribution(MicrofacetDistribution::EGGX, 0.1f), wi));
distrs.push_back(std::make_pair(MicrofacetDistribution(MicrofacetDistribution::EGGX, 0.2f, 0.3f), wi));
}
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, (int) distrs.size());
chiSqr->setLogLevel(EDebug);
for (size_t i=0; i<distrs.size(); ++i) {
Log(EInfo, "Testing %s (wi=%s)", distrs[i].first.toString().c_str(), distrs[i].second.toString().c_str());
// Initialize the tables used by the chi-square test
MicrofacetAdapter adapter(sampler, distrs[i].first, distrs[i].second);
chiSqr->fill(
boost::bind(&MicrofacetAdapter::generateSample, &adapter),
boost::bind(&MicrofacetAdapter::pdf, &adapter, _1, _2)
);
// (the following assumes that the distribution has 1 parameter, e.g. exponent value)
ChiSquare::ETestResult result = chiSqr->runTest(SIGNIFICANCE_LEVEL);
if (result == ChiSquare::EReject) {
std::string filename = formatString("failure_%i.m", (int) i);
chiSqr->dumpTables(filename);
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
"issue. Dumped the contingency tables to '%s' for user analysis",
filename.c_str()));
} else {
//chiSqr->dumpTables(formatString("success_%i.m", (int) i));
succeed();
}
}
}
};
MTS_EXPORT_TESTCASE(TestChiSquare, "Chi-square test for microfacet sampling")
MTS_NAMESPACE_END