mitsuba/src/integrators/direct/ao.cpp

145 lines
4.9 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2012 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/render/scene.h>
MTS_NAMESPACE_BEGIN
/*! \plugin{ao}{Ambient occlusion integrator}
* \order{0}
* \parameters{
* \parameter{shadingSamples}{\Integer}{Specifies the number of
* shading samples that should be computed per primary ray
* \default{1}}
*
* \parameter{rayLength}{\Float}{Specifies the world-space length of the
* ambient occlusion rays that will be cast. \default{\code{-1}, i.e. automatic}}.
* }
* \renderings{
* \rendering{A view of the scene on page \pageref{fig:rungholt}, rendered using
* the Ambient Occlusion integrator}{integrator_ao}
* \rendering{A corresponding rendering created using the standard \pluginref{path} tracer}{integrator_ao_path}
* }
* Ambient Occlusion is a simple non-photorealistic rendering technique that simulates the exposure of an object
* to uniform illumination incident from all direction. It produces approximate shadowing between closeby
* objects, as well as darkening in corners, creases, and cracks. The scattering models associated with objects
* in the scene are ignored.
*/
class AmbientOcclusionIntegrator : public SamplingIntegrator {
public:
AmbientOcclusionIntegrator(const Properties &props) : SamplingIntegrator(props) {
m_shadingSamples = props.getSize("shadingSamples", 1);
m_rayLength = props.getFloat("rayLength", -1);
}
/// Unserialize from a binary data stream
AmbientOcclusionIntegrator(Stream *stream, InstanceManager *manager)
: SamplingIntegrator(stream, manager) {
m_shadingSamples = stream->readSize();
m_rayLength = stream->readFloat();
configure();
}
void serialize(Stream *stream, InstanceManager *manager) const {
SamplingIntegrator::serialize(stream, manager);
stream->writeSize(m_shadingSamples);
stream->writeFloat(m_rayLength);
}
void configureSampler(const Scene *scene, Sampler *sampler) {
SamplingIntegrator::configureSampler(scene, sampler);
if (m_shadingSamples > 1)
sampler->request2DArray(m_shadingSamples);
}
bool preprocess(const Scene *scene, RenderQueue *queue,
const RenderJob *job, int sceneResID, int sensorResID,
int samplerResID) {
Integrator::preprocess(scene, queue, job, sceneResID,
sensorResID, samplerResID);
if (m_rayLength < 0) {
m_rayLength = scene->getAABB().getBSphere().radius * 0.5f;
Log(EInfo, "Setting occlusion ray length to %f", m_rayLength);
}
return true;
}
Spectrum Li(const RayDifferential &ray, RadianceQueryRecord &rRec) const {
/* Some aliases and local variables */
Spectrum Li(0.0f);
Point2 sample;
/* Perform the first ray intersection (or ignore if the
intersection has already been provided). */
if (!rRec.rayIntersect(ray)) {
/* If no intersection could be found, possibly return
radiance from a background emitter */
return Spectrum(1.0f);
}
/* Figure out how many shading samples to take, and where the
required random numbers should come from */
Point2 *sampleArray = &sample;
size_t numShadingSamples = m_shadingSamples;
bool adaptiveQuery = (rRec.extra & RadianceQueryRecord::EAdaptiveQuery);
if (numShadingSamples > 1 && rRec.depth == 1 && !adaptiveQuery) {
sampleArray = rRec.sampler->next2DArray(numShadingSamples);
} else {
/* This integrator is used recursively by another integrator.
Be less accurate as this sample will not directly be observed. */
numShadingSamples = 1;
sample = rRec.nextSample2D();
}
const Intersection &its = rRec.its;
for (size_t i=0; i<numShadingSamples; ++i) {
Vector d = its.toWorld(warp::squareToCosineHemisphere(sampleArray[i]));
Ray shadowRay(its.p, d, Epsilon, m_rayLength, ray.time);
if (!rRec.scene->rayIntersect(shadowRay))
Li += Spectrum(1.0f);
}
Li /= static_cast<Float>(numShadingSamples);
return Li;
}
std::string toString() const {
std::ostringstream oss;
oss << "AmbientOcclusionIntegrator[" << endl
<< " shadingSamples = " << m_shadingSamples << "," << endl
<< " rayLength = " << m_rayLength << endl
<< "]";
return oss.str();
}
MTS_DECLARE_CLASS()
private:
size_t m_shadingSamples;
Float m_rayLength;
};
MTS_IMPLEMENT_CLASS_S(AmbientOcclusionIntegrator, false, SamplingIntegrator)
MTS_EXPORT_PLUGIN(AmbientOcclusionIntegrator, "Ambient occlusion integrator");
MTS_NAMESPACE_END