PhotonMapShader.cc

Go to the documentation of this file.
00001 #include <gra/shader/PhotonMapShader.h>
00002 #include <esg/explorer/ObjsExplorer.h>
00003 #include <esg/visitor/PhotonMapBhvVisitor.h>
00004 #include <esg/geometry/Sphere.h>
00005 
00006 using namespace gra;
00007 
00008 void PhotonMapShader::_create_scene_maps(List<PhotonMapEnergy>&  maps,
00009                                          List<SceneGraphObject>& reflShapes)
00010 {
00011     PhotonMapEnergy     * pMap  = new PhotonMapEnergy();
00012     AutoPtr<EnergyCoat> * pAMap = new AutoPtr<EnergyCoat>(pMap);
00013 
00014     pAMap->registerReferer(this);
00015 
00016     ObjsExplorer explorer;
00017     explorer.explore(*(_pScene->root()));
00018     
00019     SceneGraphObject    * pObj;
00020     Matrix4               trMat;
00021     bool                  tr;
00022             
00023     while ((pObj = explorer.result(trMat, tr))) {
00024         PhotonMapBhvVisitor pmbVisitor;
00025         MatVisitor          matVisitor;
00026         pObj->inspectAttributes(pmbVisitor);
00027         pObj->inspectMaterials(matVisitor);
00028 
00029         if (_userDefinedBehaviour) {
00030             if (pmbVisitor.behaviour() &&
00031                 (pmbVisitor.behaviour()->acceptsGlobalPhotons() ||
00032                  pmbVisitor.behaviour()->acceptsCaustics()))
00033                 pObj->setEnergyState(pAMap);
00034             else
00035                 pObj->setEnergyState(NULL);
00036             
00037             if (pmbVisitor.behaviour() &&
00038                 pmbVisitor.behaviour()->makesCaustics() &&
00039                 (matVisitor.avgReflection() > 0. ||
00040                  matVisitor.avgTransparency() > 0.))
00041                 reflShapes.append(pObj);
00042         } else {
00043             if (matVisitor.avgReflection() == 0. &&
00044                 matVisitor.avgTransparency() == 0.)
00045             {
00046                 // Set photon maps of diffuse surface
00047                 pObj->setEnergyState(pAMap);
00048 
00049                 // A diffuse surface should store all photons
00050                 if (!pmbVisitor.behaviour())
00051                     pObj->appendPrivateAttribute(new PhotonMapBehaviour(PhotonMapBehaviour::ACCEPT_CAUSTICS|PhotonMapBehaviour::ACCEPT_GLOBAL_PHOTONS));
00052             } else {
00053                 if (!pmbVisitor.behaviour())
00054                     pObj->appendPrivateAttribute(new PhotonMapBehaviour(PhotonMapBehaviour::MAKE_CAUSTICS));
00055                 
00056                 // A reflective/refractive surface should not employ
00057                 // photon maps, but should be used for caustics generation
00058                 // instead.
00059                 pObj->setEnergyState(NULL);
00060                 reflShapes.append(pObj);
00061             }
00062         }
00063     }
00064 
00065     // accept new photon map iff it is used by some shape
00066     if (!AutoPtr<EnergyCoat>::destroy(pAMap, this)) maps.append(pMap);
00067 }
00068 
00069 void PhotonMapShader::_create_maps_per_shape(List<PhotonMapEnergy>&  maps,
00070                                              List<SceneGraphObject>& reflShapes)
00071 {
00072     ObjsExplorer explorer;
00073     explorer.explore(*(_pScene->root()));
00074 
00075     SceneGraphObject * pObj;
00076     Matrix4            trMat;
00077     bool               tr;
00078             
00079     while ((pObj = explorer.result(trMat, tr))) {
00080         PhotonMapBhvVisitor pmbVisitor;
00081         MatVisitor          matVisitor;
00082         pObj->inspectAttributes(pmbVisitor);
00083         pObj->inspectMaterials(matVisitor);
00084            
00085         if (_userDefinedBehaviour) {
00086             if (pmbVisitor.behaviour() &&
00087                 (pmbVisitor.behaviour()->acceptsGlobalPhotons() ||
00088                  pmbVisitor.behaviour()->acceptsCaustics()))
00089             {
00090                 PhotonMapEnergy * pMap = new PhotonMapEnergy();
00091                 AutoPtr<EnergyCoat> * pAMap = new AutoPtr<EnergyCoat>(pMap);
00092                 pObj->setEnergyState(pAMap);
00093                 maps.append(pMap);
00094             } else
00095                 pObj->setEnergyState(NULL);
00096             
00097             if (pmbVisitor.behaviour() &&
00098                 pmbVisitor.behaviour()->makesCaustics() &&
00099                 (matVisitor.avgReflection() > 0. ||
00100                  matVisitor.avgTransparency() > 0.))
00101                 reflShapes.append(pObj);
00102         } else {
00103             PhotonMapEnergy * pMap  = new PhotonMapEnergy();
00104             AutoPtr<EnergyCoat> * pAMap = new AutoPtr<EnergyCoat>(pMap);
00105             if (matVisitor.avgReflection() == 0. &&
00106                 matVisitor.avgTransparency() == 0.)
00107             {
00108                 // Set photon maps of diffuse surface
00109                 pObj->setEnergyState(pAMap);
00110                 maps.append(pMap);
00111                 // A diffuse surface should store all photons
00112                 if (!pmbVisitor.behaviour())
00113                     pObj->appendPrivateAttribute(new PhotonMapBehaviour(PhotonMapBehaviour::ACCEPT_CAUSTICS|PhotonMapBehaviour::ACCEPT_GLOBAL_PHOTONS));
00114             } else {
00115                 // A reflective/refractive surface should not employ
00116                 // photon maps, but should be used for caustics generation
00117                 // instead.
00118                 pObj->setEnergyState(NULL);
00119                 reflShapes.append(pObj);
00120             }
00121         }
00122     }
00123 }
00124 
00125 PointEnv* PhotonMapShader::_emit_global_photon(const Vector3& phOrigin,
00126                                                const Vector3& phDir)
00127 {
00128     Color3f        intensity;
00129     RayIntExplorer riExplorer(Vector3(0,0,0), Vector3(0,0,0), NULL);
00130     Intersector    intersector;
00131 
00132     // get first intersection of photon
00133     riExplorer.reinit(phOrigin, phDir, &intersector);
00134     intersector.init(ENV_WANT_INTERSECTION | ENV_WANT_NORMAL | 
00135                      ENV_WANT_ASOC_PRIMITIVE | ENV_WANT_DISTANCE | 
00136                      ENV_WANT_N_DOT_D);
00137     riExplorer.explore(*(_pScene->root()));
00138     PointEnv * pE = riExplorer.result();
00139     if (!pE || !(pE->mask & (ENV_HAVE_ASOC_PRIMITIVE | 
00140                              ENV_HAVE_INTERSECTION | 
00141                              ENV_HAVE_NORMAL)))
00142     { // no intersection
00143         if (pE) { 
00144             pE->pVisitableObj = NULL; 
00145             delete pE;
00146         }
00147         return NULL;
00148     }
00149 
00150     pE->viewerDir.set(phDir);
00151     pE->viewerDir.negate();
00152     pE->mask |= ENV_HAVE_VIEWER_DIR;
00153 
00154     return pE;
00155 }
00156 
00157 PointEnv* PhotonMapShader::_emit_caustic_photon(const Vector3& phOrigin,
00158                                                 const Vector3& phDir)
00159 {
00160     RayIntExplorer riExplorer(Vector3(0,0,0), Vector3(0,0,0), NULL);
00161     Intersector    intersector;
00162 
00163     // get first intersection of photon
00164     riExplorer.reinit(phOrigin, phDir, &intersector);
00165     intersector.init(ENV_WANT_INTERSECTION | ENV_WANT_NORMAL | 
00166                      ENV_WANT_ASOC_PRIMITIVE | ENV_WANT_DISTANCE | 
00167                      ENV_WANT_N_DOT_D);
00168     riExplorer.explore(*(_pScene->root()));
00169     PointEnv * pE = riExplorer.result();
00170     if (!pE || !(pE->mask & (ENV_HAVE_ASOC_PRIMITIVE | 
00171                              ENV_HAVE_INTERSECTION | 
00172                              ENV_HAVE_NORMAL)))
00173     { // no intersection
00174         if (pE) { 
00175             pE->pVisitableObj = NULL; 
00176             delete pE;
00177         }
00178         return NULL;
00179     }
00180 
00181     pE->viewerDir.set(phDir);
00182     pE->viewerDir.negate();
00183     pE->mask |= ENV_HAVE_ENERGY | ENV_HAVE_VIEWER_DIR;
00184 
00185     return pE;
00186 }
00187 
00188 //--------------- public ---------------
00189 
00190 void PhotonMapShader::distributeEnergy(void)
00191 {
00192     if (!_pPhotonTracing)             return;
00193     if (!_pScene || !_pScene->root()) return;
00194 
00195     _pPhotonTracing->setDiffuseBRDF(_pDefaultDiffBRDF);
00196     _pPhotonTracing->setSpecularBRDF(_pDefaultSpecBRDF);
00197     _pPhotonTracing->setScene(_pScene);
00198 
00199     if (_pCausticsEmittion) {
00200         _pCausticsEmittion->setDiffuseBRDF(_pDefaultDiffBRDF);
00201         _pCausticsEmittion->setSpecularBRDF(_pDefaultSpecBRDF);
00202         _pCausticsEmittion->setScene(_pScene);
00203     }
00204 
00205     if (_pLights) delete _pLights;
00206     LightsExplorer explorer(0);
00207     explorer.explore(*(_pScene->root()));
00208     _pLights = explorer.result();
00209     
00210     Emittance * pEmittance;
00211     PointEnv  * pE;
00212 
00213     /*
00214      * create photon maps
00215      */
00216 
00217     List<PhotonMapEnergy>  maps;
00218     List<SceneGraphObject> reflShapes;
00219     switch (_mapping) {
00220     case SCENE_MAPS:     _create_scene_maps(maps, reflShapes);     break;
00221     case MAPS_PER_SHAPE: _create_maps_per_shape(maps, reflShapes); break;
00222     default: break;
00223     }
00224 
00225     if (maps.empty()) return; // nothing to do
00226 
00227     Color3f  intensity, phPower;
00228     unsigned phPerL;
00229     Vector3  phOrigin, phDir;
00230     for (ESGint i = 0; i < LightArray::MAX_LIGHTS; i++) 
00231     {
00232         if (!_pLights->isOn(i)) continue;
00233 
00234         // get number of emitted photons proportionally to the light brightness
00235         if (!(pEmittance = _pLights->light(i).pEmittance)) continue;
00236         if (!pEmittance->intensity(intensity)) continue;
00237         phPerL = (unsigned) (_photonsPerLight *
00238                              (intensity.x+intensity.y+intensity.z) /
00239                              3.);
00240 
00241         /*
00242          * store global energy in the global photon map(s)
00243          */
00244         for (unsigned j = 0; j < phPerL; j++) {
00245             if (!_pLights->emitPhoton(phOrigin, phDir, phPower, i)) continue;
00246             if (!(pE = _emit_global_photon(phOrigin, phDir))) continue;
00247             pE->energy.set(phPower);
00248             pE->energy.scale(1./phPerL);
00249             pE->mask |= ENV_HAVE_ENERGY;
00250             _pPhotonTracing->illuminatePoint(*pE);
00251             delete pE;
00252         }
00253 
00254         if (!_pCausticsEmittion) continue;
00255 
00256         /*
00257          * Generate caustics photon map(s)
00258          */
00259         Geometry * pGeom;
00260         Geometry * pLightGeom = _pLights->getGeometry(i);
00261         Sphere   * pBoundingSphere;
00262         unsigned   phPerObj;
00263         double     bsR, bsDist;
00264         Vector3    bsVec;
00265         for (SceneGraphObject * pObj = reflShapes.firstItem();
00266              pObj;
00267              pObj = reflShapes.nextItem())
00268         {
00269             if (!(pGeom = pObj->geometry())) continue;
00270             pBoundingSphere = new Sphere(*pGeom);
00271 
00272             // phPerObj = photons per object = number of photons
00273             // casted towards the caustics object, which is relative
00274             // to the space angle (from ohOrigin) occupied by
00275             // the object relatively to the whole halfspace (180 degrees)
00276             bsVec.set(pBoundingSphere->centre());
00277             bsVec.sub(phOrigin);
00278             bsDist   = bsVec.length();
00279             bsR      = pBoundingSphere->radius() / bsDist;
00280             phPerObj = (unsigned)(phPerL * (acos(sqrt(1.-bsR*bsR))/(M_PI/2))); 
00281 
00282             for (unsigned j = 0; j < phPerObj; j++) {
00283                 // stochasticly sample the light source
00284                 if (pLightGeom) { 
00285                     PointEnv auxEnv;
00286                     pLightGeom->randomSample(ENV_WANT_SURFACE_POINT,
00287                                              auxEnv, NULL);
00288                     if (! (auxEnv.mask & ENV_HAVE_SURFACE_POINT)) continue;
00289                     phOrigin.set(auxEnv.intersection);
00290                 } else {
00291                     if (!pEmittance->sourceLocation(phOrigin)) {
00292                         if (!pEmittance->beamDirection(phDir)) continue;
00293                         phOrigin.set(phDir); // set origin to "infinity"
00294                         phOrigin.negate();
00295                         phOrigin.scale(FLT_MAX/3.);
00296                         phOrigin.add(pGeom->centroid());
00297                     }
00298                 }
00299 
00300                 // stochasticly sample object that produces caustics
00301                 if (!pBoundingSphere->randomDirection(phOrigin, phDir, NULL))
00302                     continue;
00303 
00304                 if (!(pE = _emit_caustic_photon(phOrigin, phDir))) continue;
00305                 pE->energy.set(intensity);
00306                 pE->energy.scale(1./phPerL);
00307                 pE->mask |= ENV_HAVE_ENERGY;
00308                 _pCausticsEmittion->illuminatePoint(*pE);
00309                 delete pE;
00310             }
00311 
00312             delete pBoundingSphere;
00313         }
00314     }
00315 
00316     /*
00317      * build photon maps storing global energy
00318      */
00319     
00320     for (PhotonMapEnergy* pMap = maps.firstItem();
00321          pMap;
00322          pMap = maps.nextItem())
00323     {
00324         pMap->buildGlobalMap();
00325         pMap->buildCausticsMap();
00326     }
00327 }
00328 

Generated on Tue Nov 21 15:11:42 2006 for gra by  doxygen 1.4.6