VPL pruning
parent
2d193b8b4f
commit
3e8e0bba53
|
@ -50,7 +50,7 @@ public:
|
|||
const Luminaire *luminaire, const Point &camPos, bool faceNormals);
|
||||
|
||||
/// Draw the background if there is an environment luminaire
|
||||
void drawBackground(const Transform &clipToWorld, const Point &camPos);
|
||||
void drawBackground(const Transform &clipToWorld, const Point &camPos, Float scaleFactor);
|
||||
|
||||
/// Release bound resources
|
||||
void unbind();
|
||||
|
|
|
@ -32,11 +32,11 @@ class MTS_EXPORT_RENDER PreviewWorker : public WorkProcessor {
|
|||
public:
|
||||
inline PreviewWorker(int blockSize, Point cameraO, Vector cameraTL,
|
||||
Vector cameraDx, Vector cameraDy, const VPL &vpl, Float minDist, bool coherent,
|
||||
bool diffuseSources, bool diffuseReceivers)
|
||||
bool diffuseSources, bool diffuseReceivers, Float backgroundScale)
|
||||
: m_blockSize(blockSize), m_cameraO(cameraO), m_cameraTL(cameraTL),
|
||||
m_cameraDx(cameraDx), m_cameraDy(cameraDy), m_vpl(vpl),
|
||||
m_minDist(minDist), m_coherent(coherent), m_diffuseSources(diffuseSources),
|
||||
m_diffuseReceivers(diffuseReceivers) {
|
||||
m_diffuseReceivers(diffuseReceivers), m_backgroundScale(backgroundScale) {
|
||||
}
|
||||
|
||||
void processIncoherent(const WorkUnit *workUnit, WorkResult *workResult,
|
||||
|
@ -71,6 +71,7 @@ private:
|
|||
const std::vector<const Shape *> *m_shapes;
|
||||
bool m_coherent;
|
||||
bool m_diffuseSources, m_diffuseReceivers;
|
||||
Float m_backgroundScale;
|
||||
};
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -46,16 +46,20 @@ struct VPL {
|
|||
|
||||
/**
|
||||
* Generate a series of point light sources by sampling from the Halton
|
||||
* sequence (as is done in Instant Radiosity). The parameter <code>offset</code>
|
||||
* sequence (as is done in Instant Radiosity). The parameter \c offset
|
||||
* allows setting the initial QMC sample index (should be set to 0 if no offset is
|
||||
* desired), and the last index is returned after the function finishes. This can
|
||||
* be used to generate an arbitrary number of VPLs incrementally. Note that the
|
||||
* parameter <code>count</code> is only a suggestion. Generally, the implementation
|
||||
* will produce a few more VPLs. After VPL generation is done, their power must be scaled
|
||||
* by the inverse of the returned index.
|
||||
* value supplied with the parameter \c count is only a suggestion to the implementation.
|
||||
* Generally, it will produce a few more VPLs than the requsted amount. After VPL
|
||||
* generation is done, their power must be scaled by the inverse of the returned index.
|
||||
* The implementation here also needs an pseudorandom number generator, which
|
||||
* is used to prune VPLs in an unbiased manner.
|
||||
*/
|
||||
extern MTS_EXPORT_RENDER size_t generateVPLs(const Scene *scene, size_t offset,
|
||||
size_t count, int maxDepth, std::deque<VPL> &vpls);
|
||||
extern MTS_EXPORT_RENDER size_t generateVPLs(const Scene *scene,
|
||||
Random *random, size_t offset,
|
||||
size_t count, int maxDepth, bool prune,
|
||||
std::deque<VPL> &vpls);
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/core/statistics.h>
|
||||
#include <mitsuba/core/plugin.h>
|
||||
#include <mitsuba/hw/vpl.h>
|
||||
#include <mitsuba/hw/session.h>
|
||||
#include <mitsuba/hw/device.h>
|
||||
|
@ -46,6 +47,7 @@ public:
|
|||
m_session = Session::create();
|
||||
m_device = Device::create(m_session);
|
||||
m_renderer = Renderer::create(m_session);
|
||||
|
||||
m_random = new Random();
|
||||
}
|
||||
|
||||
|
@ -73,7 +75,7 @@ public:
|
|||
m_shaderManager->unbind();
|
||||
}
|
||||
m_renderer->endDrawingMeshes();
|
||||
m_shaderManager->drawBackground(clipToWorld, camPos);
|
||||
m_shaderManager->drawBackground(clipToWorld, camPos, 1.0f);
|
||||
}
|
||||
|
||||
bool preprocess(const Scene *scene, RenderQueue *queue, const RenderJob *job,
|
||||
|
@ -81,7 +83,8 @@ public:
|
|||
Integrator::preprocess(scene, queue, job, sceneResID, cameraResID, samplerResID);
|
||||
|
||||
if (m_vpls.size() == 0) {
|
||||
Float normalization = (Float) 1 / generateVPLs(scene, 0, m_vplCount, m_maxDepth, m_vpls);
|
||||
Float normalization = (Float) 1 / generateVPLs(scene, m_random,
|
||||
0, m_vplCount, m_maxDepth, true, m_vpls);
|
||||
for (size_t i=0; i<m_vpls.size(); ++i)
|
||||
m_vpls[i].P *= normalization;
|
||||
Log(EInfo, "Generated %i virtual point lights", m_vpls.size());
|
||||
|
|
|
@ -177,8 +177,9 @@ void VPLShaderManager::init() {
|
|||
|
||||
oss << "varying vec3 d;" << endl
|
||||
<< "uniform vec3 camPos;" << endl
|
||||
<< "uniform float scale;" << endl
|
||||
<< "void main() {" << endl
|
||||
<< " gl_FragColor.rgb = " << evalName << "_background(normalize(d - camPos));" << endl
|
||||
<< " gl_FragColor.rgb = scale * " << evalName << "_background(normalize(d - camPos));" << endl
|
||||
<< " gl_FragColor.a = 1.0;" << endl
|
||||
<< "}" << endl;
|
||||
|
||||
|
@ -606,7 +607,7 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
|||
m_targetConfig.bind(program, config, textureUnitOffset);
|
||||
}
|
||||
|
||||
void VPLShaderManager::drawBackground(const Transform &clipToWorld, const Point &camPos) {
|
||||
void VPLShaderManager::drawBackground(const Transform &clipToWorld, const Point &camPos, Float scaleFactor) {
|
||||
if (m_backgroundProgram == NULL)
|
||||
return;
|
||||
int textureUnitOffset = 0;
|
||||
|
@ -615,6 +616,7 @@ void VPLShaderManager::drawBackground(const Transform &clipToWorld, const Point
|
|||
m_backgroundDependencies, textureUnitOffset);
|
||||
m_backgroundProgram->setParameter("clipToWorld", clipToWorld, false);
|
||||
m_backgroundProgram->setParameter("camPos", camPos, false);
|
||||
m_backgroundProgram->setParameter("scale", scaleFactor);
|
||||
m_renderer->blitQuad(false);
|
||||
m_backgroundProgram->unbind();
|
||||
m_backgroundDependencies.recursiveUnbind();
|
||||
|
|
|
@ -79,7 +79,7 @@ void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *work
|
|||
|
||||
++numRays;
|
||||
if (!m_kdtree->rayIntersect(primary, its)) {
|
||||
block->setPixel(pos++, m_scene->LeBackground(primary));
|
||||
block->setPixel(pos++, m_scene->LeBackground(primary)*m_backgroundScale);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe
|
|||
Point(primRay4.o[0].f[idx], primRay4.o[1].f[idx], primRay4.o[2].f[idx]),
|
||||
Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]),
|
||||
0.0f
|
||||
));
|
||||
)) * m_backgroundScale;
|
||||
memset(&direct[idx], 0, sizeof(Spectrum));
|
||||
continue;
|
||||
}
|
||||
|
@ -457,7 +457,7 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe
|
|||
ref<WorkProcessor> PreviewWorker::clone() const {
|
||||
return new PreviewWorker(m_blockSize, m_cameraO, m_cameraTL,
|
||||
m_cameraDx, m_cameraDy, m_vpl, m_minDist, m_coherent,
|
||||
m_diffuseSources, m_diffuseReceivers);
|
||||
m_diffuseSources, m_diffuseReceivers, m_backgroundScale);
|
||||
}
|
||||
|
||||
MTS_IMPLEMENT_CLASS(PreviewWorker, false, WorkProcessor)
|
||||
|
|
|
@ -18,11 +18,48 @@
|
|||
|
||||
#include <mitsuba/render/vpl.h>
|
||||
#include <mitsuba/core/plugin.h>
|
||||
#include <mitsuba/core/statistics.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDepth,
|
||||
std::deque<VPL> &vpls) {
|
||||
static StatsCounter prunedVPLs("VPL generator", "Pruned VPLs", EPercentage);
|
||||
|
||||
static void appendVPL(const Scene *scene, Random *random,
|
||||
VPL &vpl, bool prune, std::deque<VPL> &vpls) {
|
||||
prunedVPLs.incrementBase();
|
||||
if (prune) {
|
||||
/* Possibly reject VPLs if they are unlikely to be
|
||||
visible from the camera */
|
||||
int nSuccesses = 0, nSamples = 50;
|
||||
const Shape *shape;
|
||||
Normal n;
|
||||
Ray ray;
|
||||
Float t;
|
||||
for (int i=0; i<nSamples; ++i) {
|
||||
scene->getCamera()->generateRay(Point2(random->nextFloat(),
|
||||
random->nextFloat()), Point2(0.0f), 0, ray);
|
||||
if (scene->rayIntersect(ray, t, shape, n)) {
|
||||
if (!scene->isOccluded(ray(t), vpl.its.p, 0))
|
||||
++nSuccesses;
|
||||
} else {
|
||||
++nSuccesses; // be conservative
|
||||
}
|
||||
}
|
||||
/// Have a small chance of acceptance in any case
|
||||
Float acceptanceProb = (nSuccesses+1) / (Float) (nSamples+1);
|
||||
if (random->nextFloat() < acceptanceProb) {
|
||||
vpl.P /= acceptanceProb;
|
||||
vpls.push_back(vpl);
|
||||
} else {
|
||||
++prunedVPLs;
|
||||
}
|
||||
} else {
|
||||
vpls.push_back(vpl);
|
||||
}
|
||||
}
|
||||
|
||||
size_t generateVPLs(const Scene *scene, Random *random,
|
||||
size_t offset, size_t count, int maxDepth, bool prune, std::deque<VPL> &vpls) {
|
||||
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
||||
createObject(MTS_CLASS(Sampler), Properties("halton")));
|
||||
EmissionRecord eRec;
|
||||
|
@ -50,7 +87,7 @@ size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDept
|
|||
lumVPL.its.shFrame = (eRec.luminaire->getType() & Luminaire::EOnSurface)
|
||||
? Frame(eRec.sRec.n) : stdFrame;
|
||||
lumVPL.luminaire = eRec.luminaire;
|
||||
vpls.push_back(lumVPL);
|
||||
appendVPL(scene, random, lumVPL, prune, vpls);
|
||||
|
||||
weight *= eRec.luminaire->sampleEmissionDirection(eRec, dirSample);
|
||||
Float cosTheta = (eRec.luminaire->getType() & Luminaire::EOnSurface)
|
||||
|
@ -87,7 +124,7 @@ size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDept
|
|||
|
||||
VPL vpl(ESurfaceVPL, weight);
|
||||
vpl.its = its;
|
||||
vpls.push_back(vpl);
|
||||
appendVPL(scene, random, vpl, prune, vpls);
|
||||
|
||||
weight *= bsdfVal;
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ PreviewThread::PreviewThread(Device *parentDevice, Renderer *parentRenderer)
|
|||
m_renderer = Renderer::create(m_session);
|
||||
m_mutex = new Mutex();
|
||||
m_queueCV = new ConditionVariable(m_mutex);
|
||||
m_random = new Random();
|
||||
m_bufferCount = 3;
|
||||
m_backgroundScaleFactor = 1.0f;
|
||||
m_queueEntryIndex = 0;
|
||||
m_session->init();
|
||||
m_timer = new Timer();
|
||||
|
@ -57,6 +57,8 @@ PreviewThread::PreviewThread(Device *parentDevice, Renderer *parentRenderer)
|
|||
m_framebuffer = m_renderer->createGPUTexture("Framebuffer");
|
||||
for (int i=0; i<m_bufferCount; ++i)
|
||||
m_recycleQueue.push_back(PreviewQueueEntry(m_queueEntryIndex++));
|
||||
|
||||
m_random = new Random();
|
||||
|
||||
MTS_AUTORELEASE_END()
|
||||
}
|
||||
|
@ -350,9 +352,12 @@ void PreviewThread::run() {
|
|||
m_timer->reset();
|
||||
}
|
||||
|
||||
if (m_vpls.empty())
|
||||
m_vplSampleOffset = generateVPLs(m_context->scene, m_vplSampleOffset,
|
||||
1, m_context->pathLength, m_vpls);
|
||||
if (m_vpls.empty()) {
|
||||
size_t oldOffset = m_vplSampleOffset;
|
||||
m_vplSampleOffset = generateVPLs(m_context->scene, m_random,
|
||||
m_vplSampleOffset, 1, m_context->pathLength, !m_motion, m_vpls);
|
||||
m_backgroundScaleFactor = m_vplSampleOffset - oldOffset;
|
||||
}
|
||||
|
||||
VPL vpl = m_vpls.front();
|
||||
m_vpls.pop_front();
|
||||
|
@ -388,9 +393,12 @@ void PreviewThread::run() {
|
|||
m_timer->reset();
|
||||
}
|
||||
|
||||
if (m_vpls.empty())
|
||||
m_vplSampleOffset = generateVPLs(m_context->scene, m_vplSampleOffset,
|
||||
1, m_context->pathLength, m_vpls);
|
||||
if (m_vpls.empty()) {
|
||||
size_t oldOffset = m_vplSampleOffset;
|
||||
m_vplSampleOffset = generateVPLs(m_context->scene, m_random,
|
||||
m_vplSampleOffset, 1, m_context->pathLength, !m_motion, m_vpls);
|
||||
m_backgroundScaleFactor = m_vplSampleOffset - oldOffset;
|
||||
}
|
||||
|
||||
VPL vpl = m_vpls.front();
|
||||
m_vpls.pop_front();
|
||||
|
@ -500,7 +508,8 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
m_shaderManager->unbind();
|
||||
}
|
||||
m_renderer->endDrawingMeshes();
|
||||
m_shaderManager->drawBackground(clipToWorld, camPos);
|
||||
m_shaderManager->drawBackground(clipToWorld, camPos,
|
||||
m_backgroundScaleFactor);
|
||||
m_framebuffer->releaseTarget();
|
||||
|
||||
target.buffer->activateTarget();
|
||||
|
@ -592,7 +601,8 @@ void PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
target.buffer->getBitmap(),
|
||||
m_context->previewMethod == ERayTraceCoherent,
|
||||
m_context->diffuseSources,
|
||||
m_context->diffuseReceivers);
|
||||
m_context->diffuseReceivers,
|
||||
m_backgroundScaleFactor);
|
||||
m_mutex->unlock();
|
||||
|
||||
ref<Scheduler> sched = Scheduler::getInstance();
|
||||
|
|
|
@ -84,11 +84,11 @@ private:
|
|||
ref<GPUTexture> m_framebuffer;
|
||||
ref<GPUProgram> m_accumProgram;
|
||||
ref<PreviewProcess> m_previewProc;
|
||||
ref<Random> m_random;
|
||||
int m_accumProgramParam_source1;
|
||||
int m_accumProgramParam_source2;
|
||||
const GPUTexture *m_accumBuffer;
|
||||
ref<Mutex> m_mutex;
|
||||
ref<Random> m_random;
|
||||
ref<ConditionVariable> m_queueCV;
|
||||
ref<Timer> m_timer;
|
||||
ref<WaitFlag> m_started;
|
||||
|
@ -101,6 +101,7 @@ private:
|
|||
std::vector<GPUTexture *> m_releaseList;
|
||||
Point m_camPos;
|
||||
Transform m_camViewTransform;
|
||||
Float m_backgroundScaleFactor;
|
||||
bool m_quit, m_sleep, m_motion, m_useSync;
|
||||
bool m_refreshScene;
|
||||
};
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <mitsuba/render/rectwu.h>
|
||||
#include "preview_proc.h"
|
||||
|
||||
PreviewProcess::PreviewProcess(const Scene *scene, int sceneResID, int blockSize)
|
||||
: m_vpl(NULL) {
|
||||
PreviewProcess::PreviewProcess(const Scene *scene, int sceneResID,
|
||||
int blockSize) : m_vpl(NULL) {
|
||||
m_blockSize = blockSize;
|
||||
m_logLevel = ETrace;
|
||||
m_mutex = new Mutex();
|
||||
|
@ -73,7 +73,7 @@ void PreviewProcess::processResult(const WorkResult *result, bool cancelled) {
|
|||
|
||||
void PreviewProcess::configure(const VPL &vpl, Float minDist, const Point2 &jitter,
|
||||
const Bitmap *source, Bitmap *target, bool coherent, bool diffuseSources,
|
||||
bool diffuseReceivers) {
|
||||
bool diffuseReceivers, Float backgroundScale) {
|
||||
BlockedImageProcess::init(m_film->getCropOffset(), m_film->getCropSize(), m_blockSize);
|
||||
m_source = source;
|
||||
m_target = target;
|
||||
|
@ -83,6 +83,7 @@ void PreviewProcess::configure(const VPL &vpl, Float minDist, const Point2 &jitt
|
|||
m_coherent = coherent;
|
||||
m_diffuseSources = diffuseSources;
|
||||
m_diffuseReceivers = diffuseReceivers;
|
||||
m_backgroundScale = backgroundScale;
|
||||
|
||||
/* It is not necessary to shoot normalized rays. Instead, interpolate:
|
||||
here, we generate the upper left corner ray as well as the
|
||||
|
@ -109,7 +110,7 @@ void PreviewProcess::configure(const VPL &vpl, Float minDist, const Point2 &jitt
|
|||
ref<WorkProcessor> PreviewProcess::createWorkProcessor() const {
|
||||
return new PreviewWorker(m_blockSize, m_cameraO, m_cameraTL,
|
||||
m_cameraDx, m_cameraDy, *m_vpl, m_minDist, m_coherent,
|
||||
m_diffuseSources, m_diffuseReceivers);
|
||||
m_diffuseSources, m_diffuseReceivers, m_backgroundScale);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
|
||||
void configure(const VPL &vpl, Float minDist, const Point2 &jitter,
|
||||
const Bitmap *source, Bitmap *target, bool coherent,
|
||||
bool diffuseSources, bool diffuseReceivers);
|
||||
bool diffuseSources, bool diffuseReceivers, Float backgroundScale);
|
||||
inline int getRayCount() const { return m_numRays; }
|
||||
inline const Scene *getScene() const { return m_scene; }
|
||||
|
||||
|
@ -63,6 +63,7 @@ private:
|
|||
bool m_coherent;
|
||||
bool m_diffuseSources;
|
||||
bool m_diffuseReceivers;
|
||||
Float m_backgroundScale;
|
||||
};
|
||||
|
||||
#endif /* __PREVIEW_PROC_H */
|
||||
|
|
Loading…
Reference in New Issue