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
00047 pObj->setEnergyState(pAMap);
00048
00049
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
00057
00058
00059 pObj->setEnergyState(NULL);
00060 reflShapes.append(pObj);
00061 }
00062 }
00063 }
00064
00065
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
00109 pObj->setEnergyState(pAMap);
00110 maps.append(pMap);
00111
00112 if (!pmbVisitor.behaviour())
00113 pObj->appendPrivateAttribute(new PhotonMapBehaviour(PhotonMapBehaviour::ACCEPT_CAUSTICS|PhotonMapBehaviour::ACCEPT_GLOBAL_PHOTONS));
00114 } else {
00115
00116
00117
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
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 {
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
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 {
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
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
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;
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
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
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
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
00273
00274
00275
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
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);
00294 phOrigin.negate();
00295 phOrigin.scale(FLT_MAX/3.);
00296 phOrigin.add(pGeom->centroid());
00297 }
00298 }
00299
00300
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
00318
00319
00320 for (PhotonMapEnergy* pMap = maps.firstItem();
00321 pMap;
00322 pMap = maps.nextItem())
00323 {
00324 pMap->buildGlobalMap();
00325 pMap->buildCausticsMap();
00326 }
00327 }
00328