roughplastic cleanup, part 1

metadata
Wenzel Jakob 2011-07-11 22:46:05 +02:00
parent bf9dc03fd8
commit d50954b20e
2 changed files with 23 additions and 137 deletions

View File

@ -467,57 +467,6 @@ public:
return spline; return spline;
} }
/**
* \brief Compute a spline representation that gives the probability
* of choosing a reflection event when importance sampling wrt. the
* Fresnel coefficient between a sampled microsurface normal and the
* incident direction.
*
* This function is currently used by the plugin 'roughplastic'.
*
* Like \ref computeRoughTransmittance, the spline is parameterized by the
* cosine of the angle between the indident direction and the (macro-)
* surface normal.
*
* \remark This function only works for isotropic microfacet distributions
*/
CubicSpline *computeTransmissionProbability(Float extIOR, Float intIOR,
Float alpha, Float specularSamplingWeight, size_t resolution) const {
if (isAnisotropic())
SLog(EError, "MicrofacetDistribution::computeTransmissionProbability(): only "
"supports isotropic distributions!");
NDIntegrator integrator(1, 2, 5000, 0, 1e-5f);
CubicSpline *spline = new CubicSpline(resolution);
size_t nEvals, nEvalsTotal = 0;
ref<Timer> timer = new Timer();
Float stepSize = (1.0f-2*Epsilon)/(resolution-1);
for (size_t i=0; i<resolution; ++i) {
Float z = stepSize * i + Epsilon;
Vector wi(std::sqrt(std::max((Float) 0, 1-z*z)), 0, z);
Float min[2] = {0, 0}, max[2] = {1, 1},
integral = 0, error = 0;
integrator.integrateVectorized(
boost::bind(&MicrofacetDistribution::integrand2, this,
wi, extIOR, intIOR, alpha, specularSamplingWeight, _1, _2, _3),
min, max, &integral, &error, &nEvals
);
spline->append(z, integral);
nEvalsTotal += nEvals;
}
SLog(EInfo, "Created a " SIZE_T_FMT "-node cubic spline approximation to the "
"transmission probability (integration took %i ms and " SIZE_T_FMT
" function evaluations)", resolution, timer->getMilliseconds(),
nEvalsTotal);
spline->build();
return spline;
}
std::string toString() const { std::string toString() const {
switch (m_type) { switch (m_type) {
case EBeckmann: return "beckmann"; break; case EBeckmann: return "beckmann"; break;
@ -547,20 +496,6 @@ protected:
(Frame::cosTheta(wi) * Frame::cosTheta(m))); (Frame::cosTheta(wi) * Frame::cosTheta(m)));
} }
} }
/// Integrand helper function called by \ref computeTransmissionProbability
void integrand2(const Vector &wi, Float extIOR, Float intIOR, Float alpha,
Float specularSamplingWeight, size_t nPts, const Float *in, Float *out) const {
for (int i=0; i<(int) nPts; ++i) {
Normal m = sample(Point2(in[2*i], in[2*i+1]), alpha);
Float probSpecular = fresnel(dot(wi, m), extIOR, intIOR);
probSpecular = (probSpecular*specularSamplingWeight) /
(probSpecular*specularSamplingWeight +
(1-probSpecular) * (1-specularSamplingWeight));
out[i] = 1-probSpecular;
}
}
protected: protected:
EType m_type; EType m_type;
}; };

View File

