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
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
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 {
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) {
00175 nDir.set(surr.normal);
00176 nDir.scale(-2.0 * surr.nd);
00177 nDir.sub(surr.viewerDir);
00178 return REFR_DIR_REFLECTION;
00179 } else {
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
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
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
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
00250 _illuminate(*pNewSurr, actDepth+1,
00251 (rr == REFR_DIR_REFLECTION) ? false : !firstObjHit,
00252 contribution);
00253 delete pNewSurr;
00254
00255
00256 if (rr == REFR_DIR_REFLECTION) return;
00257 }
00258
00259
00260
00261
00262
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
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
00301
00302
00303
00304
00305 _check_point_of_intersection(surr);
00306
00307
00308
00309
00310
00311
00312
00313 MatVisitor* pMatVisitor = _check_material(surr.pVisitableObj, firstObjHit);
00314
00315
00316
00317
00318
00319
00320 _direct_illumination(surr, *pMatVisitor, actDepth, contribution);
00321
00322 if (actDepth >= _maxDepth) return;
00323
00324
00325
00326
00327 _cast_secondary_rays(surr, actDepth+1, firstObjHit,
00328 contribution, *pMatVisitor);
00329 }
00330
00331
00332
00333
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 }