00001 #include <esg/energy/IrradianceCache.h>
00002 #include <sstream>
00003
00004 using namespace esg;
00005
00006 IrradianceCache::IrradianceCache(const float mError, const float rootSize)
00007 throw (out_of_range) : maxError(mError)
00008 {
00009 if (mError <= 0.0f) {
00010 ostringstream message;
00011 message << "IrradianceCache::IrradianceCache(): mError: " << mError;
00012 throw out_of_range( message.str() );
00013 }
00014
00015 if (rootSize <= 0.0f) {
00016 ostringstream message;
00017 message << "IrradianceCache::IrradianceCache(): rootSize: " << rootSize;
00018 throw out_of_range( message.str() );
00019 }
00020
00021 root = new IrradianceCache::Node(rootSize, 0.0f, 0.0f, 0.0f);
00022 }
00023
00024
00025 IrradianceCache::~IrradianceCache()
00026 {
00027 if (root != NULL) delete root;
00028 treeValuesBuffer.clear();
00029 }
00030
00031
00032 bool IrradianceCache::isInside(const Vector3& position) const
00033 {
00034 float halfSize = root->getSize() / 2.0f + 0.0001f;
00035
00036 return ((fabs(position.x) <= halfSize &&
00037 fabs(position.y) <= halfSize &&
00038 fabs(position.z) <= halfSize));
00039 }
00040
00041
00042 void IrradianceCache::addValue(const Vector3& pos,
00043 const Vector3& normal,
00044 const Color3f& irrad,
00045 float meanDistance) throw (out_of_range)
00046 {
00047 if (meanDistance <= 0.0f) {
00048 ostringstream message;
00049 message << "IrradianceCache::addValue(): meanDistance: " << meanDistance;
00050 throw out_of_range( message.str() );
00051 }
00052
00053
00054 if (!isInside(pos)) {
00055 ostringstream message;
00056 message << "IrradianceCache::addValue(): Irradiance " <<
00057 pos << " is located outside of the octree";
00058 throw out_of_range( message.str() );
00059 }
00060
00061
00062 float minSize = 2.0f * maxError * meanDistance;
00063 if (minSize >= root->getSize()) {
00064 ostringstream message;
00065 message << "IrradianceCache::addValue(): Root's storage condition failed"
00066 << ": " << minSize << " >= " << root->getSize();
00067 throw out_of_range( message.str() );
00068
00069 }
00070
00071 root->addValue(pos, normal, irrad, meanDistance, minSize, minSize * 2.0f);
00072 }
00073
00074
00075 void IrradianceCache::getValue(const Vector3& pos,
00076 const Vector3& normal,
00077 vector<IrradianceCache::Value*>& buffer) const
00078 throw (out_of_range)
00079 {
00080 if (!isInside(pos)) {
00081 ostringstream message;
00082 message << "IrradianceCache::getValue(): Point " <<
00083 pos << " is outside of the octree";
00084 throw out_of_range( message.str() );
00085 }
00086 buffer.clear();
00087 root->getValue(pos, normal, buffer, this->maxError);
00088 }
00089
00090 unsigned int IrradianceCache::getNumStoredValues() const
00091 {
00092 return root->getNumStoredValues();
00093 }
00094
00095 unsigned int IrradianceCache::getNumNodes() const
00096 {
00097 return (root->getNumNodes());
00098 }
00099
00100 const IrradianceCache::Value* IrradianceCache::getNextValuePointer()
00101 {
00102 static unsigned int nodeIndex = 0;
00103 static unsigned int valueIndex = 0;
00104
00105 if (treeValuesBuffer.size() == 0) {
00106 nodeIndex = valueIndex = 0;
00107 root->getNodeValues(treeValuesBuffer);
00108 }
00109
00110 if (nodeIndex < treeValuesBuffer.size()) {
00111 if (valueIndex < treeValuesBuffer[nodeIndex]->size()) {
00112 return (treeValuesBuffer[nodeIndex]->at(valueIndex++));
00113 } else {
00114 valueIndex = 0;
00115 nodeIndex++;
00116 return getNextValuePointer();
00117 }
00118 } else
00119 return NULL;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00132
00133
00134
00135
00136 IrradianceCache::Value::Value()
00137 : position(0.0f, 0.0f, 0.0f),
00138 normal(0.0f, 0.0f, 0.0f),
00139 irradiance(0.0f, 0.0f, 0.0f),
00140 meanDistance(0.0f),
00141 weight(0.0f)
00142 {
00143 }
00144
00145
00146 IrradianceCache::Value::Value(const Vector3& pos,
00147 const Vector3& normal,
00148 const Color3f& irrad,
00149 float meanDistance)
00150 : position(pos),
00151 normal(normal),
00152 irradiance(irrad),
00153 meanDistance(meanDistance),
00154 weight(0.0f)
00155 {
00156 }
00157
00158
00159 bool IrradianceCache::Value::checkDomain(const Vector3& position,
00160 const Vector3& normal,
00161 float maxError)
00162 {
00163
00164
00165
00166
00167
00168 weight = 0.0f;
00169
00170 Vector3 d(position);
00171 d.sub(this->position);
00172 float denominator = d.length() / meanDistance;
00173
00174 if (denominator >= maxError) return false;
00175
00176 denominator += sqrtf(1.0f - normal.dot(this->normal));
00177 if (denominator >= maxError) return false;
00178
00179 weight = 1.0f / denominator;
00180
00181 return true;
00182
00183
00184
00185
00186
00187
00188
00189 Vector3 n(normal);
00190 n.add(this->normal);
00191 n.scale(0.5);
00192 return (n.dot(d) >= -0.0001f);
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00204
00205 void IrradianceCache::Node::allocate(unsigned int nodeIndex)
00206 {
00207 float newSize = size / 2.0f;
00208 float add = size / 4.0f;
00209 float leftCenterX = center.x - add;
00210 float rightCenterX = center.x + add;
00211 float upCenterY = center.y + add;
00212 float downCenterY = center.y - add;
00213 float forwardCenterZ = center.z + add;
00214 float backwardCenterZ = center.z - add;
00215
00216
00217 switch (nodeIndex) {
00218 case 0:
00219 subnodes[0] = new Node(newSize, rightCenterX,
00220 downCenterY, backwardCenterZ);
00221 break;
00222 case 1:
00223 subnodes[1] = new Node(newSize, leftCenterX,
00224 downCenterY, backwardCenterZ);
00225 break;
00226 case 2:
00227 subnodes[2] = new Node(newSize, leftCenterX,
00228 downCenterY, forwardCenterZ);
00229 break;
00230 case 3:
00231 subnodes[3] = new Node(newSize, rightCenterX,
00232 downCenterY, forwardCenterZ);
00233 break;
00234 case 4:
00235 subnodes[4] = new Node(newSize, rightCenterX,
00236 upCenterY, backwardCenterZ);
00237 break;
00238 case 5:
00239 subnodes[5] = new Node(newSize, leftCenterX,
00240 upCenterY, backwardCenterZ);
00241 break;
00242 case 6:
00243 subnodes[6] = new Node(newSize, leftCenterX,
00244 upCenterY, forwardCenterZ);
00245 break;
00246 case 7:
00247 subnodes[7] = new Node(newSize, rightCenterX,
00248 upCenterY, forwardCenterZ);
00249 break;
00250 default:
00251 break;
00252 }
00253 }
00254
00255
00256 unsigned int IrradianceCache::Node::selectSubnode(const Vector3& position) const
00257 {
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 if ( position.y - center.y >= 0.0f ) {
00270
00271 if ( position.x - center.x >= 0.0f ) {
00272
00273 if ( position.z - center.z >= 0.0f )
00274 return 7;
00275 else
00276 return 4;
00277 } else {
00278
00279 if ( position.z - center.z >= 0.0f )
00280 return 6;
00281 else
00282 return 5;
00283 }
00284 } else {
00285
00286 if ( position.x - center.x >= 0.0f ) {
00287
00288 if ( position.z - center.z >= 0.0f )
00289 return 3;
00290 else
00291 return 0;
00292 } else {
00293
00294 if ( position.z - center.z >= 0.0f )
00295 return 2;
00296 else
00297 return 1;
00298 }
00299 }
00300 }
00301
00302 bool IrradianceCache::Node::necessaryToSearch(const Vector3& position) const
00303 {
00304 return (fabs(center.x - position.x) <= size &&
00305 fabs(center.y - position.y) <= size &&
00306 fabs(center.z - position.z) <= size);
00307 }
00308
00309 IrradianceCache::Node::Node(float s, float cX, float cY, float cZ):
00310 center(cX, cY, cZ), size(s)
00311 {
00312
00313 for (register unsigned int i = 0; i < 8; i++) subnodes[i] = NULL;
00314 }
00315
00316
00317 IrradianceCache::Node::~Node()
00318 {
00319
00320 for (vector<IrradianceCache::Value*>::iterator it = irradianceValues.begin();
00321 it != irradianceValues.end();
00322 it++)
00323 {
00324 delete (*it);
00325 }
00326 irradianceValues.clear();
00327
00328
00329 for (register unsigned int i = 0; i < 8; i++)
00330 if (subnodes[i] != NULL) delete subnodes[i];
00331 }
00332
00333
00334 void IrradianceCache::Node::addValue(const Vector3& position,
00335 const Vector3& normal,
00336 const Vector3& color,
00337 float meanDistance,
00338 float minSize,
00339 float maxSize)
00340 {
00341
00342
00343
00344
00345
00346
00347
00348
00349 if (minSize < size && size <= maxSize) {
00350
00351 irradianceValues.push_back(new IrradianceCache::Value(position,
00352 normal,
00353 color,
00354 meanDistance));
00355 } else {
00356
00357 unsigned int index = selectSubnode(position);
00358
00359 if (!isAllocated(index)) allocate(index);
00360
00361
00362 return subnodes[index]->addValue(position, normal, color,
00363 meanDistance, minSize, maxSize);
00364 }
00365 }
00366
00367 void IrradianceCache::Node::getValue(const Vector3& position,
00368 const Vector3& normal,
00369 vector<IrradianceCache::Value*>& buffer,
00370 float maxError)
00371 {
00372
00373 for (vector<IrradianceCache::Value*>::iterator it = irradianceValues.begin();
00374 it != irradianceValues.end(); it++)
00375 {
00376 if ((*it)->checkDomain(position, normal, maxError))
00377 buffer.push_back(*it);
00378 }
00379
00380
00381
00382
00383
00384 for (register unsigned int i = 0; i < 8; i++) {
00385
00386 if (isAllocated(i) && subnodes[i]->necessaryToSearch(position))
00387 subnodes[i]->getValue(position, normal, buffer, maxError);
00388 }
00389 }
00390
00391 unsigned int IrradianceCache::Node::getNumStoredValues() const
00392 {
00393 unsigned int tmp = irradianceValues.size();
00394
00395 for (register unsigned int i = 0; i < 8; i++) {
00396 if ( isAllocated(i) ) tmp += subnodes[i]->getNumStoredValues();
00397 }
00398
00399 return tmp;
00400 }
00401
00402
00403 unsigned int IrradianceCache::Node::getNumNodes() const
00404 {
00405 unsigned int tmp = 1;
00406 for (register unsigned int i = 0; i < 8; i++)
00407 if (isAllocated(i)) tmp += subnodes[i]->getNumNodes();
00408 return tmp;
00409 }
00410
00411
00412 void IrradianceCache::Node::getNodeValues(vector<vector<IrradianceCache::Value*>*>& irValues)
00413 {
00414 irValues.push_back(&irradianceValues);
00415 for (register unsigned int i = 0; i < 8; i++)
00416 if (isAllocated(i)) subnodes[i]->getNodeValues(irValues);
00417 }
00418
00419
00420