////////////////////////////////////////////////////////////////////// // // Pixie // // Copyright © 1999 - 2003, Okan Arikan // // Contact: okan@cs.berkeley.edu // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // // File : photonMap.h // Classes : CPhotonMap // Description : // //////////////////////////////////////////////////////////////////////// #ifndef PHOTONMAP_H #define PHOTONMAP_H #include "common/global.h" #include "common/algebra.h" #include "ray.h" #include "renderer.h" #include "output.h" // Macros to pack/unpack directions #define dirToPhoton(theta__,phi__,D__) { \ int t__,p__; \ t__ = (int) (acos(D__[2])*(256.0 / C_PI)); \ p__ = (int) (atan2(D__[1],D__[0])*(256.0 / (2.0*C_PI))); \ if (t__ > 255) \ theta__ = (unsigned char) 255; \ else \ theta__ = (unsigned char) t__; \ \ if (p__ > 255) \ phi__ = (unsigned char) 255; \ else if (p__ < 0) \ phi__ = (unsigned char) (p__ + 256); \ else \ phi__ = (unsigned char) p__; \ } #define photonToDir(D__,theta__,phi__) { \ D__[0] = sintheta[theta__]*cosphi[phi__]; \ D__[1] = sintheta[theta__]*sinphi[phi__]; \ D__[2] = costheta[theta__]; \ } #define PDEBUG // Some extern variables defined in photon.cpp extern int inited; extern float costheta[256]; extern float sintheta[256]; extern float cosphi[256]; extern float sinphi[256]; /////////////////////////////////////////////////////////////////////// // Class : CTon // Description : Holds a generic particle // Comments : // Date last edited : 4/1/2002 class CTon { public: vector P,N; // Position and normal short flags; // Photon flags }; /////////////////////////////////////////////////////////////////////// // Class : CMap // Description : Holds a generic map // Comments : // Date last edited : 4/1/2002 template class CMap { public: /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : CMap // Description : Ctor // Return Value : // Comments : // Date last edited : 4/1/2002 CMap() { numPhotons = 0; maxPhotons = 0; photons = NULL; stepSize = 10000; initv(bmin,C_INFINITY,C_INFINITY,C_INFINITY); initv(bmax,-C_INFINITY,-C_INFINITY,-C_INFINITY); if (inited == FALSE) { int i; inited = TRUE; for (i=0;i<256;i++) { const double angle = (double) i * (1.0 / 256.0) * C_PI; costheta[i] = (float) cos(angle); sintheta[i] = (float) sin(angle); cosphi[i] = (float) cos(2 * angle); sinphi[i] = (float) sin(2 * angle); } } } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : ~CMap // Description : Dtor // Return Value : // Comments : // Date last edited : 4/1/2002 virtual ~CMap() { if (photons != NULL) delete [] photons; } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : read // Description : Read the photonmap from a file // Return Value : // Comments : // Date last edited : 9/10/2002 void read(FILE *in) { fread(&numPhotons,1,sizeof(int),in); fread(&maxPhotons,1,sizeof(int),in); photons = new T[maxPhotons+1]; fread(photons,numPhotons+1,sizeof(T),in); fread(bmin,3,sizeof(float),in); fread(bmax,3,sizeof(float),in); numPhotonsh = numPhotons >> 1; } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : write // Description : Append the photon map into a file // Return Value : // Comments : // Date last edited : 9/10/2002 void write(FILE *out) { fwrite(&numPhotons,1,sizeof(int),out); fwrite(&maxPhotons,1,sizeof(int),out); fwrite(photons,numPhotons+1,sizeof(T),out); fwrite(bmin,3,sizeof(float),out); fwrite(bmax,3,sizeof(float),out); } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : reset // Description : Reset the photonmap // Return Value : // Comments : // Date last edited : 9/10/2002 void reset() { if (photons != NULL) delete photons; numPhotons = 0; maxPhotons = 0; photons = NULL; initv(bmin,C_INFINITY,C_INFINITY,C_INFINITY); initv(bmax,-C_INFINITY,-C_INFINITY,-C_INFINITY); } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : store // Description : Store a photon // Return Value : // Comments : // Date last edited : 4/1/2002 T *store(const float *P,const float *N) { if (numPhotons < maxPhotons) { T *photon = &photons[++numPhotons]; movvv(photon->P,P); movvv(photon->N,N); addBox(bmin,bmax,P); photon->flags = 0; return photon; } else { T *newPhotons; maxPhotons += stepSize; stepSize *= 2; newPhotons = new T[maxPhotons+1]; if (numPhotons > 0) { memcpy(newPhotons,photons,(numPhotons+1)*sizeof(T)); delete [] photons; } photons = newPhotons; T *photon = &photons[++numPhotons]; movvv(photon->P,P); movvv(photon->N,N); addBox(bmin,bmax,P); photon->flags = 0; return photon; } } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : store // Description : Store a photon // Return Value : // Comments : // Date last edited : 4/1/2002 T *store(const T *item) { if (numPhotons < maxPhotons) { T *photon = &photons[++numPhotons]; photon[0] = item[0]; addBox(bmin,bmax,item->P); return photon; } else { T *newPhotons; maxPhotons += stepSize; stepSize *= 2; newPhotons = new T[maxPhotons+1]; if (numPhotons > 0) { memcpy(newPhotons,photons,(numPhotons+1)*sizeof(T)); delete [] photons; } photons = newPhotons; T *photon = &photons[++numPhotons]; photon[0] = item[0]; addBox(bmin,bmax,item->P); return photon; } } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : balance // Description : Balance the map // Return Value : - // Comments : Must be called before the map is used // Date last edited : 4/1/2002 virtual void balance() { if (numPhotons == 0) return; T **ar1 = new T*[numPhotons+1]; T **ar2 = new T*[numPhotons+1]; int i; T *finalPhotons; for (i=0;i<=numPhotons;i++) { ar2[i] = &photons[i]; } balance(ar1,ar2,1,1,numPhotons); delete [] ar2; finalPhotons = new T[numPhotons+1]; for (i=1;i<=numPhotons;i++) { finalPhotons[i] = ar1[i][0]; } delete [] ar1; delete [] photons; maxPhotons = numPhotons; photons = finalPhotons; numPhotonsh = numPhotons >> 1; } vector bmin,bmax; protected: class CLookup { public: int maxFound; int numFound; int gotHeap; vector P,N; float *distances; const T **indices; }; /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : balance // Description : Balance a particular subset // Return Value : Internally used by balance // Comments : // Date last edited : 4/1/2002 void balance(T **ar1,T **ar2,int index,int start,int end) { int median = 1; while((4*median) <= (end-start+1)) median += median; if ((3*median) <= (end-start+1)) { median += median; median += start-1; } else median = end-median+1; int axis = 2; if (((bmax[0] - bmin[0]) > (bmax[1] - bmin[1])) && ((bmax[0] - bmin[0]) > (bmax[2] - bmin[2]))) axis = 0; else if ((bmax[1] - bmin[1]) > (bmax[2] - bmin[2])) axis = 1; { #define swap(item1,item2) { \ T *tmp = ar2[item1]; \ ar2[item1] = ar2[item2]; \ ar2[item2] = tmp; \ } int left = start; int right = end; while(right > left) { const float v = ar2[right]->P[axis]; int i = left-1; int j = right; for(;;) { while(ar2[++i]->P[axis] < v); while((ar2[--j]->P[axis] > v) && (j>left)); if (i >= j) break; swap(i,j); } swap(i,right); if (i >= median) right = i-1; if (i <= median) left = i+1; } #ifdef PDEBUG // FIXME: Remove int i; for (i=start;iP[axis] <= ar2[median]->P[axis]); } for (i=median+1;i<=end;i++) { assert(ar2[i]->P[axis] >= ar2[median]->P[axis]); } // FIXME: Remove #endif #undef swap } ar1[index] = ar2[median]; ar1[index]->flags = axis; if (median > start) { if (start < (median-1)) { const float tmp = bmax[axis]; bmax[axis] = ar1[index]->P[axis]; balance(ar1,ar2,2*index,start,median-1); bmax[axis] = tmp; } else { ar1[2*index] = ar2[start]; } } if (median < end) { if ((median+1) < end) { const float tmp = bmin[axis]; bmin[axis] = ar1[index]->P[axis]; balance(ar1,ar2,2*index+1,median+1,end); bmin[axis] = tmp; } else { ar1[2*index+1] = ar2[end]; } } } public: /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : lookup // Description : Locate the nearest maxFoundPhoton photons // Return Value : Internally used // Comments : // Date last edited : 4/1/2002 void lookupWithN(CLookup *l,int index) { const T *photon = &photons[index]; float d,t; vector D; int axis = photon->flags; if (index < numPhotonsh) { d = l->P[axis] - photon->P[axis]; if (d > 0) { lookupWithN(l,2*index+1); if (d*d < l->distances[0]) { lookupWithN(l,2*index); } } else { lookupWithN(l,2*index); if (d*d < l->distances[0]) { lookupWithN(l,2*index+1); } } } subvv(D,photon->P,l->P); d = dotvv(D,D); t = dotvv(D,l->N); d += t*t*16; if (d < l->distances[0]) { if (l->numFound < l->maxFound) { l->numFound++; l->distances[l->numFound] = d; l->indices[l->numFound] = photon; } else { int j,parent; if (l->gotHeap == FALSE) { int halfPhotons = l->numFound >> 1; int k; float dtmp; const T *ptmp; for (k=halfPhotons;k>=1;k--) { parent = k; ptmp = l->indices[k]; dtmp = l->distances[k]; while(parent <= halfPhotons) { j = parent + parent; if ((j < l->numFound) && (l->distances[j] < l->distances[j+1])) j++; if (dtmp >= l->distances[j]) break; l->distances[parent] = l->distances[j]; l->indices[parent] = l->indices[j]; parent = j; } l->distances[parent] = dtmp; l->indices[parent] = ptmp; } l->gotHeap = TRUE; } for (parent=1,j=2;j<=l->numFound;) { if ((j < l->numFound) && (l->distances[j] < l->distances[j+1])) j++; if (d > l->distances[j]) break; l->distances[parent] = l->distances[j]; l->indices[parent] = l->indices[j]; parent = j; j += j; } l->distances[parent] = d; l->indices[parent] = photon; assert(l->distances[1] <= l->distances[0]); l->distances[0] = l->distances[1]; } } } /////////////////////////////////////////////////////////////////////// // Class : CMap // Method : lookup // Description : Locate the nearest maxFoundPhoton photons // Return Value : Internally used // Comments : // Date last edited : 4/1/2002 void lookup(CLookup *l,int index) { const T *photon = &photons[index]; float d; vector D; int axis = photon->flags; if (index < numPhotonsh) { d = l->P[axis] - photon->P[axis]; if (d > 0) { lookup(l,2*index+1); if (d*d < l->distances[0]) { lookup(l,2*index); } } else { lookup(l,2*index); if (d*d < l->distances[0]) { lookup(l,2*index+1); } } } subvv(D,photon->P,l->P); d = dotvv(D,D); if (d < l->distances[0]) { if (l->numFound < l->maxFound) { l->numFound++; l->distances[l->numFound] = d; l->indices[l->numFound] = photon; } else { int j,parent; if (l->gotHeap == FALSE) { int halfPhotons = l->numFound >> 1; int k; float dtmp; const T *ptmp; for (k=halfPhotons;k>=1;k--) { parent = k; ptmp = l->indices[k]; dtmp = l->distances[k]; while(parent <= halfPhotons) { j = parent + parent; if ((j < l->numFound) && (l->distances[j] < l->distances[j+1])) j++; if (dtmp >= l->distances[j]) break; l->distances[parent] = l->distances[j]; l->indices[parent] = l->indices[j]; parent = j; } l->distances[parent] = dtmp; l->indices[parent] = ptmp; } l->gotHeap = TRUE; } for (parent=1,j=2;j<=l->numFound;) { if ((j < l->numFound) && (l->distances[j] < l->distances[j+1])) j++; if (d > l->distances[j]) break; l->distances[parent] = l->distances[j]; l->indices[parent] = l->indices[j]; parent = j; j += j; } l->distances[parent] = d; l->indices[parent] = photon; assert(l->distances[1] <= l->distances[0]); l->distances[0] = l->distances[1]; } } } T *photons; int numPhotons; int maxPhotons; int numPhotonsh; int stepSize; }; /////////////////////////////////////////////////////////////////////// // // // Regular Photon Mapping stuff // // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CPhoton // Description : A Photon // Comments : // Date last edited : 4/1/2002 class CPhoton : public CTon { public: vector C; // The intensity unsigned char theta,phi; // Photon direction }; /////////////////////////////////////////////////////////////////////// // Class : CPhotonRay // Description : A Photon // Comments : // Date last edited : 4/1/2002 class CPhotonRay : public CRay { public: vector intensity; // The intensity float factor; // The product of all the factors (used for routian roulette) }; /////////////////////////////////////////////////////////////////////// // Class : CPhotonMap // Description : A Photon map // Comments : // Date last edited : 3/11/2003 class CPhotonMap : public CMap , public CFileResource { class CPhotonSample { public: vector C,P,N; float dP; CPhotonSample *next; }; class CPhotonNode { public: vector center; float side; CPhotonSample *samples; CPhotonNode *children[8]; }; public: CPhotonMap(const char *,const CXform *,FILE *); ~CPhotonMap(); void attach() { refCount++; } void detach() { refCount--; if (refCount == 0) delete this; } void check() { if (refCount == 0) delete this; } void reset(); void write(const CXform *); int probe(float *,const float *,const float *); void insert(const float *,const float *,const float *,float); void lookup(float *,const float *,int); void lookup(float *,const float *,const float *,int); void balance(); void store(const float *,const float *,const float *,const float *); CPhotonNode *root; int maxDepth; // The maximum depth of the hierarchy int refCount; int modifying; matrix toCamera,fromCamera; float maxPower; // The maximum photon power float searchRadius; }; #endif