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 "exphotonmap.h"
00025
00026 using namespace lux;
00027
00028
00029 ExPhotonIntegrator* ExPhotonIntegrator::clone() const
00030 {
00031 return new ExPhotonIntegrator(*this);
00032 }
00033
00034 EPhotonProcess::EPhotonProcess(u_int mp, const Point &P)
00035 : p(P) {
00036 photons = 0;
00037 nLookup = mp;
00038 foundPhotons = 0;
00039 }
00040 Spectrum ExPhotonIntegrator::estimateE(
00041 KdTree<EPhoton, EPhotonProcess> *map, int count,
00042 const Point &p, const Normal &n) const {
00043 if (!map) return 0.f;
00044
00045 EPhotonProcess proc(nLookup, p);
00046 proc.photons = (EClosePhoton *)alloca(nLookup *
00047 sizeof(EClosePhoton));
00048 float md2 = maxDistSquared;
00049 map->Lookup(p, proc, md2);
00050
00051 EClosePhoton *photons = proc.photons;
00052 Spectrum E(0.);
00053 for (u_int i = 0; i < proc.foundPhotons; ++i)
00054 if (Dot(n, photons[i].photon->wi) > 0.)
00055 E += photons[i].photon->alpha;
00056 return E / (float(count) * md2 * M_PI);
00057 }
00058 void EPhotonProcess::operator()(const EPhoton &photon,
00059 float distSquared, float &maxDistSquared) const {
00060
00061
00062
00063 if (foundPhotons < nLookup) {
00064
00065 photons[foundPhotons++] = EClosePhoton(&photon, distSquared);
00066 if (foundPhotons == nLookup) {
00067 std::make_heap(&photons[0], &photons[nLookup]);
00068 maxDistSquared = photons[0].distanceSquared;
00069 }
00070 }
00071 else {
00072
00073
00074 std::pop_heap(&photons[0], &photons[nLookup]);
00075 photons[nLookup-1] = EClosePhoton(&photon, distSquared);
00076 std::push_heap(&photons[0], &photons[nLookup]);
00077 maxDistSquared = photons[0].distanceSquared;
00078 }
00079 }
00080 Spectrum ExPhotonIntegrator::LPhoton(
00081 KdTree<EPhoton, EPhotonProcess> *map,
00082 int nPaths, int nLookup, BSDF *bsdf,
00083 const Intersection &isect, const Vector &wo,
00084 float maxDistSquared) {
00085 Spectrum L(0.);
00086 if (!map) return L;
00087 BxDFType nonSpecular = BxDFType(BSDF_REFLECTION |
00088 BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY);
00089 if (bsdf->NumComponents(nonSpecular) == 0)
00090 return L;
00091
00092
00093 EPhotonProcess proc(nLookup, isect.dg.p);
00094 proc.photons =
00095 (EClosePhoton *)alloca(nLookup * sizeof(EClosePhoton));
00096
00097
00098 map->Lookup(isect.dg.p, proc, maxDistSquared);
00099
00100
00101
00102
00103 EClosePhoton *photons = proc.photons;
00104 int nFound = proc.foundPhotons;
00105 Normal Nf = Dot(wo, bsdf->dgShading.nn) < 0 ? -bsdf->dgShading.nn :
00106 bsdf->dgShading.nn;
00107
00108 if (bsdf->NumComponents(BxDFType(BSDF_REFLECTION |
00109 BSDF_TRANSMISSION | BSDF_GLOSSY)) > 0) {
00110
00111 for (int i = 0; i < nFound; ++i) {
00112 const EPhoton *p = photons[i].photon;
00113 BxDFType flag = Dot(Nf, p->wi) > 0.f ?
00114 BSDF_ALL_REFLECTION : BSDF_ALL_TRANSMISSION;
00115 float k = Ekernel(p, isect.dg.p, maxDistSquared);
00116 L += (k / nPaths) * bsdf->f(wo, p->wi, flag) * p->alpha;
00117 }
00118 }
00119 else {
00120
00121 Spectrum Lr(0.), Lt(0.);
00122 for (int i = 0; i < nFound; ++i) {
00123 if (Dot(Nf, photons[i].photon->wi) > 0.f) {
00124 float k = Ekernel(photons[i].photon, isect.dg.p,
00125 maxDistSquared);
00126 Lr += (k / nPaths) * photons[i].photon->alpha;
00127 }
00128 else {
00129 float k = Ekernel(photons[i].photon, isect.dg.p,
00130 maxDistSquared);
00131 Lt += (k / nPaths) * photons[i].photon->alpha;
00132 }
00133 }
00134 L += Lr * bsdf->rho(wo, BSDF_ALL_REFLECTION) * INV_PI +
00135 Lt * bsdf->rho(wo, BSDF_ALL_TRANSMISSION) * INV_PI;
00136 }
00137 return L;
00138 }
00139
00140 ExPhotonIntegrator::ExPhotonIntegrator(int ncaus, int nind,
00141 int nl, int mdepth, float mdist, bool fg,
00142 int gs, float rrt, float ga) {
00143 nCausticPhotons = ncaus;
00144 nIndirectPhotons = nind;
00145 nLookup = nl;
00146 maxDistSquared = mdist * mdist;
00147 maxSpecularDepth = mdepth;
00148 causticMap = indirectMap = NULL;
00149 radianceMap = NULL;
00150 specularDepth = 0;
00151 finalGather = fg;
00152 gatherSamples = gs;
00153 rrTreshold = rrt;
00154 cosGatherAngle = cos(Radians(ga));
00155 }
00156 ExPhotonIntegrator::~ExPhotonIntegrator() {
00157 delete causticMap;
00158 delete indirectMap;
00159 delete radianceMap;
00160 }
00161 void ExPhotonIntegrator::RequestSamples(Sample *sample,
00162 const Scene *scene) {
00163
00164 u_int nLights = scene->lights.size();
00165 lightSampleOffset = new int[nLights];
00166 bsdfSampleOffset = new int[nLights];
00167 bsdfComponentOffset = new int[nLights];
00168 for (u_int i = 0; i < nLights; ++i) {
00169 const Light *light = scene->lights[i];
00170 int lightSamples =
00171 scene->sampler->RoundSize(light->nSamples);
00172 lightSampleOffset[i] = sample->Add2D(lightSamples);
00173 bsdfSampleOffset[i] = sample->Add2D(lightSamples);
00174 bsdfComponentOffset[i] = sample->Add1D(lightSamples);
00175 }
00176 lightNumOffset = -1;
00177
00178 if (finalGather) {
00179 gatherSamples = scene->sampler->RoundSize(max(1,
00180 gatherSamples/2));
00181 gatherSampleOffset[0] = sample->Add2D(gatherSamples);
00182 gatherSampleOffset[1] = sample->Add2D(gatherSamples);
00183 gatherComponentOffset[0] = sample->Add1D(gatherSamples);
00184 gatherComponentOffset[1] = sample->Add1D(gatherSamples);
00185 }
00186 }
00187
00188 void ExPhotonIntegrator::Preprocess(const Scene *scene) {
00189 if (scene->lights.size() == 0) return;
00190 ProgressReporter progress(nCausticPhotons+
00191 nIndirectPhotons, "Shooting photons");
00192 vector<EPhoton> causticPhotons;
00193 vector<EPhoton> indirectPhotons;
00194 vector<EPhoton> directPhotons;
00195 vector<ERadiancePhoton> radiancePhotons;
00196 causticPhotons.reserve(nCausticPhotons);
00197 indirectPhotons.reserve(nIndirectPhotons);
00198
00199 static StatsCounter nshot("Photon Map","Number of photons shot from lights");
00200 bool causticDone = (nCausticPhotons == 0);
00201 bool indirectDone = (nIndirectPhotons == 0);
00202
00203
00204 int nLights = int(scene->lights.size());
00205 float *lightPower = (float *)alloca(nLights * sizeof(float));
00206 float *lightCDF = (float *)alloca((nLights+1) * sizeof(float));
00207 for (int i = 0; i < nLights; ++i)
00208 lightPower[i] = scene->lights[i]->Power(scene).y();
00209 float totalPower;
00210 ComputeStep1dCDF(lightPower, nLights, &totalPower, lightCDF);
00211
00212 vector<Spectrum> rpReflectances, rpTransmittances;
00213
00214 while (!causticDone || !indirectDone) {
00215 ++nshot;
00216
00217 if (nshot > 500000 &&
00218 (unsuccessful(nCausticPhotons,
00219 causticPhotons.size(),
00220 nshot) ||
00221 unsuccessful(nIndirectPhotons,
00222 indirectPhotons.size(),
00223 nshot))) {
00224 luxError(LUX_CONSISTENCY,LUX_ERROR,"Unable to store enough photons. Giving up.");
00225 return;
00226 }
00227
00228
00229 float u[4];
00230 u[0] = RadicalInverse((int)nshot+1, 2);
00231 u[1] = RadicalInverse((int)nshot+1, 3);
00232 u[2] = RadicalInverse((int)nshot+1, 5);
00233 u[3] = RadicalInverse((int)nshot+1, 7);
00234
00235
00236 float lightPdf;
00237 float uln = RadicalInverse((int)nshot+1, 11);
00238 int lightNum = Floor2Int(SampleStep1d(lightPower, lightCDF,
00239 totalPower, nLights, uln, &lightPdf) * nLights);
00240 lightNum = min(lightNum, nLights-1);
00241 const Light *light = scene->lights[lightNum];
00242
00243 RayDifferential photonRay;
00244 float pdf;
00245 Spectrum alpha = light->Sample_L(scene, u[0], u[1], u[2], u[3],
00246 &photonRay, &pdf);
00247 if (pdf == 0.f || alpha.Black()) continue;
00248 alpha /= pdf * lightPdf;
00249
00250 if (!alpha.Black()) {
00251
00252 bool specularPath = false;
00253 Intersection photonIsect;
00254 int nIntersections = 0;
00255 while (scene->Intersect(photonRay, &photonIsect)) {
00256 ++nIntersections;
00257
00258 alpha *= scene->Transmittance(photonRay);
00259 Vector wo = -photonRay.d;
00260 MemoryArena arena;
00261 BSDF *photonBSDF = photonIsect.GetBSDF( photonRay);
00262 BxDFType specularType = BxDFType(BSDF_REFLECTION |
00263 BSDF_TRANSMISSION | BSDF_SPECULAR);
00264 bool hasNonSpecular = (photonBSDF->NumComponents() >
00265 photonBSDF->NumComponents(specularType));
00266 if (hasNonSpecular) {
00267
00268 EPhoton photon(photonIsect.dg.p, alpha, wo);
00269 if (nIntersections == 1) {
00270
00271 directPhotons.push_back(photon);
00272 }
00273 else {
00274
00275 if (specularPath) {
00276
00277 if (!causticDone) {
00278 causticPhotons.push_back(photon);
00279 if (causticPhotons.size() == nCausticPhotons) {
00280 causticDone = true;
00281 nCausticPaths = (int)nshot;
00282 causticMap = new KdTree<EPhoton, EPhotonProcess>(causticPhotons);
00283 }
00284 progress.Update();
00285 }
00286 }
00287 else {
00288
00289 if (!indirectDone) {
00290 indirectPhotons.push_back(photon);
00291 if (indirectPhotons.size() == nIndirectPhotons) {
00292 indirectDone = true;
00293 nIndirectPaths = (int)nshot;
00294 indirectMap = new KdTree<EPhoton, EPhotonProcess>(indirectPhotons);
00295 }
00296 progress.Update();
00297 }
00298 }
00299 }
00300 if (finalGather && lux::random::floatValue() < .125f) {
00301
00302
00303 Normal n = photonIsect.dg.nn;
00304 if (Dot(n, photonRay.d) > 0.f) n = -n;
00305 radiancePhotons.push_back(ERadiancePhoton(photonIsect.dg.p, n));
00306 Spectrum rho_r = photonBSDF->rho(BSDF_ALL_REFLECTION);
00307 rpReflectances.push_back(rho_r);
00308 Spectrum rho_t = photonBSDF->rho(BSDF_ALL_TRANSMISSION);
00309 rpTransmittances.push_back(rho_t);
00310 }
00311 }
00312
00313 Vector wi;
00314 float pdf;
00315 BxDFType flags;
00316
00317 float u1, u2, u3;
00318 if (nIntersections == 1) {
00319 u1 = RadicalInverse((int)nshot+1, 13);
00320 u2 = RadicalInverse((int)nshot+1, 17);
00321 u3 = RadicalInverse((int)nshot+1, 19);
00322 }
00323 else {
00324 u1 = lux::random::floatValue();
00325 u2 = lux::random::floatValue();
00326 u3 = lux::random::floatValue();
00327 }
00328
00329
00330 Spectrum fr = photonBSDF->Sample_f(wo, &wi, u1, u2, u3,
00331 &pdf, BSDF_ALL, &flags);
00332 if (fr.Black() || pdf == 0.f)
00333 break;
00334 Spectrum anew = alpha * fr *
00335 AbsDot(wi, photonBSDF->dgShading.nn) / pdf;
00336 float continueProb = min(1.f, anew.y() / alpha.y());
00337 if (lux::random::floatValue() > continueProb || nIntersections > 10)
00338 break;
00339 alpha = anew / continueProb;
00340 specularPath = (nIntersections == 1 || specularPath) &&
00341 ((flags & BSDF_SPECULAR) != 0);
00342 photonRay = RayDifferential(photonIsect.dg.p, wi);
00343 }
00344 }
00345
00346 }
00347
00348 progress.Done();
00349
00350
00351 KdTree<EPhoton, EPhotonProcess> directMap(directPhotons);
00352 int nDirectPaths = nshot;
00353 if (finalGather) {
00354 ProgressReporter p2(radiancePhotons.size(), "Computing photon radiances");
00355 for (u_int i = 0; i < radiancePhotons.size(); ++i) {
00356
00357 ERadiancePhoton &rp = radiancePhotons[i];
00358 const Spectrum &rho_r = rpReflectances[i];
00359 const Spectrum &rho_t = rpTransmittances[i];
00360 Spectrum E;
00361 Point p = rp.p;
00362 Normal n = rp.n;
00363 if (!rho_r.Black()) {
00364 E = estimateE(&directMap, nDirectPaths, p, n) +
00365 estimateE(indirectMap, nIndirectPaths, p, n) +
00366 estimateE(causticMap, nCausticPaths, p, n);
00367 rp.Lo += E * INV_PI * rho_r;
00368 }
00369 if (!rho_t.Black()) {
00370 E = estimateE(&directMap, nDirectPaths, p, -n) +
00371 estimateE(indirectMap, nIndirectPaths, p, -n) +
00372 estimateE(causticMap, nCausticPaths, p, -n);
00373 rp.Lo += E * INV_PI * rho_t;
00374 }
00375 p2.Update();
00376 }
00377 radianceMap = new KdTree<ERadiancePhoton,
00378 ERadiancePhotonProcess>(radiancePhotons);
00379 p2.Done();
00380 }
00381 }
00382
00383 Spectrum ExPhotonIntegrator::Li(const Scene *scene,
00384 const RayDifferential &ray, const Sample *sample,
00385 float *alpha) const {
00386
00387 Spectrum L(0.);
00388 Intersection isect;
00389 if (scene->Intersect(ray, &isect)) {
00390 if (alpha) *alpha = 1.;
00391 Vector wo = -ray.d;
00392
00393 L += isect.Le(wo);
00394
00395 BSDF *bsdf = isect.GetBSDF( ray);
00396 const Point &p = bsdf->dgShading.p;
00397 const Normal &n = bsdf->dgShading.nn;
00398 L += UniformSampleAllLights(scene, p, n,
00399 wo, bsdf, sample,
00400 lightSampleOffset, bsdfSampleOffset,
00401 bsdfComponentOffset);
00402
00403
00404 L += LPhoton(causticMap, nCausticPaths, nLookup, bsdf,
00405 isect, wo, maxDistSquared);
00406 if (finalGather) {
00407 #if 1
00408
00409 BxDFType nonSpecular = BxDFType(BSDF_REFLECTION |
00410 BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY);
00411 if (bsdf->NumComponents(nonSpecular) > 0) {
00412
00413 u_int nIndirSamplePhotons = 50;
00414 EPhotonProcess proc(nIndirSamplePhotons, p);
00415 proc.photons = (EClosePhoton *)alloca(nIndirSamplePhotons *
00416 sizeof(EClosePhoton));
00417 float searchDist2 = maxDistSquared;
00418 while (proc.foundPhotons < nIndirSamplePhotons) {
00419 float md2 = searchDist2;
00420 proc.foundPhotons = 0;
00421 indirectMap->Lookup(p, proc, md2);
00422 searchDist2 *= 2.f;
00423 }
00424
00425 Vector *photonDirs = (Vector *)alloca(nIndirSamplePhotons *
00426 sizeof(Vector));
00427 for (u_int i = 0; i < nIndirSamplePhotons; ++i)
00428 photonDirs[i] = proc.photons[i].photon->wi;
00429
00430 Spectrum Li = 0.;
00431
00432 for (int i = 0; i < gatherSamples; ++i) {
00433
00434 Vector wi;
00435 float u1 = sample->twoD[gatherSampleOffset[0]][2*i];
00436 float u2 = sample->twoD[gatherSampleOffset[0]][2*i+1];
00437 float u3 = sample->oneD[gatherComponentOffset[0]][i];
00438 float pdf;
00439 Spectrum fr = bsdf->Sample_f(wo, &wi, u1, u2, u3,
00440 &pdf, BxDFType(BSDF_ALL & (~BSDF_SPECULAR)));
00441 if (fr.Black() || pdf == 0.f) continue;
00442
00443 RayDifferential bounceRay(p, wi);
00444
00445 Intersection gatherIsect;
00446 if (scene->Intersect(bounceRay, &gatherIsect)) {
00447
00448 Spectrum Lindir = 0.f;
00449 Normal n = gatherIsect.dg.nn;
00450 if (Dot(n, bounceRay.d) > 0) n = -n;
00451 ERadiancePhotonProcess proc(gatherIsect.dg.p, n);
00452 float md2 = INFINITY;
00453 radianceMap->Lookup(gatherIsect.dg.p, proc, md2);
00454 if (proc.photon)
00455 Lindir = proc.photon->Lo;
00456 Lindir *= scene->Transmittance(bounceRay);
00457
00458
00459 float photonPdf = 0.f;
00460 float conePdf = UniformConePdf(cosGatherAngle);
00461 for (u_int j = 0; j < nIndirSamplePhotons; ++j)
00462 if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle)
00463 photonPdf += conePdf;
00464 photonPdf /= nIndirSamplePhotons;
00465 float wt = PowerHeuristic(gatherSamples, pdf,
00466 gatherSamples, photonPdf);
00467 Li += fr * Lindir * AbsDot(wi, n) * wt / pdf;
00468 }
00469 }
00470 L += Li / gatherSamples;
00471
00472 Li = 0.;
00473 for (int i = 0; i < gatherSamples; ++i) {
00474
00475 float u1 = sample->oneD[gatherComponentOffset[1]][i];
00476 float u2 = sample->twoD[gatherSampleOffset[1]][2*i];
00477 float u3 = sample->twoD[gatherSampleOffset[1]][2*i+1];
00478 int photonNum = min((int)nIndirSamplePhotons - 1,
00479 Floor2Int(u1 * nIndirSamplePhotons));
00480
00481 Vector vx, vy;
00482 CoordinateSystem(photonDirs[photonNum], &vx, &vy);
00483 Vector wi = UniformSampleCone(u2, u3, cosGatherAngle, vx, vy,
00484 photonDirs[photonNum]);
00485
00486 Spectrum fr = bsdf->f(wo, wi);
00487 if (fr.Black()) continue;
00488
00489 float photonPdf = 0.f;
00490 float conePdf = UniformConePdf(cosGatherAngle);
00491 for (u_int j = 0; j < nIndirSamplePhotons; ++j)
00492 if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle)
00493 photonPdf += conePdf;
00494 photonPdf /= nIndirSamplePhotons;
00495 RayDifferential bounceRay(p, wi);
00496
00497 Intersection gatherIsect;
00498 if (scene->Intersect(bounceRay, &gatherIsect)) {
00499
00500 Spectrum Lindir = 0.f;
00501 Normal n = gatherIsect.dg.nn;
00502 if (Dot(n, bounceRay.d) > 0) n = -n;
00503 ERadiancePhotonProcess proc(gatherIsect.dg.p, n);
00504 float md2 = INFINITY;
00505 radianceMap->Lookup(gatherIsect.dg.p, proc, md2);
00506 if (proc.photon)
00507 Lindir = proc.photon->Lo;
00508 Lindir *= scene->Transmittance(bounceRay);
00509
00510 float bsdfPdf = bsdf->Pdf(wo, wi);
00511 float wt = PowerHeuristic(gatherSamples, photonPdf,
00512 gatherSamples, bsdfPdf);
00513 Li += fr * Lindir * AbsDot(wi, n) * wt / photonPdf;
00514 }
00515 }
00516 L += Li / gatherSamples;
00517 }
00518 #else
00519
00520 Normal nn = n;
00521 if (Dot(nn, ray.d) > 0.) nn = -n;
00522 RadiancePhotonProcess proc(p, nn);
00523 float md2 = INFINITY;
00524 radianceMap->Lookup(p, proc, md2);
00525 if (proc.photon)
00526 L += proc.photon->Lo;
00527 #endif
00528
00529 }
00530 else {
00531 L += LPhoton(indirectMap, nIndirectPaths, nLookup,
00532 bsdf, isect, wo, maxDistSquared);
00533 }
00534 if (specularDepth++ < maxSpecularDepth) {
00535 Vector wi;
00536
00537 Spectrum f = bsdf->Sample_f(wo, &wi,
00538 BxDFType(BSDF_REFLECTION | BSDF_SPECULAR));
00539 if (!f.Black()) {
00540
00541 RayDifferential rd(p, wi);
00542 rd.hasDifferentials = true;
00543 rd.rx.o = p + isect.dg.dpdx;
00544 rd.ry.o = p + isect.dg.dpdy;
00545
00546 Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx +
00547 bsdf->dgShading.dndv * bsdf->dgShading.dvdx;
00548 Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy +
00549 bsdf->dgShading.dndv * bsdf->dgShading.dvdy;
00550 Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo;
00551 float dDNdx = Dot(dwodx, n) + Dot(wo, dndx);
00552 float dDNdy = Dot(dwody, n) + Dot(wo, dndy);
00553 rd.rx.d = wi -
00554 dwodx + 2 * Vector(Dot(wo, n) * dndx +
00555 dDNdx * n);
00556 rd.ry.d = wi -
00557 dwody + 2 * Vector(Dot(wo, n) * dndy +
00558 dDNdy * n);
00559 L += scene->Li(rd, sample) * f * AbsDot(wi, n);
00560 }
00561 f = bsdf->Sample_f(wo, &wi,
00562 BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR));
00563 if (!f.Black()) {
00564
00565 RayDifferential rd(p, wi);
00566 rd.hasDifferentials = true;
00567 rd.rx.o = p + isect.dg.dpdx;
00568 rd.ry.o = p + isect.dg.dpdy;
00569
00570 float eta = bsdf->eta;
00571 Vector w = -wo;
00572 if (Dot(wo, n) < 0) eta = 1.f / eta;
00573
00574 Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + bsdf->dgShading.dndv * bsdf->dgShading.dvdx;
00575 Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + bsdf->dgShading.dndv * bsdf->dgShading.dvdy;
00576
00577 Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo;
00578 float dDNdx = Dot(dwodx, n) + Dot(wo, dndx);
00579 float dDNdy = Dot(dwody, n) + Dot(wo, dndy);
00580
00581 float mu = eta * Dot(w, n) - Dot(wi, n);
00582 float dmudx = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdx;
00583 float dmudy = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdy;
00584
00585 rd.rx.d = wi + eta * dwodx - Vector(mu * dndx + dmudx * n);
00586 rd.ry.d = wi + eta * dwody - Vector(mu * dndy + dmudy * n);
00587 L += scene->Li(rd, sample) * f * AbsDot(wi, n);
00588 }
00589 }
00590 --specularDepth;
00591 }
00592 else {
00593
00594 if (alpha) *alpha = 0.;
00595 for (u_int i = 0; i < scene->lights.size(); ++i)
00596 L += scene->lights[i]->Le(ray);
00597 if (alpha && !L.Black()) *alpha = 1.;
00598 return L;
00599 }
00600 return L;
00601 }
00602 SurfaceIntegrator* ExPhotonIntegrator::CreateSurfaceIntegrator(const ParamSet ¶ms) {
00603 int nCaustic = params.FindOneInt("causticphotons", 20000);
00604 int nIndirect = params.FindOneInt("indirectphotons", 100000);
00605 int nUsed = params.FindOneInt("nused", 50);
00606 int maxDepth = params.FindOneInt("maxdepth", 5);
00607 bool finalGather = params.FindOneBool("finalgather", true);
00608 int gatherSamples = params.FindOneInt("finalgathersamples", 32);
00609 float maxDist = params.FindOneFloat("maxdist", .1f);
00610 float rrTreshold = params.FindOneFloat("rrthreshold", .05f);
00611 float gatherAngle = params.FindOneFloat("gatherangle", 10.f);
00612 return new ExPhotonIntegrator(nCaustic, nIndirect,
00613 nUsed, maxDepth, maxDist, finalGather, gatherSamples,
00614 rrTreshold, gatherAngle);
00615 }