PhotonMap.cc

Go to the documentation of this file.
00001 #include <esg/energy/PhotonMap.h>
00002 
00003 using namespace esg;
00004 
00005 #define swap(ph,a,b) { Photon *ph2=ph[a]; ph[a]=ph[b]; ph[b]=ph2; }
00006 
00007 void PhotonMap::_build(const vector<Photon>& photons)
00008 {
00009     _storedPhotons = photons.size();
00010     
00011 #ifdef WIN32
00012     _map = (Photon*) malloc((_storedPhotons+1) * sizeof(Photon));
00013 #else
00014     _map = new Photon [_storedPhotons+1];
00015 #endif
00016     
00017     if (!_map) {
00018         _storedPhotons = 0;
00019         fprintf(stderr,"PhotonMap::_build(): Out of memory initializing photon map\n");
00020         return;
00021     }
00022 
00023     _bboxMin[0] = _bboxMin[1] = _bboxMin[2] = 1e8f;
00024     _bboxMax[0] = _bboxMax[1] = _bboxMax[2] = -1e8f;
00025     
00026     for (int i = 0; i < photons.size(); i++) {
00027         _map[i] = photons[i];
00028         for (register unsigned j = 0; j < 3; j++) {
00029             if (photons[i]._position[j] < _bboxMin[j])
00030                 _bboxMin[j] = photons[i]._position[j];
00031             if (photons[i]._position[j] > _bboxMax[j])
00032                 _bboxMax[j] = photons[i]._position[j];
00033         }
00034     }
00035 
00036     /*
00037      * Creates a left balanced kd-tree from the flat photon array.
00038      * This function should be called before the photon map
00039      * is used for rendering.
00040      */
00041 
00042     if (_storedPhotons <= 1) return;
00043    
00044     // allocate two temporary arrays for the balancing procedure
00045     Photon **pa1 = (Photon**) malloc(sizeof(Photon*)*(_storedPhotons+1));
00046     Photon **pa2 = (Photon**) malloc(sizeof(Photon*)*(_storedPhotons+1));
00047     
00048     for (register unsigned i = 0; i <= _storedPhotons; i++) pa2[i] = &_map[i];
00049     
00050     _balance_segment(pa1, pa2, 1, 1, _storedPhotons);
00051     free(pa2);
00052     
00053     // reorganize balanced kd-tree (make a heap)
00054     unsigned d, j=1, foo=1;
00055     Photon foo_photon = _map[j];
00056     
00057     for (register unsigned i = 1; i <= _storedPhotons; i++) {
00058         d = pa1[j] - _map;
00059         pa1[j] = NULL;
00060         if (d != foo)
00061             _map[j] = _map[d];
00062         else {
00063             _map[j] = foo_photon;
00064             if (i < _storedPhotons) {
00065                 for (; foo <= _storedPhotons; foo++)
00066                     if (pa1[foo] != NULL) break;
00067                 foo_photon = _map[foo];
00068                 j = foo;
00069             }
00070             continue;
00071         }
00072         j = d;
00073     }
00074     free(pa1);
00075 }
00076 
00077 // median_split splits the photon array into two separate
00078 // pieces around the median with all photons below the
00079 // the median in the lower half and all photons above
00080 // than the median in the upper half. The comparison
00081 // criteria is the axis (indicated by the axis parameter)
00082 // (inspired by routine in "Algorithms in C++" by Sedgewick)
00083 void PhotonMap::_median_split(Photon **p, int start,
00084                               int end, int median, int axis)
00085 {
00086     int left = start;
00087     int right = end;
00088 
00089     while (right > left) {
00090         float v = p[right]->_position[axis];
00091         int i = left - 1;
00092         int j = right;
00093         for (;;) {
00094             while (p[++i]->_position[axis] < v);
00095             while (p[--j]->_position[axis] > v && j>left);
00096             if (i >= j) break;
00097             swap(p, i, j);
00098         }
00099 
00100         swap(p, i, right);
00101         if (i >= median) right = i - 1;
00102         if (i <= median) left  = i + 1;
00103     }
00104 }
00105 
00106   
00107 // See "Realistic image synthesis using Photon Mapping" chapter 6
00108 // for an explanation of this function
00109 void PhotonMap::_balance_segment(Photon **pbal, Photon **porg,
00110                                  int index, int start, int end )
00111 {
00112     //--------------------
00113     // compute new median
00114     //--------------------
00115     
00116     int median = 1;
00117     while ((4*median) <= (end-start+1))
00118         median += median;
00119 
00120     if ((3*median) <= (end-start+1)) {
00121         median += median;
00122         median += start-1;
00123     } else      
00124         median = end-median+1;
00125 
00126     //--------------------------
00127     // find axis to split along
00128     //--------------------------
00129     
00130     int axis=2;
00131     if ((_bboxMax[0] - _bboxMin[0]) > (_bboxMax[1] - _bboxMin[1]) &&
00132         (_bboxMax[0] - _bboxMin[0]) > (_bboxMax[2] - _bboxMin[2]))
00133         axis=0;
00134     else if ((_bboxMax[1] - _bboxMin[1]) > (_bboxMax[2] - _bboxMin[2]))
00135         axis=1;
00136 
00137     //------------------------------------------
00138     // partition photon block around the median
00139     //------------------------------------------
00140     
00141     _median_split(porg, start, end, median, axis);
00142 
00143     pbal[index] = porg[median];
00144     pbal[index]->_plane = axis;
00145 
00146     //----------------------------------------------
00147     // recursively balance the left and right block
00148     //----------------------------------------------
00149     
00150     if (median > start) {
00151         // balance left segment
00152         if (start < median-1) {
00153             float tmp = _bboxMax[axis];
00154             _bboxMax[axis] = pbal[index]->_position[axis];
00155             _balance_segment(pbal, porg, 2*index, start, median-1);
00156             _bboxMax[axis] = tmp;
00157         } else {
00158             pbal[2*index] = porg[start];
00159         }
00160     }
00161 
00162     if (median < end) {
00163         // balance right segment
00164         if (median+1 < end) {
00165             float tmp = _bboxMin[axis];         
00166             _bboxMin[axis] = pbal[index]->_position[axis];
00167             _balance_segment(pbal, porg, 2*index+1, median+1, end);
00168             _bboxMin[axis] = tmp;
00169         } else {
00170             pbal[2*index+1] = porg[end];
00171         }
00172     }   
00173 }
00174 
00175 void PhotonMap::_locate_photons(NearestPhotons * const np,
00176                                 unsigned               index) const
00177 {
00178     const Photon* p = &(np->photons[index]);
00179     float         dist1;
00180     unsigned      i2;
00181 
00182     if (index < np->halfStoredPhotons) { // inner node
00183         dist1 = np->pos[p->_plane] - p->_position[p->_plane];
00184         i2    = 2 * index;
00185 
00186         if (dist1 > 0.) { // search right plane first
00187             _locate_photons(np, i2+1);
00188             if (dist1*dist1 < np->dist2[0]) _locate_photons(np, i2);
00189         } else { // search left plane first
00190             _locate_photons(np, i2);
00191             if (dist1*dist1 < np->dist2[0]) _locate_photons(np, i2+1);
00192         }
00193     }
00194 
00195     // compute squared distance between current photon an np.pos
00196     dist1       = p->_position[0] - np->pos[0];
00197     float dist2 = dist1*dist1;
00198     dist1       = p->_position[1] - np->pos[1];
00199     dist2      += dist1*dist1;
00200     dist1       = p->_position[2] - np->pos[2];
00201     dist2      += dist1*dist1;
00202 
00203     if (dist2 < np->dist2[0]) {
00204         // we found a photon, insert it in the candidate list
00205 
00206         if (np->found < np->max) {
00207             // heap is not full; use array
00208             np->found++;
00209             np->dist2[np->found] = dist2;
00210             np->index[np->found] = p;
00211         } else {
00212             int j, parent;
00213 
00214             if (!np->gotHeap) { // Do we need to build the heap?
00215                 // Build heap
00216                 float dst2;
00217                 const Photon *phot;
00218                 int half_found = np->found>>1;
00219                 for (int k = half_found; k >= 1; k--) {
00220                     parent=k;
00221                     phot = np->index[k];
00222                     dst2 = np->dist2[k];
00223                     while (parent <= half_found) {
00224                         j = parent+parent;
00225                         if (j<np->found && np->dist2[j]<np->dist2[j+1]) j++;
00226                         if (dst2 >= np->dist2[j]) break;
00227                         np->dist2[parent] = np->dist2[j];
00228                         np->index[parent] = np->index[j];
00229                         parent=j;
00230                     }
00231                     np->dist2[parent] = dst2;
00232                     np->index[parent] = phot;
00233                 }
00234                 np->gotHeap = true;
00235             }
00236             
00237             // insert new photon into max heap
00238             // delete largest element, insert new and reorder the heap
00239 
00240             parent=1;
00241             j = 2;
00242             while (j <= np->found) {
00243                 if (j < np->found && np->dist2[j] < np->dist2[j+1] ) j++;
00244                 if (dist2 > np->dist2[j]) break;
00245                 np->dist2[parent] = np->dist2[j];
00246                 np->index[parent] = np->index[j];
00247                 parent = j;
00248                 j += j;
00249             }
00250             np->index[parent] = p;
00251             np->dist2[parent] = dist2;
00252             np->dist2[0]      = np->dist2[1];
00253         }
00254     }
00255 }
00256 
00257 
00258 
00259 
00260 
00261 
00262 
00263 PhotonMap::PhotonMap()
00264     : _map(NULL), _storedPhotons(0)
00265 {
00266     _bboxMin[0] = _bboxMin[1] = _bboxMin[2] = 1e8f;
00267     _bboxMax[0] = _bboxMax[1] = _bboxMax[2] = -1e8f;
00268 }
00269 
00270 PhotonMap::PhotonMap(const vector<Photon>& photons)
00271     : _map(NULL), _storedPhotons(0)
00272 {
00273     _build(photons);
00274 }
00275 
00276 PhotonMap::~PhotonMap()
00277 {
00278     if (_map) delete [] _map;
00279 }
00280 
00281 void PhotonMap::set(const vector<Photon>& photons)
00282 {
00283     if (_map) delete [] _map;
00284     _build(photons);
00285 }
00286 
00287 unsigned PhotonMap::numPhotons() const
00288 {
00289     return _storedPhotons;
00290 }
00291 
00292 vector<Photon*>* PhotonMap::getNeighbourhood(const Vector3& spoint,
00293                                              const Vector3* snormal,
00294                                              float          maxdist,
00295                                              unsigned       nphotons) const 
00296 {
00297     if (_storedPhotons == 0) return NULL;
00298     NearestPhotons* np = new NearestPhotons(nphotons, spoint, maxdist,
00299                                             _map, _storedPhotons/2 - 1);
00300     _locate_photons(np, 1); // locate the nearest photons
00301 
00302     if (np->found < 8) {
00303         delete np;
00304         return NULL;
00305     }
00306 
00307     vector<Photon*> * ret = new vector<Photon*>();
00308     for (int i = 0; i < np->numPhotons(); i++) {
00309         if (snormal) {
00310             if (snormal->dot((*np)(i).getDirection()) > 0.) {
00311                 ret->push_back(&(*np)(i));
00312             }
00313         } else {
00314             ret->push_back(&(*np)(i));
00315         }
00316     }
00317     delete np;
00318     return ret;
00319 }
00320 
00321 bool PhotonMap::getIrradiance(const Vector3& spoint,
00322                               const Vector3* snormal,
00323                               float          maxdist,
00324                               unsigned       nphotons,
00325                               Vector3&       irrad) const
00326 {
00327     irrad.set(0.0, 0.0, 0.0);
00328     if (_storedPhotons == 0) return false;
00329     NearestPhotons* np = new NearestPhotons(nphotons, spoint, maxdist,
00330                                             _map, _storedPhotons/2 - 1);
00331     _locate_photons(np, 1); // locate the nearest photons
00332 
00333     if (np->found < 8) {
00334         delete np;
00335         return false;
00336     }
00337 
00338     for (int i = 0; i < np->numPhotons(); i++) {
00339         if (snormal) {
00340             if (snormal->dot((*np)(i).getDirection()) > 0.)
00341                 irrad.add((*np)(i)._power);
00342         } else {
00343             irrad.add((*np)(i)._power);
00344         }
00345     }
00346     irrad.scale(1. / (M_PI * maxdist * maxdist));
00347     delete np;
00348     return true;
00349 }

Generated on Wed Jun 28 12:24:32 2006 for esg by  doxygen 1.4.6