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
00021
00022
00023 const LightArray::BlockingObj * pBO =
00024 _pLights->getBlockingObject(_useCache, i);
00025
00026 if (pBO && pBO->pObj) {
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) {
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
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
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
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;
00182 normal.negate();
00183 nl = -nl;
00184 }
00185
00186
00187
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;
00232 }
00233
00234
00235
00236
00237
00238 ldir.negate();
00239 if (!pEmittance->intensity(ldir, ldist, contribe)) continue;
00240 ldir.negate();
00241
00242 oid = _pLights->getOID(i);
00243
00244
00245
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) {
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
00287
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 }
00308
00309 return pColor;
00310 }
00311