00001 #include <esg/energy/PhotonMapEnergy.h>
00002 #include <esg/explorer/NExtentsExplorer.h>
00003 #include <gra/reflection/PhotonMapping.h>
00004 #include <assert.h>
00005
00006 using namespace gra;
00007
00008 const int PhotonMapping::DIRECT_ILLUMINATION = (1<<0);
00009 const int PhotonMapping::SPECULAR_REFLECTION = (1<<1);
00010 const int PhotonMapping::CAUSTICS = (1<<2);
00011 const int PhotonMapping::INDIRECT_ILLUMINATION = (1<<3);
00012 const int PhotonMapping::GLOBAL_ILLUMINATION = (DIRECT_ILLUMINATION |
00013 SPECULAR_REFLECTION |
00014 CAUSTICS |
00015 INDIRECT_ILLUMINATION);
00016
00017 const unsigned PhotonMapping::PARTITIONING = 30;
00018 const unsigned PhotonMapping::PARTITIONING_2 = PARTITIONING * PARTITIONING;
00019 const double PhotonMapping::ANTIBIAS_FRACTION = .001;
00020
00021 #if 0
00022 bool PhotonMapping::_interpolate_irradiance(const vector<Photon*>& np,
00023 Color3f& irradiance)
00024 {
00025 double sumW = 0.0;
00026 Color3f aux;
00027 const PhotonMap::Photon* p;
00028 Vector3 pos;
00029 double dist;
00030 double w;
00031
00032
00033
00034
00035
00036 irradiance.set(0.0, 0.0, 0.0);
00037
00038 for (int i = 0; i < np->size(); i++) {
00039 p = &((*np)[i]);
00040 if (!p->pIrradCache) continue;
00041 pos.set(np->pointLocation());
00042 pos.sub(p->location());
00043 dist = pos.length();
00044 if (p->pIrradCache->maxDistance <= dist) continue;
00045 w = p->pIrradCache->meanDistance / dist;
00046 sumW += w;
00047 aux.set(p->pIrradCache->irradiance);
00048 aux.scale(w);
00049 irradiance.add(aux);
00050 }
00051
00052 if (sumW > 0.0) {
00053 irradiance.scale(1.0 / sumW);
00054 return true;
00055 } else
00056 return false;
00057 }
00058 #endif
00059
00060 bool PhotonMapping::_interpolate_irradiance(const vector<IrradianceCache::Value*>& np,
00061 Color3f& irradiance)
00062 {
00063
00064
00065
00066
00067 irradiance.set(0.0, 0.0, 0.0);
00068 double sumW = 0.0;
00069
00070 for (unsigned i = 0; i < np.size(); i++) {
00071 float w = np[i]->getWeight();
00072 const Color3f& c = np[i]->getIrradiance();
00073 sumW += w;
00074 irradiance.x += c.x * w;
00075 irradiance.y += c.y * w;
00076 irradiance.z += c.z* w;
00077 }
00078
00079 if (sumW > 0.0) {
00080 irradiance.scale(1.0 / sumW);
00081 return true;
00082 } else
00083 return false;
00084 }
00085
00086 double* PhotonMapping::_power_square(const vector<Photon*>& np,
00087 const Vector3& normal,
00088 BRDF& brdf,
00089 const MatVisitor& matVisitor,
00090 double& squareEnergy)
00091 {
00092 squareEnergy = 0.0;
00093
00094 double* square = new double [PARTITIONING_2];
00095 for (unsigned i = 0; i < PARTITIONING_2; i++) *(square+i) = 0.0;
00096
00097
00098
00099
00100
00101 Vector2 uv;
00102 unsigned u,v;
00103 double avgPower;
00104 double cell = 1. / PARTITIONING;
00105 Vector3 pw;
00106
00107 for (unsigned i = 0; i < np.size(); i++) {
00108 uv.set(brdf.dir2uv(matVisitor, normal, np[i]->getDirection()));
00109
00110
00111 u = (v = 0);
00112 for (unsigned j = 0; j < PARTITIONING; j++) {
00113 if (uv.x > cell) { uv.x -= cell; u++; }
00114 if (uv.y > cell) { uv.y -= cell; v++; }
00115 }
00116
00117 pw.set(np[i]->getPower());
00118 avgPower = (pw.x + pw.y + pw.z) / 3.;
00119 *(square + (PARTITIONING * v) + u) += avgPower;
00120 squareEnergy += avgPower;
00121 }
00122
00123 return square;
00124 }
00125
00126 double PhotonMapping::_importance_sampling(const Vector3& normal,
00127 BRDF& brdf,
00128 const MatVisitor& matVisitor,
00129 double* square,
00130 double squareEnergy,
00131 Vector3& nDir)
00132 {
00133
00134
00135
00136
00137
00138
00139 div_t qr;
00140 double biasEllim = ANTIBIAS_FRACTION * squareEnergy;
00141 double r1 = ESG_DBL_RAND;
00142 double r = r1 * squareEnergy;
00143
00144 double* val = square;
00145 unsigned index = 0;
00146 do {
00147 if (*val == 0.) {
00148
00149
00150
00151
00152
00153
00154 squareEnergy += biasEllim;
00155 r += r1 * biasEllim;
00156 *val = biasEllim;
00157 }
00158 if (r <= *val) break;
00159 r -= *(val++);
00160 } while (++index < PARTITIONING_2);
00161
00162 qr = div((int)index, (int)PARTITIONING);
00163
00164
00165
00166
00167
00168 double s1 = (qr.quot + ESG_DBL_RAND) / PARTITIONING;
00169 double s2 = (qr.rem + ESG_DBL_RAND) / PARTITIONING;
00170
00171
00172
00173
00174
00175 brdf.importanceSample(matVisitor, normal, s1, s2, nDir, NULL);
00176 return (squareEnergy/(*(square+index)*PARTITIONING_2));
00177 }
00178
00179 void PhotonMapping::_sample_diffuse(PointEnv& surr,
00180 unsigned actDepth,
00181 bool firstObjHit,
00182 Color3f& contribution,
00183 MatVisitor& matVisitor)
00184 {
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 BRDF * pBRDF = surr.pVisitableObj->diffuseBRDF();
00195 if (!pBRDF) pBRDF = _pDiffuseBRDF;
00196 if (!pBRDF) return;
00197
00198 double avgDiff = matVisitor.avgDiffuse();
00199
00200 if (avgDiff <= 0.0) return;
00201
00202
00203
00204
00205 if (_pIrradCache) {
00206 vector<IrradianceCache::Value*> buffer;
00207 Color3f irradiance;
00208 try {
00209 _pIrradCache->getValue(surr.intersection,
00210 surr.normal,
00211 buffer);
00212 if (buffer.size() > 0 && _interpolate_irradiance(buffer,irradiance)) {
00213
00214 contribution.add(irradiance);
00215 return;
00216 }
00217 } catch (out_of_range& ore) {
00218 cerr << ore.what() << endl;
00219 }
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 Vector3 nDir;
00234 Color3f contrib(0.0, 0.0, 0.0);
00235 unsigned castPhotons = ((_pIrradCache)
00236 ? PARTITIONING_2
00237 : _photonsPerSurface);
00238 Vector3 diff(matVisitor.diffuse());
00239 Vector3 refl;
00240 PointEnv* pNewSurr;
00241 double meanDist = 0.0;
00242 unsigned meanDistRays = 0;
00243 double* lightingSquare = NULL;
00244 double squareEnergy;
00245
00246 if (_incomingLighting) {
00247
00248
00249
00250
00251 vector<Photon*>* np = _pGlobalMap->getNeighbourhood(surr.intersection,
00252 &(surr.normal),
00253 _maxDistToEst,
00254 _numPhotonsToEst);
00255 if (np) {
00256
00257
00258
00259
00260 lightingSquare = _power_square(*np, surr.normal, *pBRDF,
00261 matVisitor, squareEnergy);
00262 delete np;
00263 }
00264 }
00265
00266 if (!lightingSquare) {
00267
00268
00269
00270
00271
00272 refl.set(diff);
00273 refl.scale(1.0 / avgDiff);
00274 }
00275
00276
00277 for (unsigned i = 0; i < castPhotons; i++) {
00278 if (ESG_DBL_RAND >= avgDiff) continue;
00279
00280 if (lightingSquare) {
00281
00282
00283
00284
00285
00286
00287
00288
00289 refl.set(diff);
00290 refl.scale(_importance_sampling(surr.normal, *pBRDF, matVisitor,
00291 lightingSquare, squareEnergy,
00292 nDir));
00293 } else {
00294
00295
00296
00297
00298
00299 pBRDF->importanceSample(matVisitor, surr.normal,
00300 ESG_DBL_RAND, ESG_DBL_RAND,
00301 nDir, NULL);
00302 }
00303
00304
00305
00306
00307 if ((pNewSurr = _cast_ray(surr.intersection, nDir))) {
00308 assert(pNewSurr->mask & ENV_HAVE_DISTANCE);
00309 pNewSurr->energy.set(surr.energy);
00310 pNewSurr->energy.x *= refl.x;
00311 pNewSurr->energy.y *= refl.y;
00312 pNewSurr->energy.z *= refl.z;
00313 pNewSurr->mask |= ENV_HAVE_ENERGY;
00314 if (((pNewSurr->energy.x +
00315 pNewSurr->energy.y +
00316 pNewSurr->energy.z) / 3.) > _minRayWeight) {
00317 _illuminate(*pNewSurr, actDepth+1, firstObjHit, contrib);
00318 }
00319
00320 if (_pIrradCache) {
00321
00322
00323
00324 if (pNewSurr->distance != 0.0) {
00325 meanDist += 1.0 / pNewSurr->distance;
00326 meanDistRays ++;
00327 }
00328 }
00329 delete pNewSurr;
00330 } else {
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 }
00343
00344 }
00345
00346 contrib.scale(1. / castPhotons);
00347
00348 if (lightingSquare) delete [] lightingSquare;
00349
00350 if (_pIrradCache) {
00351
00352
00353
00354 if (meanDist > 0.0) {
00355
00356
00357
00358 meanDist = meanDistRays / meanDist;
00359
00360 try {
00361 _pIrradCache->addValue(surr.intersection,
00362 surr.normal,
00363 contrib,
00364 meanDist);
00365
00366 } catch(out_of_range& e) {
00367 cerr << e.what() << endl;
00368 }
00369
00370 } else {
00371
00372
00373
00374
00375
00376
00377
00378 }
00379
00380 }
00381
00382 contribution.add(contrib);
00383 }
00384
00385 void PhotonMapping::_sample_specular(PointEnv& surr,
00386 unsigned actDepth,
00387 bool firstObjHit,
00388 Color3f& contribution,
00389 MatVisitor& matVisitor)
00390 {
00391 Vector3 nDir;
00392 Color3f contrib(0.0, 0.0, 0.0);
00393 Vector3 refl;
00394 BRDF * pBRDF = NULL;
00395
00396
00397
00398
00399
00400
00401
00402 pBRDF = surr.pVisitableObj->specularBRDF();
00403 if (!pBRDF) pBRDF = _pSpecularBRDF;
00404 if (!pBRDF) return;
00405
00406
00407
00408
00409 for (unsigned i = 0; i < _photonsPerSpecularSurface; i++) {
00410 double r1 = ESG_DBL_RAND;
00411 double rr = r1;
00412
00413 if ((rr -= matVisitor.avgSpecular()) < 0.) {
00414 Vector3 prDir;
00415 _reflection_dir(surr, prDir);
00416 pBRDF->importanceSample(matVisitor, prDir, r1, ESG_DBL_RAND,
00417 nDir, NULL);
00418 refl.set(matVisitor.specular());
00419 refl.scale(1. / matVisitor.avgSpecular());
00420 _cast_the_ray(surr, actDepth, true, contrib, nDir, refl);
00421 } else if ((rr -= matVisitor.avgReflection()) < 0.) {
00422 _reflection_dir(surr, nDir);
00423 refl.set(matVisitor.reflection());
00424 refl.scale(1. / matVisitor.avgReflection());
00425 _cast_the_ray(surr, actDepth, true, contrib, nDir, refl);
00426 } else if ((rr -= matVisitor.avgTransparency()) < 0.) {
00427 bool foh = ((_refraction_dir(surr,
00428 matVisitor,
00429 firstObjHit,
00430 nDir)
00431 == RayTracing::REFR_DIR_REFLECTION)
00432 ? false
00433 : !firstObjHit);
00434 refl.set(matVisitor.transparency());
00435 refl.scale(1. / matVisitor.avgTransparency());
00436 _cast_the_ray(surr, actDepth, foh, contrib, nDir, refl);
00437 }
00438 }
00439
00440 contrib.scale(1./_photonsPerSpecularSurface);
00441 contribution.add(contrib);
00442 }
00443
00444 void PhotonMapping::_illuminate(PointEnv& surr,
00445 unsigned actDepth,
00446 bool firstObjHit,
00447 Color3f& contribution)
00448 {
00449
00450
00451
00452
00453
00454
00455 _check_point_of_intersection(surr);
00456
00457
00458
00459
00460
00461
00462
00463 MatVisitor* pMatVisitor = _check_material(surr.pVisitableObj, firstObjHit);
00464
00465
00466
00467
00468 AutoPtr<EnergyCoat>* pAMap = surr.pVisitableObj->getEnergyState();
00469 if (pAMap) {
00470 EnergyCoat* pCoat = pAMap->origObject();
00471 if (pCoat) {
00472 PhotonMapEnergy* pE = dynamic_cast<PhotonMapEnergy*>(pCoat);
00473 if (pE) {
00474 _pGlobalMap = pE->getGlobalMap();
00475 _pCausticsMap = pE->getCausticsMap();
00476 if (_cacheIrradiance) {
00477 _pIrradCache = pE->getIrradianceCache();
00478
00479 if (!_pIrradCache && _sceneDistance > 0) {
00480
00481 if (pE->buildIrradianceCache(1.0f/_maxError,_sceneDistance))
00482 _pIrradCache = pE->getIrradianceCache();
00483 else
00484 cerr << "PhotonMapping::_illuminate(): Irradiance cache will not be used." << endl;
00485 }
00486 } else
00487 _pIrradCache = NULL;
00488 }
00489 }
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499 if (actDepth == 0) {
00500
00501 if (_illumStage & DIRECT_ILLUMINATION)
00502 _direct_illumination(surr, *pMatVisitor, actDepth, contribution);
00503
00504
00505 if (_pCausticsMap && (_illumStage & CAUSTICS)) {
00506 Vector3 irrad;
00507 if (_pCausticsMap->getIrradiance(surr.intersection,
00508 NULL,
00509 _maxDistToEst,
00510 _numPhotonsToEst,
00511 irrad))
00512 {
00513 contribution.add(irrad);
00514 }
00515 }
00516 if (_illumStage & INDIRECT_ILLUMINATION) {
00517
00518 bool d = _diffReflection;
00519 _diffReflection = true;
00520 _sample_diffuse(surr, actDepth, firstObjHit,
00521 contribution, *pMatVisitor);
00522 _diffReflection = d;
00523 }
00524
00525 if (_illumStage & SPECULAR_REFLECTION) {
00526
00527 _specReflections++;
00528 _sample_specular(surr, actDepth, firstObjHit,
00529 contribution, *pMatVisitor);
00530 _specReflections--;
00531 }
00532
00533
00534
00535 return;
00536 }
00537
00538
00539
00540
00541 bool precise = false;
00542 if (_diffReflection) {
00543 if ((surr.mask & ENV_HAVE_DISTANCE) &&
00544 (surr.distance < _preciseIllumDist))
00545 precise = true;
00546 } else {
00547 if (_specReflections <= _preciseIllumRefl) {
00548 precise = true;
00549 } else if ((surr.mask & ENV_HAVE_DISTANCE) &&
00550 (surr.distance < _preciseIllumDist))
00551 precise = true;
00552 }
00553
00554
00555
00556
00557
00558 if (precise) {
00559
00560 _direct_illumination(surr, *pMatVisitor, actDepth, contribution);
00561
00562
00563 if (_pCausticsMap) {
00564 Vector3 irrad;
00565 if (_pCausticsMap->getIrradiance(surr.intersection,
00566 &(surr.normal),
00567 _maxDistToEst,
00568 _numPhotonsToEst,
00569 irrad))
00570 {
00571 contribution.add(irrad);
00572 }
00573 }
00574 if (actDepth < _maxDepth) {
00575
00576 bool d = _diffReflection;
00577 _diffReflection = true;
00578 _sample_diffuse(surr, actDepth, firstObjHit,
00579 contribution, *pMatVisitor);
00580 _diffReflection = d;
00581
00582
00583 _specReflections++;
00584 _sample_specular(surr, actDepth, firstObjHit,
00585 contribution, *pMatVisitor);
00586 _specReflections--;
00587 }
00588 } else {
00589
00590 if (_pGlobalMap) {
00591 Vector3 irrad;
00592 if (_pGlobalMap->getIrradiance(surr.intersection,
00593 &(surr.normal),
00594 _maxDistToEst,
00595 _numPhotonsToEst,
00596 irrad))
00597 {
00598 contribution.add(irrad);
00599 }
00600 } else
00601 _direct_illumination(surr,*pMatVisitor,actDepth,contribution);
00602
00603
00604
00605 if (_diffReflection) {
00606
00607
00608 } else {
00609 if (actDepth < _maxDepth) {
00610
00611 _specReflections++;
00612 _sample_specular(surr, actDepth, firstObjHit,
00613 contribution, *pMatVisitor);
00614 _specReflections--;
00615 }
00616 }
00617 }
00618 }
00619
00620
00621
00622
00623
00624 Color3f* PhotonMapping::illuminatePoint(PointEnv & env)
00625 {
00626 _specReflections = 0;
00627 _diffReflection = false;
00628 _pGlobalMap = NULL;
00629 _pCausticsMap = NULL;
00630 _pIrradCache = NULL;
00631 return PathTracing::illuminatePoint(env);
00632 }
00633
00634 void PhotonMapping::setScene(Scene * s)
00635 {
00636 PathTracing::setScene(s);
00637
00638 float a[3][3] = {{1.,0.,0.}, {0.,1.,0.}, {0.,0.,1.}};
00639
00640 if (_cacheIrradiance && s && s->root()) {
00641 float minD = FLT_MAX;
00642 float maxD = FLT_MIN;
00643 NExtentsExplorer e(a, 3);
00644 e.explore(*(s->root()));
00645 for (int i = 0; i < 3; i++) {
00646 Interval ext = e.result(i);
00647 if (ext.max > maxD) maxD = ext.max;
00648 if (ext.min < minD) minD = ext.min;
00649 }
00650 _sceneDistance = maxD - minD;
00651 }
00652 }