IrradianceCache.cc

Go to the documentation of this file.
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     // check position of the new irradiance value
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     // condition of the storage of new irradiance value to the root
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      * w_i(P) = 1/ [(dist(P-P_i)/R_i) + sqrt(1- N(P)*N(P_i))]
00165      * w_i(P) > 1/maxError
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; // weight w_i(P) <= 1/maxError
00178 
00179     weight = 1.0f / denominator;
00180 
00181     return true;
00182 
00183     /*
00184      * Geometry tests
00185      *
00186      * d_i(P) = (P-P_i) * [N(P)+N(P_i)]/2
00187      * d_i(P) >= 0
00188      */
00189     Vector3 n(normal);
00190     n.add(this->normal);
00191     n.scale(0.5);
00192     return (n.dot(d) >= -0.0001f); // epsilon
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       indexovani nizsi ctverice uzlu z pohledu os xz
00260       | 1 | 0 |
00261       | 2 | 3 |
00262       
00263       indexovani vyzsi ctverice uzlu pohledu os xz
00264       | 5 | 4 |
00265       | 6 | 7 |
00266     */
00267     
00268     // rozdeleni podle osy y
00269     if ( position.y - center.y >= 0.0f ) {
00270         // rozdeleni podle osy x
00271         if ( position.x - center.x >= 0.0f )  {
00272             // rozdelení podle osy z
00273             if ( position.z - center.z >= 0.0f )
00274                 return 7;
00275             else
00276                 return 4;
00277         } else {
00278             // rozdeleni podle osy z
00279             if ( position.z - center.z >= 0.0f )
00280                 return 6;
00281             else
00282                 return 5;
00283         }
00284     } else {
00285         // rozdeleni podle osy x
00286         if ( position.x - center.x >= 0.0f ) {
00287             // rozdeleni podle osy z
00288             if ( position.z - center.z >= 0.0f )
00289                 return 3;
00290             else
00291                 return 0;
00292         } else {
00293             // rozdeleni podle osy z
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     // inicializuje ukazatele na dceøiné uzly
00313     for (register unsigned int i = 0; i < 8; i++) subnodes[i] = NULL;
00314 }
00315 
00316 
00317 IrradianceCache::Node::~Node()
00318 {
00319     // odstraní v¹echny primární hodnoty z uzlu
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     // uvolní pamì» v¹ech dceøiných uzlù
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     // Rozhodne, zda primarni hodnota patri do uzlu v zavislosti
00342     // na této podmínce o ukládání primární hodnoty do uzlu:
00343     //
00344     // minSize = 2*maxError*meanDistance
00345     // maxSize = 4*maxError*meanDistance
00346     //
00347     // minSize < size <= maxSize
00348     //
00349     if (minSize < size && size <= maxSize) {
00350         // ulo¾í primární hodnotu do tohoto uzlu
00351         irradianceValues.push_back(new IrradianceCache::Value(position,
00352                                                               normal,
00353                                                               color,
00354                                                               meanDistance));
00355     } else {
00356         // vybere dceøiný uzel, do kterého hodnotu ulo¾í
00357         unsigned int index = selectSubnode(position);
00358         
00359         if (!isAllocated(index)) allocate(index);
00360         
00361         // ulozi primarni hodnotu do vybraneho poduzlu
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     // iteration through irradiances stored in the node
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     } // for
00379     
00380 
00381     /*
00382      * recursion
00383      */
00384     for (register unsigned int i = 0; i < 8; i++) {
00385         // podminka pro nutnost vyhledani primarnich hodnot v dcerinem uzlu
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 

Generated on Wed Jun 28 12:24:31 2006 for esg by  doxygen 1.4.6