added an optional feature to hide directly visible light sources -- this is convenient for making paper figures etc. where one don't want the environment map to 'bleed' into the foreground objects (see the committed images for an example)
parent
947ac53df5
commit
97f0a28ffb
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
|
@ -112,4 +112,25 @@ Some of the rendering techniques in Mitsuba are \emph{progressive}.
|
||||||
What this means is that they display a rough preview, which improves over time.
|
What this means is that they display a rough preview, which improves over time.
|
||||||
Leaving them running indefinitely will continually reduce noise (in unbiased algorithms
|
Leaving them running indefinitely will continually reduce noise (in unbiased algorithms
|
||||||
such as Metropolis Light Transport) or noise and bias (in biased
|
such as Metropolis Light Transport) or noise and bias (in biased
|
||||||
rendering techniques such as Progressive Photon Mapping).
|
endering techniques such as Progressive Photon Mapping).
|
||||||
|
\newpage
|
||||||
|
\subsubsection*{Hiding directly visible emitters}
|
||||||
|
\label{sec:hideemitters}
|
||||||
|
Several rendering algorithms in Mitsuba have a feature to hide directly
|
||||||
|
visible light sources (e.g. environment maps or area lights). While not
|
||||||
|
particularly realistic, this feature is often convenient to remove a background
|
||||||
|
from a rendering so that it can be pasted into a differently-colored document.
|
||||||
|
|
||||||
|
Note that only directly visible emitters can be hidden using this feature---a
|
||||||
|
reflection on a shiny surface will be unaffected. To perform the kind of
|
||||||
|
compositing shown in Figure~\ref{fig:hideemitters}, it is also necessary to
|
||||||
|
enable the alpha channel in the scene's film instance (Section~\ref{sec:films}).
|
||||||
|
|
||||||
|
\renderings{
|
||||||
|
\unframedrendering{Daylit smoke rendered with \code{hideEmitters} set to \code{false}
|
||||||
|
(the default setting)}{integrator_volpath_normal}
|
||||||
|
\unframedrendering{Rendered with \code{hideEmitters} set to \code{true} and alpha-composited
|
||||||
|
onto a white background.}{integrator_volpath_hideemitters}
|
||||||
|
\caption{\label{fig:hideemitters}An example application of the \code{hideEmitters} parameter
|
||||||
|
together with alpha blending}
|
||||||
|
}
|
||||||
|
|
|
@ -458,6 +458,7 @@ protected:
|
||||||
int m_maxDepth;
|
int m_maxDepth;
|
||||||
int m_rrDepth;
|
int m_rrDepth;
|
||||||
bool m_strictNormals;
|
bool m_strictNormals;
|
||||||
|
bool m_hideEmitters;
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -25,20 +25,29 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \parameter{shadingSamples}{\Integer}{This convenience parameter can be
|
* \parameter{shadingSamples}{\Integer}{This convenience parameter can be
|
||||||
* used to set both \code{emitterSamples} and \code{bsdfSamples} at
|
* used to set both \code{emitterSamples} and \code{bsdfSamples} at
|
||||||
* the same time.}
|
* the same time.
|
||||||
|
* }
|
||||||
* \parameter{emitterSamples}{\Integer}{Optional more fine-grained
|
* \parameter{emitterSamples}{\Integer}{Optional more fine-grained
|
||||||
* parameter: specifies the number of samples that should be generated
|
* parameter: specifies the number of samples that should be generated
|
||||||
* using the direct illumination strategies implemented by the scene's
|
* using the direct illumination strategies implemented by the scene's
|
||||||
* emitters\default{set to the value of \code{shadingSamples}}}
|
* emitters\default{set to the value of \code{shadingSamples}}
|
||||||
|
* }
|
||||||
* \parameter{bsdfSamples}{\Integer}{Optional more fine-grained
|
* \parameter{bsdfSamples}{\Integer}{Optional more fine-grained
|
||||||
* parameter: specifies the number of samples that should be generated
|
* parameter: specifies the number of samples that should be generated
|
||||||
* using the BSDF sampling strategies implemented by the scene's
|
* using the BSDF sampling strategies implemented by the scene's
|
||||||
* surfaces\default{set to the value of \code{shadingSamples}}}
|
* surfaces\default{set to the value of \code{shadingSamples}}
|
||||||
|
* }
|
||||||
* \parameter{strictNormals}{\Boolean}{Be strict about potential
|
* \parameter{strictNormals}{\Boolean}{Be strict about potential
|
||||||
* inconsistencies involving shading normals? See \pluginref{path}
|
* inconsistencies involving shading normals? See
|
||||||
* for details.\default{no, i.e. \code{false}}}
|
* page~\pageref{sec:strictnormals} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
|
* \parameter{hideEmitters}{\Boolean}{Hide directly visible emitters?
|
||||||
|
* See page~\pageref{sec:hideemitters} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
* \vspace{-1mm}
|
||||||
* \renderings{
|
* \renderings{
|
||||||
* \medrendering{Only BSDF sampling}{integrator_direct_bsdf}
|
* \medrendering{Only BSDF sampling}{integrator_direct_bsdf}
|
||||||
* \medrendering{Only emitter sampling}{integrator_direct_lum}
|
* \medrendering{Only emitter sampling}{integrator_direct_lum}
|
||||||
|
@ -92,6 +101,9 @@ public:
|
||||||
m_bsdfSamples = props.getSize("bsdfSamples", shadingSamples);
|
m_bsdfSamples = props.getSize("bsdfSamples", shadingSamples);
|
||||||
/* Be strict about potential inconsistencies involving shading normals? */
|
/* Be strict about potential inconsistencies involving shading normals? */
|
||||||
m_strictNormals = props.getBoolean("strictNormals", false);
|
m_strictNormals = props.getBoolean("strictNormals", false);
|
||||||
|
/* When this flag is set to true, contributions from directly
|
||||||
|
* visible emitters will not be included in the rendered image */
|
||||||
|
m_hideEmitters = props.getBoolean("hideEmitters", false);
|
||||||
Assert(m_emitterSamples + m_bsdfSamples > 0);
|
Assert(m_emitterSamples + m_bsdfSamples > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +113,7 @@ public:
|
||||||
m_emitterSamples = stream->readSize();
|
m_emitterSamples = stream->readSize();
|
||||||
m_bsdfSamples = stream->readSize();
|
m_bsdfSamples = stream->readSize();
|
||||||
m_strictNormals = stream->readBool();
|
m_strictNormals = stream->readBool();
|
||||||
|
m_hideEmitters = stream->readBool();
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +122,7 @@ public:
|
||||||
stream->writeSize(m_emitterSamples);
|
stream->writeSize(m_emitterSamples);
|
||||||
stream->writeSize(m_bsdfSamples);
|
stream->writeSize(m_bsdfSamples);
|
||||||
stream->writeBool(m_strictNormals);
|
stream->writeBool(m_strictNormals);
|
||||||
|
stream->writeBool(m_hideEmitters);
|
||||||
}
|
}
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
|
@ -142,14 +156,14 @@ public:
|
||||||
if (!rRec.rayIntersect(ray)) {
|
if (!rRec.rayIntersect(ray)) {
|
||||||
/* If no intersection could be found, possibly return
|
/* If no intersection could be found, possibly return
|
||||||
radiance from a background emitter */
|
radiance from a background emitter */
|
||||||
if (rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
if (rRec.type & RadianceQueryRecord::EEmittedRadiance && !m_hideEmitters)
|
||||||
return scene->evalEnvironment(ray);
|
return scene->evalEnvironment(ray);
|
||||||
else
|
else
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Possibly include emitted radiance if requested */
|
/* Possibly include emitted radiance if requested */
|
||||||
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
|
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance) && !m_hideEmitters)
|
||||||
Li += its.Le(-ray.d);
|
Li += its.Le(-ray.d);
|
||||||
|
|
||||||
/* Include radiance from a subsurface scattering model if requested */
|
/* Include radiance from a subsurface scattering model if requested */
|
||||||
|
@ -271,7 +285,7 @@ public:
|
||||||
/* Intersected nothing -- perhaps there is an environment map? */
|
/* Intersected nothing -- perhaps there is an environment map? */
|
||||||
const Emitter *env = scene->getEnvironmentEmitter();
|
const Emitter *env = scene->getEnvironmentEmitter();
|
||||||
|
|
||||||
if (!env)
|
if (!env || (m_hideEmitters && bRec.sampledType == BSDF::ENull))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
value = env->evalEnvironment(RayDifferential(bsdfRay));
|
value = env->evalEnvironment(RayDifferential(bsdfRay));
|
||||||
|
@ -316,6 +330,7 @@ private:
|
||||||
Float m_fracBSDF, m_fracLum;
|
Float m_fracBSDF, m_fracLum;
|
||||||
Float m_weightBSDF, m_weightLum;
|
Float m_weightBSDF, m_weightLum;
|
||||||
bool m_strictNormals;
|
bool m_strictNormals;
|
||||||
|
bool m_hideEmitters;
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(MIDirectIntegrator, false, SamplingIntegrator)
|
MTS_IMPLEMENT_CLASS_S(MIDirectIntegrator, false, SamplingIntegrator)
|
||||||
|
|
|
@ -38,7 +38,12 @@ static StatsCounter avgPathLength("Path tracer", "Average path length", EAverage
|
||||||
* }
|
* }
|
||||||
* \parameter{strictNormals}{\Boolean}{Be strict about potential
|
* \parameter{strictNormals}{\Boolean}{Be strict about potential
|
||||||
* inconsistencies involving shading normals? See the description below
|
* inconsistencies involving shading normals? See the description below
|
||||||
* for details.\default{no, i.e. \code{false}}}
|
* for details.\default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
|
* \parameter{hideEmitters}{\Boolean}{Hide directly visible emitters?
|
||||||
|
* See page~\pageref{sec:hideemitters} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* This integrator implements a basic path tracer and is a \emph{good default choice}
|
* This integrator implements a basic path tracer and is a \emph{good default choice}
|
||||||
|
@ -75,7 +80,8 @@ static StatsCounter avgPathLength("Path tracer", "Average path length", EAverage
|
||||||
* low-discrepancy sample generators (i.e. \pluginref{ldsampler},
|
* low-discrepancy sample generators (i.e. \pluginref{ldsampler},
|
||||||
* \pluginref{halton}, or \pluginref{sobol}).
|
* \pluginref{halton}, or \pluginref{sobol}).
|
||||||
*
|
*
|
||||||
* \paragraph{Strict normals:} Triangle meshes often rely on interpolated shading normals
|
* \paragraph{Strict normals:}\label{sec:strictnormals}
|
||||||
|
* Triangle meshes often rely on interpolated shading normals
|
||||||
* to suppress the inherently faceted appearance of the underlying geometry. These
|
* to suppress the inherently faceted appearance of the underlying geometry. These
|
||||||
* ``fake'' normals are not without problems, however. They can lead to paradoxical
|
* ``fake'' normals are not without problems, however. They can lead to paradoxical
|
||||||
* situations where a light ray impinges on an object from a direction that is classified as ``outside''
|
* situations where a light ray impinges on an object from a direction that is classified as ``outside''
|
||||||
|
@ -116,6 +122,7 @@ public:
|
||||||
Intersection &its = rRec.its;
|
Intersection &its = rRec.its;
|
||||||
RayDifferential ray(r);
|
RayDifferential ray(r);
|
||||||
Spectrum Li(0.0f);
|
Spectrum Li(0.0f);
|
||||||
|
bool scattered = false;
|
||||||
|
|
||||||
/* 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). */
|
||||||
|
@ -129,7 +136,8 @@ public:
|
||||||
if (!its.isValid()) {
|
if (!its.isValid()) {
|
||||||
/* If no intersection could be found, potentially return
|
/* If no intersection could be found, potentially return
|
||||||
radiance from a environment luminaire if it exists */
|
radiance from a environment luminaire if it exists */
|
||||||
if (rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
if ((rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
||||||
|
&& (!m_hideEmitters || scattered))
|
||||||
Li += throughput * scene->evalEnvironment(ray);
|
Li += throughput * scene->evalEnvironment(ray);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +145,8 @@ public:
|
||||||
const BSDF *bsdf = its.getBSDF(ray);
|
const BSDF *bsdf = its.getBSDF(ray);
|
||||||
|
|
||||||
/* Possibly include emitted radiance if requested */
|
/* Possibly include emitted radiance if requested */
|
||||||
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
|
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
||||||
|
&& (!m_hideEmitters || scattered))
|
||||||
Li += throughput * its.Le(-ray.d);
|
Li += throughput * its.Le(-ray.d);
|
||||||
|
|
||||||
/* Include radiance from a subsurface scattering model if requested */
|
/* Include radiance from a subsurface scattering model if requested */
|
||||||
|
@ -201,6 +210,8 @@ public:
|
||||||
if (bsdfWeight.isZero())
|
if (bsdfWeight.isZero())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
scattered |= bRec.sampledType != BSDF::ENull;
|
||||||
|
|
||||||
/* Prevent light leaks due to the use of shading normals */
|
/* Prevent light leaks due to the use of shading normals */
|
||||||
const Vector wo = its.toWorld(bRec.wo);
|
const Vector wo = its.toWorld(bRec.wo);
|
||||||
Float woDotGeoN = dot(its.geoFrame.n, wo);
|
Float woDotGeoN = dot(its.geoFrame.n, wo);
|
||||||
|
@ -224,6 +235,9 @@ public:
|
||||||
const Emitter *env = scene->getEnvironmentEmitter();
|
const Emitter *env = scene->getEnvironmentEmitter();
|
||||||
|
|
||||||
if (env) {
|
if (env) {
|
||||||
|
if (m_hideEmitters && !scattered)
|
||||||
|
break;
|
||||||
|
|
||||||
value = env->evalEnvironment(ray);
|
value = env->evalEnvironment(ray);
|
||||||
if (!env->fillDirectSamplingRecord(dRec, ray))
|
if (!env->fillDirectSamplingRecord(dRec, ray))
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -37,8 +37,14 @@ static StatsCounter avgPathLength("Volumetric path tracer", "Average path length
|
||||||
* 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
|
||||||
* inconsistencies involving shading normals? See \pluginref{path}
|
* inconsistencies involving shading normals? See
|
||||||
* for details.\default{no, i.e. \code{false}}}
|
* page~\pageref{sec:strictnormals} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
|
* \parameter{hideEmitters}{\Boolean}{Hide directly visible emitters?
|
||||||
|
* See page~\pageref{sec:hideemitters} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* This plugin provides a volumetric path tracer that can be used to
|
* This plugin provides a volumetric path tracer that can be used to
|
||||||
|
@ -151,7 +157,6 @@ public:
|
||||||
break;
|
break;
|
||||||
throughput *= phaseVal;
|
throughput *= phaseVal;
|
||||||
|
|
||||||
|
|
||||||
/* Trace a ray in this direction */
|
/* Trace a ray in this direction */
|
||||||
ray = Ray(mRec.p, pRec.wo, ray.time);
|
ray = Ray(mRec.p, pRec.wo, ray.time);
|
||||||
ray.mint = 0;
|
ray.mint = 0;
|
||||||
|
@ -186,7 +191,8 @@ public:
|
||||||
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)
|
||||||
|
&& (!m_hideEmitters || scattered)) {
|
||||||
Spectrum value = throughput * scene->evalEnvironment(ray);
|
Spectrum value = throughput * scene->evalEnvironment(ray);
|
||||||
if (rRec.medium)
|
if (rRec.medium)
|
||||||
value *= rRec.medium->evalTransmittance(ray);
|
value *= rRec.medium->evalTransmittance(ray);
|
||||||
|
@ -197,7 +203,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Possibly include emitted radiance if requested */
|
/* Possibly include emitted radiance if requested */
|
||||||
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
|
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
||||||
|
&& (!m_hideEmitters || scattered))
|
||||||
Li += throughput * its.Le(-ray.d);
|
Li += throughput * its.Le(-ray.d);
|
||||||
|
|
||||||
/* Include radiance from a subsurface integrator if requested */
|
/* Include radiance from a subsurface integrator if requested */
|
||||||
|
|
|
@ -37,8 +37,14 @@ static StatsCounter avgPathLength("Volumetric path tracer", "Average path length
|
||||||
* 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
|
||||||
* inconsistencies involving shading normals? See \pluginref{path}
|
* inconsistencies involving shading normals? See
|
||||||
* for details.\default{no, i.e. \code{false}}}
|
* page~\pageref{sec:strictnormals} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
|
* \parameter{hideEmitters}{\Boolean}{Hide directly visible emitters?
|
||||||
|
* See page~\pageref{sec:hideemitters} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* This plugin provides a basic volumetric path tracer that can be used to
|
* This plugin provides a basic volumetric path tracer that can be used to
|
||||||
|
@ -86,7 +92,7 @@ public:
|
||||||
MediumSamplingRecord mRec;
|
MediumSamplingRecord mRec;
|
||||||
RayDifferential ray(r);
|
RayDifferential ray(r);
|
||||||
Spectrum Li(0.0f);
|
Spectrum Li(0.0f);
|
||||||
bool nullChain = true;
|
bool nullChain = true, 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
|
||||||
|
@ -153,6 +159,7 @@ public:
|
||||||
ray.mint = 0;
|
ray.mint = 0;
|
||||||
scene->rayIntersect(ray, its);
|
scene->rayIntersect(ray, its);
|
||||||
nullChain = false;
|
nullChain = false;
|
||||||
|
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
|
||||||
|
@ -165,7 +172,8 @@ public:
|
||||||
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)
|
||||||
|
&& (!m_hideEmitters || scattered)) {
|
||||||
Spectrum value = throughput * scene->evalEnvironment(ray);
|
Spectrum value = throughput * scene->evalEnvironment(ray);
|
||||||
if (rRec.medium)
|
if (rRec.medium)
|
||||||
value *= rRec.medium->evalTransmittance(ray);
|
value *= rRec.medium->evalTransmittance(ray);
|
||||||
|
@ -175,7 +183,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Possibly include emitted radiance if requested */
|
/* Possibly include emitted radiance if requested */
|
||||||
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
|
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance)
|
||||||
|
&& (!m_hideEmitters || scattered))
|
||||||
Li += throughput * its.Le(-ray.d);
|
Li += throughput * its.Le(-ray.d);
|
||||||
|
|
||||||
/* Include radiance from a subsurface integrator if requested */
|
/* Include radiance from a subsurface integrator if requested */
|
||||||
|
@ -267,6 +276,7 @@ public:
|
||||||
/* 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) {
|
||||||
|
|
|
@ -46,6 +46,10 @@ MTS_NAMESPACE_BEGIN
|
||||||
* Granularity of photon tracing work units for the purpose
|
* Granularity of photon tracing work units for the purpose
|
||||||
* of parallelization (in \# of shot particles) \default{0, i.e. decide automatically}
|
* of parallelization (in \# of shot particles) \default{0, i.e. decide automatically}
|
||||||
* }
|
* }
|
||||||
|
* \parameter{hideEmitters}{\Boolean}{Hide directly visible emitters?
|
||||||
|
* See page~\pageref{sec:hideemitters} for details.
|
||||||
|
* \default{no, i.e. \code{false}}
|
||||||
|
* }
|
||||||
* \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}}
|
||||||
|
@ -126,6 +130,9 @@ public:
|
||||||
m_gatherLocally = props.getBoolean("gatherLocally", true);
|
m_gatherLocally = props.getBoolean("gatherLocally", true);
|
||||||
/* Indicates if the gathering steps should be canceled if not enough photons are generated. */
|
/* Indicates if the gathering steps should be canceled if not enough photons are generated. */
|
||||||
m_autoCancelGathering = props.getBoolean("autoCancelGathering", true);
|
m_autoCancelGathering = props.getBoolean("autoCancelGathering", true);
|
||||||
|
/* When this flag is set to true, contributions from directly
|
||||||
|
* visible emitters will not be included in the rendered image */
|
||||||
|
m_hideEmitters = props.getBoolean("hideEmitters", false);
|
||||||
|
|
||||||
if (m_maxDepth == 0) {
|
if (m_maxDepth == 0) {
|
||||||
Log(EError, "maxDepth must be greater than zero!");
|
Log(EError, "maxDepth must be greater than zero!");
|
||||||
|
@ -159,6 +166,7 @@ public:
|
||||||
m_volumeLookupSize = stream->readInt();
|
m_volumeLookupSize = stream->readInt();
|
||||||
m_gatherLocally = stream->readBool();
|
m_gatherLocally = stream->readBool();
|
||||||
m_autoCancelGathering = stream->readBool();
|
m_autoCancelGathering = stream->readBool();
|
||||||
|
m_hideEmitters = stream->readBool();
|
||||||
m_causticPhotonMapID = m_globalPhotonMapID = m_breID = 0;
|
m_causticPhotonMapID = m_globalPhotonMapID = m_breID = 0;
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
@ -190,6 +198,7 @@ public:
|
||||||
stream->writeInt(m_volumeLookupSize);
|
stream->writeInt(m_volumeLookupSize);
|
||||||
stream->writeBool(m_gatherLocally);
|
stream->writeBool(m_gatherLocally);
|
||||||
stream->writeBool(m_autoCancelGathering);
|
stream->writeBool(m_autoCancelGathering);
|
||||||
|
stream->writeBool(m_hideEmitters);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configure the sampler for a specified amount of direct illumination samples
|
/// Configure the sampler for a specified amount of direct illumination samples
|
||||||
|
@ -261,11 +270,11 @@ public:
|
||||||
if (proc->getReturnStatus() != ParallelProcess::ESuccess)
|
if (proc->getReturnStatus() != ParallelProcess::ESuccess)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Log(EDebug, "Global photon map full. Shot " SIZE_T_FMT " particles, excess photons due to parallelism: "
|
|
||||||
SIZE_T_FMT, proc->getShotParticles(), proc->getExcessPhotons());
|
|
||||||
|
|
||||||
ref<PhotonMap> globalPhotonMap = proc->getPhotonMap();
|
ref<PhotonMap> globalPhotonMap = proc->getPhotonMap();
|
||||||
if (globalPhotonMap->isFull()) {
|
if (globalPhotonMap->isFull()) {
|
||||||
|
Log(EDebug, "Global photon map full. Shot " SIZE_T_FMT " particles, excess photons due to parallelism: "
|
||||||
|
SIZE_T_FMT, proc->getShotParticles(), proc->getExcessPhotons());
|
||||||
|
|
||||||
m_globalPhotonMap = globalPhotonMap;
|
m_globalPhotonMap = globalPhotonMap;
|
||||||
m_globalPhotonMap->setScaleFactor(1 / (Float) proc->getShotParticles());
|
m_globalPhotonMap->setScaleFactor(1 / (Float) proc->getShotParticles());
|
||||||
m_globalPhotonMap->build();
|
m_globalPhotonMap->build();
|
||||||
|
@ -292,11 +301,11 @@ public:
|
||||||
if (proc->getReturnStatus() != ParallelProcess::ESuccess)
|
if (proc->getReturnStatus() != ParallelProcess::ESuccess)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Log(EDebug, "Caustic photon map full. Shot " SIZE_T_FMT " particles, excess photons due to parallelism: "
|
|
||||||
SIZE_T_FMT, proc->getShotParticles(), proc->getExcessPhotons());
|
|
||||||
|
|
||||||
ref<PhotonMap> causticPhotonMap = proc->getPhotonMap();
|
ref<PhotonMap> causticPhotonMap = proc->getPhotonMap();
|
||||||
if (causticPhotonMap->isFull()) {
|
if (causticPhotonMap->isFull()) {
|
||||||
|
Log(EDebug, "Caustic photon map full. Shot " SIZE_T_FMT " particles, excess photons due to parallelism: "
|
||||||
|
SIZE_T_FMT, proc->getShotParticles(), proc->getExcessPhotons());
|
||||||
|
|
||||||
m_causticPhotonMap = causticPhotonMap;
|
m_causticPhotonMap = causticPhotonMap;
|
||||||
m_causticPhotonMap->setScaleFactor(1 / (Float) proc->getShotParticles());
|
m_causticPhotonMap->setScaleFactor(1 / (Float) proc->getShotParticles());
|
||||||
m_causticPhotonMap->build();
|
m_causticPhotonMap->build();
|
||||||
|
@ -324,11 +333,11 @@ public:
|
||||||
if (proc->getReturnStatus() != ParallelProcess::ESuccess)
|
if (proc->getReturnStatus() != ParallelProcess::ESuccess)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Log(EDebug, "Volume photon map full. Shot " SIZE_T_FMT " particles, excess photons due to parallelism: "
|
|
||||||
SIZE_T_FMT, proc->getShotParticles(), proc->getExcessPhotons());
|
|
||||||
|
|
||||||
ref<PhotonMap> volumePhotonMap = proc->getPhotonMap();
|
ref<PhotonMap> volumePhotonMap = proc->getPhotonMap();
|
||||||
if (volumePhotonMap->isFull()) {
|
if (volumePhotonMap->isFull()) {
|
||||||
|
Log(EDebug, "Volume photon map full. Shot " SIZE_T_FMT " particles, excess photons due to parallelism: "
|
||||||
|
SIZE_T_FMT, proc->getShotParticles(), proc->getExcessPhotons());
|
||||||
|
|
||||||
volumePhotonMap->setScaleFactor(1 / (Float) proc->getShotParticles());
|
volumePhotonMap->setScaleFactor(1 / (Float) proc->getShotParticles());
|
||||||
volumePhotonMap->build();
|
volumePhotonMap->build();
|
||||||
m_bre = new BeamRadianceEstimator(volumePhotonMap, m_volumeLookupSize);
|
m_bre = new BeamRadianceEstimator(volumePhotonMap, m_volumeLookupSize);
|
||||||
|
@ -407,13 +416,13 @@ public:
|
||||||
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) && !m_hideEmitters)
|
||||||
LiSurf = scene->evalEnvironment(ray);
|
LiSurf = scene->evalEnvironment(ray);
|
||||||
return LiSurf * transmittance + LiMedium;
|
return LiSurf * transmittance + LiMedium;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Possibly include emitted radiance if requested */
|
/* Possibly include emitted radiance if requested */
|
||||||
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
|
if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance) && !m_hideEmitters)
|
||||||
LiSurf += its.Le(-ray.d);
|
LiSurf += its.Le(-ray.d);
|
||||||
|
|
||||||
/* Include radiance from a subsurface scattering model if requested */
|
/* Include radiance from a subsurface scattering model if requested */
|
||||||
|
@ -446,7 +455,7 @@ public:
|
||||||
RadianceQueryRecord rRec2;
|
RadianceQueryRecord rRec2;
|
||||||
for (int i=0; i<compCount; i++) {
|
for (int i=0; i<compCount; i++) {
|
||||||
unsigned int type = bsdf->getType(i);
|
unsigned int type = bsdf->getType(i);
|
||||||
if (!(type & BSDF::EDelta) && type == BSDF::ENull)
|
if (!(type & BSDF::EDelta))
|
||||||
continue;
|
continue;
|
||||||
/* Sample the BSDF and recurse */
|
/* Sample the BSDF and recurse */
|
||||||
BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
|
BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
|
||||||
|
@ -676,6 +685,7 @@ private:
|
||||||
int m_granularity, m_directSamples, m_glossySamples;
|
int m_granularity, m_directSamples, m_glossySamples;
|
||||||
int m_rrDepth, m_maxDepth, m_maxSpecularDepth;
|
int m_rrDepth, m_maxDepth, m_maxSpecularDepth;
|
||||||
bool m_gatherLocally, m_autoCancelGathering;
|
bool m_gatherLocally, m_autoCancelGathering;
|
||||||
|
bool m_hideEmitters;
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(PhotonMapIntegrator, false, SamplingIntegrator)
|
MTS_IMPLEMENT_CLASS_S(PhotonMapIntegrator, false, SamplingIntegrator)
|
||||||
|
|
|
@ -211,6 +211,12 @@ MonteCarloIntegrator::MonteCarloIntegrator(const Properties &props) : SamplingIn
|
||||||
*/
|
*/
|
||||||
m_strictNormals = props.getBoolean("strictNormals", false);
|
m_strictNormals = props.getBoolean("strictNormals", false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When this flag is set to true, contributions from directly
|
||||||
|
* visible emitters will not be included in the rendered image
|
||||||
|
*/
|
||||||
|
m_hideEmitters = props.getBoolean("hideEmitters", false);
|
||||||
|
|
||||||
if (m_rrDepth <= 0)
|
if (m_rrDepth <= 0)
|
||||||
Log(EError, "'rrDepth' must be set to a value greater than zero!");
|
Log(EError, "'rrDepth' must be set to a value greater than zero!");
|
||||||
|
|
||||||
|
@ -223,6 +229,7 @@ MonteCarloIntegrator::MonteCarloIntegrator(Stream *stream, InstanceManager *mana
|
||||||
m_rrDepth = stream->readInt();
|
m_rrDepth = stream->readInt();
|
||||||
m_maxDepth = stream->readInt();
|
m_maxDepth = stream->readInt();
|
||||||
m_strictNormals = stream->readBool();
|
m_strictNormals = stream->readBool();
|
||||||
|
m_hideEmitters = stream->readBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonteCarloIntegrator::serialize(Stream *stream, InstanceManager *manager) const {
|
void MonteCarloIntegrator::serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
|
@ -230,6 +237,7 @@ void MonteCarloIntegrator::serialize(Stream *stream, InstanceManager *manager) c
|
||||||
stream->writeInt(m_rrDepth);
|
stream->writeInt(m_rrDepth);
|
||||||
stream->writeInt(m_maxDepth);
|
stream->writeInt(m_maxDepth);
|
||||||
stream->writeBool(m_strictNormals);
|
stream->writeBool(m_strictNormals);
|
||||||
|
stream->writeBool(m_hideEmitters);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RadianceQueryRecord::toString() const {
|
std::string RadianceQueryRecord::toString() const {
|
||||||
|
|
|
@ -41,6 +41,10 @@
|
||||||
implicitly have <tt>strictNormals</tt> activated. Hence, another use of this parameter
|
implicitly have <tt>strictNormals</tt> activated. Hence, another use of this parameter
|
||||||
is to match renderings created by these methods.</p>
|
is to match renderings created by these methods.</p>
|
||||||
</param>
|
</param>
|
||||||
|
<param name="hideEmitters" readableName="Hide directly visible emitters" type="boolean" default="false" importance="1">
|
||||||
|
Hide light sources (e.g. area or environment light sources) that are directly visible to the camera?
|
||||||
|
Reflections of light sources remain unaffected.
|
||||||
|
</param>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin type="integrator" name="irrcache" readableName="Irradiance cache"
|
<plugin type="integrator" name="irrcache" readableName="Irradiance cache"
|
||||||
|
@ -191,6 +195,10 @@
|
||||||
implicitly have <tt>strictNormals</tt> activated. Hence, another use of this parameter
|
implicitly have <tt>strictNormals</tt> activated. Hence, another use of this parameter
|
||||||
is to match renderings created by these methods.</p>
|
is to match renderings created by these methods.</p>
|
||||||
</param>
|
</param>
|
||||||
|
<param name="hideEmitters" readableName="Hide directly visible emitters" type="boolean" default="false" importance="1">
|
||||||
|
Hide light sources (e.g. area or environment light sources) that are directly visible to the camera?
|
||||||
|
Reflections of light sources remain unaffected.
|
||||||
|
</param>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin type="integrator" name="path" readableName="Path tracer"
|
<plugin type="integrator" name="path" readableName="Path tracer"
|
||||||
|
@ -350,6 +358,10 @@
|
||||||
Specifies the minimum path depth, after which the implementation will start to use the
|
Specifies the minimum path depth, after which the implementation will start to use the
|
||||||
"russian roulette" path termination criterion when tracing photons (set to <tt>-1</tt> to disable).
|
"russian roulette" path termination criterion when tracing photons (set to <tt>-1</tt> to disable).
|
||||||
</param>
|
</param>
|
||||||
|
<param name="hideEmitters" readableName="Hide directly visible emitters" type="boolean" default="false" importance="1">
|
||||||
|
Hide light sources (e.g. area or environment light sources) that are directly visible to the camera?
|
||||||
|
Reflections of light sources remain unaffected.
|
||||||
|
</param>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin type="integrator" name="ppm" readableName="Progressive photon mapper"
|
<plugin type="integrator" name="ppm" readableName="Progressive photon mapper"
|
||||||
|
|
Loading…
Reference in New Issue