RayTracing.cc

Go to the documentation of this file.
00001 #include <gra/reflection/RayTracing.h>
00002 #include <esg/Statistics.h>
00003 
00004 using namespace gra;
00005 
00006 void RayTracing::_check_point_of_intersection(PointEnv& surr) const
00007 {
00008     // transform found intersection
00009     if (surr.mask & ENV_HAVE_TRANSFORMATION) {
00010         Matrix3 rotMat;
00011         surr.trMat.get(rotMat);
00012         surr.trMat.transform(surr.intersection);
00013         rotMat.transform(surr.normal);
00014     }
00015 
00016     // Get & orient normal and get its dot product with view dir.
00017     if (!(surr.mask & ENV_HAVE_N_DOT_D)) {
00018         surr.nd = -surr.normal.dot(surr.viewerDir);
00019         surr.mask |= ENV_HAVE_N_DOT_D;
00020     }
00021     if (surr.nd > 0.) {
00022        surr.normal.negate();
00023        surr.nd = -surr.nd;
00024        surr.normalOrientation = PointEnv::RANDOM_NORMAL;
00025     }
00026 }
00027 
00028 MatVisitor* RayTracing::_check_material(SceneGraphObject* o, bool firstObjHit)
00029 {
00030     SceneGraphObject::OID oid = o->getOID();
00031     MatVisitor * pMatVisitor = _matCache[oid];
00032     if (!pMatVisitor) {
00033         pMatVisitor = new MatVisitor;
00034         o->inspectMaterials(*pMatVisitor);
00035         _matCache[oid] = pMatVisitor;
00036     }
00037     if (_pLocalReflection && firstObjHit) {
00038         _pLocalReflection->setEmittance(o->emittance());
00039         DiffuseBRDF * pDiffBRDF = o->diffuseBRDF();
00040         SpecularBRDF* pSpecBRDF = o->specularBRDF();
00041         _pLocalReflection->setDiffuseBRDF((pDiffBRDF)
00042                                           ? pDiffBRDF
00043                                           : _pDiffuseBRDF);
00044         _pLocalReflection->setSpecularBRDF((pSpecBRDF)
00045                                            ? pSpecBRDF
00046                                            : _pSpecularBRDF);
00047         _pTexture = o->texture();
00048     }
00049 
00050     return pMatVisitor;
00051 }
00052 
00053 PointEnv* RayTracing::_cast_ray(const Vector3& src, const Vector3& dir)
00054 {
00055     _riExplorer.reinit(src, dir, _pIntersector);
00056     _pIntersector->init(ENV_WANT_INTERSECTION | ENV_WANT_NORMAL | 
00057                         ENV_WANT_ASOC_PRIMITIVE | ENV_WANT_DISTANCE | 
00058                         ENV_WANT_N_DOT_D);
00059     _riExplorer.explore(*(_pScene->root()));
00060     PointEnv* pNewSurr = _riExplorer.result();
00061 
00062     if (!pNewSurr) return NULL;
00063 
00064     if (!pNewSurr->mask & (ENV_HAVE_ASOC_PRIMITIVE | 
00065                            ENV_HAVE_INTERSECTION | 
00066                            ENV_HAVE_NORMAL))
00067     { // no intersection
00068         pNewSurr->pVisitableObj = NULL; 
00069         delete pNewSurr;
00070         return NULL;
00071     }
00072 
00073     pNewSurr->viewerDir.set(dir);
00074     pNewSurr->viewerDir.negate();
00075     
00076     if (!(pNewSurr->mask & ENV_HAVE_DISTANCE)) 
00077         pNewSurr->distance = ((Vector3)(pNewSurr->intersection-src)).length();
00078 
00079     pNewSurr->mask |= ENV_HAVE_VIEWER_DIR|ENV_HAVE_DISTANCE;
00080 
00081     return pNewSurr;
00082 }
00083 
00084 void RayTracing::_apply_texture(PointEnv& surr, Color3f& a)
00085 {
00086     if (!_pTexture) return;
00087     
00088     Color3f c; 
00089     if (_pTexture->mapping() & Texture::UV_MAPPING) { 
00090         if (surr.mask & ENV_HAVE_UV_COORD) { 
00091             (void) _pTexture->mapUV(surr.uvCoord, c); 
00092             a.x *= c.x;
00093             a.y *= c.y;
00094             a.z *= c.z; 
00095         } else { 
00096             Geometry* g = surr.pVisitableObj->geometry(); 
00097             if (g) { 
00098                 Vector2 uv; 
00099                 if (g->mapToUV(surr.intersection, uv)) { 
00100                     (void) _pTexture->mapUV(uv, c); 
00101                     a.x *= c.x;
00102                     a.y *= c.y;
00103                     a.z *= c.z; 
00104                 } 
00105             } 
00106         }
00107     } else { 
00108         if (_pTexture->mapXYZ(surr.intersection, c)) {
00109             a.x *= c.x;
00110             a.y *= c.y;
00111             a.z *= c.z;  
00112         } 
00113     } 
00114 }
00115 
00116 void RayTracing::_apply_texture(PointEnv& surr, Vector3& a)
00117 {
00118     if (!_pTexture) return;
00119     
00120     Color3f c; 
00121     if (_pTexture->mapping() & Texture::UV_MAPPING) { 
00122         if (surr.mask & ENV_HAVE_UV_COORD) { 
00123             (void) _pTexture->mapUV(surr.uvCoord, c); 
00124             a.x *= c.x;
00125             a.y *= c.y;
00126             a.z *= c.z; 
00127         } else { 
00128             Geometry* g = surr.pVisitableObj->geometry(); 
00129             if (g) { 
00130                 Vector2 uv; 
00131                 if (g->mapToUV(surr.intersection, uv)) { 
00132                     (void) _pTexture->mapUV(uv, c); 
00133                     a.x *= c.x;
00134                     a.y *= c.y;
00135                     a.z *= c.z; 
00136                 } 
00137             } 
00138         }
00139     } else { 
00140         if (_pTexture->mapXYZ(surr.intersection, c)) {
00141             a.x *= c.x;
00142             a.y *= c.y;
00143             a.z *= c.z;  
00144         } 
00145     } 
00146 }
00147 
00148 void RayTracing::_direct_illumination(PointEnv&   surr,
00149                                       MatVisitor& matVisitor,
00150                                       unsigned    actDepth,
00151                                       Color3f&    contribution)
00152 {
00153     _pLocalReflection->setActBlockingObjCache(actDepth);
00154     Color3f* pContrib = _pLocalReflection->illuminatePoint(surr, matVisitor);
00155     if (pContrib) {
00156         _apply_texture(surr, *pContrib);
00157         contribution.x += pContrib->x * surr.energy.x;
00158         contribution.y += pContrib->y * surr.energy.y;
00159         contribution.z += pContrib->z * surr.energy.z;
00160         delete pContrib;
00161     }
00162 }
00163 
00164 RayTracing::RefrDir RayTracing::_refraction_dir(PointEnv&   surr,
00165                                                 MatVisitor& matVisitor,
00166                                                 bool        firstObjHit,
00167                                                 Vector3&    nDir)
00168 {
00169     double ior = ((firstObjHit) ?
00170                   _defaultMediumRefraction / matVisitor.indexOfRefraction() :
00171                   matVisitor.indexOfRefraction() / _defaultMediumRefraction);
00172     double t = 1.0 + (ior * ior) * ((surr.nd * surr.nd) - 1.0);
00173     
00174     if (t < 0.0) { // reflection inside medium
00175         nDir.set(surr.normal);
00176         nDir.scale(-2.0 * surr.nd);
00177         nDir.sub(surr.viewerDir);
00178         return REFR_DIR_REFLECTION;
00179     } else { // refraction into medium on another side
00180         Vector3 aux(surr.normal);
00181         nDir.set(surr.viewerDir);
00182         aux.scale(-ior * surr.nd - sqrt(t));
00183         nDir.scaleAdd(-ior, aux);
00184         return REFR_DIR_REFRACTION;
00185     }
00186 }
00187 
00188 void RayTracing::_reflection_dir(PointEnv& surr, Vector3& nDir)
00189 {
00190     // Get reflection direction R = 2(N*L)N - L, L = vDir
00191     nDir.set(surr.normal);
00192     nDir.scale(-2.0 * surr.nd);
00193     nDir.sub(surr.viewerDir);
00194 
00195 #ifdef ESG_STATISTICS
00196     _numReflections++;
00197 #endif
00198 }
00199 
00200 void RayTracing::_cast_secondary_rays(PointEnv&   surr,
00201                                       unsigned    actDepth,
00202                                       bool        firstObjHit,
00203                                       Color3f&    contribution,
00204                                       MatVisitor& matVisitor)
00205 {
00206     Vector3 nDir;
00207     Vector3 newPower;
00208 
00209     /*
00210      * Treat refraction
00211      */ 
00212 
00213     RefrDir       rr;
00214     bool          transmit;
00215     const Vector3 refraction = matVisitor.transparency();
00216     
00217     if (refraction.x <= 0. && refraction.y <= 0. && refraction.z <= 0.) {
00218         transmit = false;
00219     } else {    
00220         newPower.set(surr.energy.x * refraction.x,
00221                      surr.energy.y * refraction.y,
00222                      surr.energy.z * refraction.z);
00223         _apply_texture(surr, newPower);
00224 
00225         // skip too small contribution
00226         if (newPower.x < _minRayWeight &&
00227             newPower.y < _minRayWeight &&
00228             newPower.z < _minRayWeight)
00229         {
00230             transmit = false;
00231         } else {
00232 #ifdef ESG_STATISTICS
00233             _numRefractions++;
00234 #endif
00235             rr = _refraction_dir(surr, matVisitor, firstObjHit, nDir);
00236             transmit = true;
00237         }
00238     }
00239 
00240     if (transmit) {
00241         PointEnv* pNewSurr = _cast_ray(surr.intersection, nDir);
00242         if (!pNewSurr) { 
00243             contribution.x += _background.x * newPower.x; 
00244             contribution.y += _background.y * newPower.y; 
00245             contribution.z += _background.z * newPower.z; 
00246             return; 
00247         } 
00248         pNewSurr->energy.set(newPower);
00249         /* We have new intersection => trace the ray racursivelly */
00250         _illuminate(*pNewSurr, actDepth+1,
00251                     (rr == REFR_DIR_REFLECTION) ? false : !firstObjHit,
00252                     contribution); 
00253         delete pNewSurr;
00254 
00255         // skip potential second reflection
00256         if (rr == REFR_DIR_REFLECTION) return; 
00257     }
00258 
00259 
00260 
00261     /*
00262      * Treat reflection
00263      */
00264 
00265     const Vector3 reflection = matVisitor.reflection();
00266     if (!firstObjHit ||
00267         (reflection.x <= 0. && reflection.y <= 0. && reflection.z <= 0))
00268         return;
00269     
00270     newPower.set(surr.energy.x * reflection.x,
00271                  surr.energy.y * reflection.y,
00272                  surr.energy.z * reflection.z);
00273     _apply_texture(surr, newPower);
00274 
00275     if (newPower.x < _minRayWeight &&
00276         newPower.y < _minRayWeight &&
00277         newPower.z < _minRayWeight) return;
00278 
00279     _reflection_dir(surr, nDir);
00280 
00281     PointEnv* pNewSurr = _cast_ray(surr.intersection, nDir);
00282     if (!pNewSurr) { 
00283         contribution.x += _background.x * newPower.x; 
00284         contribution.y += _background.y * newPower.y; 
00285         contribution.z += _background.z * newPower.z; 
00286         return; 
00287     } 
00288     pNewSurr->energy.set(newPower);
00289     /* We have new intersection => trace the ray racursivelly */
00290     _illuminate(*pNewSurr, actDepth+1, true, contribution); 
00291     delete pNewSurr; 
00292 }
00293 
00294 void RayTracing::_illuminate(PointEnv&      surr,
00295                              unsigned       actDepth,
00296                              bool           firstObjHit,
00297                              Color3f&       contribution)
00298 {
00299     /*
00300      * We suppose that the given "surr" contains proper point of intersection,
00301      * normal vector and associated primitive.
00302      *
00303      * Transform point of intersection and properly orient normal.
00304      */
00305     _check_point_of_intersection(surr);
00306     
00307     /*
00308      * Inspect attributes that are necessary for local illumination,
00309      * reflection and transmission. Set correct BRDF and emittance for local
00310      * reflection. If the point of interest is the second point of refraction
00311      * ray then previous material is used (the object was not changed)
00312      */
00313     MatVisitor* pMatVisitor = _check_material(surr.pVisitableObj, firstObjHit);
00314 
00315     /*
00316      * Get local contribution from visible lights. Light visibility
00317      * is checked inside the local reflection when intersector is
00318      * properly set.
00319      */
00320     _direct_illumination(surr, *pMatVisitor, actDepth, contribution);
00321 
00322     if (actDepth >= _maxDepth) return;
00323 
00324     /*
00325      * Traverse transmission and mirror rays
00326      */
00327     _cast_secondary_rays(surr, actDepth+1, firstObjHit,
00328                          contribution, *pMatVisitor);
00329 }
00330 
00331 
00332 
00333 // --------- public ----------------
00334 
00335 Color3f* RayTracing::illuminatePoint(PointEnv & env)
00336 {
00337     if (!(_pLocalReflection && (_pDiffuseBRDF || _pSpecularBRDF))) return NULL;
00338     if (!(_pScene && _pScene->root())) return NULL;
00339     if (!_pIntersector) return NULL;
00340     if (!(env.mask & (ENV_HAVE_INTERSECTION|
00341                       ENV_HAVE_NORMAL|
00342                       ENV_HAVE_ASOC_PRIMITIVE|
00343                       ENV_HAVE_VIEWER_DIR))) return NULL;
00344     
00345     if (! env.pVisitableObj) return NULL;
00346 
00347     if (!(env.mask & ENV_HAVE_ENERGY)) env.energy.set(1.,1.,1.);
00348 
00349     Color3f* pColor = new Color3f(0.0, 0.0, 0.0);
00350 
00351 #ifdef esG_STATISTICS
00352     _numReflections = (_numRefractions = 0);
00353 #endif
00354 
00355     _illuminate(env, 0, true, *pColor);
00356 
00357 #ifdef ESG_STATISTICS
00358     ((Counter*)Statistics::instance()->get(Statistics::OID_REFLECTIONS)->receptor())->add(_numReflections);
00359     ((Counter*)Statistics::instance()->get(Statistics::OID_REFRACTIONS)->receptor())->add(_numRefractions);
00360 #endif
00361     
00362     return pColor;
00363 }

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