00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "photonmap.h"
00024 #include "common/misc/binarystream.h"
00025 #include "common/misc/minmax.h"
00026 #include "context.h"
00027 #include "ibdf.h"
00028 #include "isurfaceshader.h"
00029 #include "surfacebasis.h"
00030
00031 #include <algorithm>
00032 #include <cmath>
00033 #include <cstdio>
00034
00035 using namespace sheep;
00036 using namespace std;
00037 using namespace toxic;
00038
00039
00040
00041 const string PhotonMap::m_photon_map_sig = "toxic photon map file version 1";
00042
00043
00044 const int PHOTONMAP_IO_BUFFER_SIZE = 1024 * 1024;
00045
00046 PhotonMap::PhotonMap() :
00047 m_stored_photons(0),
00048 m_half_stored_photons(0),
00049 m_prev_scale(1)
00050 {
00051 m_photons.push_back(Photon());
00052
00053 m_bbox_min[0] = m_bbox_min[1] = m_bbox_min[2] = 1.0e8f;
00054 m_bbox_max[0] = m_bbox_max[1] = m_bbox_max[2] = -1.0e8f;
00055
00056
00057
00058 m_dist2_buf = new float32[BUF_SIZE];
00059 m_index_buf = new const Photon *[BUF_SIZE];
00060 }
00061
00062 PhotonMap::~PhotonMap() {
00063 delete [] m_index_buf;
00064 delete [] m_dist2_buf;
00065 }
00066
00067 int PhotonMap::GetSizeInMemory() const {
00068 return
00069 sizeof(PhotonMap) +
00070 sizeof(Photon) * static_cast<int>(m_photons.capacity()) +
00071 sizeof(float32) * BUF_SIZE +
00072 sizeof(Photon *) * BUF_SIZE;
00073 }
00074
00075 void PhotonMap::StorePhoton(const Point3 &position,
00076 const Color3 &power,
00077 const Vector3 &direction
00078 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00079 , const Vector3 &normal
00080 #endif
00081 )
00082 {
00083 Photon photon;
00084
00085 photon.SetPosition(position);
00086 photon.SetPower(power);
00087 photon.SetIncidentDirection(direction);
00088
00089 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00090 photon.SetSurfaceNormal(normal);
00091 #endif // ENABLE_RADIANCES_PRECOMPUTATION
00092
00093 m_photons.push_back(photon);
00094
00095 ++m_stored_photons;
00096
00097
00098 if(position.m_x < m_bbox_min[0]) m_bbox_min[0] = static_cast<float32>(position.m_x);
00099 if(position.m_x > m_bbox_max[0]) m_bbox_max[0] = static_cast<float32>(position.m_x);
00100 if(position.m_y < m_bbox_min[1]) m_bbox_min[1] = static_cast<float32>(position.m_y);
00101 if(position.m_y > m_bbox_max[1]) m_bbox_max[1] = static_cast<float32>(position.m_y);
00102 if(position.m_z < m_bbox_min[2]) m_bbox_min[2] = static_cast<float32>(position.m_z);
00103 if(position.m_z > m_bbox_max[2]) m_bbox_max[2] = static_cast<float32>(position.m_z);
00104 }
00105
00106 void PhotonMap::ScalePhotonPower(Real scale) {
00107 for(int i = m_prev_scale; i <= m_stored_photons; ++i)
00108 m_photons[i].ScalePower(scale);
00109
00110 m_prev_scale = m_stored_photons + 1;
00111 }
00112
00113 void PhotonMap::Balance() {
00114 if(m_stored_photons > 1) {
00115
00116 Photon **pa1 = new Photon *[m_stored_photons + 1];
00117 Photon **pa2 = new Photon *[m_stored_photons + 1];
00118
00119 for(int i = 0; i <= m_stored_photons; ++i)
00120 pa2[i] = &m_photons[i];
00121
00122 balance_segment(pa1, pa2, 1, 1, m_stored_photons);
00123
00124 delete [] pa2;
00125
00126
00127 int j = 1, foo = 1;
00128 Photon foo_photon = m_photons[j];
00129
00130 for(int i = 1; i <= m_stored_photons; ++i) {
00131
00132 const int d = pa1[j] - &m_photons[0];
00133
00134 pa1[j] = 0;
00135
00136 if(d != foo)
00137 m_photons[j] = m_photons[d];
00138 else {
00139 m_photons[j] = foo_photon;
00140
00141 if(i < m_stored_photons) {
00142 for(; foo <= m_stored_photons; ++foo)
00143 if(pa1[foo] != 0)
00144 break;
00145 foo_photon = m_photons[foo];
00146 j = foo;
00147 }
00148
00149 continue;
00150 }
00151
00152 j = d;
00153 }
00154
00155 delete [] pa1;
00156 }
00157
00158 m_half_stored_photons = m_stored_photons / 2 - 1;
00159 }
00160
00161 Color3 PhotonMap::ComputeRadiance(const Context &context,
00162 const Point3 &point,
00163 const Vector3 &normal,
00164 const Vector3 &outgoing,
00165 const ShadingData &shadingdata,
00166 Real max_dist,
00167 int max_photons) const
00168 {
00169 assert(max_photons + 1 <= BUF_SIZE);
00170
00171 nearest_photons np;
00172 np.m_dist2 = m_dist2_buf;
00173 np.m_index = m_index_buf;
00174 np.m_position[0] = static_cast<float32>(point.m_x);
00175 np.m_position[1] = static_cast<float32>(point.m_y);
00176 np.m_position[2] = static_cast<float32>(point.m_z);
00177 np.m_max = max_photons;
00178 np.m_found = 0;
00179 np.m_got_heap = 0;
00180 np.m_dist2[0] = static_cast<float32>(max_dist * max_dist);
00181
00182
00183 locate_photons(&np, 1);
00184
00185
00186 if(np.m_found < 8)
00187 return Color3(0.0);
00188
00189 const SurfaceBasis surfacebasis(normal);
00190 const Vector3 local_outgoing = surfacebasis.TransformToLocal(outgoing);
00191
00192 Color3 radiant_intensity(0.0);
00193
00194 for(int i = 1; i <= np.m_found; ++i) {
00195 const Photon *p = np.m_index[i];
00196
00197 #ifdef CHECK_FOR_THIN_SURFACES
00198 if(p->GetIncidentDirection() * normal <= 0.0)
00199 continue;
00200 #endif // CHECK_FOR_THIN_SURFACES
00201
00202 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00203
00204
00205
00206 const Real THRESHOLD = 0.9;
00207 if(p->GetSurfaceNormal() * normal < THRESHOLD)
00208 continue;
00209 #endif // ENABLE_RADIANCES_PRECOMPUTATION
00210
00211
00212 const Real bsdf_value =
00213 shadingdata.m_bdf->Evaluate(
00214 context,
00215 surfacebasis.TransformToLocal(p->GetIncidentDirection()),
00216 local_outgoing);
00217
00218
00219
00220 radiant_intensity += bsdf_value * p->GetPower();
00221 }
00222
00223
00224
00225
00226 assert(fnz(np.m_dist2[0]));
00227 const Real inv_disc_area = (1.0 / PI) / np.m_dist2[0];
00228
00229
00230 const Color3 radiance = radiant_intensity * inv_disc_area;
00231
00232 return shadingdata.m_reflectance * radiance;
00233 }
00234
00235 Color3 PhotonMap::ApproximateRadiance(const Point3 &point,
00236 const Vector3 &normal,
00237 const ShadingData &shadingdata,
00238 Real max_dist,
00239 int max_photons) const
00240 {
00241 assert(max_photons + 1 <= BUF_SIZE);
00242
00243 nearest_photons np;
00244 np.m_dist2 = m_dist2_buf;
00245 np.m_index = m_index_buf;
00246 np.m_position[0] = static_cast<float32>(point.m_x);
00247 np.m_position[1] = static_cast<float32>(point.m_y);
00248 np.m_position[2] = static_cast<float32>(point.m_z);
00249 np.m_max = max_photons;
00250 np.m_found = 0;
00251 np.m_got_heap = 0;
00252 np.m_dist2[0] = static_cast<float32>(max_dist * max_dist);
00253
00254
00255 locate_photons(&np, 1);
00256
00257
00258 if(np.m_found < 8)
00259 return Color3(0.0);
00260
00261 Color3 radiant_intensity(0.0);
00262
00263 for(int i = 1; i <= np.m_found; ++i) {
00264 const Photon *p = np.m_index[i];
00265
00266 #ifdef CHECK_FOR_THIN_SURFACES
00267 if(p->GetIncidentDirection() * normal <= 0.0)
00268 continue;
00269 #endif // CHECK_FOR_THIN_SURFACES
00270
00271 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00272
00273
00274
00275 const Real THRESHOLD = 0.9;
00276 if(p->GetSurfaceNormal() * normal < THRESHOLD)
00277 continue;
00278 #endif // ENABLE_RADIANCES_PRECOMPUTATION
00279
00280
00281
00282 const Real bsdf_value = (1.0 / PI);
00283
00284
00285 radiant_intensity += bsdf_value * p->GetPower();
00286 }
00287
00288
00289
00290
00291 assert(fnz(np.m_dist2[0]));
00292 const Real inv_disc_area = (1.0 / PI) / np.m_dist2[0];
00293
00294
00295 const Color3 radiance = radiant_intensity * inv_disc_area;
00296
00297 return shadingdata.m_reflectance * radiance;
00298 }
00299
00300 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00301
00302 void PhotonMap::PrecomputeRadiances(int spacing,
00303 Real max_dist,
00304 int max_photons,
00305 ProgressMonitor *progmon )
00306 {
00307 assert(spacing >= 1);
00308 assert(max_photons > 0);
00309
00310 if(progmon && m_stored_photons > 0)
00311 progmon->StartJob(0.0, m_stored_photons);
00312
00313 ShadingData fakeshadingdata;
00314 fakeshadingdata.m_reflectance = Color3(1.0);
00315
00316 for(int i = 1; i <= m_stored_photons; i += spacing) {
00317 if(progmon)
00318 progmon->SetJobProgress(i);
00319
00320 Photon *photon = &m_photons[i];
00321
00322 const Color3 radiance =
00323 ApproximateRadiance(
00324 photon->GetPosition(),
00325 photon->GetSurfaceNormal(),
00326 fakeshadingdata,
00327 max_dist,
00328 max_photons);
00329
00330 photon->SetPrecomputedRadiance(radiance);
00331 }
00332
00333 if(progmon)
00334 progmon->Done();
00335 }
00336
00337 Color3 PhotonMap::GetPrecomputedRadiance(const Point3 &point,
00338 const Vector3 &normal,
00339 const ShadingData &shadingdata,
00340 Real max_dist) const
00341 {
00342 nearest_photons np;
00343 np.m_dist2 = m_dist2_buf;
00344 np.m_index = m_index_buf;
00345 np.m_position[0] = static_cast<float32>(point.m_x);
00346 np.m_position[1] = static_cast<float32>(point.m_y);
00347 np.m_position[2] = static_cast<float32>(point.m_z);
00348 np.m_dist2[0] = static_cast<float32>(max_dist * max_dist);
00349
00350 np.m_index[0] = 0;
00351
00352
00353 locate_nearest_photon_with_irradiance(normal, &np, 1);
00354
00355 const Photon *nearest = np.m_index[0];
00356
00357 if(!nearest)
00358 return Color3(0.0);
00359
00360 return shadingdata.m_reflectance * nearest->GetPrecomputedRadiance();
00361 }
00362
00363 #endif // ENABLE_RADIANCES_PRECOMPUTATION
00364
00365 void PhotonMap::BuildPhotonDirectionHistogram(const Point3 &position,
00366 const SurfaceBasis &surfacebasis,
00367 Real max_dist,
00368 int max_photons,
00369 Real *histogram,
00370 int m, int n,
00371 Real *total_power) const
00372 {
00373 assert(max_photons + 1 <= BUF_SIZE);
00374 assert(histogram);
00375 assert(total_power);
00376
00377 for(int i = m * n - 1; i >= 0; --i)
00378 histogram[i] = 0.0;
00379
00380 *total_power = 0.0;
00381
00382 nearest_photons np;
00383 np.m_dist2 = m_dist2_buf;
00384 np.m_index = m_index_buf;
00385 np.m_position[0] = static_cast<float32>(position.m_x);
00386 np.m_position[1] = static_cast<float32>(position.m_y);
00387 np.m_position[2] = static_cast<float32>(position.m_z);
00388 np.m_max = max_photons;
00389 np.m_found = 0;
00390 np.m_got_heap = 0;
00391 np.m_dist2[0] = static_cast<float32>(max_dist * max_dist);
00392
00393
00394 locate_photons(&np, 1);
00395
00396 for(int i = 1; i <= np.m_found; ++i) {
00397 const Photon *p = np.m_index[i];
00398
00399 #ifdef CHECK_FOR_THIN_SURFACES
00400 if(p->GetIncidentDirection() * surfacebasis.GetNormal() <= 0.0)
00401 continue;
00402 #endif // CHECK_FOR_THIN_SURFACES
00403
00404 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00405
00406
00407 const Real THRESHOLD = 0.0;
00408 if(p->GetSurfaceNormal() * surfacebasis.GetNormal() < THRESHOLD)
00409 continue;
00410 #endif // ENABLE_RADIANCES_PRECOMPUTATION
00411
00412
00413 const Vector3 photon_dir = p->GetIncidentDirection();
00414
00415
00416 const Vector3 local_photon_dir = surfacebasis.TransformToLocal(photon_dir);
00417 assert(local_photon_dir.IsUnitLength());
00418 assert(local_photon_dir.m_y > 0.0);
00419
00420
00421 Real phi, theta;
00422 VectorToSphericalCoords(local_photon_dir, &phi, &theta);
00423 assert(phi >= 0.0 && phi <= 2.0 * PI);
00424 assert(theta >= 0.0 && theta <= PI);
00425
00426 const Real cos_theta = cos(theta);
00427 const Real u1 = phi / (2.0 * PI);
00428 const Real v1 = cos_theta * cos_theta;
00429
00430 assert(u1 >= 0.0 && u1 <= 1.0);
00431 assert(v1 >= 0.0 && v1 <= 1.0);
00432
00433 const int hi = min(m - 1, static_cast<int>(u1 * m));
00434 const int hj = min(n - 1, static_cast<int>(v1 * n));
00435
00436 assert(hi >= 0 && hi < m);
00437 assert(hj >= 0 && hj < n);
00438
00439 const Real photon_power = p->GetPower().Average();
00440
00441 histogram[hj * m + hi] += photon_power;
00442 *total_power += photon_power;
00443 }
00444
00445 const Real frac = *total_power / (m * n * 10.0);
00446
00447 for(int i = m * n - 1; i >= 0; --i) {
00448 if(histogram[i] == 0.0) {
00449 histogram[i] = frac;
00450 *total_power += frac;
00451 }
00452 }
00453 }
00454
00455 bool PhotonMap::WriteToFile(const string &filename,
00456 ProgressMonitor *progmon ) const
00457 {
00458 try {
00459 BinaryStream os(
00460 filename.c_str(),
00461 BinaryStream::OutputStream,
00462 BinaryStream::BigEndian
00463 );
00464
00465 if(!os.IsOpen())
00466 return false;
00467
00468
00469 os.SetBufferSize(PHOTONMAP_IO_BUFFER_SIZE);
00470
00471
00472 os.Write(m_photon_map_sig.c_str(), m_photon_map_sig.size());
00473
00474
00475 os.Write(m_stored_photons);
00476
00477 if(progmon && m_stored_photons > 0)
00478 progmon->StartJob(0.0, m_stored_photons);
00479
00480
00481 for(int i = 1; i <= m_stored_photons; ++i) {
00482 m_photons[i].WriteToStream(os);
00483
00484 if(progmon && ((i & 16383) == 0))
00485 progmon->SetJobProgress(i);
00486 }
00487
00488 if(progmon)
00489 progmon->Done();
00490
00491
00492 os.Write(m_bbox_min[0]);
00493 os.Write(m_bbox_min[1]);
00494 os.Write(m_bbox_min[2]);
00495 os.Write(m_bbox_max[0]);
00496 os.Write(m_bbox_max[1]);
00497 os.Write(m_bbox_max[2]);
00498
00499
00500 os.Write(m_half_stored_photons);
00501
00502
00503 return true;
00504 }
00505 catch(BinaryStream::BaseException) {
00506
00507 return false;
00508 }
00509 }
00510
00511 PhotonMap *PhotonMap::CreateFromFile(const string &filename,
00512 ProgressMonitor *progmon )
00513 {
00514 PhotonMap *photon_map = 0;
00515
00516 try {
00517 BinaryStream is(
00518 filename.c_str(),
00519 BinaryStream::InputStream,
00520 BinaryStream::BigEndian
00521 );
00522
00523 if(!is.IsOpen())
00524 return 0;
00525
00526
00527 is.SetBufferSize(PHOTONMAP_IO_BUFFER_SIZE);
00528
00529
00530 char *buf = new char[m_photon_map_sig.size() + 1];
00531 is.Read(buf, m_photon_map_sig.size());
00532 buf[m_photon_map_sig.size()] = '\0';
00533 if(string(buf) != m_photon_map_sig)
00534 return 0;
00535 delete [] buf;
00536
00537
00538 photon_map = new PhotonMap();
00539
00540
00541 is.Read(&photon_map->m_stored_photons);
00542
00543 if(photon_map->m_stored_photons > 0)
00544 photon_map->m_photons.reserve(photon_map->m_stored_photons);
00545
00546 if(progmon && photon_map->m_stored_photons > 0)
00547 progmon->StartJob(1.0, photon_map->m_stored_photons);
00548
00549
00550 for(int i = 1; i <= photon_map->m_stored_photons; ++i) {
00551 Photon photon;
00552 photon.ReadFromStream(is);
00553 photon_map->m_photons.push_back(photon);
00554
00555 if(progmon && ((i & 32767) == 0))
00556 progmon->SetJobProgress(i);
00557 }
00558
00559 if(progmon)
00560 progmon->Done();
00561
00562
00563 is.Read(&photon_map->m_bbox_min[0]);
00564 is.Read(&photon_map->m_bbox_min[1]);
00565 is.Read(&photon_map->m_bbox_min[2]);
00566 is.Read(&photon_map->m_bbox_max[0]);
00567 is.Read(&photon_map->m_bbox_max[1]);
00568 is.Read(&photon_map->m_bbox_max[2]);
00569
00570
00571 is.Read(&photon_map->m_half_stored_photons);
00572
00573
00574 return photon_map;
00575 }
00576 catch(BinaryStream::BaseException) {
00577
00578 delete photon_map;
00579 return 0;
00580 }
00581 }
00582
00583 void PhotonMap::median_split(Photon **p,
00584 int start, int end,
00585 int median,
00586 int axis) const
00587 {
00588 assert(p);
00589
00590 int left = start;
00591 int right = end;
00592
00593 while(right > left) {
00594 const float32 v = p[right]->m_position[axis];
00595 int i = left - 1;
00596 int j = right;
00597
00598 while(true) {
00599 while(p[++i]->m_position[axis] < v) ;
00600 while(p[--j]->m_position[axis] > v && j > left) ;
00601
00602 if(i >= j)
00603 break;
00604
00605 swap(p[i], p[j]);
00606 }
00607
00608 swap(p[i], p[right]);
00609
00610 if(i >= median)
00611 right = i - 1;
00612 if(i <= median)
00613 left = i + 1;
00614 }
00615 }
00616
00617 void PhotonMap::balance_segment(Photon **pbal,
00618 Photon **porg,
00619 int index,
00620 int start, int end)
00621 {
00622 assert(pbal);
00623 assert(porg);
00624
00625
00626
00627 int median = 1;
00628
00629 while(4 * median <= end - start + 1)
00630 median += median;
00631
00632 if(3 * median <= end - start + 1) {
00633 median += median;
00634 median += start - 1;
00635 } else median = end - median + 1;
00636
00637
00638
00639 int axis = 2;
00640
00641 if( (m_bbox_max[0] - m_bbox_min[0] > m_bbox_max[1] - m_bbox_min[1]) &&
00642 (m_bbox_max[0] - m_bbox_min[0] > m_bbox_max[2] - m_bbox_min[2]))
00643 axis = 0;
00644 else if(m_bbox_max[1] - m_bbox_min[1] > m_bbox_max[2] - m_bbox_min[2])
00645 axis = 1;
00646
00647
00648
00649 median_split(porg, start, end, median, axis);
00650
00651 pbal[index] = porg[median];
00652 pbal[index]->SetSplittingPlaneAxis(axis);
00653
00654
00655
00656 if(median > start) {
00657
00658 if(start < median - 1) {
00659 const float32 tmp = m_bbox_max[axis];
00660 m_bbox_max[axis] = pbal[index]->m_position[axis];
00661 balance_segment(pbal, porg, 2 * index, start, median - 1);
00662 m_bbox_max[axis] = tmp;
00663 } else pbal[2 * index] = porg[start];
00664 }
00665
00666 if(median < end) {
00667
00668 if(median + 1 < end) {
00669 const float32 tmp = m_bbox_min[axis];
00670 m_bbox_min[axis] = pbal[index]->m_position[axis];
00671 balance_segment(pbal, porg, 2 * index + 1, median + 1, end);
00672 m_bbox_min[axis] = tmp;
00673 } else pbal[2 * index + 1] = porg[end];
00674 }
00675 }
00676
00677 void PhotonMap::locate_photons(nearest_photons *np, int index) const {
00678 const Photon *p = &m_photons[index];
00679
00680 if(index < m_half_stored_photons) {
00681
00682
00683 const int plane = p->GetSplittingPlaneAxis();
00684 const float32 dist1 = np->m_position[plane] - p->m_position[plane];
00685
00686 if(dist1 > 0.0f) {
00687 locate_photons(np, 2 * index + 1);
00688
00689 if(dist1 * dist1 < np->m_dist2[0])
00690 locate_photons(np, 2 * index);
00691 } else {
00692 locate_photons(np, 2 * index);
00693
00694 if(dist1 * dist1 < np->m_dist2[0])
00695 locate_photons(np, 2 * index + 1);
00696 }
00697 }
00698
00699
00700 float32 dist1;
00701 dist1 = p->m_position[0] - np->m_position[0];
00702 float32 dist2 = dist1 * dist1;
00703 dist1 = p->m_position[1] - np->m_position[1];
00704 dist2 += dist1 * dist1;
00705 dist1 = p->m_position[2] - np->m_position[2];
00706 dist2 += dist1 * dist1;
00707
00708 if(dist2 < np->m_dist2[0]) {
00709
00710
00711 if(np->m_found < np->m_max) {
00712
00713 ++np->m_found;
00714 np->m_dist2[np->m_found] = dist2;
00715 np->m_index[np->m_found] = p;
00716 } else {
00717 int j, parent;
00718
00719 if(np->m_got_heap == 0) {
00720
00721
00722 float32 dst2;
00723 const Photon *phot;
00724 const int half_found = np->m_found >> 1;
00725
00726 for(int k = half_found; k >= 1; --k) {
00727 parent = k;
00728 phot = np->m_index[k];
00729 dst2 = np->m_dist2[k];
00730
00731 while(parent <= half_found) {
00732 j = parent + parent;
00733
00734 if(j < np->m_found && np->m_dist2[j] < np->m_dist2[j + 1])
00735 ++j;
00736
00737 if(dst2 >= np->m_dist2[j])
00738 break;
00739
00740 np->m_dist2[parent] = np->m_dist2[j];
00741 np->m_index[parent] = np->m_index[j];
00742
00743 parent = j;
00744 }
00745
00746 np->m_dist2[parent] = dst2;
00747 np->m_index[parent] = phot;
00748 }
00749
00750 np->m_got_heap = 1;
00751 }
00752
00753
00754
00755
00756 parent = 1;
00757 j = 2;
00758
00759 while(j <= np->m_found) {
00760 if(j < np->m_found && np->m_dist2[j] < np->m_dist2[j + 1])
00761 ++j;
00762
00763 if(dist2 > np->m_dist2[j])
00764 break;
00765
00766 np->m_dist2[parent] = np->m_dist2[j];
00767 np->m_index[parent] = np->m_index[j];
00768 parent = j;
00769
00770 j += j;
00771 }
00772
00773
00774
00775 np->m_index[parent] = p;
00776 np->m_dist2[parent] = dist2;
00777
00778 np->m_dist2[0] = np->m_dist2[1];
00779 }
00780 }
00781 }
00782
00783 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00784
00785 void PhotonMap::locate_nearest_photon_with_irradiance(const Vector3 &normal,
00786 nearest_photons *np,
00787 int index) const
00788 {
00789 const Photon *p = &m_photons[index];
00790
00791 if(index < m_half_stored_photons) {
00792
00793
00794 const int plane = p->GetSplittingPlaneAxis();
00795 const float32 dist1 = np->m_position[plane] - p->m_position[plane];
00796
00797 if(dist1 > 0.0f) {
00798 locate_nearest_photon_with_irradiance(normal, np, 2 * index + 1);
00799
00800 if(dist1 * dist1 < np->m_dist2[0])
00801 locate_nearest_photon_with_irradiance(normal, np, 2 * index);
00802 } else {
00803 locate_nearest_photon_with_irradiance(normal, np, 2 * index);
00804
00805 if(dist1 * dist1 < np->m_dist2[0])
00806 locate_nearest_photon_with_irradiance(normal, np, 2 * index + 1);
00807 }
00808 }
00809
00810 if(p->HasPrecomputedRadiance()) {
00811 const Real THRESHOLD = 0.9;
00812
00813 if(normal * p->GetSurfaceNormal() >= THRESHOLD) {
00814
00815 float32 dist1;
00816 dist1 = p->m_position[0] - np->m_position[0];
00817 float32 dist2 = dist1 * dist1;
00818 dist1 = p->m_position[1] - np->m_position[1];
00819 dist2 += dist1 * dist1;
00820 dist1 = p->m_position[2] - np->m_position[2];
00821 dist2 += dist1 * dist1;
00822
00823 if(dist2 < np->m_dist2[0]) {
00824
00825 np->m_dist2[0] = dist2;
00826 np->m_index[0] = p;
00827 }
00828 }
00829 }
00830 }
00831
00832 #endif // ENABLE_RADIANCES_PRECOMPUTATION