BSDFQueryRecord: it is now assumed that a sampler is always there
parent
334002cc46
commit
fad581de2f
|
@ -423,21 +423,7 @@ public:
|
|||
Float prob = m_distribution.pdf(H, alphaU, alphaV);
|
||||
|
||||
if (hasTransmission && hasReflection) {
|
||||
/* Please see the sample() methods if the
|
||||
following seems confusing */
|
||||
Float F;
|
||||
if (bRec.sampler) {
|
||||
/* We have access to extra random numbers and are
|
||||
thus able to sample the exact Fresnel term
|
||||
with respect to the microfacet normal */
|
||||
F = fresnel(dot(bRec.wi, H), m_extIOR, m_intIOR);
|
||||
} else {
|
||||
/* Only a simple 2D sample is given, and hence the
|
||||
best we can do is to sample a clamped Fresnel term
|
||||
that is taken with respect to the surface normal */
|
||||
F = std::min((Float) 0.9f, std::max((Float) 0.1f,
|
||||
fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR)));
|
||||
}
|
||||
Float F = fresnel(dot(bRec.wi, H), m_extIOR, m_intIOR);
|
||||
prob *= reflect ? F : (1-F);
|
||||
}
|
||||
|
||||
|
@ -454,43 +440,8 @@ public:
|
|||
choseReflection = hasReflection,
|
||||
sampleExactFresnelTerm = false;
|
||||
|
||||
Float sampleF = 1.0f;
|
||||
if (hasReflection && hasTransmission) {
|
||||
if (!bRec.sampler) {
|
||||
/* By default, the sample() method is given exactly two
|
||||
uniformly chosen random numbers, which is a problem
|
||||
when wanting to choose between the reflection and the
|
||||
transmission component: by the time the microfacet normal
|
||||
has been sampled, we have already "used up" both of them,
|
||||
and no random bits are left. Therefore, the following
|
||||
somewhat crude approach is taken here when no extra sampler
|
||||
instance is provided:
|
||||
1. Take the Fresnel term with respect to the surface
|
||||
normal to be a good approximation to the microsurface
|
||||
Fresnel term -- this will be less true for higher
|
||||
roughness values. To be safe, clamp it to some
|
||||
reasonable range.
|
||||
2. Use this approximate term and a random number to
|
||||
choose between reflection and refraction component.
|
||||
3. Recycle the used random number! This is possible,
|
||||
since we so far only used the knowledge that it is
|
||||
smaller or larget than the purely deterministic value
|
||||
from step 2.
|
||||
*/
|
||||
sampleF = std::min((Float) 0.9f, std::max((Float) 0.1f,
|
||||
fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR)));
|
||||
if (sample.x < sampleF) {
|
||||
sample.x /= sampleF;
|
||||
} else {
|
||||
sample.x = (sample.x - sampleF) / (1 - sampleF);
|
||||
choseReflection = false;
|
||||
}
|
||||
} else {
|
||||
sampleExactFresnelTerm = true;
|
||||
}
|
||||
} else if (!hasReflection && !hasTransmission) {
|
||||
if (!hasReflection && !hasTransmission)
|
||||
return Spectrum(0.0f);
|
||||
}
|
||||
|
||||
/* Evaluate the roughness */
|
||||
Float alphaU = m_distribution.transformRoughness(
|
||||
|
@ -512,9 +463,9 @@ public:
|
|||
const Normal m = m_distribution.sample(sample,
|
||||
sampleAlphaU, sampleAlphaV);
|
||||
|
||||
if (sampleExactFresnelTerm) {
|
||||
sampleF = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR);
|
||||
if (bRec.sampler->next1D() > sampleF)
|
||||
if (hasReflection && hasTransmission) {
|
||||
Float F = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR);
|
||||
if (bRec.sampler->next1D() > F)
|
||||
choseReflection = false;
|
||||
}
|
||||
|
||||
|
@ -559,17 +510,6 @@ public:
|
|||
Float denominator = m_distribution.pdf(m, sampleAlphaU, sampleAlphaV)
|
||||
* Frame::cosTheta(bRec.wi);
|
||||
|
||||
if (!sampleExactFresnelTerm) {
|
||||
Float F = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR);
|
||||
if (!choseReflection) {
|
||||
sampleF = 1-sampleF;
|
||||
F = 1-F;
|
||||
}
|
||||
numerator *= F;
|
||||
if (hasReflection && hasTransmission)
|
||||
denominator *= sampleF;
|
||||
}
|
||||
|
||||
return result * std::abs(numerator / denominator);
|
||||
}
|
||||
|
||||
|
@ -583,42 +523,8 @@ public:
|
|||
choseReflection = hasReflection,
|
||||
sampleExactFresnelTerm = false;
|
||||
|
||||
if (hasReflection && hasTransmission) {
|
||||
if (!bRec.sampler) {
|
||||
/* By default, the sample() method is given exactly two
|
||||
uniformly chosen random numbers, which is a problem
|
||||
when wanting to choose between the reflection and the
|
||||
transmission component: by the time the microfacet normal
|
||||
has been sampled, we have already "used up" both of them,
|
||||
and no random bits are left. Therefore, the following
|
||||
somewhat crude approach is taken here when no extra sampler
|
||||
instance is provided:
|
||||
1. Take the Fresnel term with respect to the surface
|
||||
normal to be a good approximation to the microsurface
|
||||
Fresnel term -- this will be less true for higher
|
||||
roughness values. To be safe, clamp it to some
|
||||
reasonable range.
|
||||
2. Use this approximate term and a random number to
|
||||
choose between reflection and refraction component.
|
||||
3. Recycle the used random number! This is possible,
|
||||
since we so far only used the knowledge that it is
|
||||
smaller or larget than the purely deterministic value
|
||||
from step 2.
|
||||
*/
|
||||
Float sampleF = std::min((Float) 0.9f, std::max((Float) 0.1f,
|
||||
fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR)));
|
||||
if (sample.x < sampleF) {
|
||||
sample.x /= sampleF;
|
||||
} else {
|
||||
sample.x = (sample.x - sampleF) / (1 - sampleF);
|
||||
choseReflection = false;
|
||||
}
|
||||
} else {
|
||||
sampleExactFresnelTerm = true;
|
||||
}
|
||||
} else if (!hasReflection && !hasTransmission) {
|
||||
if (!hasReflection && !hasTransmission)
|
||||
return Spectrum(0.0f);
|
||||
}
|
||||
|
||||
/* Evaluate the roughness */
|
||||
Float alphaU = m_distribution.transformRoughness(
|
||||
|
@ -640,9 +546,9 @@ public:
|
|||
const Normal m = m_distribution.sample(sample,
|
||||
sampleAlphaU, sampleAlphaV);
|
||||
|
||||
if (sampleExactFresnelTerm) {
|
||||
Float sampleF = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR);
|
||||
if (bRec.sampler->next1D() > sampleF)
|
||||
if (hasReflection && hasTransmission) {
|
||||
Float F = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR);
|
||||
if (bRec.sampler->next1D() > F)
|
||||
choseReflection = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ size_t generateVPLs(const Scene *scene, Random *random,
|
|||
}
|
||||
|
||||
BSDFQueryRecord bRec(its, EImportance);
|
||||
bRec.sampler = sampler;
|
||||
bsdfVal = bsdf->sample(bRec, sampler->next2D());
|
||||
if (bsdfVal.isZero())
|
||||
break;
|
||||
|
|
|
@ -94,10 +94,9 @@ public:
|
|||
/// Adapter to use BSDFs in the chi-square test
|
||||
class BSDFAdapter {
|
||||
public:
|
||||
BSDFAdapter(const BSDF *bsdf, Sampler *sampler, const Vector &wi,
|
||||
int component, bool passSamplerToBSDF)
|
||||
BSDFAdapter(const BSDF *bsdf, Sampler *sampler, const Vector &wi, int component)
|
||||
: m_bsdf(bsdf), m_sampler(sampler), m_wi(wi), m_component(component),
|
||||
m_largestWeight(0), m_passSamplerToBSDF(passSamplerToBSDF) {
|
||||
m_largestWeight(0) {
|
||||
m_fakeSampler = new FakeSampler(m_sampler);
|
||||
m_its.uv = Point2(0.0f);
|
||||
m_its.dpdu = Vector(1, 0, 0);
|
||||
|
@ -125,8 +124,7 @@ public:
|
|||
an arbitrary random number stream vs. those that only use
|
||||
a single uniform 2D sample */
|
||||
|
||||
if (m_passSamplerToBSDF)
|
||||
bRec.sampler = m_fakeSampler;
|
||||
bRec.sampler = m_fakeSampler;
|
||||
|
||||
/* Check the various sampling routines for agreement
|
||||
amongst each other */
|
||||
|
@ -196,8 +194,7 @@ public:
|
|||
bRec.component = m_component;
|
||||
bRec.wi = m_wi;
|
||||
bRec.wo = wo;
|
||||
if (m_passSamplerToBSDF)
|
||||
bRec.sampler = m_sampler;
|
||||
bRec.sampler = m_sampler;
|
||||
|
||||
#if defined(MTS_DEBUG_FP)
|
||||
enableFPExceptions();
|
||||
|
@ -223,7 +220,6 @@ public:
|
|||
Vector m_wi;
|
||||
int m_component;
|
||||
Float m_largestWeight;
|
||||
bool m_passSamplerToBSDF;
|
||||
};
|
||||
|
||||
/// Adapter to use Phase functions in the chi-square test
|
||||
|
@ -334,104 +330,88 @@ public:
|
|||
|
||||
Log(EInfo, "Processing BSDF model %s", bsdf->toString().c_str());
|
||||
|
||||
for (int pass=0; pass<2; ++pass) {
|
||||
Log(EInfo, "Checking the model for %i incident directions and 2D sampling", wiSamples);
|
||||
progress->reset();
|
||||
Log(EInfo, "Checking the model for %i incident directions and 2D sampling", wiSamples);
|
||||
progress->reset();
|
||||
|
||||
/**
|
||||
* Do a second pass when the BSDF can optionally make use of
|
||||
* an infinite random number stream. The sampling method is likely
|
||||
* quite different in this case, so everything has to be checked
|
||||
* again.
|
||||
*/
|
||||
/* Test for a number of different incident directions */
|
||||
for (size_t j=0; j<wiSamples; ++j) {
|
||||
Vector wi;
|
||||
|
||||
if (bsdf->getType() & BSDF::EBackSide)
|
||||
wi = squareToSphere(sampler->next2D());
|
||||
else
|
||||
wi = squareToHemispherePSA(sampler->next2D());
|
||||
|
||||
if (pass == 1) {
|
||||
if (!(bsdf->getType() & BSDF::ECanUseSampler))
|
||||
break;
|
||||
else
|
||||
Log(EInfo, "Checking the model again, but now with access to an infinite random number stream.");
|
||||
BSDFAdapter adapter(bsdf, sampler, wi, -1);
|
||||
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, wiSamples);
|
||||
chiSqr->setLogLevel(EDebug);
|
||||
|
||||
// Initialize the tables used by the chi-square test
|
||||
chiSqr->fill(
|
||||
boost::bind(&BSDFAdapter::generateSample, &adapter),
|
||||
boost::bind(&BSDFAdapter::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", failureCount++);
|
||||
chiSqr->dumpTables(filename);
|
||||
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
|
||||
"issue for wi=%s. Dumped the contingency tables to '%s' for user analysis",
|
||||
wi.toString().c_str(), filename.c_str()));
|
||||
} else {
|
||||
succeed();
|
||||
}
|
||||
largestWeight = std::max(largestWeight, adapter.getLargestWeight());
|
||||
++testCount;
|
||||
progress->update(j+1);
|
||||
}
|
||||
Log(EInfo, "The largest encountered importance weight was = %.2f", largestWeight);
|
||||
largestWeight = 0;
|
||||
|
||||
/* Test for a number of different incident directions */
|
||||
for (size_t j=0; j<wiSamples; ++j) {
|
||||
Vector wi;
|
||||
|
||||
if (bsdf->getType() & BSDF::EBackSide)
|
||||
wi = squareToSphere(sampler->next2D());
|
||||
else
|
||||
wi = squareToHemispherePSA(sampler->next2D());
|
||||
if (bsdf->getComponentCount() > 1) {
|
||||
for (int comp=0; comp<bsdf->getComponentCount(); ++comp) {
|
||||
progress->reset();
|
||||
Log(EInfo, "Individually checking BSDF component %i", comp);
|
||||
|
||||
BSDFAdapter adapter(bsdf, sampler, wi, -1, pass == 1);
|
||||
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, wiSamples);
|
||||
chiSqr->setLogLevel(EDebug);
|
||||
/* Test for a number of different incident directions */
|
||||
for (size_t j=0; j<wiSamples; ++j) {
|
||||
Vector wi;
|
||||
|
||||
if (bsdf->getType(comp) & BSDF::EBackSide)
|
||||
wi = squareToSphere(sampler->next2D());
|
||||
else
|
||||
wi = squareToHemispherePSA(sampler->next2D());
|
||||
|
||||
// Initialize the tables used by the chi-square test
|
||||
chiSqr->fill(
|
||||
boost::bind(&BSDFAdapter::generateSample, &adapter),
|
||||
boost::bind(&BSDFAdapter::pdf, &adapter, _1, _2)
|
||||
);
|
||||
BSDFAdapter adapter(bsdf, sampler, wi, comp);
|
||||
|
||||
// (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", failureCount++);
|
||||
chiSqr->dumpTables(filename);
|
||||
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
|
||||
"issue for wi=%s. Dumped the contingency tables to '%s' for user analysis",
|
||||
wi.toString().c_str(), filename.c_str()));
|
||||
} else {
|
||||
succeed();
|
||||
}
|
||||
largestWeight = std::max(largestWeight, adapter.getLargestWeight());
|
||||
++testCount;
|
||||
progress->update(j+1);
|
||||
}
|
||||
Log(EInfo, "The largest encountered importance weight was = %.2f", largestWeight);
|
||||
largestWeight = 0;
|
||||
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, wiSamples);
|
||||
chiSqr->setLogLevel(EDebug);
|
||||
|
||||
if (bsdf->getComponentCount() > 1) {
|
||||
for (int comp=0; comp<bsdf->getComponentCount(); ++comp) {
|
||||
progress->reset();
|
||||
Log(EInfo, "Individually checking BSDF component %i", comp);
|
||||
// Initialize the tables used by the chi-square test
|
||||
chiSqr->fill(
|
||||
boost::bind(&BSDFAdapter::generateSample, &adapter),
|
||||
boost::bind(&BSDFAdapter::pdf, &adapter, _1, _2)
|
||||
);
|
||||
|
||||
/* Test for a number of different incident directions */
|
||||
for (size_t j=0; j<wiSamples; ++j) {
|
||||
Vector wi;
|
||||
|
||||
if (bsdf->getType(comp) & BSDF::EBackSide)
|
||||
wi = squareToSphere(sampler->next2D());
|
||||
else
|
||||
wi = squareToHemispherePSA(sampler->next2D());
|
||||
|
||||
BSDFAdapter adapter(bsdf, sampler, wi, comp, pass == 1);
|
||||
|
||||
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, wiSamples);
|
||||
chiSqr->setLogLevel(EDebug);
|
||||
|
||||
// Initialize the tables used by the chi-square test
|
||||
chiSqr->fill(
|
||||
boost::bind(&BSDFAdapter::generateSample, &adapter),
|
||||
boost::bind(&BSDFAdapter::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", failureCount++);
|
||||
chiSqr->dumpTables(filename);
|
||||
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
|
||||
"issue for wi=%s. Dumped the contingency tables to '%s' for user analysis",
|
||||
wi.toString().c_str(), filename.c_str()));
|
||||
} else {
|
||||
succeed();
|
||||
}
|
||||
largestWeight = std::max(largestWeight, adapter.getLargestWeight());
|
||||
++testCount;
|
||||
progress->update(j+1);
|
||||
// (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", failureCount++);
|
||||
chiSqr->dumpTables(filename);
|
||||
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
|
||||
"issue for wi=%s. Dumped the contingency tables to '%s' for user analysis",
|
||||
wi.toString().c_str(), filename.c_str()));
|
||||
} else {
|
||||
succeed();
|
||||
}
|
||||
Log(EInfo, "The largest encountered importance weight was = %.2f", largestWeight);
|
||||
largestWeight = 0;
|
||||
largestWeight = std::max(largestWeight, adapter.getLargestWeight());
|
||||
++testCount;
|
||||
progress->update(j+1);
|
||||
}
|
||||
Log(EInfo, "The largest encountered importance weight was = %.2f", largestWeight);
|
||||
largestWeight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue