00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdafx.h"
00027 #include "integrators/irradiancecache.h"
00028 #include "camera.h"
00029 #include "progressreporter.h"
00030 #include "scene.h"
00031 #include "montecarlo.h"
00032 #include "film.h"
00033 #include "samplers/halton.h"
00034 #include "intersection.h"
00035 #include "paramset.h"
00036
00037
00038 struct IrradiancePrimeTask : public Task {
00039 IrradiancePrimeTask(const Scene *sc, const Renderer *sr, const Camera *c, Sampler *samp,
00040 Sample *s, IrradianceCacheIntegrator *ic, ProgressReporter &pr,
00041 int tn, int nt) : progress(pr) {
00042 scene = sc;
00043 renderer = sr;
00044 camera = c;
00045 origSample = s;
00046 sampler = samp->GetSubSampler(tn, nt);
00047 irradianceCache = ic;
00048 taskNum = tn;
00049 numTasks = nt;
00050 }
00051 void Run();
00052
00053 const Scene *scene;
00054 const Camera *camera;
00055 const Renderer *renderer;
00056 Sampler *sampler;
00057 Sample *origSample;
00058 IrradianceCacheIntegrator *irradianceCache;
00059 ProgressReporter &progress;
00060 int taskNum, numTasks;
00061 };
00062
00063
00064 struct IrradProcess {
00065
00066 IrradProcess(const Point &P, const Normal &N, float mw, float cmsad) {
00067 p = P;
00068 n = N;
00069 minWeight = mw;
00070 cosMaxSampleAngleDifference = cmsad;
00071 nFound = 0;
00072 sumWt = 0.;
00073 E = 0.;
00074 wAvg = Vector(0,0,0);
00075 }
00076 bool operator()(const IrradianceSample *sample);
00077 bool Successful() {
00078 return sumWt >= minWeight;
00079 }
00080 Spectrum GetIrradiance() const { return E / sumWt; }
00081 Vector GetAverageDirection() const { return wAvg; }
00082
00083
00084 Point p;
00085 Normal n;
00086 float minWeight, cosMaxSampleAngleDifference, sumWt;
00087 int nFound;
00088 Spectrum E;
00089 Vector wAvg;
00090 };
00091
00092
00093 struct IrradianceSample {
00094
00095 IrradianceSample() { }
00096 IrradianceSample(const Spectrum &e, const Point &P, const Normal &N,
00097 const Vector &pd, float md) : E(e), n(N), p(P), wAvg(pd) {
00098 maxDist = md;
00099 }
00100 Spectrum E;
00101 Normal n;
00102 Point p;
00103 Vector wAvg;
00104 float maxDist;
00105 };
00106
00107
00108
00109
00110 void IrradianceCacheIntegrator::RequestSamples(Sampler *sampler,
00111 Sample *sample, const Scene *scene) {
00112
00113
00114 uint32_t nLights = scene->lights.size();
00115 lightSampleOffsets = new LightSampleOffsets[nLights];
00116 bsdfSampleOffsets = new BSDFSampleOffsets[nLights];
00117 for (uint32_t i = 0; i < nLights; ++i) {
00118 const Light *light = scene->lights[i];
00119 int nSamples = light->nSamples;
00120 if (sampler) nSamples = sampler->RoundSize(nSamples);
00121 lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample);
00122 bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample);
00123 }
00124 }
00125
00126
00127 void IrradianceCacheIntegrator::Preprocess(const Scene *scene,
00128 const Camera *camera, const Renderer *renderer) {
00129 BBox wb = scene->WorldBound();
00130 Vector delta = .01f * (wb.pMax - wb.pMin);
00131 wb.pMin -= delta;
00132 wb.pMax += delta;
00133 octree = new Octree<IrradianceSample *>(wb);
00134
00135 minWeight *= 1.5f;
00136 int xstart, xend, ystart, yend;
00137 camera->film->GetSampleExtent(&xstart, &xend, &ystart, ¥d);
00138 HaltonSampler sampler(xstart, xend, ystart, yend, 1,
00139 camera->shutterOpen, camera->shutterClose);
00140 Sample *sample = new Sample(&sampler, this, NULL, scene);
00141 const int nTasks = 64;
00142 ProgressReporter progress(nTasks, "Priming irradiance cache");
00143 vector<Task *> tasks;
00144 for (int i = 0; i < nTasks; ++i)
00145 tasks.push_back(new IrradiancePrimeTask(scene, renderer, camera,
00146 &sampler, sample, this,
00147 progress, i, nTasks));
00148 EnqueueTasks(tasks);
00149 WaitForAllTasks();
00150 for (uint32_t i = 0; i < tasks.size(); ++i)
00151 delete tasks[i];
00152 progress.Done();
00153 delete sample;
00154 minWeight /= 1.5f;
00155 }
00156
00157
00158 IrradianceCacheIntegrator::~IrradianceCacheIntegrator() {
00159 delete octree;
00160 RWMutex::Destroy(mutex);
00161 delete[] lightSampleOffsets;
00162 delete[] bsdfSampleOffsets;
00163 }
00164
00165
00166 void IrradiancePrimeTask::Run() {
00167 if (!sampler) { progress.Update(); return; }
00168 MemoryArena arena;
00169 int sampleCount;
00170 RNG rng(29 * taskNum);
00171 int maxSamples = sampler->MaximumSampleCount();
00172 Sample *samples = origSample->Duplicate(maxSamples);
00173 while ((sampleCount = sampler->GetMoreSamples(samples, rng)) > 0) {
00174 for (int i = 0; i < sampleCount; ++i) {
00175 RayDifferential ray;
00176 camera->GenerateRayDifferential(samples[i], &ray);
00177 Intersection isect;
00178 if (scene->Intersect(ray, &isect))
00179 (void)irradianceCache->Li(scene, renderer, ray, isect, &samples[i], rng, arena);
00180 }
00181 arena.FreeAll();
00182 }
00183 delete[] samples;
00184 delete sampler;
00185 progress.Update();
00186 }
00187
00188
00189 Spectrum IrradianceCacheIntegrator::Li(const Scene *scene,
00190 const Renderer *renderer, const RayDifferential &ray, const Intersection &isect,
00191 const Sample *sample, RNG &rng, MemoryArena &arena) const {
00192 Spectrum L(0.);
00193
00194 BSDF *bsdf = isect.GetBSDF(ray, arena);
00195 Vector wo = -ray.d;
00196 const Point &p = bsdf->dgShading.p;
00197 const Normal &n = bsdf->dgShading.nn;
00198 L += isect.Le(wo);
00199
00200 L += UniformSampleAllLights(scene, renderer, arena, p, n, wo,
00201 isect.rayEpsilon, ray.time, bsdf, sample, rng,
00202 lightSampleOffsets, bsdfSampleOffsets);
00203
00204
00205 if (ray.depth + 1 < maxSpecularDepth) {
00206 Vector wi;
00207
00208 L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample,
00209 arena);
00210 L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample,
00211 arena);
00212 }
00213
00214
00215 Normal ng = isect.dg.nn;
00216 ng = Faceforward(ng, wo);
00217
00218
00219 float pixelSpacing = sqrtf(Cross(isect.dg.dpdx, isect.dg.dpdy).Length());
00220 BxDFType flags = BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE | BSDF_GLOSSY);
00221 L += indirectLo(p, ng, pixelSpacing, wo, isect.rayEpsilon,
00222 bsdf, flags, rng, scene, renderer, arena);
00223 flags = BxDFType(BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY);
00224 L += indirectLo(p, -ng, pixelSpacing, wo, isect.rayEpsilon,
00225 bsdf, flags, rng, scene, renderer, arena);
00226 return L;
00227 }
00228
00229
00230 Spectrum IrradianceCacheIntegrator::indirectLo(const Point &p,
00231 const Normal &ng, float pixelSpacing, const Vector &wo,
00232 float rayEpsilon, BSDF *bsdf, BxDFType flags, RNG &rng,
00233 const Scene *scene, const Renderer *renderer,
00234 MemoryArena &arena) const {
00235 if (bsdf->NumComponents(flags) == 0)
00236 return Spectrum(0.);
00237 Spectrum E;
00238 Vector wi;
00239
00240 if (!interpolateE(scene, p, ng, &E, &wi)) {
00241
00242 PBRT_IRRADIANCE_CACHE_STARTED_COMPUTING_IRRADIANCE(const_cast<Point *>(&p), const_cast<Normal *>(&ng));
00243 uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() };
00244 float minHitDistance = INFINITY;
00245 Vector wAvg(0,0,0);
00246 Spectrum LiSum = 0.f;
00247 for (int i = 0; i < nSamples; ++i) {
00248
00249 float u[2];
00250 Sample02(i, scramble, u);
00251 Vector w = CosineSampleHemisphere(u[0], u[1]);
00252 RayDifferential r(p, bsdf->LocalToWorld(w), rayEpsilon);
00253 r.d = Faceforward(r.d, ng);
00254
00255
00256 PBRT_IRRADIANCE_CACHE_STARTED_RAY(&r);
00257 Spectrum L = pathL(r, scene, renderer, rng, arena);
00258 LiSum += L;
00259 wAvg += r.d * L.y();
00260 minHitDistance = min(minHitDistance, r.maxt);
00261 PBRT_IRRADIANCE_CACHE_FINISHED_RAY(&r, r.maxt, &L);
00262 }
00263 E = (M_PI / float(nSamples)) * LiSum;
00264 PBRT_IRRADIANCE_CACHE_FINISHED_COMPUTING_IRRADIANCE(const_cast<Point *>(&p), const_cast<Normal *>(&ng));
00265
00266
00267
00268
00269 float maxDist = maxSamplePixelSpacing * pixelSpacing;
00270 float minDist = minSamplePixelSpacing * pixelSpacing;
00271 float contribExtent = Clamp(minHitDistance / 2.f, minDist, maxDist);
00272 BBox sampleExtent(p);
00273 sampleExtent.Expand(contribExtent);
00274 PBRT_IRRADIANCE_CACHE_ADDED_NEW_SAMPLE(const_cast<Point *>(&p), const_cast<Normal *>(&ng), contribExtent, &E, &wAvg, pixelSpacing);
00275
00276
00277 IrradianceSample *sample = new IrradianceSample(E, p, ng, wAvg,
00278 contribExtent);
00279 RWMutexLock lock(*mutex, WRITE);
00280 octree->Add(sample, sampleExtent);
00281 wi = wAvg;
00282 }
00283
00284
00285 if (wi.LengthSquared() == 0.f) return Spectrum(0.);
00286 return bsdf->f(wo, Normalize(wi), flags) * E;
00287 }
00288
00289
00290 bool IrradianceCacheIntegrator::interpolateE(const Scene *scene,
00291 const Point &p, const Normal &n, Spectrum *E,
00292 Vector *wi) const {
00293 if (!octree) return false;
00294 PBRT_IRRADIANCE_CACHE_STARTED_INTERPOLATION(const_cast<Point *>(&p), const_cast<Normal *>(&n));
00295 IrradProcess proc(p, n, minWeight, cosMaxSampleAngleDifference);
00296 RWMutexLock lock(*mutex, READ);
00297 octree->Lookup(p, proc);
00298 PBRT_IRRADIANCE_CACHE_FINISHED_INTERPOLATION(const_cast<Point *>(&p), const_cast<Normal *>(&n),
00299 proc.Successful() ? 1 : 0, proc.nFound);
00300 if (!proc.Successful()) return false;
00301 *E = proc.GetIrradiance();
00302 *wi = proc.GetAverageDirection();
00303 return true;
00304 }
00305
00306
00307 bool IrradProcess::operator()(const IrradianceSample *sample) {
00308
00309 float perr = Distance(p, sample->p) / sample->maxDist;
00310 float nerr = sqrtf((1.f - Dot(n, sample->n)) /
00311 (1.f - cosMaxSampleAngleDifference));
00312 float err = max(perr, nerr);
00313 PBRT_IRRADIANCE_CACHE_CHECKED_SAMPLE(const_cast<IrradianceSample *>(sample), perr, nerr);
00314 if (err < 1.) {
00315 ++nFound;
00316 float wt = 1.f - err;
00317 E += wt * sample->E;
00318 wAvg += wt * sample->wAvg;
00319 sumWt += wt;
00320 }
00321 return true;
00322 }
00323
00324
00325 Spectrum IrradianceCacheIntegrator::pathL(Ray &r, const Scene *scene,
00326 const Renderer *renderer, RNG &rng, MemoryArena &arena) const {
00327 Spectrum L(0.f);
00328 Spectrum pathThroughput = 1.;
00329 RayDifferential ray(r);
00330 bool specularBounce = false;
00331 for (int pathLength = 0; ; ++pathLength) {
00332
00333 Intersection isect;
00334 if (!scene->Intersect(ray, &isect))
00335 break;
00336 if (pathLength == 0)
00337 r.maxt = ray.maxt;
00338 pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena);
00339
00340 if (specularBounce)
00341 L += pathThroughput * isect.Le(-ray.d);
00342
00343 BSDF *bsdf = isect.GetBSDF(ray, arena);
00344
00345 const Point &p = bsdf->dgShading.p;
00346 const Normal &n = bsdf->dgShading.nn;
00347 Vector wo = -ray.d;
00348 L += pathThroughput *
00349 UniformSampleOneLight(scene, renderer, arena, p, n, wo, isect.rayEpsilon,
00350 ray.time, bsdf, NULL, rng);
00351 if (pathLength+1 == maxIndirectDepth) break;
00352
00353
00354 Vector wi;
00355 float pdf;
00356 BxDFType flags;
00357 Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng),
00358 &pdf, BSDF_ALL, &flags);
00359 if (f.IsBlack() || pdf == 0.)
00360 break;
00361 specularBounce = (flags & BSDF_SPECULAR) != 0;
00362 pathThroughput *= f * AbsDot(wi, n) / pdf;
00363 ray = RayDifferential(p, wi, ray, isect.rayEpsilon);
00364
00365 if (pathLength > 2) {
00366 float rrProb = min(1.f, pathThroughput.y());
00367 if (rng.RandomFloat() > rrProb)
00368 break;
00369 pathThroughput /= rrProb;
00370 }
00371 }
00372 return L;
00373 }
00374
00375
00376 IrradianceCacheIntegrator *CreateIrradianceCacheIntegrator(const ParamSet ¶ms) {
00377 float minWeight = params.FindOneFloat("minweight", 0.5f);
00378 float minSpacing = params.FindOneFloat("minpixelspacing", 2.5f);
00379 float maxSpacing = params.FindOneFloat("maxpixelspacing", 15.f);
00380 float maxAngle = params.FindOneFloat("maxangledifference", 10.f);
00381 int maxSpecularDepth = params.FindOneInt("maxspeculardepth", 5);
00382 int maxIndirectDepth = params.FindOneInt("maxindirectdepth", 3);
00383 int nSamples = params.FindOneInt("nsamples", 4096);
00384 if (PbrtOptions.quickRender) nSamples = max(1, nSamples / 16);
00385 return new IrradianceCacheIntegrator(minWeight, minSpacing, maxSpacing, maxAngle,
00386 maxSpecularDepth, maxIndirectDepth, nSamples);
00387 }
00388
00389