//********************************************** void Photon_map :: irradiance_estimate( float irrad[3], // returned irradiance const float pos[3], // surface position const float normal[3], // surface normal at pos const float max_dist, // max distance to look for photons const int nphotons ) const // number of photons to use //********************************************** { irrad[0] = irrad[1] = irrad[2] = 0.0; NearestPhotons np; np.dist2 = (float*)alloca( sizeof(float)*(nphotons+1) ); np.index = (const Photon**)alloca( sizeof(Photon*)*(nphotons+1) ); np.pos[0] = pos[0]; np.pos[1] = pos[1]; np.pos[2] = pos[2]; np.max = nphotons; np.found = 0; np.got_heap = 0; np.dist2[0] = max_dist*max_dist; // locate the nearest photons locate_photons( &np, 1 ); // if less than 8 photons return if (np.found<8) return; float pdir[3]; // sum irradiance from all photons for (int i=1; i<=np.found; i++) { const Photon *p = np.index[i]; // the photon_dir call and following if can be omitted (for speed) // if the scene does not have any thin surfaces photon_dir( pdir, p ); if ( (pdir[0]*normal[0]+pdir[1]*normal[1]+pdir[2]*normal[2]) < 0.0f ) { irrad[0] += p->power[0]; irrad[1] += p->power[1]; irrad[2] += p->power[2]; } } const float tmp=(1.0f/PI)/(np.dist2[0]); // estimate of density irrad[0] *= tmp; irrad[1] *= tmp; irrad[2] *= tmp; }
//****************************************** void PhotonMap::locate_photons(NearestPhotons *const np, const int index) const //****************************************** { const Photon *p = &photons[index]; float dist1; if (index < half_stored_photons) { dist1 = np->pos[p->plane] - p->pos[p->plane]; if (dist1 > 0.0) { // if dist1 is positive search right plane locate_photons(np, 2 * index + 1); if (dist1 * dist1 < np->dist2[0]) locate_photons(np, 2 * index); } else { // dist1 is negative search left first locate_photons(np, 2 * index); if (dist1 * dist1 < np->dist2[0]) locate_photons(np, 2 * index + 1); } } // compute squared distance between current photon and np->pos dist1 = p->pos[0] - np->pos[0]; float dist2 = dist1 * dist1; dist1 = p->pos[1] - np->pos[1]; dist2 += dist1 * dist1; dist1 = p->pos[2] - np->pos[2]; dist2 += dist1 * dist1; if (dist2 < np->dist2[0]) { // we found a photon [:)] Insert it in the candidate list if (np->found < np->max) { // heap is not full; use array np->found++; np->dist2[np->found] = dist2; np->index[np->found] = p; } else { int j, parent; if (np->got_heap == 0) { // Do we need to build the heap? // Build heap float dst2; const Photon *phot; int half_found = np->found >> 1; for (int k = half_found; k >= 1; k--) { parent = k; phot = np->index[k]; dst2 = np->dist2[k]; while (parent <= half_found) { j = parent + parent; if (j < np->found && np->dist2[j] < np->dist2[j + 1]) j++; if (dst2 >= np->dist2[j]) break; np->dist2[parent] = np->dist2[j]; np->index[parent] = np->index[j]; parent = j; } np->dist2[parent] = dst2; np->index[parent] = phot; } np->got_heap = 1; } // insert new photon into max heap // delete largest element, insert new and reorder the heap parent = 1; j = 2; while (j <= np->found) { if (j < np->found && np->dist2[j] < np->dist2[j + 1]) j++; if (dist2 > np->dist2[j]) break; np->dist2[parent] = np->dist2[j]; np->index[parent] = np->index[j]; parent = j; j += j; } np->index[parent] = p; np->dist2[parent] = dist2; np->dist2[0] = np->dist2[1]; } }