microflake bugfixes
parent
d3ad21f0da
commit
9f58f35623
|
@ -22,7 +22,6 @@
|
||||||
#include <mitsuba/core/fresolver.h>
|
#include <mitsuba/core/fresolver.h>
|
||||||
#include <mitsuba/core/quad.h>
|
#include <mitsuba/core/quad.h>
|
||||||
#include <mitsuba/core/timer.h>
|
#include <mitsuba/core/timer.h>
|
||||||
#include <mitsuba/core/random.h>
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/math/distributions/chi_squared.hpp>
|
#include <boost/math/distributions/chi_squared.hpp>
|
||||||
|
|
||||||
|
@ -42,10 +41,16 @@ MTS_NAMESPACE_BEGIN
|
||||||
* integrated over the area of each bin. Comparing the actual and reference
|
* integrated over the area of each bin. Comparing the actual and reference
|
||||||
* bin counts yields the desired test statistic.
|
* bin counts yields the desired test statistic.
|
||||||
*
|
*
|
||||||
* Given a BSDF/phase function with the following interface
|
* Given a probability distribution with the following interface
|
||||||
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* class MyDistribution {
|
* class MyDistribution {
|
||||||
* Vector sample(const Point2 &uniformSample) const;
|
* // Sample a (optionally weighted) direction. A non-unity weight
|
||||||
|
* // in the return value is needed when the sampling distribution
|
||||||
|
* // doesn't exactly match the implementation in pdf()
|
||||||
|
* std::pair<Vector, Float> generateSample() const;
|
||||||
|
*
|
||||||
|
* /// Compute the probability density for the specified direction
|
||||||
* Float pdf(const Vector &direction) const;
|
* Float pdf(const Vector &direction) const;
|
||||||
* };
|
* };
|
||||||
* </code>
|
* </code>
|
||||||
|
@ -58,7 +63,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
*
|
*
|
||||||
* // Initialize the tables used by the chi-square test
|
* // Initialize the tables used by the chi-square test
|
||||||
* chiSqr.fill(
|
* chiSqr.fill(
|
||||||
* boost::bind(&MyDistribution::sample, myDistrInstance, _1),
|
* boost::bind(&MyDistribution::generateSample, myDistrInstance),
|
||||||
* boost::bind(&MyDistribution::pdf, myDistrInstance, _1)
|
* boost::bind(&MyDistribution::pdf, myDistrInstance, _1)
|
||||||
* );
|
* );
|
||||||
*
|
*
|
||||||
|
@ -85,7 +90,7 @@ public:
|
||||||
*
|
*
|
||||||
* \param sampleCount
|
* \param sampleCount
|
||||||
* Number of samples to be used when computing the bin
|
* Number of samples to be used when computing the bin
|
||||||
* values. The default is \c thetaBins*phiBins*1000
|
* values. The default is \c thetaBins*phiBins*5000
|
||||||
*/
|
*/
|
||||||
ChiSquareTest(int thetaBins = 10, int phiBins = 0, size_t sampleCount = 0)
|
ChiSquareTest(int thetaBins = 10, int phiBins = 0, size_t sampleCount = 0)
|
||||||
: m_thetaBins(thetaBins), m_phiBins(phiBins), m_sampleCount(sampleCount) {
|
: m_thetaBins(thetaBins), m_phiBins(phiBins), m_sampleCount(sampleCount) {
|
||||||
|
@ -93,7 +98,7 @@ public:
|
||||||
m_phiBins = 2*m_thetaBins;
|
m_phiBins = 2*m_thetaBins;
|
||||||
if (m_sampleCount == 0)
|
if (m_sampleCount == 0)
|
||||||
m_sampleCount = m_thetaBins * m_phiBins * 1000;
|
m_sampleCount = m_thetaBins * m_phiBins * 1000;
|
||||||
m_table = new uint32_t[m_thetaBins*m_phiBins];
|
m_table = new Float[m_thetaBins*m_phiBins];
|
||||||
m_refTable = new Float[m_thetaBins*m_phiBins];
|
m_refTable = new Float[m_thetaBins*m_phiBins];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,10 +115,9 @@ public:
|
||||||
* on how to invoke this function
|
* on how to invoke this function
|
||||||
*/
|
*/
|
||||||
void fill(
|
void fill(
|
||||||
const boost::function<Vector (const Point2 &)> &sampleFn,
|
const boost::function<std::pair<Vector, Float>()> &sampleFn,
|
||||||
const boost::function<Float (const Vector &)> &pdfFn) {
|
const boost::function<Float (const Vector &)> &pdfFn) {
|
||||||
ref<Random> random = new Random();
|
memset(m_table, 0, m_thetaBins*m_phiBins*sizeof(Float));
|
||||||
memset(m_table, 0, m_thetaBins*m_phiBins*sizeof(uint32_t));
|
|
||||||
|
|
||||||
SLog(EInfo, "Accumulating " SIZE_T_FMT " samples into a %ix%i"
|
SLog(EInfo, "Accumulating " SIZE_T_FMT " samples into a %ix%i"
|
||||||
" contingency table", m_sampleCount, m_thetaBins, m_phiBins);
|
" contingency table", m_sampleCount, m_thetaBins, m_phiBins);
|
||||||
|
@ -121,15 +125,15 @@ public:
|
||||||
|
|
||||||
ref<Timer> timer = new Timer();
|
ref<Timer> timer = new Timer();
|
||||||
for (size_t i=0; i<m_sampleCount; ++i) {
|
for (size_t i=0; i<m_sampleCount; ++i) {
|
||||||
Point2 sample(random->nextFloat(), random->nextFloat());
|
std::pair<Vector, Float> sample = sampleFn();
|
||||||
Point2 sphCoords = toSphericalCoordinates(sampleFn(sample));
|
Point2 sphCoords = toSphericalCoordinates(sample.first);
|
||||||
|
|
||||||
int thetaBin = std::min(std::max(0,
|
int thetaBin = std::min(std::max(0,
|
||||||
floorToInt(sphCoords.x * factor.x)), m_thetaBins-1);
|
floorToInt(sphCoords.x * factor.x)), m_thetaBins-1);
|
||||||
int phiBin = std::min(std::max(0,
|
int phiBin = std::min(std::max(0,
|
||||||
floorToInt(sphCoords.y * factor.y)), m_phiBins-1);
|
floorToInt(sphCoords.y * factor.y)), m_phiBins-1);
|
||||||
|
|
||||||
++m_table[thetaBin * m_phiBins + phiBin];
|
m_table[thetaBin * m_phiBins + phiBin] += sample.second;
|
||||||
}
|
}
|
||||||
SLog(EInfo, "Done, took %i ms.", timer->getMilliseconds());
|
SLog(EInfo, "Done, took %i ms.", timer->getMilliseconds());
|
||||||
factor = Point2(M_PI / m_thetaBins, (2*M_PI) / m_phiBins);
|
factor = Point2(M_PI / m_thetaBins, (2*M_PI) / m_phiBins);
|
||||||
|
@ -139,7 +143,7 @@ public:
|
||||||
Float min[2], max[2];
|
Float min[2], max[2];
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
|
|
||||||
NDIntegrator integrator(1, 2, 50000, 0, 1e-6f);
|
NDIntegrator integrator(1, 2, 100000, 0, 1e-6f);
|
||||||
Float maxError = 0, integral = 0;
|
Float maxError = 0, integral = 0;
|
||||||
for (int i=0; i<m_thetaBins; ++i) {
|
for (int i=0; i<m_thetaBins; ++i) {
|
||||||
min[0] = i * factor.x;
|
min[0] = i * factor.x;
|
||||||
|
@ -269,7 +273,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
int m_thetaBins, m_phiBins;
|
int m_thetaBins, m_phiBins;
|
||||||
size_t m_sampleCount;
|
size_t m_sampleCount;
|
||||||
uint32_t *m_table;
|
Float *m_table;
|
||||||
Float *m_refTable;
|
Float *m_refTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
* \brief Evaluate the phase function for an outward-pointing
|
* \brief Evaluate the phase function for an outward-pointing
|
||||||
* pair of directions (wi, wo)
|
* pair of directions (wi, wo)
|
||||||
*/
|
*/
|
||||||
virtual Spectrum f(const PhaseFunctionQueryRecord &pRec) const = 0;
|
virtual Float f(const PhaseFunctionQueryRecord &pRec) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Importance sample the phase function.
|
* \brief Importance sample the phase function.
|
||||||
|
@ -83,7 +83,7 @@ public:
|
||||||
* Weight value equal to the throughput divided by
|
* Weight value equal to the throughput divided by
|
||||||
* the probability of the sampled direction.
|
* the probability of the sampled direction.
|
||||||
*/
|
*/
|
||||||
virtual Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
virtual Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Sampler *sampler) const = 0;
|
Sampler *sampler) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,7 +95,7 @@ public:
|
||||||
* \return
|
* \return
|
||||||
* Phase function value for the direction pair (wi, wo)
|
* Phase function value for the direction pair (wi, wo)
|
||||||
*/
|
*/
|
||||||
virtual Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
virtual Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Float &pdf, Sampler *sampler) const = 0;
|
Float &pdf, Sampler *sampler) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -81,9 +81,9 @@ public:
|
||||||
if (rRec.type & RadianceQueryRecord::EDirectMediumRadiance &&
|
if (rRec.type & RadianceQueryRecord::EDirectMediumRadiance &&
|
||||||
scene->sampleAttenuatedLuminaire(mRec.p, ray.time, rRec.medium, lRec, rRec.nextSample2D())) {
|
scene->sampleAttenuatedLuminaire(mRec.p, ray.time, rRec.medium, lRec, rRec.nextSample2D())) {
|
||||||
/* Evaluate the phase function */
|
/* Evaluate the phase function */
|
||||||
Spectrum phaseVal = phase->f(PhaseFunctionQueryRecord(mRec, -ray.d, -lRec.d));
|
Float phaseVal = phase->f(PhaseFunctionQueryRecord(mRec, -ray.d, -lRec.d));
|
||||||
|
|
||||||
if (!phaseVal.isZero()) {
|
if (phaseVal != 0) {
|
||||||
/* Calculate prob. of having sampled that direction using
|
/* Calculate prob. of having sampled that direction using
|
||||||
phase function sampling */
|
phase function sampling */
|
||||||
Float phasePdf = (lRec.luminaire->isIntersectable()
|
Float phasePdf = (lRec.luminaire->isIntersectable()
|
||||||
|
@ -102,8 +102,8 @@ public:
|
||||||
|
|
||||||
Float phasePdf;
|
Float phasePdf;
|
||||||
PhaseFunctionQueryRecord pRec(mRec, -ray.d);
|
PhaseFunctionQueryRecord pRec(mRec, -ray.d);
|
||||||
Spectrum phaseVal = phase->sample(pRec, phasePdf, rRec.sampler);
|
Float phaseVal = phase->sample(pRec, phasePdf, rRec.sampler);
|
||||||
if (phaseVal.isZero())
|
if (phaseVal == 0)
|
||||||
break;
|
break;
|
||||||
phaseVal /= phasePdf;
|
phaseVal /= phasePdf;
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,8 @@ public:
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
|
|
||||||
PhaseFunctionQueryRecord pRec(mRec, -ray.d);
|
PhaseFunctionQueryRecord pRec(mRec, -ray.d);
|
||||||
Spectrum phaseVal = phase->sample(pRec, rRec.sampler);
|
Float phaseVal = phase->sample(pRec, rRec.sampler);
|
||||||
if (phaseVal.isZero())
|
if (phaseVal == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Trace a ray in this direction */
|
/* Trace a ray in this direction */
|
||||||
|
|
|
@ -15,7 +15,7 @@ std::string PhaseFunctionQueryRecord::toString() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Float PhaseFunction::pdf(const PhaseFunctionQueryRecord &pRec) const {
|
Float PhaseFunction::pdf(const PhaseFunctionQueryRecord &pRec) const {
|
||||||
return f(pRec)[0];
|
return f(pRec);
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS(PhaseFunction, true, ConfigurableObject)
|
MTS_IMPLEMENT_CLASS(PhaseFunction, true, ConfigurableObject)
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
stream->writeFloat(m_g);
|
stream->writeFloat(m_g);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
inline Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Sampler *sampler) const {
|
Sampler *sampler) const {
|
||||||
Point2 sample(sampler->next2D());
|
Point2 sample(sampler->next2D());
|
||||||
|
|
||||||
|
@ -71,21 +71,19 @@ public:
|
||||||
cosTheta);
|
cosTheta);
|
||||||
pRec.wo = Frame(-pRec.wi).toWorld(dir);
|
pRec.wo = Frame(-pRec.wi).toWorld(dir);
|
||||||
|
|
||||||
return Spectrum(1.0f);
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Float &pdf, Sampler *sampler) const {
|
Float &pdf, Sampler *sampler) const {
|
||||||
HGPhaseFunction::sample(pRec, sampler);
|
HGPhaseFunction::sample(pRec, sampler);
|
||||||
|
return HGPhaseFunction::f(pRec);
|
||||||
pdf = HGPhaseFunction::f(pRec)[0];
|
|
||||||
return Spectrum(pdf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Spectrum f(const PhaseFunctionQueryRecord &pRec) const {
|
Float f(const PhaseFunctionQueryRecord &pRec) const {
|
||||||
return Spectrum(1/(4*M_PI) * (1 - m_g*m_g) /
|
return 1/(4*M_PI) * (1 - m_g*m_g) /
|
||||||
std::pow(1.f + m_g*m_g - 2.f * m_g * dot(-pRec.wi, pRec.wo), (Float) 1.5f));
|
std::pow(1.f + m_g*m_g - 2.f * m_g * dot(-pRec.wi, pRec.wo), (Float) 1.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
|
|
|
@ -41,22 +41,22 @@ public:
|
||||||
PhaseFunction::serialize(stream, manager);
|
PhaseFunction::serialize(stream, manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Sampler *sampler) const {
|
Sampler *sampler) const {
|
||||||
Point2 sample(sampler->next2D());
|
Point2 sample(sampler->next2D());
|
||||||
pRec.wo = squareToSphere(sample);
|
pRec.wo = squareToSphere(sample);
|
||||||
return Spectrum(1.0f);
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Float &pdf, Sampler *sampler) const {
|
Float &pdf, Sampler *sampler) const {
|
||||||
pRec.wo = squareToSphere(sampler->next2D());
|
pRec.wo = squareToSphere(sampler->next2D());
|
||||||
pdf = 1/(4 * (Float) M_PI);
|
pdf = 1/(4 * (Float) M_PI);
|
||||||
return Spectrum(pdf);
|
return pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum f(const PhaseFunctionQueryRecord &pRec) const {
|
Float f(const PhaseFunctionQueryRecord &pRec) const {
|
||||||
return Spectrum(1/(4 * (Float) M_PI));
|
return 1/(4 * (Float) M_PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
|
|
|
@ -79,13 +79,13 @@ public:
|
||||||
stream->writeFloat(m_exponent);
|
stream->writeFloat(m_exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Sampler *sampler) const {
|
Sampler *sampler) const {
|
||||||
pRec.wo = squareToSphere(sampler->next2D());
|
pRec.wo = squareToSphere(sampler->next2D());
|
||||||
return f(pRec) * (4 * M_PI);
|
return f(pRec) * (4 * M_PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Float &pdf, Sampler *sampler) const {
|
Float &pdf, Sampler *sampler) const {
|
||||||
pRec.wo = squareToSphere(sampler->next2D());
|
pRec.wo = squareToSphere(sampler->next2D());
|
||||||
pdf = 1/(4 * M_PI);
|
pdf = 1/(4 * M_PI);
|
||||||
|
@ -96,9 +96,9 @@ public:
|
||||||
return 1/(4 * M_PI);
|
return 1/(4 * M_PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum f(const PhaseFunctionQueryRecord &pRec) const {
|
Float f(const PhaseFunctionQueryRecord &pRec) const {
|
||||||
if (pRec.mRec.orientation.length() == 0)
|
if (pRec.mRec.orientation.length() == 0)
|
||||||
return Spectrum(m_kd / (4*M_PI));
|
return m_kd / (4*M_PI);
|
||||||
|
|
||||||
Frame frame(normalize(pRec.mRec.orientation));
|
Frame frame(normalize(pRec.mRec.orientation));
|
||||||
Vector reflectedLocal = frame.toLocal(pRec.wo);
|
Vector reflectedLocal = frame.toLocal(pRec.wo);
|
||||||
|
@ -110,8 +110,8 @@ public:
|
||||||
reflectedLocal.x *= a;
|
reflectedLocal.x *= a;
|
||||||
Vector R = frame.toWorld(reflectedLocal);
|
Vector R = frame.toWorld(reflectedLocal);
|
||||||
|
|
||||||
return Spectrum((std::pow(std::max((Float) 0, dot(R, pRec.wo)), m_exponent))
|
return std::pow(std::max((Float) 0, dot(R, pRec.wo)), m_exponent)
|
||||||
* m_normalization * m_ks + m_kd / (4*M_PI));
|
* m_normalization * m_ks + m_kd / (4*M_PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
|
|
|
@ -17,20 +17,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <mitsuba/core/chisquare.h>
|
#include <mitsuba/core/chisquare.h>
|
||||||
|
#include <mitsuba/core/frame.h>
|
||||||
#include <mitsuba/render/phase.h>
|
#include <mitsuba/render/phase.h>
|
||||||
|
#include <mitsuba/render/medium.h>
|
||||||
#include <mitsuba/render/sampler.h>
|
#include <mitsuba/render/sampler.h>
|
||||||
|
|
||||||
|
#define MICROFLAKE_STATISTICS 1
|
||||||
#include "microflake_fiber.h"
|
#include "microflake_fiber.h"
|
||||||
|
|
||||||
|
#include <mitsuba/core/plugin.h>///XXX
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#if defined(MICROFLAKE_STATISTICS)
|
||||||
|
static StatsCounter avgSampleIterations("Micro-flake model",
|
||||||
|
"Average rejection sampling iterations", EAverage);
|
||||||
|
#endif
|
||||||
|
|
||||||
class MicroflakePhaseFunction : public PhaseFunction {
|
class MicroflakePhaseFunction : public PhaseFunction {
|
||||||
public:
|
public:
|
||||||
MicroflakePhaseFunction(const Properties &props) : PhaseFunction(props) {
|
MicroflakePhaseFunction(const Properties &props) : PhaseFunction(props) {
|
||||||
m_fiberDistr = GaussianFiberDistribution(props.getFloat("stddev"));
|
m_fiberDistr = GaussianFiberDistribution(props.getFloat("stddev"));
|
||||||
ChiSquareTest test(7);
|
ChiSquareTest test(7);
|
||||||
|
Sampler *sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
||||||
|
createObject(MTS_CLASS(Sampler), Properties("independent")));
|
||||||
test.fill(
|
test.fill(
|
||||||
boost::bind(&GaussianFiberDistribution::sample, m_fiberDistr, _1),
|
boost::bind(&MicroflakePhaseFunction::testSample, this, sampler),
|
||||||
boost::bind(&GaussianFiberDistribution::pdf, m_fiberDistr, _1)
|
boost::bind(&MicroflakePhaseFunction::testF, this, _1)
|
||||||
);
|
);
|
||||||
test.dumpTables("test.m");
|
test.dumpTables("test.m");
|
||||||
test.runTest(1);
|
test.runTest(1);
|
||||||
|
@ -49,22 +62,69 @@ public:
|
||||||
void configure() {
|
void configure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
Float f(const PhaseFunctionQueryRecord &pRec) const {
|
||||||
Sampler *sampler) const {
|
if (pRec.mRec.orientation.isZero())
|
||||||
Point2 sample(sampler->next2D());
|
return 0.0f;
|
||||||
pRec.wo = squareToSphere(sample);
|
|
||||||
return Spectrum(1.0f);
|
Frame frame(pRec.mRec.orientation);
|
||||||
|
Vector wi = frame.toLocal(pRec.wi);
|
||||||
|
Vector wo = frame.toLocal(pRec.wo);
|
||||||
|
Vector H = wi + wo;
|
||||||
|
Float length = H.length();
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
Float cosThetaH = H.z/length;
|
||||||
|
return 0.5 * m_fiberDistr.pdfCosTheta(cosThetaH)
|
||||||
|
/ m_fiberDistr.sigmaT(Frame::cosTheta(wi));
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
inline Float sample(PhaseFunctionQueryRecord &pRec, Sampler *sampler) const {
|
||||||
|
if (pRec.mRec.orientation.isZero())
|
||||||
|
return 0.0f;
|
||||||
|
Frame frame(pRec.mRec.orientation);
|
||||||
|
Vector wi = frame.toLocal(pRec.wi);
|
||||||
|
|
||||||
|
#if defined(MICROFLAKE_STATISTICS)
|
||||||
|
avgSampleIterations.incrementBase();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int iterations = 0, maxIterations = 1000;
|
||||||
|
while (true) {
|
||||||
|
Vector H = m_fiberDistr.sample(sampler->next2D());
|
||||||
|
#if defined(MICROFLAKE_STATISTICS)
|
||||||
|
++avgSampleIterations;
|
||||||
|
#endif
|
||||||
|
++iterations;
|
||||||
|
|
||||||
|
if (sampler->next1D() < absDot(wi, H)) {
|
||||||
|
Vector wo = H*(2*dot(wi, H)) - wi;
|
||||||
|
pRec.wo = frame.toWorld(wo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iterations >= maxIterations) {
|
||||||
|
Log(EWarn, "Sample generation unsuccessful after %i iterations"
|
||||||
|
" (dp=%f, fiberOrientation=%s, wi=%s)", iterations,
|
||||||
|
absDot(pRec.wi, pRec.mRec.orientation),
|
||||||
|
pRec.mRec.orientation.toString().c_str(),
|
||||||
|
pRec.wi.toString().c_str());
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float sample(PhaseFunctionQueryRecord &pRec,
|
||||||
Float &pdf, Sampler *sampler) const {
|
Float &pdf, Sampler *sampler) const {
|
||||||
pRec.wo = squareToSphere(sampler->next2D());
|
if (sample(pRec, sampler) == 0) {
|
||||||
pdf = 1/(4 * (Float) M_PI);
|
pdf = 0;
|
||||||
return Spectrum(pdf);
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
pdf = f(pRec);
|
||||||
Spectrum f(const PhaseFunctionQueryRecord &pRec) const {
|
return pdf;
|
||||||
return Spectrum(1/(4 * (Float) M_PI));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
|
|
|
@ -181,10 +181,10 @@ double sigmaT_fiberDist(double stddev, double sinTheta) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static StatsCounter brentSolves("Micro-flake model",
|
#if defined(MICROFLAKE_STATISTICS)
|
||||||
"Brent solver calls");
|
|
||||||
static StatsCounter avgBrentFunEvals("Micro-flake model",
|
static StatsCounter avgBrentFunEvals("Micro-flake model",
|
||||||
"Average Brent solver function evaluations", EAverage);
|
"Average Brent solver function evaluations", EAverage);
|
||||||
|
#endif
|
||||||
|
|
||||||
class GaussianFiberDistribution {
|
class GaussianFiberDistribution {
|
||||||
public:
|
public:
|
||||||
|
@ -250,8 +250,10 @@ public:
|
||||||
boost::bind(&GaussianFiberDistribution::cdfFunctor,
|
boost::bind(&GaussianFiberDistribution::cdfFunctor,
|
||||||
this, sample.x, _1), -1, 1);
|
this, sample.x, _1), -1, 1);
|
||||||
SAssert(result.success);
|
SAssert(result.success);
|
||||||
avgBrentFunEvals.incrementBase();
|
|
||||||
++brentSolves;
|
#if defined(MICROFLAKE_STATISTICS)
|
||||||
|
avgBrentFunEvals.incrementBase();
|
||||||
|
#endif
|
||||||
|
|
||||||
Float cosTheta = result.x,
|
Float cosTheta = result.x,
|
||||||
sinTheta = std::sqrt(std::max((Float) 0, 1-cosTheta*cosTheta)),
|
sinTheta = std::sqrt(std::max((Float) 0, 1-cosTheta*cosTheta)),
|
||||||
|
@ -275,7 +277,9 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
Float cdfFunctor(Float xi, Float cosTheta) const {
|
Float cdfFunctor(Float xi, Float cosTheta) const {
|
||||||
++avgBrentFunEvals;
|
#if defined(MICROFLAKE_STATISTICS)
|
||||||
|
++avgBrentFunEvals;
|
||||||
|
#endif
|
||||||
return cdf(cosTheta)-xi;
|
return cdf(cosTheta)-xi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue