LocalReflection.cc

Go to the documentation of this file.
00001 #include <gra/reflection/LocalReflection.h>
00002 #include <esg/SceneGraphObject.h>
00003 #include <esg/Statistics.h>
00004 #include <esg/explorer/ShadowExplorer.h>
00005 
00006 
00007 using namespace gra;
00008 
00009 bool LocalReflection::_light_visible(unsigned              i,
00010                                      const Vector3&        ldir,
00011                                      double                ldist,
00012                                      const Vector3&        inters,
00013                                      SceneGraphObject::OID loid)
00014 {
00015     static Matrix3  rMat;
00016     static Vector3  tVec, sVec;
00017     static PointEnv surr;
00018 
00019     /*
00020      * test cached blocking objects
00021      */
00022     
00023     const LightArray::BlockingObj * pBO =
00024         _pLights->getBlockingObject(_useCache, i);
00025                 
00026     if (pBO && pBO->pObj) { // test cached blocking objects first
00027         Geometry * pGeom = pBO->pObj->geometry();
00028         if (pGeom) {
00029             if (pBO->transformed) {
00030                 Vector3 o;
00031                 Vector3 d;
00032                 pBO->trMat.get(rMat, tVec, sVec);
00033                 ESG_INVERSE_TR_RAY(rMat, tVec, sVec, inters, o, ldir, d);
00034                 pGeom->rayIntersection(&surr,
00035                                        ENV_WANT_INTERFERENCE|ENV_USE_CACHE,
00036                                        o, d, ldist);
00037             } else {
00038                 pGeom->rayIntersection(&surr,
00039                                        ENV_WANT_INTERFERENCE|ENV_USE_CACHE,
00040                                        inters, ldir, ldist);
00041             }
00042             if (surr.mask & ENV_HAVE_INTERFERENCE) return false;
00043             else _pLights->setBlockingObj(_useCache,i,NULL,NULL);
00044         }
00045     }
00046 
00047     ShadowExplorer shExplorer(inters, ldir, loid, ldist);
00048     shExplorer.explore(*(_pScene->root()));
00049     pBO = &(shExplorer.getBlockingObj());
00050     if (pBO->pObj) { // we have shading object
00051         _pLights->setBlockingObj(_useCache, i, pBO->pObj,
00052                                  (pBO->transformed) ? &(pBO->trMat) : NULL);
00053         return false;
00054     } else {
00055         _pLights->setBlockingObj(_useCache, i, NULL, NULL);
00056         return true;
00057     }
00058 }
00059 
00060 LocalReflection::LocalReflection(DiffuseBRDF     * db,
00061                                  SpecularBRDF    * sb,
00062                                  Emittance       * e,
00063                                  ShadowDetection   s,
00064                                  unsigned          ns,
00065                                  unsigned          c,
00066                                  unsigned          u)
00067     : ReflectionModel(db, sb, e),
00068       _pLights(NULL),
00069       _shadowDetection(s),
00070       _lightTests(ns),
00071       _numCaches(c),
00072       _useCache(u)
00073 {
00074 }
00075 
00076 void LocalReflection::setScene(Scene * s)
00077 {
00078     _pScene = s;
00079     if (_pLights) delete _pLights;
00080     LightsExplorer explorer(_numCaches);
00081     if (_pScene && _pScene->root()) explorer.explore(*(_pScene->root()));
00082     _pLights = explorer.result();
00083 }
00084 
00085 Color3f* LocalReflection::illuminatePoint(PointEnv& env)
00086 {
00087     if ((env.mask & ENV_HAVE_ASOC_PRIMITIVE) && env.pVisitableObj) {
00088         MatVisitor visitor;
00089         env.pVisitableObj->inspectMaterials(visitor);
00090         return illuminatePoint(env, visitor);
00091     } else
00092         return NULL;
00093 }
00094 
00095 Color3f* LocalReflection::illuminatePoint(PointEnv& env, MatVisitor& visitor)
00096 {
00097     static Matrix3  rMat;
00098     static Vector3  tVec, sVec;
00099     
00100     if (!(_pDiffuseBRDF || _pSpecularBRDF)) {
00101         fprintf(stderr,"LocalReflection::illuminatePoint(): No BRDF defined\n");
00102         return NULL;
00103     }
00104 
00105     if (!(env.mask & (ENV_HAVE_INTERSECTION | ENV_HAVE_NORMAL))) return NULL;
00106 
00107     if (!_pScene) return NULL;
00108 
00109     Vector3       ldir;
00110     float         ldist;
00111     Color3f       contribe;
00112     Vector3       contribc;
00113     Vector3       contribb;
00114     Emittance   * pEmittance;
00115     Matrix4     * pTrMat;
00116     double        nl, nv = -1.0;
00117     Vector3       normal(env.normal);
00118     Vector3       trInt;
00119     Vector3     * pInt;
00120     SceneGraphObject::OID oid;
00121 
00122     // orient normal towards view dir (if exists)
00123     if (env.mask & ENV_HAVE_VIEWER_DIR) {
00124         nv = (env.mask & ENV_HAVE_N_DOT_D) ? -env.nd : env.viewerDir.dot(normal);
00125         if (nv == 0.0) return NULL;
00126         if (nv < 0.0) {
00127             normal.negate();
00128             nv = -nv;
00129         }
00130     }
00131 
00132     Color3f * pColor = new Color3f(0.0, 0.0, 0.0);
00133 
00134      // self-emitting point of interest:
00135     if (_pEmittance && (env.mask & (ENV_HAVE_VIEWER_DIR|ENV_HAVE_DISTANCE))) 
00136         (void) _pEmittance->intensity(env.viewerDir, env.distance, *pColor);
00137     
00138     if (!_pLights) return pColor;
00139 
00140     Color3f auxColor;
00141 
00142     for (ESGint i = 0; i < LightArray::MAX_LIGHTS; i++) 
00143     {
00144         if (!_pLights->isOn(i)) continue;
00145         
00146         pEmittance = _pLights->getEmittance(i);
00147         if (!pEmittance) continue;
00148 
00149         /*
00150          * Get direction to the emittance and its distance
00151          */
00152         if (pEmittance->sourceLocation(ldir)) {
00153             pTrMat = _pLights->getTransformation(i);
00154             if (pTrMat) {
00155                 pTrMat->get(rMat, tVec, sVec);
00156                 ESG_INVERSE_TR_POINT(rMat, tVec, sVec,
00157                                      env.intersection, trInt);
00158                 ldir.sub(trInt);
00159                 pInt = &trInt;
00160             } else {
00161                 ldir.sub(env.intersection);
00162                 pInt = &(env.intersection);
00163             }
00164             ldist = ldir.length();
00165             ldir.scale(1.0 / ldist);
00166         } else {
00167             if (!pEmittance->beamDirection(ldir)) continue;
00168             pTrMat = _pLights->getTransformation(i);
00169             ldist = MAXFLOAT;
00170             if (pTrMat) {
00171                 pTrMat->get(rMat);
00172                 ESG_INVERSE_TR_DIR(rMat, ldir, ldir);
00173             }
00174             ldir.negate();
00175             pInt = NULL;
00176         }
00177 
00178         nl = ldir.dot(normal);
00179         if (nl == 0.0) continue;
00180         if (nl < 0.0) {
00181             if (env.mask & ENV_HAVE_VIEWER_DIR) continue; // light is on opposite half-space
00182             normal.negate();     // orient normal towards light source
00183             nl = -nl;
00184         }
00185 
00186         /*
00187          * Get/check BRDF reflectance of emitting source
00188          */
00189         BRDF::RetVal brdfRetDiff = BRDF::ZERO_CONTRIB;
00190         BRDF::RetVal brdfRetSpec = BRDF::ZERO_CONTRIB;
00191         if (_pDiffuseBRDF) {
00192             if (env.mask & ENV_HAVE_VIEWER_DIR) {
00193                 brdfRetDiff = _pDiffuseBRDF->reflectanceVNL(visitor,
00194                                                             &ldir,
00195                                                             &(env.viewerDir),
00196                                                             &(normal),
00197                                                             nv,
00198                                                             nl,
00199                                                             contribb);
00200             } else {
00201                 brdfRetDiff = _pDiffuseBRDF->reflectanceNL(visitor,
00202                                                            &ldir,
00203                                                            NULL,
00204                                                            &(normal),
00205                                                            nl,
00206                                                            contribb);
00207             }
00208         }
00209         if (_pSpecularBRDF) {
00210             if (env.mask & ENV_HAVE_VIEWER_DIR) {
00211                 brdfRetSpec = _pSpecularBRDF->reflectanceVNL(visitor,
00212                                                              &ldir,
00213                                                              &(env.viewerDir),
00214                                                              &(normal),
00215                                                              nv,
00216                                                              nl,
00217                                                              contribc);
00218             } else {
00219                 brdfRetSpec = _pSpecularBRDF->reflectanceNL(visitor,
00220                                                             &ldir,
00221                                                             NULL,
00222                                                             &(normal),
00223                                                             nl,
00224                                                             contribc);
00225             }
00226         }
00227         if (brdfRetDiff == BRDF::NONZERO_CONTRIB) {
00228             if (brdfRetSpec == BRDF::NONZERO_CONTRIB) contribb.add(contribc);
00229         } else{
00230             if (brdfRetSpec == BRDF::NONZERO_CONTRIB) contribb.set(contribc);
00231             else continue; // no contribution
00232         }
00233 
00234         /*
00235          * Then get the light intensity
00236          * edir = -ldir
00237          */
00238         ldir.negate();
00239         if (!pEmittance->intensity(ldir, ldist, contribe)) continue;
00240         ldir.negate();
00241 
00242         oid = _pLights->getOID(i);
00243 
00244         /*
00245          * Check the light visibility
00246          */
00247         if (_shadowDetection != SD_NONE) {
00248             Geometry * pGeom = _pLights->getGeometry(i);
00249             if (_shadowDetection == SD_RAY_FROM_EMITTANCE ||
00250                 (_shadowDetection == SD_GEOMETRY_SAMPLING && ! pGeom))
00251             {           
00252 #ifdef ESG_STATISTICS
00253                 ((Counter*)Statistics::instance()->get(Statistics::OID_SHADOW_TESTS)->receptor())->increment();
00254                 if (! _light_visible(i, ldir, ldist, env.intersection, oid)) {
00255                     ((Counter*)Statistics::instance()->get(Statistics::OID_SHADOW_TESTS_SUC)->receptor())->increment();
00256                     continue;
00257                 }
00258 #else
00259                 if (! _light_visible(i, ldir, ldist, env.intersection, oid))
00260                     continue;
00261 #endif // ESG_STATISTICS
00262             } else {
00263                 PointEnv auxEnv;
00264                 unsigned hits = 0;
00265 
00266                 if (!pInt) {
00267                     if (pTrMat) { // pTrMat is set above
00268                         pTrMat->get(rMat, tVec, sVec);
00269                         ESG_INVERSE_TR_POINT(rMat, tVec, sVec,
00270                                              env.intersection, trInt);
00271                         pInt = &trInt;
00272                     } else {
00273                         pInt = &(env.intersection);
00274                     }
00275                 }
00276 
00277                 for (unsigned j = _lightTests; j > 0; j--) {
00278                     pGeom->randomSample(ENV_WANT_SURFACE_POINT, auxEnv, NULL);
00279                     if (auxEnv.mask & ENV_HAVE_SURFACE_POINT) {
00280                         ldir.set(auxEnv.intersection);
00281                         ldir.sub(*pInt);
00282                         ldist = ldir.length();
00283                         ldir.scale(1.0 / ldist);                               
00284                         if (_light_visible(i,ldir,ldist,env.intersection,oid))
00285                             hits++;
00286                         //else 
00287                             //fprintf(stderr,"%f %f %f, %f %f %f\n",env.intersection.x,env.intersection.y,env.intersection.z,ldir.x,ldir.y,ldir.z);
00288                     }
00289                 }
00290 
00291                 if (hits == 0 || _lightTests == 0) continue;
00292 
00293 #ifdef ESG_STATISTICS
00294                 ((Counter*)Statistics::instance()->get(Statistics::OID_SHADOW_TESTS)->receptor())->add(_lightTests);
00295                 ((Counter*)Statistics::instance()->get(Statistics::OID_SHADOW_TESTS_SUC)->receptor())->add(_lightTests - hits);
00296 #endif
00297 
00298                 if (_lightTests > 1 && hits != _lightTests) 
00299                     contribe.scale((double) hits / (double) _lightTests);
00300             }
00301         }
00302 
00303         pColor->x += contribe.x * contribb.x * nl;
00304         pColor->y += contribe.y * contribb.y * nl;
00305         pColor->z += contribe.z * contribb.z * nl;
00306 
00307     } // for (ESGint i = 0; ...)
00308 
00309     return pColor;
00310 }
00311 

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