@ -24,7 +24,7 @@
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
#define SPLINE_PRECOMP_NODES 200 #define TRANSMITTANCE_PRECOMP_NODES 200
/*!\plugin{roughplastic}{Rough plastic material} /*!\plugin{roughplastic}{Rough plastic material}
* \order{8} * \order{8}
@ -107,7 +107,6 @@ public:
m_specularReflectance = static_cast<Texture *>(manager->getInstance(stream)); m_specularReflectance = static_cast<Texture *>(manager->getInstance(stream));
m_diffuseReflectance = static_cast<Texture *>(manager->getInstance(stream)); m_diffuseReflectance = static_cast<Texture *>(manager->getInstance(stream));
m_roughTransmittance = static_cast<CubicSpline *>(manager->getInstance(stream)); m_roughTransmittance = static_cast<CubicSpline *>(manager->getInstance(stream));
m_diffuseProb = static_cast<CubicSpline *>(manager->getInstance(stream));
m_alpha = stream->readFloat(); m_alpha = stream->readFloat();
m_intIOR = stream->readFloat(); m_intIOR = stream->readFloat();
m_extIOR = stream->readFloat(); m_extIOR = stream->readFloat();
@ -121,8 +120,8 @@ public:
void configure() { void configure() {
m_components.clear(); m_components.clear();
m_components.push_back(EGlossyReflection | ECanUseSampler | EFrontSide); m_components.push_back(EGlossyReflection | EFrontSide);
m_components.push_back(EDiffuseReflection | ECanUseSampler | EFrontSide); m_components.push_back(EDiffuseReflection | EFrontSide);
/* Verify the input parameters and fix them if necessary */ /* Verify the input parameters and fix them if necessary */
m_specularReflectance = ensureEnergyConservation( m_specularReflectance = ensureEnergyConservation(
@ -138,14 +137,7 @@ public:
/* Precompute the rough transmittance through the interface */ /* Precompute the rough transmittance through the interface */
m_roughTransmittance = m_distribution.computeRoughTransmittance( m_roughTransmittance = m_distribution.computeRoughTransmittance(
m_extIOR, m_intIOR, m_alpha, SPLINE_PRECOMP_NODES); m_extIOR, m_intIOR, m_alpha, TRANSMITTANCE_PRECOMP_NODES);
/* Precompute a spline that specifies the probability of
sampling the diffuse component for different angles
of incidence. */
m_diffuseProb = m_distribution.computeTransmissionProbability(
m_extIOR, m_intIOR, m_alpha, m_specularSamplingWeight,
SPLINE_PRECOMP_NODES);
BSDF::configure(); BSDF::configure();
} }
@ -213,29 +205,17 @@ public:
/* Calculate the reflection half-vector */ /* Calculate the reflection half-vector */
const Vector H = normalize(bRec.wo+bRec.wi); const Vector H = normalize(bRec.wo+bRec.wi);
Float probSpecular, probDiffuse; Float probDiffuse, probSpecular;
if (sampleSpecular && sampleDiffuse) { if (sampleSpecular && sampleDiffuse) {
if (bRec.sampler && false) { /* Find the probability of sampling the specular component */
/* Fancy sampling strategy */ probSpecular = 1-m_roughTransmittance->eval(Frame::cosTheta(bRec.wi));
probSpecular = fresnel(dot(bRec.wi, H), m_extIOR, m_intIOR);
/* Reallocate samples */
probSpecular = (probSpecular*m_specularSamplingWeight) /
(probSpecular*m_specularSamplingWeight +
(1-probSpecular) * (1-m_specularSamplingWeight));
probDiffuse = m_diffuseProb->eval(Frame::cosTheta(bRec.wi));
} else {
/* Basic sampling strategy that only needs 2 random numbers */
probSpecular = 1 - m_roughTransmittance->eval(Frame::cosTheta(bRec.wi));
/* Reallocate samples */ /* Reallocate samples */
probSpecular = (probSpecular*m_specularSamplingWeight) / probSpecular = (probSpecular*m_specularSamplingWeight) /
(probSpecular*m_specularSamplingWeight + (probSpecular*m_specularSamplingWeight +
(1-probSpecular) * (1-m_specularSamplingWeight)); (1-probSpecular) * (1-m_specularSamplingWeight));
probDiffuse = 1 - probSpecular; probDiffuse = 1 - probSpecular;
}
} else { } else {
probDiffuse = probSpecular = 1.0f; probDiffuse = probSpecular = 1.0f;
} }
@ -272,52 +252,25 @@ public:
Point2 sample(_sample); Point2 sample(_sample);
if (sampleSpecular && sampleDiffuse) { if (sampleSpecular && sampleDiffuse) {
if (bRec.sampler && false) { /* Find the probability of sampling the diffuse component */
/** Float probSpecular = 1 - m_roughTransmittance->eval(Frame::cosTheta(bRec.wi));
* We have access to a sampler -- use a good sampling
* technique, which is somewhat wasteful in terms of
* random numbers
*/
m = m_distribution.sample(sample, m_alpha);
Float probSpecular = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR); /* Reallocate samples */
probSpecular = (probSpecular*m_specularSamplingWeight) /
(probSpecular*m_specularSamplingWeight +
(1-probSpecular) * (1-m_specularSamplingWeight));
/* Reallocate samples */ if (sample.x <= probSpecular) {
probSpecular = (probSpecular*m_specularSamplingWeight) / sample.x /= probSpecular;
(probSpecular*m_specularSamplingWeight +
(1-probSpecular) * (1-m_specularSamplingWeight));
if (bRec.sampler->next1D() > probSpecular) {
choseSpecular = false;
sample = bRec.sampler->next2D();
}
} else { } else {
/** sample.x = (sample.x - probSpecular) / (1 - probSpecular);
* Basic strategy -- use a clamped Fresnel coefficient choseSpecular = false;
* wrt. the macro-surface normal to choose between
* diffuse and specular component.
*/
Float probSpecular = 1 - m_roughTransmittance->eval(Frame::cosTheta(bRec.wi));
/* Reallocate samples */
probSpecular = (probSpecular*m_specularSamplingWeight) /
(probSpecular*m_specularSamplingWeight +
(1-probSpecular) * (1-m_specularSamplingWeight));
if (sample.x < probSpecular) {
sample.x /= probSpecular;
m = m_distribution.sample(sample, m_alpha);
} else {
sample.x = (sample.x - probSpecular) / (1 - probSpecular);
choseSpecular = false;
}
} }
} else if (choseSpecular) {
m = m_distribution.sample(sample, m_alpha);
} }
if (choseSpecular) { if (choseSpecular) {
/* Perfect specular reflection based on the microsurface normal */ /* Perfect specular reflection based on the microsurface normal */
m = m_distribution.sample(sample, m_alpha);
bRec.wo = reflect(bRec.wi, m); bRec.wo = reflect(bRec.wi, m);
bRec.sampledComponent = 0; bRec.sampledComponent = 0;
bRec.sampledType = EGlossyReflection; bRec.sampledType = EGlossyReflection;
@ -369,7 +322,6 @@ public:
manager->serialize(stream, m_specularReflectance.get()); manager->serialize(stream, m_specularReflectance.get());
manager->serialize(stream, m_diffuseReflectance.get()); manager->serialize(stream, m_diffuseReflectance.get());
manager->serialize(stream, m_roughTransmittance.get()); manager->serialize(stream, m_roughTransmittance.get());
manager->serialize(stream, m_diffuseProb.get());
stream->writeFloat(m_alpha); stream->writeFloat(m_alpha);
stream->writeFloat(m_intIOR); stream->writeFloat(m_intIOR);
stream->writeFloat(m_extIOR); stream->writeFloat(m_extIOR);
@ -397,7 +349,6 @@ public:
private: private:
MicrofacetDistribution m_distribution; MicrofacetDistribution m_distribution;
ref<CubicSpline> m_roughTransmittance; ref<CubicSpline> m_roughTransmittance;
ref<CubicSpline> m_diffuseProb;
ref<Texture> m_diffuseReflectance; ref<Texture> m_diffuseReflectance;
ref<Texture> m_specularReflectance; ref<Texture> m_specularReflectance;
Float m_alpha, m_intIOR, m_extIOR; Float m_alpha, m_intIOR, m_extIOR;