src/rcrt/lights/sampling/AreaLightSampler.cpp

Go to the documentation of this file.
00001 #include "AreaLightSampler.h"
00002 
00003 using namespace std;
00004 
00005 namespace rcrt
00006 {
00007 
00008 
00009 LSTreeLeaf::LSTreeLeaf(LightSample sa, const Point2D& uvMi, const Point2D& uvMa,
00010                 const Point2D& uv, LSTreeNode* p)
00011         :LSTree(sa.power() == RGBColor(0,0,0) ? FULL : NONE, 1, p)
00012         ,sample(sa),uvMin(uvMi), uvMax(uvMa), uvs(uv)
00013 {
00014 }
00015 
00016 const RGBColor& LSTreeLeaf::getMean() const
00017 {
00018         return sample.power();
00019 }
00020 
00021 const RGBColor& LSTreeLeaf::getVariance() const
00022 {
00023         return RGBColor::BLACK;
00024 }
00025 
00026 const float& LSTreeLeaf::getWeight() const
00027 {
00028         return sample.weight();
00029 }
00030 
00031 void LSTreeLeaf::setWeight(const float& w)
00032 {
00033         sample.setWeight(w);
00034 }
00035 
00036 void LSTreeLeaf::getSamples(std::vector<LightSample>& samples) const
00037 {
00038         samples.push_back(sample);
00039 }
00040 
00041 bool LSTreeLeaf::isLeaf()
00042 {
00043         return true;
00044 }
00045 
00046 LSTreeLeaf* LSTreeLeaf::refine()
00047 {
00048         return this;
00049 }
00050 
00051 /*LSTreeNode Methods*/
00052 
00053 LSTreeNode::LSTreeNode(const Point2D& uvMi, const Point2D& uvMa, LSTreeNode* p)
00054         :LSTree(p),lc(0), rc(0), uvMin(uvMi), uvMax(uvMa)
00055 {
00056 }
00057 
00058 LSTreeNode::LSTreeNode(LSTree* l, LSTree* r, LSTreeNode* p, const Point2D& uvMi, const Point2D& uvMa)
00059         :LSTree(p),lc(l), rc(r), uvMin(uvMi), uvMax(uvMa)
00060 {
00061         update();
00062 }
00063 
00064 void LSTreeNode::setLeft(LSTree* l)
00065 {
00066         lc = l;
00067         update();
00068 }
00069 
00070 void LSTreeNode::setRight(LSTree* r)
00071 {
00072         rc = r;
00073         update();
00074 }
00075 
00076 void LSTreeNode::update(){
00077         weight = lc->getWeight()+rc->getWeight();
00078         mean = lc->getMean() * lc->getWeight() + rc->getMean()*rc->getWeight();
00079         mean = mean / weight;
00080         size = lc->getSize() + rc->getSize();//number of leafs
00081         if(lc->getType() == rc->getType() && lc->getType() != PENUMBRA){
00082                 type = lc->getType();
00083                 variance = 0;
00084         }
00085         else
00086         {
00087                 const float& lw = lc->getWeight();
00088                 const float& rw = rc->getWeight();
00089                 RGBColor lv = lc->getMean() - mean;
00090                 lv = lv * lv * lc->getWeight();
00091                 RGBColor rv = rc->getMean() - mean;
00092                 rv = rv * rv * rc->getWeight();                 
00093                 variance = weight/(weight*weight - lw * lw - rw * rw);
00094                 variance = (lv + rv) * variance;
00095                 type = PENUMBRA;
00096         }
00097         if(parent)
00098                 parent->update();
00099 }
00100 
00101 LSTreeLeaf* LSTreeNode::refine()
00102 {
00103         //enforce minimum difference in subdivision level between
00104         //subtrees.
00105         if(fabs(lc->getSize() - rc->getSize()) > 2){
00106                 if(lc->getSize() < rc->getSize())
00107                         return lc->refine();
00108                 else
00109                         return rc->refine();
00110         }       
00111         
00112         if(lc->getType() == PENUMBRA || rc->getType() == PENUMBRA){
00113                 if(lc->getType() != PENUMBRA)
00114                         return rc->refine();
00115                 else if(rc->getType() != PENUMBRA)
00116                         return lc->refine();
00117                 else{
00118                         if(lc->getSize() < rc->getSize())
00119                                 return lc->refine();
00120                         else
00121                                 return rc->refine();
00122                 }
00123         }
00124         else if(parent != 0){
00125                 //compare with nodes at same subdivision level
00126                 //refine the node with the type that differs most
00127                 //from the rest, or the one that has the least size
00128                 LSTree* other = parent->getOtherChild(this);
00129                 if(other->isLeaf()){
00130                         if(lc->getType() != rc->getType() &&
00131                                         lc->getType() == other->getType())
00132                                         return rc->refine();
00133                 }
00134                 else {
00135                         LSTree* olc = ((LSTreeNode*)other)->lc;
00136                         LSTree* orc = ((LSTreeNode*)other)->rc;
00137                         if(lc->getType() != rc->getType()){
00138                                 int lcount, rcount;
00139                                 lcount = rcount = 0;
00140                                 if(lc->getType() != olc->getType())
00141                                         lcount++;
00142                                 if(lc->getType() != orc->getType())
00143                                         lcount++;
00144                                 if(rc->getType() != olc->getType())
00145                                         rcount++;
00146                                 if(rc->getType() != orc->getType())
00147                                         rcount++;
00148                                 if(rcount > lcount)
00149                                         return rc->refine();
00150                                 else if(lcount > rcount)
00151                                         return lc->refine();
00152                         }
00153                 }
00154         }        
00155         if(lc->getSize() > rc->getSize())
00156                 return rc->refine();
00157         return lc->refine();
00158 }
00159 
00160 LSTree* LSTreeNode::getOtherChild(LSTree* c)
00161 {
00162         if(lc != c)
00163                 return lc;
00164         else
00165                 return rc;
00166 }
00167         
00168 const RGBColor& LSTreeNode::getMean() const
00169 {
00170         return mean;
00171 }
00172         
00173 const float& LSTreeNode::getWeight() const
00174 {
00175         return weight;
00176 }
00177 
00178 void LSTreeNode::setWeight(const float& w)
00179 {
00180         weight = w;
00181 }
00182 
00183 void LSTreeNode::getSamples(std::vector<LightSample>& samples) const
00184 {
00185         lc->getSamples(samples);
00186         rc->getSamples(samples);
00187 }
00188         
00189 const RGBColor& LSTreeNode::getVariance() const
00190 {
00191         return variance;
00192 }
00193 
00194 /*AreaLightSampler methods*/
00195 
00196 AreaLightSampler::AreaLightSampler(AreaLight* l)
00197         :light(l),root(0)
00198 {
00199 }
00200 
00201 void AreaLightSampler::subdivide(LSTreeLeaf* leaf, vector<LightSample>& samples,
00202                 const Point3D& p, const Vec3D& no, Scene* scene)
00203 {
00204         //cout << "[AreaLightSampler] subdivide:" << endl;
00205         LSTreeNode* parent = leaf->getParent();
00206         const Point2D& uvMin = leaf->uvMin;
00207         const Point2D& uvMax = leaf->uvMax;
00208         float length[2] = {
00209                         uvMax.x()-uvMin.x(),
00210                         uvMax.y()-uvMin.y()
00211                 };
00212         int splitAxis = length[0] < length[1] ? 1/*y*/ : 0/*x*/;
00213         float split = uvMin[splitAxis] + 0.5 * length[splitAxis];
00214         
00215         //generate a new subdivided node and insert it
00216         //cout << "[AreaLightSampler]            generating new parent node" << endl;
00217         LSTreeNode* newParent = 0;
00218         if(parent->lc == leaf){
00219                 parent->lc = new LSTreeNode(uvMin,uvMax,parent);
00220                 newParent = (LSTreeNode*) parent->lc;
00221         }else{
00222                 parent->rc = new LSTreeNode(uvMin,uvMax,parent);
00223                 newParent = (LSTreeNode*) parent->rc;
00224         }
00225         //cout << "[AreaLightSampler]            setting parent " << newParent << " on leaf" << endl;
00226         leaf->parent = newParent;
00227         float leafWeight = leaf->sample.weight()*0.5;
00228         leaf->setWeight(leafWeight);
00229         
00230         //insert the previous sample and a new sample
00231         //cout << "[AreaLightSampler]            inserting samples" << endl;
00232         if(leaf->uvs[splitAxis] < split){
00233                 Point2D ruvMin = uvMin;
00234                 ruvMin[splitAxis] = split;
00235                 Point2D rLeafPos = uvMin;
00236                 rLeafPos[splitAxis] += 0.75*length[splitAxis];
00237                 rLeafPos[1-splitAxis] += 0.5*length[1-splitAxis];
00238                 
00239                 newParent->rc = new LSTreeLeaf(
00240                                 light->getSample(rLeafPos,no,p,scene),
00241                                 ruvMin,uvMax, rLeafPos, newParent);
00242                 newParent->rc->setWeight(leafWeight);
00243                 leaf->uvMax[splitAxis] = split;
00244                 newParent->lc = leaf;
00245         } else {
00246                 Point2D luvMax = uvMax;
00247                 luvMax[splitAxis] = split;
00248                 Point2D rLeafPos = uvMin;
00249                 rLeafPos[splitAxis] += 0.25*length[splitAxis];
00250                 rLeafPos[1-splitAxis] += 0.5*length[1-splitAxis];
00251                 newParent->lc = new LSTreeLeaf(
00252                                 light->getSample(rLeafPos,no,p,scene),
00253                                 uvMin,luvMax, rLeafPos, newParent);
00254                 newParent->lc->setWeight(leafWeight);
00255                 leaf->uvMin[splitAxis] = split;
00256                 newParent->rc = leaf;
00257         }
00258         //cout << "[AreaLightSampler]            updating parent " << endl;
00259         
00260         newParent->update();
00261         
00262 }
00263         
00264 void AreaLightSampler::sample(const Point3D& p, const Vec3D& no,
00265                 vector<LightSample>& samples, const int& maxSamples, Scene* scene)
00266 {
00267         //cout << "[AreaLightSampler] sample:" << endl;
00268         
00269         const Point3D& base = light->base;
00270         const Vec3D& span1 = light->span1;
00271         const Vec3D& span2 = light->span2;
00272         
00273         //TODO reuse of previous sampling pattern if lastPos near p, for now, recalculate
00274         if(root != 0){
00275                 //cout << "[AreaLightSampler]         deleting current tree" << endl;
00276                 delete root;
00277         }
00278 
00279         //do initial sampling
00280         int count = 0;
00281         
00282         //use a 2x2 rotated grid
00283         Point2D uvs[4] = {
00284                         Point2D(0.375, 0.125),
00285                         Point2D(0.875, 0.375),
00286                         Point2D(0.625, 0.875),
00287                         Point2D(0.125, 0.625)                   
00288                 };
00289         Point3D loc[4] = {
00290                         Point3D(base+uvs[0].x()*span1+uvs[0].y()*span2),
00291                         Point3D(base+uvs[1].x()*span1+uvs[1].y()*span2),
00292                         Point3D(base+uvs[2].x()*span1+uvs[2].y()*span2),
00293                         Point3D(base+uvs[3].x()*span1+uvs[3].y()*span2)
00294                         };
00295         LightSample initSamples[4] = {
00296                         light->getSample(p,no,loc[0],scene),
00297                         light->getSample(p,no,loc[1],scene),
00298                         light->getSample(p,no,loc[2],scene),
00299                         light->getSample(p,no,loc[3],scene)
00300                 };
00301         for(int s = 0; s < 4; s++){
00302                 initSamples[s].setWeight(0.25f);
00303                 count++;
00304         }
00305         //construct initial tree
00306         root = new LSTreeNode(Point2D(0,0),Point2D(1,1));
00307         root->lc = new LSTreeNode(Point2D(0,0), Point2D(1,0.5), root);
00308         root->rc = new LSTreeNode(Point2D(0,0.5), Point2D(1,1), root);
00309         LSTreeNode* rlc = (LSTreeNode*)root->lc;
00310         LSTreeNode* rrc = (LSTreeNode*)root->rc;
00311         rlc->lc = new LSTreeLeaf(initSamples[0], Point2D(0,0), Point2D(0.5,0.5), uvs[0], rlc);
00312         rlc->rc = new LSTreeLeaf(initSamples[1], Point2D(0.5,0), Point2D(1,0.5), uvs[1], rlc);
00313         rlc->update();
00314         rrc->lc = new LSTreeLeaf(initSamples[2], Point2D(0.5,0.5), Point2D(1,1), uvs[2], rrc);
00315         rrc->rc = new LSTreeLeaf(initSamples[3], Point2D(0,0.5), Point2D(0.5,1), uvs[3], rrc);
00316         rrc->update();
00317         //cout << "[AreaLightSampler]         generated initial tree" << endl;
00318         //refine the tree until maximum samples reached
00319         //or variance small enough      
00320         RGBColor lastMean = root->getMean();
00321         float minSamples = maxSamples/2;
00322         while(count < maxSamples){
00323                 //get the leaf that we want to refine
00324                 //cout << "[AreaLightSampler]         getting leaf to refine" << endl;
00325                 LSTreeLeaf* leaf = root->refine();
00326                 //cout << "[AreaLightSampler]         subdividing leaf" << endl;
00327                 subdivide(leaf, samples, p, no, scene);
00328                 count++;
00329                 RGBColor difference = root->getMean() - lastMean;
00330                 if(count > minSamples
00331                                 && fabs(difference.r()) < 0.00001f
00332                                 && fabs(difference.g()) < 0.00001f
00333                                 && fabs(difference.b()) < 0.00001f)
00334                         break;
00335                 lastMean = root->getMean();
00336         }
00337         
00338         root->getSamples(samples);
00339         /*
00340         cout << "[AreaLightSampler]         got "<<count <<" samples:" << endl;
00341         cout << "[AreaLightSampler]         ";
00342         float totalW = 0;
00343         for(unsigned int i = 0; i < samples.size(); i++){
00344                 totalW += samples[i].weight();
00345                 cout << " w=" << samples[i].weight();
00346         }
00347         cout << endl << "[AreaLightSampler]         total weight="<<totalW<<endl;
00348         */
00349 }
00350 
00351 
00352 
00353 } //Namespace

Generated on Thu Jan 31 19:26:19 2008 for RenderingCompetitionRayTracer by  doxygen 1.5.3