00001 #include <gra/reflection/Radiosity.h>
00002 #include <esg/explorer/ShadowExplorer.h>
00003 #include <esg/explorer/ObjsExplorer.h>
00004 #include <assert.h>
00005
00006 using namespace gra;
00007
00009
00010 Radiosity::Patch::Patch(PolygonalEnergy * e,
00011 Mesh::Plane * p,
00012 const Vector3 & re,
00013 const Vector3 & em,
00014 const Vector3 & c,
00015 float a)
00016 : pEnergy(e),
00017 pMeshPlane(p),
00018 reflectance(re),
00019 emittance(em),
00020 normal(p->a, p->b, p->c),
00021 centre(c),
00022 area(a)
00023 {
00024 }
00025
00026
00028
00029 float Radiosity::_edge_area(const Vector3& p,const Vector3& q,const Vector3& n)
00030 {
00031
00032
00033
00034
00035
00036
00037
00038 const float epsilon = 1e-6;
00039 float sinFactor, qdotp, projArea;
00040 Vector3 aux;
00041
00042 qdotp = p.dot(q);
00043 sinFactor = p.lengthSquared() * q.lengthSquared() - Math::sqr(qdotp);
00044
00045 aux.cross(p,q);
00046 aux.negate();
00047 projArea = aux.dot(n);
00048
00049 if (sinFactor > 0) {
00050
00051 sinFactor = sqrt(sinFactor);
00052 return(projArea * (PI/2.0 - atan(qdotp / sinFactor)) /
00053 (2 * PI * sinFactor));
00054 } else if (qdotp > epsilon)
00055 return(0);
00056 else if (qdotp < -epsilon)
00057 return(0.5);
00058 else
00059 return(0.125);
00060 }
00061
00062 float Radiosity::_est_patch_factor(Patch& patch,
00063 const Vector3& point,
00064 const Vector3& normal)
00065 {
00066
00067
00068
00069
00070
00071 float result, rad;
00072 Vector3 temp(point);
00073
00074 temp.sub(patch.centre);
00075
00076 result = (patch.normal.x * temp.x +
00077 patch.normal.y * temp.y +
00078 patch.normal.z * temp.z);
00079
00080 if (result <= 0) result = 0;
00081 else {
00082 result *= -normal.dot(temp);
00083 if (result <= 0) result = 0;
00084 else {
00085 rad = Math::sqr(temp.lengthSquared());
00086 result *= patch.area;
00087 result /= (rad * PI);
00088 }
00089 }
00090
00091 return result;
00092 }
00093
00094 float Radiosity::_patch_factor(Patch& patch,
00095 const Vector3& point,
00096 const Vector3& normal)
00097 {
00098
00099
00100
00101
00102
00103
00104 assert(patch.pMeshPlane);
00105
00106 Vector3 x1, x2, x3;
00107 float sum = 0.0;
00108 bool isFirst = true;
00109
00110 Mesh::Edge * pE = patch.pMeshPlane->any_edge; assert(pE);
00111 do {
00112
00113 if (pE->LeftLoop == patch.pMeshPlane)
00114 x2.set(pE->V1->x, pE->V1->y, pE->V1->z);
00115 else
00116 x2.set(pE->V2->x, pE->V2->y, pE->V2->z);
00117 x2.sub(point);
00118
00119 if (isFirst) {
00120 x3.set(x2);
00121 isFirst = false;
00122 } else
00123 sum += _edge_area(x1, x2, normal);
00124
00125 x1.set(x2);
00126
00127
00128 if (pE->LeftLoop == patch.pMeshPlane) pE = pE->LeftOut;
00129 else pE = pE->RightOut;
00130 } while (pE != patch.pMeshPlane->any_edge);
00131
00132 sum += _edge_area(x1, x3, normal);
00133
00134 if (sum > 0.0) return sum;
00135 else return 0.0;
00136 }
00137
00138 #define _MAX(a,b) (((a)<(b))?(b):(a))
00139 float Radiosity::_est_form_factor(Patch& from, Patch& to)
00140 {
00141 float result, rad, npt, res2;
00142 Vector3 temp(to.centre);
00143
00144 temp.sub(from.centre);
00145
00146 result = -(to.normal.x*temp.x + to.normal.y*temp.y + to.normal.z*temp.z);
00147 if (result <= 0.0) return 0.0;
00148
00149 npt = (from.normal.x*temp.x + from.normal.y*temp.y + from.normal.z*temp.z);
00150 if (npt <= 0.0) return 0.0;
00151
00152 rad = Math::sqr(temp.lengthSquared());
00153 result *= from.area / PI;
00154 res2 = result * _MAX(npt, 0.25 * sqrt(from.area));
00155
00156 if (_quadLevel == 0 || rad * _dFError >= res2) return result*(npt/rad);
00157
00158
00159
00160
00161 Vector3 v;
00162 float sum = 0.0;
00163 int numV = 0;
00164
00165 if (_quadLevel > 1) {
00166
00167
00168 Mesh::Edge * pE = to.pMeshPlane->any_edge; assert(pE);
00169 do {
00170 if (pE->LeftLoop == to.pMeshPlane)
00171 v.set(pE->V1->x, pE->V1->y, pE->V1->z);
00172 else
00173 v.set(pE->V2->x, pE->V2->y, pE->V2->z);
00174 sum += _patch_factor(from, v, to.normal);
00175 numV++;
00176
00177 if (pE->LeftLoop == to.pMeshPlane) pE = pE->LeftOut;
00178 else pE = pE->RightOut;
00179 } while (pE != to.pMeshPlane->any_edge);
00180
00181 if (_quadLevel > 2) {
00182
00183
00184
00185 sum += 2.0 * _patch_factor(from, to.centre, to.normal);
00186 sum /= numV + 2;
00187 } else
00188 sum /= numV;
00189 } else
00190 sum = _patch_factor(from, to.centre, to.normal);
00191
00192 return sum;
00193 }
00194 #undef _MAX
00195
00196 void Radiosity::_make_form_factors(Patch& fromPatch, Vector3 result[])
00197 {
00198 float rho, factor, visibility;
00199 int i = 0;
00200
00201 for (Patch * curPatch = _scenePatches.firstItem();
00202 curPatch;
00203 curPatch = _scenePatches.nextItem())
00204 {
00205 rho = curPatch->reflectance.length();
00206 if (rho < 0.0001) { result[i++].set(0,0,0); continue; }
00207
00208 factor = _est_form_factor(fromPatch, *curPatch);
00209
00210 #ifdef RAD_SPEEDY
00211 if (rho * factor < 1e-5) { result[i++].set(0,0,0); continue; }
00212 #endif
00213
00214 visibility = _visibility(fromPatch, *curPatch);
00215
00216 if (visibility > 0.0001) {
00217 result[i].set(curPatch->reflectance);
00218 result[i++].scale(factor * visibility);
00219 } else
00220 result[i++].set(0,0,0);
00221 }
00222 }
00223
00224 float Radiosity::_visibility(Patch& from, Patch& to)
00225
00226 {
00227 float d;
00228
00229
00230 d = from.normal.dot(from.centre);
00231 if (from.normal.dot(to.centre) <= d) return 0.0;
00232
00233
00234 d = to.normal.dot(to.centre);
00235 if (from.centre.dot(to.normal) <= d) return 0.0;
00236
00237
00238
00239 assert(_pIntersector);
00240
00241 Vector3 dir(to.centre);
00242 dir.sub(from.centre);
00243 float maxDist = dir.length();
00244 dir.normalize();
00245
00246 _pIntersector->init(ENV_WANT_INTERFERENCE, maxDist);
00247 #warning "FIX ME: Light OID"
00248 ShadowExplorer explorer(from.centre, dir, maxDist);
00249 if (explorer.result()) return 0.0;
00250 else return 1.0;
00251 }
00252
00253
00254
00255
00256 void Radiosity::setScene(Scene * pScene)
00257 {
00258 ReflectionModel::setScene(pScene);
00259 if (!_pScene || !_pScene->root()) return;
00260
00261 ObjsExplorer explorer;
00262 Matrix4 trMat;
00263 bool transformed;
00264 Mesh* pMesh;
00265
00266 PolygonalEnergy* pE;
00267 AutoPtr<EnergyCoat> * pAE;
00268 AutoPtr<Mesh> * pAMesh;
00269 Vector3 emission;
00270 Vector3 reflectance;
00271 MatVisitor visitor;
00272
00273 _scenePatches.deleteAll();
00274
00275 explorer.explore(*(_pScene->root()));
00276
00277 for (SceneGraphObject * pObj = explorer.result(trMat, transformed);
00278 pObj;
00279 pObj = explorer.result(trMat, transformed))
00280 {
00281
00282 if (!pObj->supportsEnergy()) continue;
00283
00284 pAE = pObj->getEnergyState();
00285 if (!pAE) continue;
00286
00287 if (!pAE->origObject() ||
00288 pAE->origObject()->type() != EnergyCoat::POLYGONAL) continue;
00289
00290 pE = (PolygonalEnergy*) pAE->origObject();
00291 if (pE->getRegionsDescr() != PolygonalEnergy::FACET_BASED) continue;
00292
00293 pAMesh = pE->getMesh();
00294 if (!pAMesh) continue;
00295
00296 pMesh = pAMesh->origObject();
00297 if (!pMesh) continue;
00298
00299
00300 visitor.init();
00301 pObj->inspectMaterials(visitor);
00302 reflectance.set(visitor.diffuse());
00303
00304
00305 pMesh->resetActSolid();
00306 do {
00307 pMesh->resetActPlane();
00308 do {
00309 if (!(pE->getRegionEnergy(pMesh->getActPlaneID(), emission)))
00310
00311 fprintf(stderr,"Radiosity::setScene(): Uninitilized facet energy or facet ID mismatch\n");
00312
00313
00314 _scenePatches.append(new Patch((PolygonalEnergy*) pE,
00315 pMesh->getActPlane(),
00316 reflectance,
00317 emission,
00318 pMesh->getActPlaneCentroid(),
00319 pMesh->getActPlaneArea()));
00320 } while (pMesh->goToNextPlane());
00321 } while (pMesh->goToNextSolid());
00322 }
00323 }
00324
00325 Color3f* Radiosity::illuminatePoint(PointEnv&)
00326 {
00327 float power, maxPower;
00328 Patch * pMaxPowerPatch = _scenePatches.firstItem();
00329 Vector3 rgbToLum(1.0/3.0, 1.0/3.0, 1.0/3.0);
00330 Vector3 radToShoot;
00331 Vector3 envPower;
00332 Vector3 deltaRad;
00333 float origShoot = 0;
00334 int iterations = 0;
00335 unsigned i;
00336 Vector3 envRefl(0,0,0);
00337 float envArea = 0.0;
00338 unsigned maxPowerIndex;
00339 float error = 1.0;
00340 Vector3 envRad(1,1,1);
00341 bool finished = false;
00342
00343 if (!_pIntersector) return NULL;
00344
00345 Vector3* ffRow = new Vector3 [_scenePatches.length()];
00346 Vector3* S = new Vector3 [_scenePatches.length()];
00347
00348
00349 i = 0;
00350 for (Patch * curPatch = _scenePatches.firstItem();
00351 curPatch;
00352 curPatch = _scenePatches.nextItem())
00353 {
00354 envRefl.add(curPatch->reflectance * curPatch->area);
00355 envArea += curPatch->area;
00356 S[i].set(curPatch->emittance);
00357 i++;
00358 }
00359
00360 envRefl.x /= 1 / (1 - envRefl.x / envArea);
00361 envRefl.y /= 1 / (1 - envRefl.y / envArea);
00362 envRefl.z /= 1 / (1 - envRefl.z / envArea);
00363
00364
00365 while (!finished) {
00366 maxPower = 0;
00367 envPower.set(0,0,0);
00368 maxPowerIndex = 0;
00369 pMaxPowerPatch = NULL;
00370
00371 iterations++;
00372
00373
00374 i = 0;
00375 for (Patch * curPatch = _scenePatches.firstItem();
00376 curPatch;
00377 curPatch = _scenePatches.nextItem())
00378 {
00379 power = rgbToLum.dot(S[i] * curPatch->area);
00380 if (maxPower < power) {
00381 maxPower = power;
00382 pMaxPowerPatch = curPatch;
00383 maxPowerIndex = i;
00384 }
00385 i++;
00386 }
00387
00388 assert(pMaxPowerPatch);
00389
00390
00391
00392 radToShoot.set(S[maxPowerIndex]);
00393 S[maxPowerIndex].set(0,0,0);
00394
00395 _make_form_factors(*pMaxPowerPatch, ffRow);
00396
00397 envPower.set(0,0,0);
00398 error = 0.0;
00399
00400
00401 i = 0;
00402 for (Patch * curPatch = _scenePatches.firstItem();
00403 curPatch;
00404 curPatch = _scenePatches.nextItem())
00405 {
00406 deltaRad.x = ffRow[i].x * radToShoot.x;
00407 deltaRad.y = ffRow[i].y * radToShoot.y;
00408 deltaRad.z = ffRow[i].z * radToShoot.z;
00409 curPatch->emittance.add(deltaRad);
00410 S[i].add(deltaRad);
00411 error += deltaRad.lengthSquared();
00412 envPower.add(S[i] * curPatch->area);
00413 i++;
00414 }
00415
00416 if (_useAmbient) {
00417 envRad.x = envRefl.x * envPower.x / envArea;
00418 envRad.y = envRefl.y * envPower.y / envArea;
00419 envRad.z = envRefl.z * envPower.z / envArea;
00420 } else
00421 envRad.set(0,0,0);
00422
00423 error = sqrt(error);
00424
00425 if (iterations == 1) origShoot = maxPower;
00426 else
00427 if (maxPower <= 0.01 * origShoot) finished = true;
00428 }
00429
00430
00431 if (_useAmbient) {
00432 for (Patch * curPatch = _scenePatches.firstItem();
00433 curPatch;
00434 curPatch = _scenePatches.nextItem())
00435 {
00436 curPatch->emittance.x += curPatch->reflectance.x*envRad.x;
00437 curPatch->emittance.y += curPatch->reflectance.x*envRad.y;
00438 curPatch->emittance.z += curPatch->reflectance.x*envRad.z;
00439 }
00440 }
00441
00442
00443 for (Patch * curPatch = _scenePatches.firstItem();
00444 curPatch;
00445 curPatch = _scenePatches.nextItem())
00446 {
00447
00448 curPatch->pEnergy->setRegionEnergy(curPatch->pMeshPlane->jmeno_roviny,
00449 curPatch->emittance);
00450 }
00451
00452 delete [] ffRow;
00453 delete [] S;
00454
00455 return NULL;
00456 }