mitsuba/src/librender/gatherproc.cpp

177 lines
5.2 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 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/gatherproc.h>
MTS_NAMESPACE_BEGIN
/**
* This stores a number of photons, which can be sent over
* the wire as needed. Used to implement parallel photon
* tracing passes.
*/
class PhotonVector : public WorkResult {
public:
PhotonVector() { }
inline void put(const PhotonMap::Photon &p) {
m_photons.push_back(p);
}
inline size_t size() const {
return m_photons.size();
}
inline void clear() {
m_photons.clear();
}
inline const PhotonMap::Photon &operator[](size_t index) const {
return m_photons[index];
}
void load(Stream *stream) {
m_photons.clear();
size_t count = stream->readUInt();
m_photons.resize(count);
for (size_t i=0; i<count; ++i)
m_photons[i] = PhotonMap::Photon(stream);
}
void save(Stream *stream) const {
stream->writeUInt((unsigned int) m_photons.size());
for (size_t i=0; i<m_photons.size(); ++i)
m_photons[i].serialize(stream);
}
std::string toString() const {
std::ostringstream oss;
oss << "PhotonVector[size=" << m_photons.size() << "]";
return oss.str();
}
MTS_DECLARE_CLASS()
protected:
// Virtual destructor
virtual ~PhotonVector() { }
private:
std::vector<PhotonMap::Photon> m_photons;
};
/**
* This class does the actual photon tracing work
*/
class GatherPhotonWorker : public ParticleTracer {
public:
GatherPhotonWorker(GatherPhotonProcess::EGatherType type, int granularity,
int maxDepth, int rrDepth)
: ParticleTracer(maxDepth, true, rrDepth),
m_type(type), m_granularity(granularity) {
}
GatherPhotonWorker(Stream *stream, InstanceManager *manager)
: ParticleTracer(stream, manager) {
m_type = (GatherPhotonProcess::EGatherType) stream->readInt();
m_granularity = stream->readUInt();
}
ref<WorkProcessor> clone() const {
return new GatherPhotonWorker(m_type, m_granularity, m_maxDepth,
m_rrDepth);
}
void serialize(Stream *stream, InstanceManager *manager) const {
ParticleTracer::serialize(stream, manager);
stream->writeInt(m_type);
stream->writeUInt(m_granularity);
}
ref<WorkResult> createWorkResult() const {
return new PhotonVector();
}
void process(const WorkUnit *workUnit, WorkResult *workResult,
const bool &stop) {
m_workResult = static_cast<PhotonVector *>(workResult);
m_workResult->clear();
ParticleTracer::process(workUnit, workResult, stop);
m_workResult = NULL;
}
void handleSurfaceInteraction(int depth, bool caustic, const Intersection &its, const Spectrum &weight) {
int bsdfType = its.shape->getBSDF()->getType();
if (!(bsdfType & BSDF::EDiffuseReflection) && !(bsdfType & BSDF::EGlossyReflection))
return;
if ((m_type == GatherPhotonProcess::ECausticPhotons && depth > 1 && caustic)
|| (m_type == GatherPhotonProcess::ESurfacePhotons && depth > 1 && !caustic)
|| (m_type == GatherPhotonProcess::EAllSurfacePhotons))
m_workResult->put(PhotonMap::Photon(its.p, its.geoFrame.n, -its.toWorld(its.wi), weight, depth));
}
void handleMediumInteraction(int depth, bool caustic, const MediumSamplingRecord &mRec, const Vector &wi,
const Spectrum &weight) {
if (m_type == GatherPhotonProcess::EVolumePhotons && depth > 1)
m_workResult->put(PhotonMap::Photon(mRec.p, Normal(), -wi, weight, depth));
}
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~GatherPhotonWorker() { }
protected:
GatherPhotonProcess::EGatherType m_type;
unsigned int m_granularity;
ref<PhotonVector> m_workResult;
};
GatherPhotonProcess::GatherPhotonProcess(EGatherType type, size_t photonCount,
unsigned int granularity, int maxDepth, int rrDepth, const void *progressReporterPayload)
: ParticleProcess(ParticleProcess::EGather, photonCount, granularity, "Gathering photons",
progressReporterPayload), m_type(type), m_maxDepth(maxDepth), m_rrDepth(rrDepth),
m_excess(0), m_numShot(0) {
m_photonMap = new PhotonMap(photonCount);
}
ref<WorkProcessor> GatherPhotonProcess::createWorkProcessor() const {
return new GatherPhotonWorker(m_type, m_granularity, m_maxDepth,
m_rrDepth);
}
void GatherPhotonProcess::processResult(const WorkResult *wr, bool cancelled) {
if (cancelled)
return;
const PhotonVector &vec = *static_cast<const PhotonVector *>(wr);
m_resultMutex->lock();
increaseResultCount(vec.size());
for (size_t i=0; i<vec.size(); ++i) {
if (!m_photonMap->storePhoton(vec[i])) {
m_excess += vec.size() - i;
break;
}
}
m_numShot += m_granularity;
m_resultMutex->unlock();
}
MTS_IMPLEMENT_CLASS(GatherPhotonProcess, false, ParticleProcess)
MTS_IMPLEMENT_CLASS_S(GatherPhotonWorker, false, ParticleTracer)
MTS_IMPLEMENT_CLASS(PhotonVector, false, WorkResult)
MTS_NAMESPACE_END