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
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();
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
00104
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
00126
00127
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
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
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 : 0;
00213 float split = uvMin[splitAxis] + 0.5 * length[splitAxis];
00214
00215
00216
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
00226 leaf->parent = newParent;
00227 float leafWeight = leaf->sample.weight()*0.5;
00228 leaf->setWeight(leafWeight);
00229
00230
00231
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
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
00268
00269 const Point3D& base = light->base;
00270 const Vec3D& span1 = light->span1;
00271 const Vec3D& span2 = light->span2;
00272
00273
00274 if(root != 0){
00275
00276 delete root;
00277 }
00278
00279
00280 int count = 0;
00281
00282
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
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
00318
00319
00320 RGBColor lastMean = root->getMean();
00321 float minSamples = maxSamples/2;
00322 while(count < maxSamples){
00323
00324
00325 LSTreeLeaf* leaf = root->refine();
00326
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
00341
00342
00343
00344
00345
00346
00347
00348
00349 }
00350
00351
00352
00353 }