mitsuba/src/subsurface/irrproc.cpp

162 lines
5.1 KiB
C++

#include <mitsuba/core/plugin.h>
#include <mitsuba/render/range.h>
#include "irrproc.h"
MTS_NAMESPACE_BEGIN
/* Parallel irradiance sampling implementation (worker) */
class IrradianceSamplingWorker : public WorkProcessor {
public:
IrradianceSamplingWorker(size_t sampleCount, int ssIndex)
: m_sampleCount(sampleCount), m_ssIndex(ssIndex) {
}
IrradianceSamplingWorker(Stream *stream, InstanceManager *manager) {
m_sampleCount = (size_t) stream->readLong();
m_ssIndex = stream->readInt();
}
void serialize(Stream *stream, InstanceManager *manager) const {
stream->writeLong(m_sampleCount);
stream->writeInt(m_ssIndex);
}
ref<WorkUnit> createWorkUnit() const {
return new RangeWorkUnit();
}
ref<WorkResult> createWorkResult() const {
return new IrradianceRecordVector();
}
void prepare() {
m_scene = static_cast<Scene *>(getResource("scene"));
m_integrator = static_cast<SampleIntegrator *>(m_scene->getIntegrator());
Properties props;
props.setLong("sampleCount", m_sampleCount);
props.setPluginName("hammersley");
m_sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(Sampler::m_theClass, props));
props.setPluginName("independent");
m_independentSampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(Sampler::m_theClass, props));
m_scene->wakeup(m_resources);
const Subsurface *ss = m_scene->getSubsurfaceIntegrators()[m_ssIndex];
m_shapes = ss->getShapes();
for (size_t i=0; i<m_shapes.size(); ++i)
m_areaPDF.put(m_shapes[i]->getSurfaceArea());
m_areaPDF.build();
}
void process(const WorkUnit *workUnit, WorkResult *workResult,
const bool &stop) {
const RangeWorkUnit *range = static_cast<const RangeWorkUnit *>(workUnit);
IrradianceRecordVector *result = static_cast<IrradianceRecordVector *>(workResult);
const SampleIntegrator *integrator = m_integrator.get();
result->clear();
for (size_t i=range->getRangeStart(); i<range->getRangeEnd(); ++i) {
m_sampler->setSampleIndex(i);
Point2 sample = m_sampler->next2D();
Float expSamples;
unsigned int index = m_areaPDF.sampleReuse(sample.x, expSamples);
expSamples *= m_sampleCount;
ShapeSamplingRecord sRec;
Float pdf = m_shapes[index]->sampleArea(sRec, sample) * expSamples;
result->put(IrradianceSample(
sRec.p,
integrator->E(m_scene.get(), sRec.p, sRec.n, m_independentSampler),
1/pdf
));
}
}
ref<WorkProcessor> clone() const {
return new IrradianceSamplingWorker(m_sampleCount, m_ssIndex);
}
MTS_DECLARE_CLASS()
protected:
virtual ~IrradianceSamplingWorker() { }
private:
ref<Scene> m_scene;
ref<Camera> m_camera;
ref<Sampler> m_sampler, m_independentSampler;
ref<SampleIntegrator> m_integrator;
DiscretePDF m_areaPDF;
std::vector<Shape *> m_shapes;
size_t m_sampleCount;
int m_ssIndex;
};
void IrradianceRecordVector::load(Stream *stream) {
clear();
size_t count = stream->readUInt();
m_samples.resize(count);
for (size_t i=0; i<count; ++i)
m_samples[i] = IrradianceSample(stream);
}
void IrradianceRecordVector::save(Stream *stream) const {
stream->writeUInt((unsigned int) m_samples.size());
for (size_t i=0; i<m_samples.size(); ++i)
m_samples[i].serialize(stream);
}
std::string IrradianceRecordVector::toString() const {
std::ostringstream oss;
oss << "IrradianceRecordVector[size="
<< m_samples.size() << "]";
return oss.str();
}
IrradianceSamplingProcess::IrradianceSamplingProcess(size_t sampleCount,
size_t granularity, int ssIndex, const void *progressReporterPayload)
: m_sampleCount(sampleCount), m_granularity(granularity), m_ssIndex(ssIndex) {
m_resultCount = 0;
m_resultMutex = new Mutex();
m_samples = new IrradianceRecordVector();
m_samplesRequested = 0;
m_progress = new ProgressReporter("Sampling irradiance", sampleCount,
progressReporterPayload);
}
IrradianceSamplingProcess::~IrradianceSamplingProcess() {
if (m_progress)
delete m_progress;
}
ref<WorkProcessor> IrradianceSamplingProcess::createWorkProcessor() const {
return new IrradianceSamplingWorker(m_sampleCount, m_ssIndex);
}
ParallelProcess::EStatus IrradianceSamplingProcess::generateWork(WorkUnit *unit, int worker) {
if (m_samplesRequested == m_sampleCount)
return EFailure;
/* Reserve a sequence of at most 'granularity' samples */
size_t workSize = std::min(m_granularity, m_sampleCount - m_samplesRequested);
RangeWorkUnit *range = static_cast<RangeWorkUnit *>(unit);
range->setRange(m_samplesRequested, m_samplesRequested + workSize - 1);
m_samplesRequested += workSize;
return ESuccess;
}
void IrradianceSamplingProcess::processResult(const WorkResult *wr, bool cancelled) {
const IrradianceRecordVector *result = static_cast<const IrradianceRecordVector *>(wr);
m_resultMutex->lock();
for (size_t i=0; i<result->size(); ++i)
m_samples->put((*result)[i]);
m_resultCount += result->size();
m_progress->update(m_resultCount);
m_resultMutex->unlock();
}
MTS_IMPLEMENT_CLASS(IrradianceRecordVector, false, WorkResult);
MTS_IMPLEMENT_CLASS_S(IrradianceSamplingWorker, false, WorkProcessor);
MTS_IMPLEMENT_CLASS(IrradianceSamplingProcess, false, ParallelProcess);
MTS_NAMESPACE_END