/* 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 . */ #include 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; iwriteUInt((unsigned int) m_photons.size()); for (size_t i=0; i 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 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 createWorkResult() const { return new PhotonVector(); } void process(const WorkUnit *workUnit, WorkResult *workResult, const bool &stop) { m_workResult = static_cast(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 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 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(wr); m_resultMutex->lock(); increaseResultCount(vec.size()); for (size_t i=0; istorePhoton(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