00001 #include "PhotonMap.h"
00002 #include <boost/thread/thread.hpp>
00003 #include <boost/bind.hpp>
00004 #include "../Ray.h"
00005 #include "../materials/Material.h"
00006
00007 using namespace std;
00008
00009 namespace rcrt
00010 {
00011
00012 PhotonMap::PhotonMap(Scene* s, const float& maxRad, const int& maxB, const float& flatten):
00013 scene(s),globalTree(maxRad * maxRad), causticTree(maxRad * maxRad),
00014 maxRadius(maxRad), maxBounces(maxB), currentRadius(maxRad / 8.0f),flat(flatten)
00015 {
00016 }
00017
00018 PhotonMap::~PhotonMap()
00019 {
00020 for(unsigned int i = 0; i < photons.size(); i++)
00021 delete photons[i];
00022 }
00023
00024 void PhotonMap::generate(const int& noPhotons)
00025 {
00026 photons.reserve(noPhotons);
00027 caustics.reserve(noPhotons/4);
00028 vector<Light*>* lights = scene->getLights();
00029
00030
00031 int noPhotonsPL[lights->size()];
00032 float totalPower = 0;
00033 int phots = 0;
00034 for(unsigned int i = 0; i < lights->size(); i++){
00035 totalPower += lights->at(i)->getPower().avg();
00036 }
00037 for(unsigned int i = 0; i < lights->size(); i++){
00038 noPhotonsPL[i] = (int)floor((lights->at(i)->getPower().avg() / totalPower) * noPhotons);
00039 phots += noPhotonsPL[i];
00040 }
00041 phots = noPhotons - phots;
00042 unsigned int i = 0;
00043 while(phots > 0){
00044 if(i >= lights->size())
00045 i = 0;
00046 noPhotonsPL[i]++;
00047 phots--;
00048 }
00049
00050 RGBColor totalPowerRem(0);
00051
00052
00053 i = 0;
00054
00055 if(lights->size() % 2 != 0){
00056 vector<Photon*> caustics1;
00057 caustics1.reserve(noPhotonsPL[0]/4);
00058 vector<Photon*> photons1;
00059 photons1.reserve(noPhotonsPL[0]);
00060 int storedTotal = 0;
00061 cout << "[PhotonMap] Sending "<<noPhotonsPL[0]<<" photons for light: " << 0 << endl;
00062 boost::thread first(boost::bind(boost::mem_fn(&PhotonMap::generateJob), this, lights->at(0),
00063 &photons1, &caustics1, boost::cref(noPhotonsPL[0]), boost::ref(storedTotal)));
00064 i++;
00065 first.join();
00066 const float weight = 1.0f / float(storedTotal);
00067 cout << "[PhotonMap] Sent " << noPhotonsPL[0] << " photons, with weight " << weight << endl;
00068 for(unsigned int k = 0; k < caustics1.size(); k++){
00069 Photon* p = caustics1[k];
00070 p->setWeight(weight);
00071 caustics.push_back(p);
00072 totalPowerRem = totalPowerRem + p->getPower();
00073 }
00074 for(unsigned int k = 0; k < photons1.size(); k++){
00075 Photon* p = photons1[k];
00076 p->setWeight(weight);
00077 photons.push_back(photons1[k]);
00078
00079 totalPowerRem = totalPowerRem + p->getPower();
00080 }
00081 }
00082
00083 for(; i < lights->size(); i += 2){
00084 cout << "[PhotonMap] Sending "<< noPhotonsPL[i] << " photons for light: " << i << endl;
00085 cout << "[PhotonMap] Sending "<< noPhotonsPL[i+1] << " photons for light: " << i+1 << endl;
00086 vector<Photon*> caustics1;
00087 caustics1.reserve(noPhotonsPL[i]/4);
00088 vector<Photon*> caustics2;
00089 caustics2.reserve(noPhotonsPL[i+1]/4);
00090 vector<Photon*> photons1;
00091 photons1.reserve(noPhotonsPL[i]);
00092 vector<Photon*> photons2;
00093 photons2.reserve(noPhotonsPL[i+1]);
00094 int storedTotal1 = 0;
00095 int storedTotal2 = 0;
00096
00097 boost::thread first(boost::bind(boost::mem_fn(&PhotonMap::generateJob), this, lights->at(i),
00098 &photons1, &caustics1, boost::cref(noPhotonsPL[i]), boost::ref(storedTotal1)));
00099 boost::thread second(boost::bind(boost::mem_fn(&PhotonMap::generateJob), this, lights->at(i+1),
00100 &photons2, &caustics2, boost::cref(noPhotonsPL[i+1]), boost::ref(storedTotal2)));
00101
00102 first.join();
00103 const float weight1 = 1.0f / float(storedTotal1);
00104 cout << "[PhotonMap] Sent " << noPhotonsPL[i] << " photons with weight "<< weight1 << endl;
00105 second.join();
00106 const float weight2 = 1.0f / float(storedTotal2);
00107 cout << "[PhotonMap] Sent " << noPhotonsPL[i+1] << " photons with weight "<< weight2 << endl;
00108 for(unsigned int k = 0; k < caustics1.size(); k++){
00109 Photon* p = caustics1[k];
00110 p->setWeight(weight1);
00111 caustics.push_back(p);
00112 totalPowerRem = totalPowerRem + p->getPower();
00113 }
00114 for(unsigned int k = 0; k < caustics2.size(); k++){
00115 Photon* p = caustics2[k];
00116 p->setWeight(weight2);
00117 caustics.push_back(p);
00118 totalPowerRem = totalPowerRem + p->getPower();
00119 }
00120 for(unsigned int k = 0; k < photons1.size(); k++){
00121 Photon* p = photons1[k];
00122 p->setWeight(weight1);
00123 photons.push_back(p);
00124 totalPowerRem = totalPowerRem + p->getPower();
00125 }
00126 for(unsigned int k = 0; k < photons2.size(); k++){
00127 Photon* p = photons2[k];
00128 p->setWeight(weight2);
00129 photons.push_back(p);
00130 totalPowerRem = totalPowerRem + p->getPower();
00131 }
00132 }
00133
00134 cout << " building global photon kdtree of size "<< photons.size() << endl;
00135 globalTree.buildTree(&photons);
00136 cout << " building caustic photon kdtree of size " << caustics.size() << endl;
00137 causticTree.buildTree(&caustics);
00138 cout << " total power in the photon map: " << totalPowerRem << endl;
00139 }
00140
00141 void PhotonMap::generateJob(Light* light, vector<Photon*>* photons, vector<Photon*>* caustics,
00142 const int& noPhotons, int& storedTotal)
00143 {
00144 int storedGlobal = 0;
00145 int storedCaustic = 0;
00146 while(storedGlobal+storedCaustic < noPhotons){
00147
00148 Photon* photon = new Photon();
00149
00150 light->emitPhoton(photon);
00151
00152
00153 Ray photRay(photon->getPos(), photon->getDir());
00154 Intersection is(scene->intersect(photRay));
00155
00156 if(!is.isValid()){
00157
00158
00159 delete photon;
00160 continue;
00161 } else {
00162 complex<float> prevIOR(1,0);
00163 is.setLastIOR(prevIOR);
00164 Material* prevMat = is.getPrimitive()->getMaterial();
00165 RGBColor prevPower = photon->getPower();
00166 Vec3D prevIncDir = photon->getDir();
00167 bool prevBackSide = is.backSide();
00168 ScatterEvent scEvent = prevMat->scatterPhoton(is, photon);
00169 ScatterEvent lastScEvent = scEvent;
00170 if(scEvent == INVALID || scEvent == STORE){
00171 delete photon;
00172 continue;
00173 }
00174
00175 bool causticPath = false;
00176
00177 while(scEvent != INVALID
00178 && scEvent != STORE){
00179 if(photon->getBounces() == maxBounces){
00180 scEvent = STORE;
00181 break;
00182 }
00183
00184 if(photon->getBounces() > 2 && scEvent == DIFFUSE) {
00185 if(causticPath){
00186 caustics->push_back(
00187 new Photon(prevPower,
00188 prevIncDir, photon->getPos(), photon->getBounces()));
00189 storedCaustic++;
00190 } else {
00191 photons->push_back(
00192 new Photon(prevPower,
00193 prevIncDir, photon->getPos(), photon->getBounces()));
00194
00195 storedGlobal++;
00196 }
00197 }
00198
00199 causticPath = causticPath || scEvent == SPECULAR || scEvent == REFRACTED;
00200
00201 Ray nextRay = Ray(photon->getPos(), photon->getDir());
00202 is = scene->intersect(photRay);
00203 if(!is.isValid()){
00204 scEvent = INVALID;
00205 break;
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 if(lastScEvent == REFRACTED)
00218 is.setLastIOR(prevMat->getIOR());
00219 else
00220 is.setLastIOR(complex<float>(1,0));
00221 prevMat = is.getPrimitive()->getMaterial();
00222 photRay = nextRay;
00223 prevPower = photon->getPower();
00224 prevIncDir = photon->getDir();
00225 lastScEvent = scEvent;
00226 scEvent = prevMat->scatterPhoton(is, photon);
00227 photon->addBounce();
00228
00229 if(photon->getPower().sum()-0.001f <= numeric_limits<float>::epsilon()){
00230 scEvent = INVALID;
00231 break;
00232 }
00233 }
00234 if(scEvent == INVALID){
00235
00236
00237
00238 photon->setDir(prevIncDir);
00239 photon->setPower(prevPower);
00240
00241 photons->push_back(photon);
00242 storedGlobal++;
00243 } else {
00244 photons->push_back(photon);
00245 storedGlobal++;
00246 }
00247 }
00248 }
00249
00250 storedTotal = storedGlobal + storedCaustic;
00251 }
00252
00253 RGBColor PhotonMap::getRadiance(const Vec3D& wOut,
00254 const int& noGPhotons, const int& noCPhotons, Intersection& is)
00255 {
00256 Material* mat = is.getPrimitive()->getMaterial();
00257 Vec3D normal(mat->getShadingNormal(is));
00258 const Point3D& pos(is.getPosition());
00259
00260
00261 float currRSqr = maxRadius*maxRadius;
00262
00263 std::vector<PKDSearchP> global;
00264 if(noGPhotons != 0) globalTree.getKNearest(&global, noGPhotons, pos, normal, currRSqr, flat);
00265
00266 std::vector<PKDSearchP> caustic;
00267 if(noCPhotons != 0) causticTree.getKNearest(&caustic, noCPhotons, pos, normal, currRSqr/2, flat);
00268
00269 static const float gauss_norm = 1.8790;
00270 static const float alpha = 0.918 * gauss_norm;
00271 static const float beta = 1.953;
00272 static const float divG = 1.0f / (1.0 - exp(-beta));
00273
00274
00275 float maxGR = -numeric_limits<float>::infinity();
00276
00277 for(unsigned int i = 0; i < global.size(); i++){
00278 const float& distSqr(global[i].distSqr);
00279
00280 if(distSqr > maxGR) maxGR = distSqr;
00281 }
00282
00283 RGBColor globalR(0);
00284 for(unsigned int i = 0; i < global.size(); i++){
00285 const float& distSqr(global[i].distSqr);
00286 const float gauss = alpha * (1.0 - (1.0 - exp( -beta * distSqr / (M_PI * maxGR) )) * divG);
00287 Photon* p = global[i].p;
00288 globalR = globalR + p->getPower() * fabs(normal * p->getDir())
00289 * p->getWeight() * mat->sample(wOut, p->getDir(), is)
00290 * gauss;
00291 }
00292
00293 float maxCR = -numeric_limits<float>::infinity();
00294
00295 for(unsigned int i = 0; i < caustic.size(); i++){
00296 const float& distSqr(caustic[i].distSqr);
00297 if(distSqr > maxCR) maxCR = distSqr;
00298 }
00299
00300 RGBColor causticR(0);
00301 for(unsigned int i = 0; i < caustic.size(); i++){
00302 const float& distSqr(caustic[i].distSqr);
00303 const float gauss = alpha * (1.0 - (1.0 - exp( -beta * distSqr / (M_PI * maxCR) )) * divG);
00304 Photon* p = caustic[i].p;
00305 causticR = causticR + p->getPower() * fabs(normal * p->getDir())
00306 * p->getWeight() * mat->sample(wOut, p->getDir(), is)
00307 * gauss;
00308 }
00309
00310 return globalR + causticR;
00311 }
00312
00313 const float& PhotonMap::getMaxRadius() const
00314 {
00315 return maxRadius;
00316 }
00317
00318 }