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 "light.h"
00026 #include "paramset.h"
00027
00028 using namespace lux;
00029
00030
00031 void BidirIntegrator::RequestSamples(Sample *sample, const Scene *scene)
00032 {
00033 if (lightStrategy == SAMPLE_AUTOMATIC) {
00034 if (scene->lights.size() > 5)
00035 lightStrategy = SAMPLE_ONE_UNIFORM;
00036 else
00037 lightStrategy = SAMPLE_ALL_UNIFORM;
00038 }
00039
00040 lightNumOffset = sample->Add1D(1);
00041 lightPosOffset = sample->Add2D(1);
00042 lightDirOffset = sample->Add2D(1);
00043 vector<u_int> structure;
00044 structure.push_back(2);
00045 structure.push_back(1);
00046 structure.push_back(2);
00047 structure.push_back(1);
00048 sampleDirectOffset = sample->AddxD(structure, maxEyeDepth);
00049 structure.clear();
00050 structure.push_back(1);
00051 structure.push_back(2);
00052 structure.push_back(1);
00053 sampleEyeOffset = sample->AddxD(structure, maxEyeDepth);
00054 structure.clear();
00055 structure.push_back(1);
00056 structure.push_back(2);
00057 structure.push_back(1);
00058 sampleLightOffset = sample->AddxD(structure, maxLightDepth);
00059 }
00060 static int generateLightPath(const Scene *scene, BSDF *bsdf,
00061 const Sample *sample, const int sampleOffset,
00062 vector<BidirVertex> &vertices)
00063 {
00064 RayDifferential ray;
00065 Intersection isect;
00066 int nVerts = 0;
00067 while (nVerts < (int)(vertices.size())) {
00068 BidirVertex &v = vertices[nVerts];
00069 const float *data = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), sampleOffset, nVerts);
00070 if (nVerts == 0) {
00071 v.wi = Vector(bsdf->dgShading.nn);
00072 v.bsdf = bsdf;
00073 v.p = bsdf->dgShading.p;
00074 v.ng = bsdf->dgShading.nn;
00075 } else {
00076 v.wi = -ray.d;
00077 v.bsdf = isect.GetBSDF(ray, fabsf(2.f * data[3] - 1.f));
00078 v.p = isect.dg.p;
00079 v.ng = isect.dg.nn;
00080 }
00081 v.ns = bsdf->dgShading.nn;
00082
00083 v.f = v.bsdf->Sample_f(v.wi, &v.wo, data[1], data[2], data[3],
00084 &v.bsdfWeight, BSDF_ALL, &v.flags, &v.bsdfRWeight);
00085 ++nVerts;
00086 if (v.bsdfWeight == 0.f || v.f.Black())
00087 break;
00088 v.rrWeight = min<float>(1.f,
00089 v.f.filter() * AbsDot(v.wo, v.ns) / v.bsdfWeight);
00090 v.rrRWeight = min<float>(1.f,
00091 v.f.filter() * AbsDot(v.wi, v.ns) / v.bsdfRWeight);
00092 if (nVerts > 3 && v.rrWeight < data[0])
00093 break;
00094
00095 ray = RayDifferential(v.p, v.wo);
00096 if (!scene->Intersect(ray, &isect))
00097 break;
00098 }
00099
00100 for (int i = 0; i < nVerts - 1; ++i) {
00101 vertices[i + 1].dAWeight = vertices[i].bsdfWeight *
00102 AbsDot(vertices[i + 1].wi, vertices[i + 1].ns) /
00103 DistanceSquared(vertices[i].p, vertices[i + 1].p);
00104 vertices[i].dARWeight = vertices[i + 1].bsdfRWeight *
00105 AbsDot(vertices[i].wo, vertices[i].ns) /
00106 DistanceSquared(vertices[i].p, vertices[i + 1].p);
00107 }
00108 return nVerts;
00109 }
00110 SWCSpectrum BidirIntegrator::Li(const Scene *scene, const RayDifferential &ray,
00111 const Sample *sample, float *alpha) const
00112 {
00113 SampleGuard guard(sample->sampler, sample);
00114 SWCSpectrum L(0.f);
00115 *alpha = 1.f;
00116
00117 vector<BidirVertex> eyePath(maxEyeDepth), lightPath(maxLightDepth), directPath(1);
00118 int nEye = generatePath(scene, ray, sample, sampleEyeOffset, eyePath);
00119 if (nEye == 0) {
00120 L = eyePath[0].Le;
00121 XYZColor color(L.ToXYZ());
00122
00123 if (color.Black())
00124 *alpha = 0.f;
00125 if (color.y() > 0.f)
00126 sample->AddContribution(sample->imageX, sample->imageY,
00127 color, alpha ? *alpha : 1.f);
00128 return L;
00129 }
00130 eyePath[0].dAWeight = 0.f;
00131
00132 int numberOfLights = static_cast<int>(scene->lights.size());
00133 int lightNum = Floor2Int(sample->oneD[lightNumOffset][0] *
00134 numberOfLights);
00135 lightNum = min<int>(lightNum, numberOfLights - 1);
00136 Light *light = scene->lights[lightNum];
00137 float lightWeight = numberOfLights;
00138
00139 Ray lightRay;
00140 float lightPdf;
00141 float u[4];
00142 u[0] = sample->twoD[lightPosOffset][0];
00143 u[1] = sample->twoD[lightPosOffset][1];
00144 u[2] = sample->twoD[lightDirOffset][0];
00145 u[3] = sample->twoD[lightDirOffset][1];
00146
00147 BSDF *lightBsdf;
00148 SWCSpectrum Le = light->Sample_L(scene, u[0], u[1], &lightBsdf, &lightPdf);
00149
00150 int nLight;
00151 if (lightPdf == 0.f) {
00152 Le = 0.f;
00153 nLight = 0;
00154 } else {
00155 Le *= lightWeight / lightPdf;
00156 nLight = generateLightPath(scene, lightBsdf, sample,
00157 sampleLightOffset, lightPath);
00158 }
00159
00160
00161 if (nLight > 0 && !light->IsDeltaLight())
00162 lightPath[0].dAWeight = lightPdf;
00163 else
00164 lightPath[0].dAWeight = 0.f;
00165
00166 float lightDirectPdf;
00167 if (nLight > 1)
00168 lightDirectPdf = light->Pdf(lightPath[1].p, lightPath[1].ns,
00169 lightPath[1].wi) *
00170 DistanceSquared(lightPath[1].p, lightPath[0].p) /
00171 AbsDot(lightPath[0].ns, lightPath[0].wo);
00172 else
00173 lightDirectPdf = 0.f;
00174
00175 for (int i = 0; i < nEye; ++i) {
00176
00177 if (i == 0)
00178 L += eyePath[i].Le;
00179 if (i > 0 && eyePath[i].ePdf > 0.f && !eyePath[i].Le.Black()) {
00180
00181 directPath[0].wi = Vector(eyePath[i].ng);
00182 directPath[0].bsdf = eyePath[i].eBsdf;
00183 directPath[0].p = eyePath[i].p;
00184 directPath[0].ng = eyePath[i].ng;
00185 directPath[0].ns = eyePath[i].ns;
00186 directPath[0].dAWeight = eyePath[i].ePdf;
00187 float err = eyePath[i].rrWeight;
00188 float errR = eyePath[i].rrRWeight;
00189 eyePath[i].Le *= evalPath(scene, eyePath, i + 1, directPath, 0);
00190 if (!eyePath[i].Le.Black()) {
00191 eyePath[i].Le /= weightPath(eyePath, i + 1, directPath, 0, eyePath[i].ePdfDirect, false);
00192 L += eyePath[i].Le;
00193 }
00194 eyePath[i].rrWeight = err;
00195 eyePath[i].rrRWeight = errR;
00196 }
00197 if (eyePath[i].bsdf == NULL) {
00198 for (unsigned int lightNumber = 0; lightNumber < scene->lights.size(); ++lightNumber) {
00199 Light *light = scene->lights[lightNumber];
00200 if (i == 0)
00201 L += light->Le(RayDifferential(eyePath[i].p, -eyePath[i].wi));
00202 else {
00203 eyePath[i].Le = light->Le(scene, RayDifferential(eyePath[i].p, -eyePath[i].wi), eyePath[i - 1].ns, &(directPath[0].bsdf), &(directPath[0].dAWeight), &(eyePath[i].ePdfDirect));
00204 if (directPath[0].bsdf && directPath[0].dAWeight > 0.f && !eyePath[i].Le.Black()) {
00205 eyePath[i].p = directPath[0].bsdf->dgShading.p;
00206 directPath[0].p = eyePath[i].p;
00207 eyePath[i].ng = directPath[0].bsdf->dgShading.nn;
00208 directPath[0].ng = eyePath[i].ng;
00209 directPath[0].wi = Vector(directPath[0].ng);
00210 eyePath[i].ns = eyePath[i].ng;
00211 directPath[0].ns = directPath[0].ng;
00212 eyePath[i].rrWeight = 1.f;
00213 eyePath[i].rrRWeight = 1.f;
00214 eyePath[i].f = 1.f;
00215 eyePath[i].Le *= evalPath(scene, eyePath, i + 1, directPath, 0);
00216 if (!eyePath[i].Le.Black()) {
00217 eyePath[i].Le /= weightPath(eyePath, i + 1, directPath, 0, eyePath[i].ePdfDirect, false);
00218 L += eyePath[i].Le;
00219 }
00220 }
00221 }
00222 }
00223 break;
00224 }
00225
00226 float *data = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), sampleDirectOffset, i);
00227 for (int lightDirectNumber = 0; lightDirectNumber < numberOfLights; ++lightDirectNumber) {
00228 float portal = data[2];
00229 if (lightStrategy == SAMPLE_ONE_UNIFORM) {
00230
00231 portal *= numberOfLights;
00232 lightDirectNumber = min(Floor2Int(portal),
00233 numberOfLights - 1);
00234 portal -= lightDirectNumber;
00235 }
00236 Light *lightDirect = scene->lights[lightDirectNumber];
00237 float pdfDirect;
00238 BSDF *bsdfDirect;
00239 VisibilityTester visibility;
00240
00241 SWCSpectrum Ld = lightDirect->Sample_L(scene, eyePath[i].p, eyePath[i].ns,
00242 data[0], data[1], portal, &bsdfDirect, &(directPath[0].dAWeight), &pdfDirect,
00243 &visibility);
00244
00245 if (pdfDirect > 0.f && !Ld.Black() && visibility.Unoccluded(scene)) {
00246
00247 directPath[0].wi = Vector(bsdfDirect->dgShading.nn);
00248 directPath[0].bsdf = bsdfDirect;
00249 directPath[0].p = bsdfDirect->dgShading.p;
00250 directPath[0].ng = bsdfDirect->dgShading.nn;
00251 directPath[0].ns = directPath[0].ng;
00252
00253 float err = eyePath[i].rrWeight;
00254 float errR = eyePath[i].rrRWeight;
00255 Ld *= evalPath(scene, eyePath, i + 1, directPath, 1);
00256 if (!Ld.Black()) {
00257 if (lightStrategy == SAMPLE_ONE_UNIFORM)
00258 pdfDirect /= lightWeight;
00259 Ld /= pdfDirect *
00260 weightPath(eyePath, i + 1, directPath, 1, pdfDirect, true);
00261 L += Ld;
00262 }
00263 eyePath[i].rrWeight = err;
00264 eyePath[i].rrRWeight = errR;
00265 }
00266 if (lightStrategy == SAMPLE_ONE_UNIFORM)
00267 break;
00268 }
00269
00270 float directPdf = light->Pdf(eyePath[i].p, eyePath[i].ns,
00271 Normalize(lightPath[0].p - eyePath[i].p)) *
00272 DistanceSquared(eyePath[i].p, lightPath[0].p) /
00273 AbsDot(lightPath[0].ns, lightPath[0].wo);
00274 for (int j = 1; j <= nLight; ++j) {
00275 SWCSpectrum Ll(Le);
00276 float err = eyePath[i].rrWeight;
00277 float errR = eyePath[i].rrRWeight;
00278 float lrr = lightPath[j - 1].rrWeight;
00279 float lrrR = lightPath[j - 1].rrRWeight;
00280 Ll *= evalPath(scene, eyePath, i + 1, lightPath, j);
00281 if (!Ll.Black()) {
00282 Ll /= weightPath(eyePath, i + 1, lightPath, j, j == 1 ? directPdf : lightDirectPdf, false);
00283 L += Ll;
00284 }
00285 eyePath[i].rrWeight = err;
00286 eyePath[i].rrRWeight = errR;
00287 lightPath[j - 1].rrWeight = lrr;
00288 lightPath[j - 1].rrRWeight = lrrR;
00289 }
00290 }
00291 XYZColor color(L.ToXYZ());
00292 if (color.y() > 0.f)
00293 sample->AddContribution(sample->imageX, sample->imageY,
00294 color, alpha ? *alpha : 1.f);
00295 return L;
00296 }
00297 int BidirIntegrator::generatePath(const Scene *scene, const Ray &r,
00298 const Sample *sample, const int sampleOffset,
00299 vector<BidirVertex> &vertices) const
00300 {
00301 RayDifferential ray(r.o, r.d);
00302 int nVerts = 0;
00303 while (nVerts < (int)(vertices.size())) {
00304
00305 BidirVertex &v = vertices[nVerts];
00306 const float *data = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), sampleOffset, nVerts);
00307 Intersection isect;
00308 ++nVerts;
00309 v.wi = -ray.d;
00310 if (!scene->Intersect(ray, &isect)) {
00311 v.p = ray.o;
00312 v.bsdf = NULL;
00313 break;
00314 }
00315 v.bsdf = isect.GetBSDF(ray, fabsf(2.f * data[3] - 1.f));
00316 if (nVerts == 1)
00317 v.Le = isect.Le(v.wi);
00318 else
00319 v.Le = isect.Le(ray, vertices[nVerts - 2].ns, &v.eBsdf, &v.ePdf, &v.ePdfDirect);
00320 v.p = isect.dg.p;
00321 v.ng = isect.dg.nn;
00322 v.ns = v.bsdf->dgShading.nn;
00323
00324 v.f = v.bsdf->Sample_f(v.wi, &v.wo, data[1], data[2], data[3],
00325 &v.bsdfWeight, BSDF_ALL, &v.flags, &v.bsdfRWeight);
00326 if (v.bsdfWeight == 0.f || v.f.Black())
00327 break;
00328 v.rrWeight = min<float>(1.f,
00329 v.f.filter() * AbsDot(v.wo, v.ns) / v.bsdfWeight);
00330 v.rrRWeight = min<float>(1.f,
00331 v.f.filter() * AbsDot(v.wi, v.ns) / v.bsdfRWeight);
00332 if (nVerts > 3 && v.rrWeight < data[0])
00333 break;
00334
00335 ray = RayDifferential(v.p, v.wo);
00336 }
00337
00338 for (int i = 0; i < nVerts - 1; ++i) {
00339 vertices[i + 1].dAWeight = vertices[i].bsdfWeight *
00340 AbsDot(vertices[i + 1].wi, vertices[i + 1].ns) /
00341 DistanceSquared(vertices[i].p, vertices[i + 1].p);
00342 if (vertices[i + 1].bsdf == NULL)
00343 break;
00344 vertices[i].dARWeight = vertices[i + 1].bsdfRWeight *
00345 AbsDot(vertices[i].wo, vertices[i].ns) /
00346 DistanceSquared(vertices[i].p, vertices[i + 1].p);
00347 }
00348 return nVerts;
00349 }
00350
00351 float BidirIntegrator::weightPath(vector<BidirVertex> &eye, int nEye,
00352 vector<BidirVertex> &light, int nLight, float pdfLight, bool directLight) const
00353 {
00354
00355 float weight = 1.f, p = 1.f, pdfDirect = 0.f;
00356 int eyePos, lightPos;
00357
00358
00359
00360 if (nLight == 0) {
00361
00362 p *= light[0].dAWeight / eye[nEye - 1].dAWeight;
00363
00364
00365
00366 if (p > 0.f && (eye[nEye - 2].flags & BSDF_SPECULAR) == 0)
00367 weight += p;
00368 eyePos = nEye - 2;
00369 lightPos = 0;
00370 } else {
00371 eyePos = nEye - 1;
00372 lightPos = nLight - 1;
00373 }
00374
00375
00376
00377 if (lightPos == 0) {
00378
00379 if (light[0].dAWeight > 0.f)
00380 pdfDirect = p * pdfLight / light[0].dAWeight;
00381 else
00382 pdfDirect = p;
00383
00384
00385 if (pdfDirect > 0.f && (nEye <= 1 || (eye[nEye - 2].flags & BSDF_SPECULAR) == 0))
00386 weight += pdfDirect;
00387 }
00388
00389
00390
00391
00392
00393 if (eyePos >= 0 && nLight + nEye - eyePos - 1 < maxLightDepth) {
00394 Vector w = light[lightPos].p - eye[eyePos].p;
00395 float squaredDistance = Dot(w, w);
00396 w /= sqrtf(squaredDistance);
00397 float pdf = light[lightPos].bsdf->Pdf(light[lightPos].wi, -w);
00398 pdf *= AbsDot(eye[eyePos].ns, w) / squaredDistance;
00399
00400 if (nLight > 3) {
00401 if (pdf > 0.f)
00402 pdf *= light[lightPos].rrWeight;
00403 else
00404 pdf = 0.f;
00405 }
00406 p *= pdf / eye[eyePos].dAWeight;
00407
00408
00409 if (p > 0.f && eye[eyePos].dAWeight > 0.f && (eyePos == 0 || (eye[eyePos - 1].flags & BSDF_SPECULAR) == 0))
00410 weight += p;
00411 }
00412
00413
00414
00415 for (int i = eyePos - 1; i > max(0, nEye + nLight - maxLightDepth - 1); --i) {
00416 p *= eye[i].dARWeight / eye[i].dAWeight;
00417 if (nLight + nEye - i > 3)
00418 p *= eye[i + 1].rrRWeight;
00419 if (i > 3)
00420 p /= eye[i - 1].rrWeight;
00421
00422
00423 if (p > 0.f && (eye[i].flags & BSDF_SPECULAR) == 0 &&
00424 (eye[i - 1].flags & BSDF_SPECULAR) == 0)
00425 weight += p;
00426 }
00427
00428
00429 if (nEye > 0 && nEye + nLight - maxLightDepth - 1 <= 0 && eye[0].dAWeight > 0.f) {
00430 p *= eye[0].dARWeight / eye[0].dAWeight;
00431 if (nLight + nEye > 3) {
00432 if (nEye > 1)
00433 p *= eye[1].rrRWeight;
00434 else
00435 p *= light[nLight - 1].rrWeight;
00436 }
00437 if (p > 0.f)
00438 weight += p;
00439 }
00440
00441
00442 p = 1.f;
00443
00444
00445
00446 if (nEye == 0) {
00447 p *= eye[0].dAWeight / light[nLight - 1].dAWeight;
00448 if (p > 0.f && (light[nLight - 2].flags & BSDF_SPECULAR) == 0)
00449 weight += p;
00450 lightPos = nLight - 2;
00451 eyePos = 0;
00452 } else {
00453 lightPos = nLight - 1;
00454 eyePos = nEye - 1;
00455 }
00456
00457
00458
00459
00460
00461 if (lightPos >= 0 && nEye + nLight - lightPos - 1 < maxEyeDepth) {
00462 Vector w = eye[eyePos].p - light[lightPos].p;
00463 float squaredDistance = Dot(w, w);
00464 w /= sqrtf(squaredDistance);
00465 float pdf = eye[eyePos].bsdf->Pdf(eye[eyePos].wi, -w);
00466 pdf *= AbsDot(light[lightPos].ns, w) / squaredDistance;
00467
00468 if (nEye > 3) {
00469 if (pdf > 0.f)
00470 pdf *= eye[eyePos].rrWeight;
00471 else
00472 pdf = 0.f;
00473 }
00474 p *= pdf / light[lightPos].dAWeight;
00475
00476
00477 if (p > 0.f && light[lightPos].dAWeight > 0.f && (lightPos == 0 || (light[lightPos - 1].flags & BSDF_SPECULAR) == 0))
00478 weight += p;
00479 }
00480
00481
00482
00483 for (int i = lightPos - 1; i > max(0, nLight + nEye - maxEyeDepth - 1); --i) {
00484 p *= light[i].dARWeight / light[i].dAWeight;
00485 if (nEye + nLight - i > 3)
00486 p *= light[i + 1].rrRWeight;
00487 if (i > 3)
00488 p /= light[i - 1].rrWeight;
00489
00490
00491 if (p > 0.f && (light[i].flags & BSDF_SPECULAR) == 0 &&
00492 (light[i - 1].flags & BSDF_SPECULAR) == 0)
00493 weight += p;
00494 }
00495
00496
00497
00498 if (nLight > 1 && nLight + nEye - maxEyeDepth - 1 <= 0 && pdfLight > 0. && light[0].dAWeight > 0.f) {
00499 if (light[0].dAWeight > 0.f)
00500 pdfDirect = p * pdfLight / light[0].dAWeight;
00501 else
00502 pdfDirect = p;
00503 if (pdfDirect > 0.f && (light[1].flags & BSDF_SPECULAR) == 0)
00504 weight += pdfDirect;
00505 }
00506
00507
00508 if (nLight > 0 && nLight + nEye - maxEyeDepth - 1 <= 0 && light[0].dAWeight > 0.f) {
00509 p *= light[0].dARWeight / light[0].dAWeight;
00510 if (nEye + nLight > 3) {
00511 if (nLight > 1)
00512 p *= light[1].rrRWeight;
00513 else
00514 p *= eye[nEye - 1].rrWeight;
00515 }
00516 if (p > 0.f)
00517 weight += p;
00518 }
00519
00520
00521 if (directLight && pdfDirect > 0.f)
00522 weight /= pdfDirect;
00523 return max(1.f, weight);
00524 }
00525 SWCSpectrum BidirIntegrator::evalPath(const Scene *scene, vector<BidirVertex> &eye,
00526 int nEye, vector<BidirVertex> &light, int nLight) const
00527 {
00528 SWCSpectrum L(1.f);
00529 for (int i = 0; i < nEye - 1; ++i)
00530 L *= eye[i].f * AbsDot(eye[i].wo, eye[i].ns) /
00531 (eye[i].bsdfWeight * (i > 3 ? eye[i].rrWeight : 1.f));
00532 if (nLight > 0 && nEye > 0) {
00533 Vector w = Normalize(light[nLight - 1].p - eye[nEye - 1].p);
00534 L *= eye[nEye - 1].bsdf->f(eye[nEye - 1].wi, w) *
00535 G(eye[nEye - 1], light[nLight - 1]) *
00536 light[nLight - 1].bsdf->f(light[nLight - 1].wi, -w);
00537 eye[nEye - 1].rrWeight = min<float>(1.f,
00538 eye[nEye - 1].bsdf->f(eye[nEye - 1].wi, w).filter() *
00539 AbsDot(eye[nEye - 1].ns, w) /
00540 eye[nEye - 1].bsdf->Pdf(eye[nEye - 1].wi, w));
00541 eye[nEye - 1].rrRWeight = min<float>(1.f,
00542 eye[nEye - 1].bsdf->f(w, eye[nEye - 1].wi).filter() *
00543 AbsDot(eye[nEye - 1].wi, eye[nEye - 1].ns) /
00544 eye[nEye - 1].bsdf->Pdf(w, eye[nEye - 1].wi));
00545 light[nLight - 1].rrWeight = min<float>(1.f,
00546 light[nLight - 1].bsdf->f(light[nLight - 1].wi, -w).filter() *
00547 AbsDot(light[nLight - 1].ns, -w) /
00548 light[nLight - 1].bsdf->Pdf(light[nLight - 1].wi, -w));
00549 light[nLight - 1].rrRWeight = min<float>(1.f,
00550 light[nLight - 1].bsdf->f(-w, light[nLight - 1].wi).filter() *
00551 AbsDot(light[nLight - 1].wi, light[nLight - 1].ns) /
00552 light[nLight - 1].bsdf->Pdf(-w, light[nLight - 1].wi));
00553 }
00554 for (int i = nLight - 2; i >= 0; --i)
00555 L *= light[i].f * AbsDot(light[i].wo, light[i].ns) /
00556 (light[i].bsdfWeight * (i > 3 ? light[i].rrWeight : 1.f));
00557 if (L.Black())
00558 return 0.;
00559 if (nLight > 0 && nEye > 0 && !visible(scene, eye[nEye - 1].p, light[nLight - 1].p))
00560 return 0.;
00561 return L;
00562 }
00563 float BidirIntegrator::G(const BidirVertex &v0, const BidirVertex &v1)
00564 {
00565 Vector w = Normalize(v1.p - v0.p);
00566 return AbsDot(v0.ns, w) * AbsDot(v1.ns, -w) /
00567 DistanceSquared(v0.p, v1.p);
00568 }
00569 bool BidirIntegrator::visible(const Scene *scene, const Point &P0,
00570 const Point &P1)
00571 {
00572 Ray ray(P0, P1 - P0, RAY_EPSILON, 1.f - RAY_EPSILON);
00573 return !scene->IntersectP(ray);
00574 }
00575 SurfaceIntegrator* BidirIntegrator::CreateSurfaceIntegrator(const ParamSet ¶ms)
00576 {
00577 int eyeDepth = params.FindOneInt("eyedepth", 8);
00578 int lightDepth = params.FindOneInt("lightdepth", 8);
00579 LightStrategy estrategy;
00580 string st = params.FindOneString("strategy", "auto");
00581 if (st == "one") estrategy = SAMPLE_ONE_UNIFORM;
00582 else if (st == "all") estrategy = SAMPLE_ALL_UNIFORM;
00583 else if (st == "auto") estrategy = SAMPLE_AUTOMATIC;
00584 else {
00585 std::stringstream ss;
00586 ss<<"Strategy '"<<st<<"' for direct lighting unknown. Using \"auto\".";
00587 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00588 estrategy = SAMPLE_AUTOMATIC;
00589 }
00590 return new BidirIntegrator(eyeDepth, lightDepth, estrategy);
00591 }