00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "bidirectional.h"
00025 #include "reflection/bxdf.h"
00026 #include "light.h"
00027 #include "camera.h"
00028 #include "sampling.h"
00029 #include "scene.h"
00030 #include "paramset.h"
00031 #include "dynload.h"
00032
00033 using namespace lux;
00034
00035 static const u_int passThroughLimit = 10000;
00036
00037 struct BidirVertex {
00038 BidirVertex() : pdf(0.f), pdfR(0.f), tPdf(1.f), tPdfR(1.f),
00039 dAWeight(0.f), dARWeight(0.f), rr(1.f), rrR(1.f), prob(1.f),
00040 flux(0.f), f(0.f), Le(0.f), bsdf(NULL), flags(BxDFType(0)),
00041 ePdf(0.f), ePdfDirect(0.f), eBsdf(NULL) {}
00042 float cosi, coso, pdf, pdfR, tPdf, tPdfR, dAWeight, dARWeight, rr, rrR, prob, d2;
00043 SWCSpectrum flux;
00044 SWCSpectrum f, Le;
00045 BSDF *bsdf;
00046 BxDFType flags;
00047 Vector wi, wo;
00048 Normal ng, ns;
00049 Point p;
00050 float ePdf, ePdfDirect;
00051 BSDF *eBsdf;
00052 int eGroup;
00053 };
00054
00055
00056 void BidirIntegrator::RequestSamples(Sample *sample, const Scene *scene)
00057 {
00058 if (lightStrategy == SAMPLE_AUTOMATIC) {
00059 if (scene->sampler->IsMutating() || scene->lights.size() > 5)
00060 lightStrategy = SAMPLE_ONE_UNIFORM;
00061 else
00062 lightStrategy = SAMPLE_ALL_UNIFORM;
00063 }
00064
00065 lightNumOffset = sample->Add1D(1);
00066 lightComponentOffset = sample->Add1D(1);
00067 lightPosOffset = sample->Add2D(1);
00068 lightDirOffset = sample->Add2D(1);
00069 vector<u_int> structure;
00070
00071 for (u_int i = 0; i < scene->lights.size(); ++i) {
00072 structure.push_back(2);
00073 structure.push_back(1);
00074 if (lightStrategy == SAMPLE_ONE_UNIFORM)
00075 break;
00076 }
00077 sampleDirectOffset = sample->AddxD(structure, maxEyeDepth);
00078 structure.clear();
00079
00080 structure.push_back(1);
00081 structure.push_back(2);
00082 structure.push_back(1);
00083 sampleEyeOffset = sample->AddxD(structure, maxEyeDepth);
00084 structure.clear();
00085
00086 structure.push_back(1);
00087 structure.push_back(2);
00088 structure.push_back(1);
00089 sampleLightOffset = sample->AddxD(structure, maxLightDepth);
00090 }
00091 void BidirIntegrator::Preprocess(const TsPack *tspack, const Scene *scene)
00092 {
00093
00094 BufferOutputConfig config = BUF_FRAMEBUFFER;
00095 if (debug)
00096 config = BufferOutputConfig(config | BUF_STANDALONE);
00097 BufferType type = BUF_TYPE_PER_PIXEL;
00098 scene->sampler->GetBufferType(&type);
00099 eyeBufferId = scene->camera->film->RequestBuffer(type, config, "eye");
00100 lightBufferId = scene->camera->film->RequestBuffer(BUF_TYPE_PER_SCREEN,
00101 config, "light");
00102 }
00103
00104 static int generateEyePath(const TsPack *tspack, const Scene *scene, BSDF *bsdf,
00105 const Sample *sample, const BidirIntegrator &bidir,
00106 vector<BidirVertex> &vertices, float directWeight)
00107 {
00108 if (vertices.size() == 0)
00109 return 0;
00110 RayDifferential ray;
00111 Intersection isect;
00112 ray.d = -Vector(bsdf->dgShading.nn);
00113 isect.dg.p = bsdf->dgShading.p;
00114 isect.dg.nn = bsdf->dgShading.nn;
00115 u_int nVerts = 0;
00116 const float dummy[] = {0.f, tspack->camera->IsLensBased() ? sample->imageX : sample->lensU, tspack->camera->IsLensBased() ? sample->imageY : sample->lensV, 0.5f};
00117 const float *data = (const float *)&dummy;
00118 u_int through = 0;
00119 SWCSpectrum throughFlux(1.f);
00120 float throughProb(1.f);
00121 while (true) {
00122
00123 BidirVertex &v = vertices[nVerts];
00124 if (nVerts == 0) {
00125 v.bsdf = bsdf;
00126 } else {
00127 v.bsdf = isect.GetBSDF(tspack, ray);
00128 RayDifferential r(vertices[nVerts - 1].p, vertices[nVerts - 1].wi);
00129 r.time = tspack->time;
00130 v.Le = isect.Le(tspack, r, vertices[nVerts - 1].ng,
00131 &v.eBsdf, &v.ePdf, &v.ePdfDirect);
00132 if (v.eBsdf) {
00133 v.ePdf /= scene->lights.size();
00134 v.ePdfDirect *= directWeight;
00135 v.eGroup = isect.arealight->group;
00136 }
00137 }
00138 v.wo = -ray.d;
00139 v.p = isect.dg.p;
00140 v.ng = isect.dg.nn;
00141 v.ns = v.bsdf->dgShading.nn;
00142 v.coso = AbsDot(v.wo, v.ng);
00143 ++nVerts;
00144
00145 if (nVerts == vertices.size())
00146 break;
00147 if (!v.bsdf->Sample_f(tspack, v.wo, &v.wi, data[1], data[2],
00148 data[3], &v.f, &v.pdfR, BSDF_ALL, &v.flags, &v.pdf,
00149 true))
00150 break;
00151 if (v.flags != (BSDF_TRANSMISSION | BSDF_SPECULAR) ||
00152 !(v.bsdf->Pdf(tspack, v.wi, v.wo, BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)) > 0.f)) {
00153 v.cosi = AbsDot(v.wi, v.ng);
00154 const float cosins = AbsDot(v.wi, v.ns);
00155 v.flux = v.f * cosins;
00156 v.prob = v.pdfR;
00157 if (through > 0) {
00158 v.flux *= throughFlux;
00159 v.prob *= throughProb;
00160 throughFlux = SWCSpectrum(1.f);
00161 throughProb = 1.f;
00162 through = 0;
00163 }
00164 v.f *= cosins / v.cosi;
00165 v.rrR = min(1.f, max(bidir.eyeThreshold, v.flux.Filter(tspack) / v.prob));
00166 if (nVerts > 3) {
00167 if (v.rrR < data[0])
00168 break;
00169 v.prob *= v.rrR;
00170 }
00171 v.rr = min(1.f, max(bidir.lightThreshold,
00172 v.f.Filter(tspack) * v.coso / v.pdf));
00173 if (nVerts > 1) {
00174 v.flux *= vertices[nVerts - 2].flux;
00175 v.prob *= vertices[nVerts - 2].prob;
00176 }
00177 } else {
00178 const float cosins = AbsDot(v.wi, v.ns);
00179 throughFlux *= v.f * cosins;
00180 throughProb *= v.pdfR;
00181 vertices[nVerts - 2].tPdfR *= v.pdfR;
00182 vertices[nVerts - 1].tPdf *= v.pdf;
00183 --nVerts;
00184 if (through++ > passThroughLimit)
00185 break;
00186 }
00187
00188 ray = RayDifferential(v.p, v.wi);
00189 ray.time = tspack->time;
00190 if (nVerts == 1 && through == 0)
00191 tspack->camera->ClampRay(ray);
00192 if (!scene->Intersect(ray, &isect)) {
00193 vertices[nVerts].wo = -ray.d;
00194 vertices[nVerts].bsdf = NULL;
00195 ++nVerts;
00196 break;
00197 }
00198 data = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), bidir.sampleEyeOffset, nVerts);
00199 }
00200
00201 for (u_int i = 0; i < nVerts - 1; ++i) {
00202 if (vertices[i + 1].bsdf == NULL)
00203 break;
00204 vertices[i].d2 =
00205 DistanceSquared(vertices[i].p, vertices[i + 1].p);
00206 vertices[i + 1].dARWeight = vertices[i].pdfR * vertices[i].tPdfR *
00207 vertices[i + 1].coso / vertices[i].d2;
00208 vertices[i].dAWeight = vertices[i + 1].pdf * vertices[i + 1].tPdf *
00209 vertices[i].cosi / vertices[i].d2;
00210 }
00211 return nVerts;
00212 }
00213
00214 static int generateLightPath(const TsPack *tspack, const Scene *scene,
00215 BSDF *bsdf, const Sample *sample, const BidirIntegrator &bidir,
00216 vector<BidirVertex> &vertices)
00217 {
00218 if (vertices.size() == 0)
00219 return 0;
00220 RayDifferential ray;
00221 Intersection isect;
00222 ray.d = -Vector(bsdf->dgShading.nn);
00223 isect.dg.p = bsdf->dgShading.p;
00224 isect.dg.nn = bsdf->dgShading.nn;
00225 u_int nVerts = 0;
00226 u_int through = 0;
00227 SWCSpectrum throughFlux(1.f);
00228 float throughProb(1.f);
00229 while (true) {
00230 BidirVertex &v = vertices[nVerts];
00231 const float *data = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), bidir.sampleLightOffset, nVerts);
00232 if (nVerts == 0) {
00233 v.bsdf = bsdf;
00234 } else {
00235 v.bsdf = isect.GetBSDF(tspack, ray);
00236 }
00237 v.wi = -ray.d;
00238 v.p = isect.dg.p;
00239 v.ng = isect.dg.nn;
00240 v.ns = v.bsdf->dgShading.nn;
00241 v.cosi = AbsDot(v.wi, v.ng);
00242 ++nVerts;
00243
00244 if (nVerts == vertices.size())
00245 break;
00246 if (!v.bsdf->Sample_f(tspack, v.wi, &v.wo, data[1], data[2],
00247 data[3], &v.f, &v.pdf, BSDF_ALL, &v.flags, &v.pdfR))
00248 break;
00249 if (v.flags != (BSDF_TRANSMISSION | BSDF_SPECULAR) ||
00250 !(v.bsdf->Pdf(tspack, v.wi, v.wo, BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)) > 0.f)) {
00251 v.flux = v.f;
00252 v.coso = AbsDot(v.wo, v.ng);
00253 const float cosins = AbsDot(v.wi, v.ns);
00254 v.flux *= v.coso * cosins;
00255 v.prob = v.pdf * v.cosi;
00256 if (through > 0) {
00257 v.flux *= throughFlux;
00258 v.prob *= throughProb;
00259 throughFlux = SWCSpectrum(1.f);
00260 throughProb = 1.f;
00261 through = 0;
00262 }
00263 v.rr = min(1.f, max(bidir.lightThreshold, v.flux.Filter(tspack) / v.prob));
00264 if (nVerts > 3) {
00265 if (v.rr < data[0])
00266 break;
00267 v.prob *= v.rr;
00268 }
00269 v.rrR = min(1.f, max(bidir.eyeThreshold,
00270 v.f.Filter(tspack) * cosins / v.pdfR));
00271 if (nVerts > 1) {
00272 v.flux *= vertices[nVerts - 2].flux;
00273 v.prob *= vertices[nVerts - 2].prob;
00274 }
00275 } else {
00276 const float cosins = AbsDot(v.wi, v.ns);
00277 throughFlux *= v.f * cosins;
00278
00279 throughProb *= v.pdf;
00280 vertices[nVerts - 2].tPdf *= v.pdf;
00281 vertices[nVerts - 1].tPdfR *= v.pdfR;
00282 --nVerts;
00283 if (through++ > passThroughLimit)
00284 break;
00285 }
00286
00287 ray = RayDifferential(v.p, v.wo);
00288 ray.time = tspack->time;
00289 if (!scene->Intersect(ray, &isect))
00290 break;
00291 }
00292
00293 for (u_int i = 0; i < nVerts - 1; ++i) {
00294 vertices[i].d2 =
00295 DistanceSquared(vertices[i].p, vertices[i + 1].p);
00296 vertices[i + 1].dAWeight = vertices[i].pdf * vertices[i].tPdf *
00297 vertices[i + 1].cosi / vertices[i].d2;
00298 vertices[i].dARWeight = vertices[i + 1].pdfR * vertices[i + 1].tPdfR *
00299 vertices[i].coso / vertices[i].d2;
00300 }
00301 return nVerts;
00302 }
00303
00304
00305 static float G(float cosins, float coso, float d2)
00306 {
00307 return cosins * coso / d2;
00308 }
00309
00310
00311 static bool visible(const TsPack *tspack, const Scene *scene, const Point &P0,
00312 const Point &P1, float *pdf, float *pdfR, SWCSpectrum *f)
00313 {
00314 VisibilityTester vt;
00315 vt.SetSegment(P0, P1, tspack->time);
00316 return vt.TestOcclusion(tspack, scene, f, pdf, pdfR);
00317 }
00318
00319
00320 static float weightPath(const vector<BidirVertex> &eye, int nEye, int eyeDepth,
00321 const vector<BidirVertex> &light, int nLight, int lightDepth,
00322 float pdfLightDirect, bool isLightDirect)
00323 {
00324
00325
00326
00327 const float pBase = (nLight == 1 && isLightDirect) ?
00328 fabsf(light[0].dAWeight) / pdfLightDirect : 1.f;
00329 float weight = 1.f, p = pBase;
00330
00331
00332
00333 if (nLight == 1) {
00334 if (isLightDirect) {
00335 if ((light[0].flags & BSDF_SPECULAR) == 0 && lightDepth > 0)
00336 weight += pBase * pBase;
00337 } else {
00338 const float pDirect = pdfLightDirect / fabsf(light[0].dAWeight);
00339 weight += pDirect * pDirect;
00340 }
00341 }
00342
00343
00344
00345
00346 if (nLight == 0 && (eye[nEye - 2].flags & BSDF_SPECULAR) == 0) {
00347 float pDirect = pdfLightDirect / eye[nEye - 1].dARWeight;
00348 if (nEye > 4)
00349 pDirect /= eye[nEye - 2].rrR;
00350 weight += pDirect * pDirect;
00351 }
00352
00353 for (int i = nEye - 1; i >= max(0, nEye - (lightDepth - nLight)); --i) {
00354
00355 if (!(eye[i].dARWeight > 0.f && eye[i].dAWeight > 0.f))
00356 break;
00357
00358 p *= eye[i].dAWeight / eye[i].dARWeight;
00359
00360 if (i > 3)
00361 p /= eye[i - 1].rrR;
00362 if (nLight + nEye - i > 4) {
00363 if (i == nEye - 1)
00364 p *= light[nLight - 1].rr;
00365 else
00366 p *= eye[i + 1].rr;
00367 }
00368
00369
00370 if ((eye[i].flags & BSDF_SPECULAR) == 0 &&
00371 (i == 0 || (eye[i - 1].flags & BSDF_SPECULAR) == 0))
00372 weight += p * p;
00373 }
00374
00375 p = pBase;
00376
00377 for (int i = nLight - 1; i >= max(0, nLight - (eyeDepth - nEye)); --i) {
00378
00379 if (!(light[i].dARWeight > 0.f && light[i].dAWeight > 0.f))
00380 break;
00381
00382 p *= light[i].dARWeight / light[i].dAWeight;
00383
00384 if (i > 3)
00385 p /= light[i - 1].rr;
00386 if (nEye + nLight - i > 4) {
00387 if (i == nLight - 1)
00388 p *= eye[nEye - 1].rrR;
00389 else
00390 p *= light[i + 1].rrR;
00391 }
00392
00393
00394 if ((light[i].flags & BSDF_SPECULAR) == 0 &&
00395 (i == 0 || (light[i - 1].flags & BSDF_SPECULAR) == 0))
00396 weight += p * p;
00397
00398
00399 if (i == 1) {
00400 float pDirect = p * pdfLightDirect / fabsf(light[0].dAWeight);
00401
00402
00403
00404
00405 if ((light[1].flags & BSDF_SPECULAR) == 0)
00406 weight += pDirect * pDirect;
00407 }
00408 }
00409 return weight;
00410 }
00411
00412 static bool evalPath(const TsPack *tspack, const Scene *scene,
00413 const BidirIntegrator &bidir,
00414 vector<BidirVertex> &eye, int nEye,
00415 vector<BidirVertex> &light, int nLight,
00416 float pdfLightDirect, bool isLightDirect, float *weight, SWCSpectrum *L)
00417 {
00418 const int eyeDepth = bidir.maxEyeDepth;
00419 const int lightDepth = bidir.maxLightDepth;
00420 const float eyeThreshold = bidir.eyeThreshold;
00421 const float lightThreshold = bidir.lightThreshold;
00422 *weight = 0.f;
00423 float eWeight = 0.0f, lWeight = 0.0f;
00424 float prob;
00425
00426
00427 if (nLight > 0 && nEye > 0) {
00428 BidirVertex &eyeV(eye[nEye - 1]);
00429 BidirVertex &lightV(light[nLight - 1]);
00430
00431 eyeV.flags = BxDFType(~BSDF_SPECULAR);
00432 eyeV.wi = Normalize(lightV.p - eyeV.p);
00433 eyeV.pdfR = eyeV.bsdf->Pdf(tspack, eyeV.wo, eyeV.wi, eyeV.flags);
00434 if (!(eyeV.pdfR > 0.f))
00435 return false;
00436 lightV.flags = BxDFType(~BSDF_SPECULAR);
00437 lightV.wo = -eyeV.wi;
00438 lightV.pdf = lightV.bsdf->Pdf(tspack, lightV.wi, lightV.wo, lightV.flags);
00439 if (!(lightV.pdf > 0.f))
00440 return false;
00441 eyeV.f = eyeV.bsdf->f(tspack, eyeV.wi, eyeV.wo, eyeV.flags);
00442 if (eyeV.f.Black())
00443 return false;
00444 lightV.f = lightV.bsdf->f(tspack, lightV.wi, lightV.wo, lightV.flags);
00445 if (lightV.f.Black())
00446 return false;
00447 lightV.tPdf = 1.f;
00448 eyeV.tPdfR = 1.f;
00449 if (!visible(tspack, scene, lightV.p, eyeV.p, &lightV.tPdf,
00450 &eyeV.tPdfR, L))
00451 return false;
00452
00453 eyeV.cosi = AbsDot(eyeV.wi, eyeV.ng);
00454 eyeV.d2 = DistanceSquared(eyeV.p, lightV.p);
00455 if (eyeV.d2 < max(MachineEpsilon::E(eyeV.p), MachineEpsilon::E(lightV.p)))
00456 return false;
00457 const float ecosins = AbsDot(eyeV.wi, eyeV.ns);
00458 eyeV.flux = eyeV.f;
00459 eyeV.prob = 1.f;
00460 if (nEye > 1) {
00461 eyeV.flux *= eye[nEye - 2].flux;
00462 eyeV.prob *= eye[nEye - 2].prob;
00463 }
00464
00465 lightV.coso = AbsDot(lightV.wo, lightV.ng);
00466 lightV.d2 = eyeV.d2;
00467 const float lcosins = AbsDot(lightV.wi, lightV.ns);
00468 lightV.flux = lightV.f * lcosins;
00469 lightV.prob = lightV.cosi;
00470 if (nLight > 1) {
00471 lightV.flux *= light[nLight - 2].flux;
00472 lightV.prob *= light[nLight - 2].prob;
00473 }
00474
00475 prob = eyeV.prob * lightV.prob;
00476 if (!(prob > 0.f))
00477 return false;
00478 *L *= eyeV.flux;
00479 *L *= lightV.flux;
00480 *L *= G(ecosins, lightV.coso, eyeV.d2);
00481 if (L->Black())
00482 return false;
00483
00484 eyeV.pdf = eyeV.bsdf->Pdf(tspack, eyeV.wi, eyeV.wo, eyeV.flags);
00485 eyeV.rr = min(1.f, max(lightThreshold, eyeV.f.Filter(tspack) *
00486 ecosins / eyeV.cosi * eyeV.coso / eyeV.pdf));
00487 eyeV.rrR = min(1.f, max(eyeThreshold, eyeV.f.Filter(tspack) *
00488 ecosins / eyeV.pdfR));
00489 eyeV.dAWeight = lightV.pdf * lightV.tPdf * eyeV.cosi / eyeV.d2;
00490 if (nEye > 1) {
00491 eWeight = eye[nEye - 2].dAWeight;
00492 eye[nEye - 2].dAWeight = eyeV.pdf * eyeV.tPdf *
00493 eye[nEye - 2].cosi / eye[nEye - 2].d2;
00494 eyeV.dARWeight = eye[nEye - 2].pdfR * eye[nEye - 2].tPdfR *
00495 eyeV.coso / eye[nEye - 2].d2;
00496 }
00497
00498 lightV.pdfR = lightV.bsdf->Pdf(tspack, lightV.wo, lightV.wi, lightV.flags);
00499 lightV.rr = min(1.f, max(lightThreshold, lightV.f.Filter(tspack) *
00500 lcosins / lightV.cosi * lightV.coso / lightV.pdf));
00501 lightV.rrR = min(1.f, max(eyeThreshold, lightV.f.Filter(tspack) *
00502 lcosins / lightV.pdfR));
00503 lightV.dARWeight = eyeV.pdfR * eyeV.tPdfR * lightV.coso / lightV.d2;
00504 if (nLight > 1) {
00505 lWeight = light[nLight - 2].dARWeight;
00506 light[nLight - 2].dARWeight = lightV.pdfR * lightV.tPdfR *
00507 light[nLight - 2].coso / light[nLight - 2].d2;
00508 lightV.dAWeight = light[nLight - 2].pdf * light[nLight - 2].tPdf *
00509 lightV.cosi / light[nLight - 2].d2;
00510 }
00511 } else if (nEye > 1) {
00512 BidirVertex &v(eye[nEye - 1]);
00513
00514 v.dAWeight = v.ePdf;
00515 v.flags = BxDFType(~BSDF_SPECULAR);
00516 v.pdf = v.eBsdf->Pdf(tspack, Vector(v.ng), v.wo, v.flags);
00517 if (!(v.pdf > 0.f))
00518 return false;
00519 prob = eye[nEye - 2].prob;
00520 if (!(prob > 0.f))
00521 return false;
00522 *L *= eye[nEye - 2].flux;
00523 if (L->Black())
00524 return false;
00525 eWeight = eye[nEye - 2].dAWeight;
00526 eye[nEye - 2].dAWeight = v.pdf * v.tPdf *
00527 eye[nEye - 2].cosi / eye[nEye - 2].d2;
00528 } else if (nLight > 1) {
00529 BidirVertex &v(light[nLight - 1]);
00530
00531 v.dARWeight = v.ePdf;
00532 v.flags = BxDFType(~BSDF_SPECULAR);
00533 v.pdfR = v.eBsdf->Pdf(tspack, v.wo, Vector(v.ns), v.flags);
00534 if (!(v.pdfR > 0.f))
00535 return false;
00536 prob = light[nLight - 2].prob;
00537 if (!(prob > 0.f))
00538 return false;
00539 *L *= light[nLight - 2].flux;
00540 if (L->Black())
00541 return false;
00542 lWeight = light[nLight - 2].dARWeight;
00543 light[nLight - 2].dARWeight = v.pdfR * v.tPdfR *
00544 light[nLight - 2].coso / light[nLight - 2].d2;
00545 } else
00546 return false;
00547 const float w = weightPath(eye, nEye, eyeDepth, light, nLight,
00548 lightDepth, pdfLightDirect, isLightDirect);
00549 *weight = 1.f / w;
00550 *L /= w * prob;
00551 if (nEye > 1)
00552 eye[nEye - 2].dAWeight = eWeight;
00553 if (nLight > 1)
00554 light[nLight - 2].dARWeight = lWeight;
00555 return true;
00556 }
00557
00558 static bool getLightHit(const TsPack *tspack, const Scene *scene,
00559 const BidirIntegrator &bidir,
00560 vector<BidirVertex> &eyePath, int length,
00561 vector<SWCSpectrum> &Le, vector<float> &weight)
00562 {
00563 BidirVertex &v(eyePath[length - 1]);
00564 if (!(v.ePdf > 0.f) || v.Le.Black())
00565 return false;
00566 vector<BidirVertex> path(0);
00567 BidirVertex e(v);
00568 float totalWeight;
00569 if (!evalPath(tspack, scene, bidir, eyePath, length, path, 0,
00570 v.ePdfDirect, false, &totalWeight, &(v.Le))) {
00571 v = e;
00572 return false;
00573 }
00574 Le[v.eGroup] += v.Le;
00575 weight[v.eGroup] += v.Le.Filter(tspack) * totalWeight;
00576 v = e;
00577 return true;
00578 }
00579
00580 static bool getEnvironmentLight(const TsPack *tspack, const Scene *scene,
00581 const BidirIntegrator &bidir,
00582 vector<BidirVertex> &eyePath, int length, float directWeight,
00583 vector<SWCSpectrum> &Le, vector<float> &weight,
00584 int &nrContribs)
00585 {
00586 BidirVertex &v(eyePath[length - 1]);
00587 if (v.bsdf)
00588 return false;
00589
00590 vector<BidirVertex> path(0);
00591 float totalWeight = 0.f;
00592 for (u_int lightNumber = 0; lightNumber < scene->lights.size(); ++lightNumber) {
00593 const Light *light = scene->lights[lightNumber];
00594 if (!light->IsEnvironmental())
00595 continue;
00596 RayDifferential ray(eyePath[length - 2].p,
00597 eyePath[length - 2].wi);
00598 ray.time = tspack->time;
00599 v.Le = light->Le(tspack, scene, ray, eyePath[length - 2].ng,
00600 &v.eBsdf, &v.ePdf, &v.ePdfDirect);
00601 if (v.eBsdf == NULL || v.Le.Black())
00602 continue;
00603 v.p = v.eBsdf->dgShading.p;
00604 v.ns = v.eBsdf->dgShading.nn;
00605 v.ng = v.ns;
00606 v.coso = AbsDot(v.wo, v.ng);
00607 v.ePdf /= scene->lights.size();
00608 v.ePdfDirect *= directWeight;
00609
00610 eyePath[length - 2].d2 =
00611 DistanceSquared(eyePath[length - 2].p, v.p);
00612 v.dARWeight = eyePath[length - 2].pdfR * eyePath[length - 2].tPdfR *
00613 v.coso / eyePath[length - 2].d2;
00614 if (evalPath(tspack, scene, bidir, eyePath, length, path, 0,
00615 v.ePdfDirect, false, &totalWeight, &(v.Le))) {
00616 Le[light->group] += v.Le;
00617 weight[light->group] += totalWeight *
00618 Le[light->group].Filter(tspack);
00619 ++nrContribs;
00620 }
00621 }
00622 v.bsdf = NULL;
00623 return true;
00624 }
00625
00626 static bool getDirectLight(const TsPack *tspack, const Scene *scene,
00627 const BidirIntegrator &bidir,
00628 vector<BidirVertex> &eyePath, int length,
00629 const Light *light, float u0, float u1, float portal,
00630 float directWeight, const SWCSpectrum &We,
00631 const Sample *sample, vector<SWCSpectrum> &Ld, vector<float> &weight)
00632 {
00633 vector<BidirVertex> lightPath(1);
00634 BidirVertex &vE(eyePath[length - 1]);
00635 BidirVertex &vL(lightPath[0]);
00636 VisibilityTester visibility;
00637 SWCSpectrum L;
00638
00639 if (!light->Sample_L(tspack, scene, vE.p, vE.ng, u0, u1, portal,
00640 &vL.bsdf, &vL.dAWeight, &vL.ePdfDirect, &visibility, &L))
00641 return false;
00642 vL.p = vL.bsdf->dgShading.p;
00643 vL.ns = vL.bsdf->dgShading.nn;
00644 vL.ng = vL.ns;
00645 vL.wi = Vector(vL.ns);
00646 vL.cosi = AbsDot(vL.wi, vL.ng);
00647 vL.dAWeight /= scene->lights.size();
00648 if (light->IsDeltaLight())
00649 vL.dAWeight = -vL.dAWeight;
00650 vL.ePdfDirect *= directWeight;
00651 BidirVertex e(vE);
00652 float totalWeight;
00653 if (!evalPath(tspack, scene, bidir, eyePath, length,
00654 lightPath, 1, vL.ePdfDirect, true, &totalWeight, &L)) {
00655 vE = e;
00656 return false;
00657 }
00658 L /= vL.ePdfDirect;
00659 if (length > 1) {
00660 Ld[light->group] += L;
00661 weight[light->group] += L.Filter(tspack) * totalWeight;
00662 } else {
00663 const float distance = sqrtf(lightPath[0].d2);
00664 float xd, yd;
00665 if (!tspack->camera->GetSamplePosition(vE.p, vE.wi, distance, &xd, &yd)) {
00666 vE = e;
00667 return false;
00668 }
00669 L *= We;
00670 XYZColor color(L.ToXYZ(tspack));
00671 const float alpha = light->IsEnvironmental() ? 0.f : 1.f;
00672 sample->AddContribution(xd, yd, color, alpha, distance, totalWeight, bidir.lightBufferId, light->group);
00673 }
00674 vE = e;
00675 return true;
00676 }
00677
00678 static bool getLight(const TsPack *tspack, const Scene *scene,
00679 const BidirIntegrator &bidir,
00680 vector<BidirVertex> &eyePath, int nEye,
00681 vector<BidirVertex> &lightPath, int nLight,
00682 float lightDirectPdf, SWCSpectrum *Ll, float *weight)
00683 {
00684 BidirVertex vE(eyePath[nEye - 1]), vL(lightPath[nLight - 1]);
00685 bool result = evalPath(tspack, scene, bidir, eyePath, nEye,
00686 lightPath, nLight, lightDirectPdf, false, weight, Ll);
00687 eyePath[nEye - 1] = vE;
00688 lightPath[nLight - 1] = vL;
00689 return result;
00690 }
00691
00692 int BidirIntegrator::Li(const TsPack *tspack, const Scene *scene,
00693 const Sample *sample) const
00694 {
00695 int nrContribs = 0;
00696 vector<BidirVertex> eyePath(maxEyeDepth), lightPath(maxLightDepth);
00697 float alpha = 1.f;
00698 const int numberOfLights = static_cast<int>(scene->lights.size());
00699 const float directWeight = (lightStrategy == SAMPLE_ONE_UNIFORM) ?
00700 1.f / numberOfLights : 1.f;
00701
00702 BSDF *eyeBsdf;
00703 float eyePdf;
00704 SWCSpectrum We;
00705 const float posX = tspack->camera->IsLensBased() ? sample->lensU : sample->imageX;
00706 const float posY = tspack->camera->IsLensBased() ? sample->lensV : sample->imageY;
00707
00708 if (!tspack->camera->Sample_W(tspack, scene,
00709 posX, posY, .5f, &eyeBsdf, &eyePdf, &We))
00710 return nrContribs;
00711 We /= eyePdf;
00712 int nEye = generateEyePath(tspack, scene, eyeBsdf, sample,
00713 *this, eyePath, directWeight);
00714
00715 eyePath[0].dARWeight = 0.f;
00716
00717 const int nGroups = scene->lightGroups.size();
00718 const int lightNum = min(Floor2Int(sample->oneD[lightNumOffset][0] *
00719 numberOfLights), numberOfLights - 1);
00720 const Light *light = scene->lights[lightNum];
00721 const int lightGroup = light->group;
00722 const float *data = sample->twoD[lightPosOffset];
00723 const float component = sample->oneD[lightComponentOffset][0];
00724 BSDF *lightBsdf;
00725 float lightPdf;
00726 SWCSpectrum Le;
00727 int nLight = 0;
00728 if (light->Sample_L(tspack, scene, data[0], data[1], component,
00729 &lightBsdf, &lightPdf, &Le)) {
00730 lightPdf /= numberOfLights;
00731
00732
00733 Le /= lightPdf;
00734 nLight = generateLightPath(tspack, scene, lightBsdf, sample,
00735 *this, lightPath);
00736 }
00737 float lightDirectPdf = 0.f;
00738 if (nLight > 0) {
00739
00740
00741 lightPath[0].dAWeight = max(lightPdf, 0.f);
00742 if (light->IsDeltaLight())
00743 lightPath[0].dAWeight = -lightPath[0].dAWeight;
00744 if (nLight > 1)
00745 lightDirectPdf = light->Pdf(lightPath[1].p,
00746 lightPath[1].ng, lightPath[0].p,
00747 lightPath[0].ng) * directWeight;
00748 }
00749 vector<SWCSpectrum> vecL(nGroups, SWCSpectrum(0.f));
00750 SWCSpectrum &L(vecL[lightGroup]);
00751 vector<float> vecV(nGroups, 0.f);
00752 float &variance(vecV[lightGroup]);
00753
00754 for (int i = 1; i <= nEye; ++i) {
00755
00756 if (i > 1) {
00757 if (getEnvironmentLight(tspack, scene, *this,
00758 eyePath, i, directWeight, vecL, vecV,
00759 nrContribs)) {
00760 if (i == 2)
00761 alpha = 0.f;
00762 break;
00763 } else if (getLightHit(tspack, scene, *this, eyePath, i,
00764 vecL, vecV))
00765 ++nrContribs;
00766 }
00767
00768 const float *directData = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), sampleDirectOffset, i - 1);
00769 switch(lightStrategy) {
00770 case SAMPLE_ONE_UNIFORM: {
00771 float portal = directData[2] * numberOfLights;
00772 const int lightDirectNumber =
00773 min(Floor2Int(portal),
00774 numberOfLights - 1);
00775 portal -= lightDirectNumber;
00776 if (getDirectLight(tspack, scene, *this,
00777 eyePath, i,
00778 scene->lights[lightDirectNumber],
00779 directData[0], directData[1], portal,
00780 directWeight, We, sample, vecL, vecV)) {
00781 ++nrContribs;
00782 }
00783 break;
00784 }
00785 case SAMPLE_ALL_UNIFORM:
00786 for (u_int l = 0; l < scene->lights.size(); ++l) {
00787 if (getDirectLight(tspack, scene, *this,
00788 eyePath, i, scene->lights[l],
00789 directData[0], directData[1],
00790 directData[2], directWeight,
00791 We, sample, vecL, vecV)) {
00792 ++nrContribs;
00793 }
00794 directData += 3;
00795 }
00796 break;
00797 default:
00798 break;
00799 }
00800 if (nLight > 0) {
00801
00802 float directPdf = light->Pdf(eyePath[i - 1].p,
00803 eyePath[i - 1].ng, lightPath[0].p,
00804 lightPath[0].ng) * directWeight;
00805
00806 for (int j = 1; j <= nLight; ++j) {
00807 if ((i == nEye || eyePath[i - 1].flags & (BSDF_DIFFUSE | BSDF_GLOSSY)) && (j == nLight || lightPath[j - 1].flags & (BSDF_DIFFUSE | BSDF_GLOSSY))) {
00808 SWCSpectrum Ll(Le);
00809 float weight;
00810 if (getLight(tspack, scene, *this,
00811 eyePath, i, lightPath, j, directPdf,
00812 &Ll, &weight)) {
00813 if (i > 1) {
00814 L += Ll;
00815 variance += weight *
00816 Ll.Filter(tspack);
00817 } else {
00818 const float d = Distance(lightPath[j - 1].p, eyePath[0].p);
00819 float xl, yl;
00820 if (tspack->camera->GetSamplePosition(eyePath[0].p, (lightPath[j - 1].p - eyePath[0].p) / d, d, &xl, &yl)) {
00821 Ll *= We;
00822 XYZColor color(Ll.ToXYZ(tspack));
00823 const float a = (j == 1 && light->IsEnvironmental()) ? 0.f : 1.f;
00824 sample->AddContribution(xl, yl, color, a, d, weight, lightBufferId, lightGroup);
00825 }
00826 }
00827 ++nrContribs;
00828 }
00829 }
00830
00831 if (j == 1)
00832 directPdf = lightDirectPdf;
00833 }
00834 }
00835 }
00836 const float d = (nEye > 1 && eyePath[1].bsdf) ? eyePath[0].d2 : INFINITY;
00837 float xl, yl;
00838 if (!tspack->camera->GetSamplePosition(eyePath[0].p, eyePath[0].wi, sqrtf(eyePath[0].d2), &xl, &yl))
00839 return nrContribs;
00840 for (int i = 0; i < nGroups; ++i) {
00841 if (!vecL[i].Black())
00842 vecV[i] /= vecL[i].Filter(tspack);
00843 vecL[i] *= We;
00844 XYZColor color(vecL[i].ToXYZ(tspack));
00845 sample->AddContribution(xl, yl,
00846 color, alpha, d, vecV[i], eyeBufferId, i);
00847 }
00848 return nrContribs;
00849 }
00850
00851 SurfaceIntegrator* BidirIntegrator::CreateSurfaceIntegrator(const ParamSet ¶ms)
00852 {
00853 int eyeDepth = params.FindOneInt("eyedepth", 8);
00854 int lightDepth = params.FindOneInt("lightdepth", 8);
00855 float eyeThreshold = params.FindOneFloat("eyerrthreshold", 0.f);
00856 float lightThreshold = params.FindOneFloat("lightrrthreshold", 0.f);
00857 LightStrategy estrategy;
00858 string st = params.FindOneString("strategy", "auto");
00859 if (st == "one") estrategy = SAMPLE_ONE_UNIFORM;
00860 else if (st == "all") estrategy = SAMPLE_ALL_UNIFORM;
00861 else if (st == "auto") estrategy = SAMPLE_AUTOMATIC;
00862 else {
00863 std::stringstream ss;
00864 ss<<"Strategy '"<<st<<"' for direct lighting unknown. Using \"auto\".";
00865 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00866 estrategy = SAMPLE_AUTOMATIC;
00867 }
00868 bool debug = params.FindOneBool("debug", false);
00869 return new BidirIntegrator(eyeDepth, lightDepth, eyeThreshold, lightThreshold, estrategy, debug);
00870 }
00871
00872 static DynamicLoader::RegisterSurfaceIntegrator<BidirIntegrator> r("bidirectional");