volpath_simple: fixed a minor logic error that could cause errors in light paths that simultaneously involve multiple index-matched and index-mismatched medium transitions
parent
f041cd58eb
commit
8e2bfb7340
|
@ -29,11 +29,11 @@ static StatsCounter avgPathLength("Volumetric path tracer", "Average path length
|
||||||
* \parameter{maxDepth}{\Integer}{Specifies the longest path depth
|
* \parameter{maxDepth}{\Integer}{Specifies the longest path depth
|
||||||
* in the generated output image (where \code{-1} corresponds to $\infty$).
|
* in the generated output image (where \code{-1} corresponds to $\infty$).
|
||||||
* A value of \code{1} will only render directly visible light sources.
|
* A value of \code{1} will only render directly visible light sources.
|
||||||
* \code{2} will lead to single-bounce (direct-only) illumination,
|
* \code{2} will lead to single-bounce (direct-only) illumination,
|
||||||
* and so on. \default{\code{-1}}
|
* and so on. \default{\code{-1}}
|
||||||
* }
|
* }
|
||||||
* \parameter{rrDepth}{\Integer}{Specifies the minimum path depth, after
|
* \parameter{rrDepth}{\Integer}{Specifies the minimum path depth, after
|
||||||
* which the implementation will start to use the ``russian roulette''
|
* which the implementation will start to use the ``russian roulette''
|
||||||
* path termination criterion. \default{\code{5}}
|
* path termination criterion. \default{\code{5}}
|
||||||
* }
|
* }
|
||||||
* \parameter{strictNormals}{\Boolean}{Be strict about potential
|
* \parameter{strictNormals}{\Boolean}{Be strict about potential
|
||||||
|
@ -51,12 +51,12 @@ static StatsCounter avgPathLength("Volumetric path tracer", "Average path length
|
||||||
* or one of the bidirectional techniques.
|
* or one of the bidirectional techniques.
|
||||||
*
|
*
|
||||||
* \remarks{
|
* \remarks{
|
||||||
* \item This integrator performs poorly when rendering
|
* \item This integrator performs poorly when rendering
|
||||||
* participating media that have a different index of refraction compared
|
* participating media that have a different index of refraction compared
|
||||||
* to the surrounding medium.
|
* to the surrounding medium.
|
||||||
* \item This integrator has difficulties rendering
|
* \item This integrator has difficulties rendering
|
||||||
* scenes that contain relatively glossy materials (\pluginref{volpath} is preferable in this case).
|
* scenes that contain relatively glossy materials (\pluginref{volpath} is preferable in this case).
|
||||||
* \item This integrator has poor convergence properties when rendering
|
* \item This integrator has poor convergence properties when rendering
|
||||||
* caustics and similar effects. In this case, \pluginref{bdpt} or
|
* caustics and similar effects. In this case, \pluginref{bdpt} or
|
||||||
* one of the photon mappers may be preferable.
|
* one of the photon mappers may be preferable.
|
||||||
* }
|
* }
|
||||||
|
@ -79,7 +79,7 @@ public:
|
||||||
bool scattered = false;
|
bool scattered = false;
|
||||||
Float eta = 1.0f;
|
Float eta = 1.0f;
|
||||||
|
|
||||||
/* Perform the first ray intersection (or ignore if the
|
/* Perform the first ray intersection (or ignore if the
|
||||||
intersection has already been provided). */
|
intersection has already been provided). */
|
||||||
rRec.rayIntersect(ray);
|
rRec.rayIntersect(ray);
|
||||||
Spectrum throughput(1.0f);
|
Spectrum throughput(1.0f);
|
||||||
|
@ -144,7 +144,7 @@ public:
|
||||||
scene->rayIntersect(ray, its);
|
scene->rayIntersect(ray, its);
|
||||||
scattered = true;
|
scattered = true;
|
||||||
} else {
|
} else {
|
||||||
/* Sample
|
/* Sample
|
||||||
tau(x, y) * (Surface integral). This happens with probability mRec.pdfFailure
|
tau(x, y) * (Surface integral). This happens with probability mRec.pdfFailure
|
||||||
Account for this and multiply by the proper per-color-channel transmittance.
|
Account for this and multiply by the proper per-color-channel transmittance.
|
||||||
*/
|
*/
|
||||||
|
@ -153,9 +153,9 @@ public:
|
||||||
throughput *= mRec.transmittance / mRec.pdfFailure;
|
throughput *= mRec.transmittance / mRec.pdfFailure;
|
||||||
|
|
||||||
if (!its.isValid()) {
|
if (!its.isValid()) {
|
||||||
/* If no intersection could be found, possibly return
|
/* If no intersection could be found, possibly return
|
||||||
attenuated radiance from a background luminaire */
|
attenuated radiance from a background luminaire */
|
||||||
if (rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
if (rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
||||||
Li += throughput * scene->evalEnvironment(ray);
|
Li += throughput * scene->evalEnvironment(ray);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -171,17 +171,17 @@ public:
|
||||||
/* Prevent light leaks due to the use of shading normals */
|
/* Prevent light leaks due to the use of shading normals */
|
||||||
Float wiDotGeoN = -dot(its.geoFrame.n, ray.d),
|
Float wiDotGeoN = -dot(its.geoFrame.n, ray.d),
|
||||||
wiDotShN = Frame::cosTheta(its.wi);
|
wiDotShN = Frame::cosTheta(its.wi);
|
||||||
if (m_strictNormals && wiDotGeoN * wiDotShN < 0)
|
if (m_strictNormals && wiDotGeoN * wiDotShN < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
/* Direct illumination sampling */
|
/* Direct illumination sampling */
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
|
|
||||||
const BSDF *bsdf = its.getBSDF(ray);
|
const BSDF *bsdf = its.getBSDF(ray);
|
||||||
|
|
||||||
/* Estimate the direct illumination if this is requested */
|
/* Estimate the direct illumination if this is requested */
|
||||||
if (rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance &&
|
if (rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance &&
|
||||||
(bsdf->getType() & BSDF::ESmooth)) {
|
(bsdf->getType() & BSDF::ESmooth)) {
|
||||||
DirectSamplingRecord dRec(its);
|
DirectSamplingRecord dRec(its);
|
||||||
int maxInteractions = m_maxDepth - rRec.depth - 1;
|
int maxInteractions = m_maxDepth - rRec.depth - 1;
|
||||||
|
@ -210,7 +210,7 @@ public:
|
||||||
/* Sample BSDF * cos(theta) */
|
/* Sample BSDF * cos(theta) */
|
||||||
BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
|
BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
|
||||||
Spectrum bsdfVal = bsdf->sample(bRec, rRec.nextSample2D());
|
Spectrum bsdfVal = bsdf->sample(bRec, rRec.nextSample2D());
|
||||||
if (bsdfVal.isZero())
|
if (bsdfVal.isZero())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Recursively gather indirect illumination? */
|
/* Recursively gather indirect illumination? */
|
||||||
|
@ -223,8 +223,12 @@ public:
|
||||||
if ((rRec.depth < m_maxDepth || m_maxDepth < 0) &&
|
if ((rRec.depth < m_maxDepth || m_maxDepth < 0) &&
|
||||||
(rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance) &&
|
(rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance) &&
|
||||||
(bRec.sampledType & BSDF::EDelta) &&
|
(bRec.sampledType & BSDF::EDelta) &&
|
||||||
!((bRec.sampledType & BSDF::ENull) && scattered))
|
!((bRec.sampledType & BSDF::ENull) && scattered)) {
|
||||||
recursiveType |= RadianceQueryRecord::EEmittedRadiance;
|
recursiveType |= RadianceQueryRecord::EEmittedRadiance;
|
||||||
|
scattered = false;
|
||||||
|
} else {
|
||||||
|
scattered |= bRec.sampledType != BSDF::ENull;
|
||||||
|
}
|
||||||
|
|
||||||
/* Potentially stop the recursion if there is nothing more to do */
|
/* Potentially stop the recursion if there is nothing more to do */
|
||||||
if (recursiveType == 0)
|
if (recursiveType == 0)
|
||||||
|
@ -236,28 +240,27 @@ public:
|
||||||
Float woDotGeoN = dot(its.geoFrame.n, wo);
|
Float woDotGeoN = dot(its.geoFrame.n, wo);
|
||||||
if (woDotGeoN * Frame::cosTheta(bRec.wo) <= 0 && m_strictNormals)
|
if (woDotGeoN * Frame::cosTheta(bRec.wo) <= 0 && m_strictNormals)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Keep track of the throughput, medium, and relative
|
/* Keep track of the throughput, medium, and relative
|
||||||
refractive index along the path */
|
refractive index along the path */
|
||||||
throughput *= bsdfVal;
|
throughput *= bsdfVal;
|
||||||
eta *= bRec.eta;
|
eta *= bRec.eta;
|
||||||
if (its.isMediumTransition())
|
if (its.isMediumTransition())
|
||||||
rRec.medium = its.getTargetMedium(wo);
|
rRec.medium = its.getTargetMedium(wo);
|
||||||
|
|
||||||
/* In the next iteration, trace a ray in this direction */
|
/* In the next iteration, trace a ray in this direction */
|
||||||
ray = Ray(its.p, wo, ray.time);
|
ray = Ray(its.p, wo, ray.time);
|
||||||
scene->rayIntersect(ray, its);
|
scene->rayIntersect(ray, its);
|
||||||
scattered |= bRec.sampledType != BSDF::ENull;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rRec.depth++ >= m_rrDepth) {
|
if (rRec.depth++ >= m_rrDepth) {
|
||||||
/* Russian roulette: try to keep path weights equal to one,
|
/* Russian roulette: try to keep path weights equal to one,
|
||||||
while accounting for the solid angle compression at refractive
|
while accounting for the solid angle compression at refractive
|
||||||
index boundaries. Stop with at least some probability to avoid
|
index boundaries. Stop with at least some probability to avoid
|
||||||
getting stuck (e.g. due to total internal reflection) */
|
getting stuck (e.g. due to total internal reflection) */
|
||||||
|
|
||||||
Float q = std::min(throughput.max() * eta * eta, (Float) 0.95f);
|
Float q = std::min(throughput.max() * eta * eta, (Float) 0.95f);
|
||||||
if (rRec.nextSample1D() >= q)
|
if (rRec.nextSample1D() >= q)
|
||||||
break;
|
break;
|
||||||
throughput /= q;
|
throughput /= q;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue