Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

Cluster.cc

Go to the documentation of this file.
00001 /*
00002     File:       Cluster.cc
00003     
00004     Purpose:    Implements volume clustering for wavelet radiosity
00005     
00006     Author:     Andrew Willmott
00007     
00008     Notes:      
00009 
00010 */
00011 
00012 #include "Cluster.h"
00013 #include "RadMethod.h"
00014 #include "Samples.h"
00015 
00016 #include "gcl/VecUtil.h"
00017 #include "gcl/Draw.h"
00018 
00019 const Int kMinClusterElems = 32;
00020 const Int kMaxClusterLevels = 16;
00021 
00022 // Cluster #defines
00023 #define RAD_NON_ISO_SOURCE
00024 #define RAD_NON_ISO_DEST
00025 // the above should always be defined, except for experiments showing how
00026 // bad the isotropic assumption is =)
00027 #define RAD_SAMPLE_ERROR
00028 // find error by sampling
00029 #define RAD_PTB
00030 // calculate intra-cluster visibility; don't include inter-cluster objects.
00031 
00032 #define DBG_COUT if (0) cerr
00033 
00034 Cluster::Cluster() : HRElem(), elems()
00035 {
00036     Int i;
00037     
00038     centre = vl_0;
00039     
00040     for (i = 0; i < 8; i++)
00041         child[i] = 0;       
00042 
00043     flags.Set(hrCluster);
00044 }
00045 
00046 Cluster::~Cluster()
00047 {
00048     Int i;
00049 
00050     DBG_COUT << "deleting cluster" << endl;
00051 
00052     for (i = 0; i < 8; i++)
00053         delete child[i];
00054 }
00055 
00056 Void Cluster::Reset()
00057 {
00058     Int     i;
00059     
00060     HRElem::Reset();
00061     for (i = 0; i < 8; i++)
00062         if (child[i])
00063             child[i]->Reset();
00064 }
00065 
00066 Void Cluster::CreateBounds()
00067 {
00068     Int     i;
00069     
00070     min = max = elems[0]->EltCentre();
00071     for (i = 0; i < elems.NumItems(); i++)
00072         elems[i]->EltUpdateBounds(min, max);
00073 
00074     centre = (min + max) / 2.0;
00075 }
00076 
00077 Void Cluster::SetElems(HRElemList *elemsIn)
00078 {
00079     elems = *elemsIn;
00080     CreateBounds();
00081 
00082     clusterVol = BoxVol(min, max);
00083     level = 0;
00084 #ifdef RAD_VIS
00085     eltParent = 0;
00086 #endif
00087 }
00088 
00089 Void Cluster::PushElems()
00090 {
00091     Vector      d1, d2;
00092     Int         i, j;
00093     Point       emin, emax, eCentroid;
00094     HRElemList  newElems;
00095 
00096     for (j = 0; j < elems.NumItems(); j++)
00097     {
00098         emin = emax = elems[j]->EltCentre();
00099         elems[j]->EltUpdateBounds(emin, emax);
00100         d1 = emax - emin;
00101         d2 = (max - min) / 2.0;
00102         
00103         DBG_COUT << "size check: " << d1 << " < " << d2 << endl;
00104 
00105         // if the element is bigger in size than an octant, add it to this
00106         // level of the cluster hierarchy.
00107         if (d1[0] > d2[0] || d1[1] > d2[1] || d1[2] > d2[2])
00108         {
00109             newElems.Append(elems[j]);
00110             continue;
00111         }
00112             
00113         // find the octant the element's centroid belongs to...
00114         eCentroid = (emin + emax) / 2.0;
00115         d1 = eCentroid - centre;
00116         if (sqrlen(d1) < 1e-8)
00117         {
00118             // if it's close to the centre, add it to this level after all.
00119             newElems.Append(elems[j]);
00120             continue;
00121         }
00122         
00123         i = 0;
00124         if (d1[0] >= 0.0) i += 1;
00125         if (d1[1] >= 0.0) i += 2;
00126         if (d1[2] >= 0.0) i += 4;
00127         
00128         // add it to the given octant
00129         if (child[i] == 0)
00130             child[i] = new Cluster;
00131         child[i]->elems.Append(elems[j]);
00132     }
00133 
00134     for (i = 0; i < 8; i++)
00135         if (child[i] && child[i]->elems.NumItems() <= 1)
00136         {
00137             DBG_COUT << "REDACTING cluster with only 1 item" << endl;
00138             newElems.Append(child[i]->elems[0]);
00139             delete child[i];
00140             child[i] = 0;
00141         }
00142     
00143     elems.Replace(newElems);
00144 }
00145  
00146 Cluster *Cluster::CreateHierarchy()
00147 {
00148     Int         i, n = 0, lightElems;
00149     Cluster     *lastChild = 0, *curChild;  
00150 
00151     E = vl_0;
00152     clusterArea = 0.0;
00153     maxRho = cBlack;
00154     clusterVol = BoxVol(min, max);
00155     flags.UnSet(hrMixed);
00156 
00157     if (elems.NumItems() >= kMinClusterElems && level < kMaxClusterLevels)
00158     {
00159         PushElems();
00160 
00161         for (i = 0; i < 8; i++) 
00162             if (child[i]) 
00163             {   
00164                 
00165                 curChild = child[i];
00166 
00167                 child[i]->CreateBounds();
00168                 if (sqrlen(child[i]->max - child[i]->min) < 1e-15)
00169                     cerr << "WARNING: zero-volume cluster" << endl;
00170                 child[i]->level = level + 1;
00171 #ifdef RAD_VIS
00172                 child[i]->eltParent = this;
00173 #endif
00174                 child[i] = child[i]->CreateHierarchy();
00175                 if (child[i] != curChild)
00176                     delete curChild;
00177 
00178                 if (child[i])
00179                 {
00180                     E += child[i]->E * child[i]->clusterArea; // sum power
00181                     clusterArea += child[i]->clusterArea;
00182                     FindMaxCmpts(child[i]->EltRho(), maxRho, maxRho);
00183                     flags.Set(child[i]->flags & hrMixed);
00184                     lastChild = child[i];
00185                     n++;
00186                 }
00187             }
00188     }
00189     
00190     // if there are no elements at this level, and we only have one child,
00191     // we can replace this node with its child.
00192     if (elems.NumItems() == 0 && n <= 1)
00193     {
00194         DBG_COUT << "REDACTING: cluster node with one child cluster" << endl;
00195         return(lastChild);
00196     }
00197 
00198     // Add in emitted power of child elements at this level
00199     
00200     lightElems = 0;
00201     for (i = 0; i < elems.NumItems(); i++)
00202     {
00203         if (len(elems[i]->EltE()) > 0.0)
00204         {
00205             E += elems[i]->EltE() * elems[i]->EltArea();
00206             // NOTE -- E currently unused. Should only be needed at
00207             // leaves.
00208             lightElems++;
00209         }
00210         clusterArea += elems[i]->EltArea();
00211         FindMaxCmpts(elems[i]->EltRho(), maxRho, maxRho);
00212 #ifdef RAD_VIS
00213         elems[i]->eltParent = this; 
00214 #endif
00215     }
00216 
00217     if (clusterArea < 1e-15)
00218     {
00219         cerr << "REDACTING: cluster with zero surface area" << endl;
00220         return(0);
00221     }
00222     
00223     if (lightElems > 0)
00224         flags.Set(hrHasLights);
00225     if (lightElems < elems.NumItems())
00226         flags.Set(hrHasNonLights);
00227     
00228     // divide by area to give equivalent point src...
00229     if (clusterArea > 0.0)
00230         E /= clusterArea;
00231     else
00232         E = vl_0;
00233 
00234     DBG_COUT << "--- Cluster at level " << level << " has E = " << 
00235         E << ", " << elems.NumItems() << " elems, " <<
00236         n << " sub-clusters." << endl;
00237 
00238     return(this);
00239 }
00240 
00241 Void Cluster::Print(ostream &s)
00242 {
00243     HRLinkIter i;
00244     
00245     s << "level " << level << " cluster: " << endl;
00246     s << elems.NumItems() << " patch children" << endl;
00247     s << "E = " << E << " B = " << B << endl;
00248     s << "links: ";
00249     for (i.Begin(links); !i.AtEnd(); i.Inc())
00250         s << i.Data();
00251         
00252     s << endl;
00253 }
00254 
00255 Void Cluster::DrawNodeElem(Renderer &r)
00256 {
00257     Int     i;
00258 
00259     DrawLeafElem(r);
00260     for (i = 0; i < 8; i++)
00261         if (child[i])
00262             child[i]->DrawElem(r);
00263 }
00264 
00265 Void Cluster::DrawLeafElem(Renderer &r)
00266 {
00267 #ifdef RAD_VIS
00268     if (eltHighlight != 0)
00269     {
00270         if (eltHighlight == 1)
00271             r.C(Colour4(cRed, 0.3));
00272         else if (eltHighlight == 2)
00273             r.C(Colour4(cYellow, 0.3));
00274         else if (eltHighlight == 3)
00275             r.C(Colour4(cGreen, 0.3));
00276         PaintBox(r, min, max);
00277 
00278         r.C(HSVCol(hsvYellow + level * 60, 1, 1));
00279         FrameBox(r, min, max);
00280     }
00281     else if (gRadControl->outlineClusters)
00282     {
00283         r.C(HSVCol(hsvYellow + level * 60, 1, 1));
00284         FrameBox(r, min, max);
00285         
00286         DrawPatches(r);
00287     }
00288 #endif
00289 }
00290 
00291 Void Cluster::DrawPatches(Renderer &r)
00292 {
00293     Int i;
00294 
00295     for (i = 0; i < elems.NumItems(); i++)
00296         elems[i]->DrawLeafElem(r);
00297 
00298     for (i = 0; i < 8; i++)
00299         if (child[i])
00300             child[i]->DrawPatches(r);
00301 }
00302 
00303 // --- Radiosity transfer -----------------------------------------------------
00304 
00305 Colour Cluster::lastB;
00306 
00307 Void Cluster::Add()
00308 {
00309     DBG_COUT << "Cluster add: " << B;
00310     B += R;
00311     DBG_COUT << " -> " << B << endl;
00312 }
00313 
00314 Void Cluster::Push()
00315 {
00316     Int i;
00317     
00318     for (i = 0; i < 8; i++)
00319         if (child[i])
00320             child[i]->B = B;
00321 
00322 #ifdef RAD_NON_ISO_DEST
00323     for (i = 0; i < elems.NumItems(); i++)
00324         elems[i]->ClearB();
00325 #else
00326     for (i = 0; i < elems.NumItems(); i++)
00327         elems[i]->B_Coeffs()[0] = B;
00328 #endif
00329 }
00330 
00331 Void Cluster::Pull()
00332 {
00333     Int     i;
00334     
00335     B = vl_0;
00336     for (i = 0; i < 8; i++)
00337         if (child[i])
00338             B += child[i]->EltBA();
00339 
00340     Assert(vl_is_finite(sqrlen(B)), "bad cluster power");
00341 
00342     for (i = 0; i < elems.NumItems(); i++)
00343     {
00344         HRElem *fuckYouGDB = elems[i];
00345         B += elems[i]->EltBA();
00346         Assert(vl_is_finite(sqrlen(B)), "bad cluster power");
00347     }
00348     
00349     Assert(vl_is_finite(sqrlen(B)), "bad cluster power");
00350 
00351     Expect(vl_is_finite(clusterArea) && (clusterArea > 0), "trivial cluster");
00352     if (clusterArea > 0.0)
00353         B /= clusterArea;
00354 
00355     Assert(vl_is_finite(sqrlen(B)), "bad cluster B");
00356 }
00357 
00358 Void Cluster::ClearB()
00359 {
00360     lastB = B;
00361     B = vl_0;
00362 }
00363 
00364 Void Cluster::CalcLeafRadiosity()
00365 {
00366     _Error("Cluster can't be a leaf");
00367     // this might change when/if we handle volume-based radiosity
00368 }
00369 
00370 Void Cluster::InitRad()
00371 {
00372     Int     i;
00373     
00374     for (i = 0; i < elems.NumItems(); i++)
00375         elems[i]->InitRad();
00376         
00377     for (i = 0; i < 8; i++)
00378         if (child[i])
00379             child[i]->InitRad();
00380 
00381     Pull(); 
00382 }
00383 
00384 GCLReal Cluster::Error()
00385 {
00386     return(dot(kRadRGBToLum, B - lastB));
00387 }
00388 
00389 Void Cluster::ClearR()
00390 {
00391     R = vl_0;
00392 }
00393 
00394 // --- Link handling ----------------------------------------------------------
00395 
00396 
00397 Void Cluster::MakeChildLinks(HRElem *other, HRLink *link,
00398                              Int which, Int levels)
00399 // Splits a link into sublinks that point to the children of
00400 // either 'from' or 'to'.
00401 {
00402     Int i;
00403 
00404     if (which == kSubTo)
00405     {
00406         // add to cluster children
00407         for (i = 0; i < 8; i++)
00408             if (child[i])
00409                 child[i]->RefineLink(
00410                     link->CreateSubLink(other, child[i]),
00411                 levels);
00412         // add to patch children
00413         for (i = 0; i < elems.NumItems(); i++)
00414             elems[i]->RefineLink(
00415                 link->CreateSubLink(other, elems[i]),
00416             levels);                
00417     }
00418     else if (which == kSubFrom)
00419     {
00420         // add links to cluster children
00421         for (i = 0; i < 8; i++)
00422             if (child[i])
00423                 other->RefineLink(
00424                     link->CreateSubLink(child[i], other),
00425                     levels);
00426 
00427         // add to patch children
00428         for (i = 0; i < elems.NumItems(); i++)
00429             other->RefineLink(
00430                 link->CreateSubLink(elems[i], other),
00431                 levels);
00432     }
00433     else if (which == kSubBoth)
00434     {
00435         for (i = 0; i < 8; i++)
00436             if (child[i])
00437                 other->MakeChildLinks(child[i], link, kSubFrom, levels);
00438         for (i = 0; i < elems.NumItems(); i++)
00439                 other->MakeChildLinks(elems[i], link, kSubFrom, levels);
00440     }
00441     else
00442         _Error("split type not implemented");
00443 }
00444 
00445 
00446 // --- children abstraction ---------------------------------------------------
00447 
00448 
00449 Bool Cluster::IsLeaf()
00450 {
00451     return(false);
00452 }
00453 
00454 Void Cluster::ApplyToChildren(Void (HRElem::*method)(Void*), Void *ref)
00455 {
00456     Int i;
00457 
00458     for (i = 0; i < 8; i++)
00459         if (child[i])
00460             (child[i]->*method)(ref);
00461 
00462     for (i = 0; i < elems.NumItems(); i++)
00463         (elems[i]->*method)(ref);
00464 }
00465 
00466 
00467 // --- transport calculations -------------------------------------------------
00468 
00469 
00470 Void Cluster::EltSampleTransport(
00471                     Int         numSamples, 
00472                     Point       p[], 
00473                     Vector      n[],
00474                     Matd        &coeffs
00475                 )
00476 {
00477     Int     i;
00478     GCLReal result, rLen;
00479     Vector  r;
00480 #ifdef RAD_NON_ISO_SOURCE
00481     Vector  dir = vl_0;
00482 #endif
00483 
00484     for (i = 0; i < numSamples; i++)
00485     {
00486         r = centre;
00487         r -= p[i];
00488 
00489         rLen = len(r);
00490         if (rLen > 0.0)
00491             r /= rLen;
00492         result = dot(n[i], r);
00493 
00494         if (result <= 0.0)
00495         {
00496             coeffs[i][0] = 0.0;
00497             continue;
00498         }
00499 
00500         result /= (sqr(rLen) * vl_pi);
00501 #ifdef RAD_NON_ISO_SOURCE
00502         // use the sample to weight our average direction normal...
00503         dir += r;
00504 #endif
00505 
00506         coeffs[i][0] = result;
00507         Assert(vl_is_finite(coeffs[i][0]), "TS: bad transport coeff!!!");
00508     }
00509 
00510 #ifdef RAD_NON_ISO_SOURCE
00511     // now that we have an average direction normal, multiply
00512     // in projected area.
00513     rLen = len(dir);
00514     if (rLen > 0.0)
00515         result = EltProjArea(-dir) / rLen;
00516     else
00517         result = 0.0;
00518 
00519     coeffs *= result;
00520 #else
00521     // if we're doing isotropic, the equivalent projected area
00522     // is the total projected area over 4. (We're assuming a sphere,
00523     // basically.)
00524     coeffs *= clusterArea / 4.0;
00525 #endif
00526 
00527     DBG_COUT << "ClusEST: sampled coeffs = " << coeffs << endl;
00528 }
00529 
00530 const Int kNumCubeSamples = 16;
00531 
00532 static Int gRotPick = 0;
00533 
00534 Void Cluster::EltGetSamples(Int numSamples, Point p[])
00535 {
00536     Vector      d, *offsets = (Vector*) tCubeSamples;
00537     Int         i;
00538     
00539     d = max - min;
00540 
00541     for (i = 0; i < numSamples; i++)
00542         p[i] = min + offsets[i] * d;
00543 }
00544 
00545 GCLReal Cluster::EltCalcTransport(HRElem *from, Matd &coeffs)
00546 {
00547     Vector      r;
00548     GCLReal     rLen, error;
00549 
00550     if (from == this)
00551     {
00552         coeffs[0][0] = 1.0;
00553         error = 1.0;
00554     }
00555     else
00556     {
00557         r = from->EltCentre();
00558         r -= centre;
00559         rLen = len(r);
00560         if (rLen > 0.0)
00561             r /= rLen;
00562             
00563 #ifndef RAD_NON_ISO_DEST
00564         // Assume isotropic, and thus one quarter of total surface
00565         // area facing the source.
00566         r *= 0.25;
00567 #endif
00568 
00569 #ifndef RAD_SAMPLE_ERROR
00570         from->EltSampleTransport(1, &centre, &r, coeffs);
00571         error = coeffs[0][0];
00572 #else
00573         Point       p[kNumCubeSamples];
00574         Vector      n[kNumCubeSamples];
00575         static Matd trans;
00576         Int         i, samples;
00577 
00578         EltGetSamples(kNumCubeSamples, p);
00579         for (i = 0; i < kNumCubeSamples; i++)
00580             n[i] = r;
00581 
00582         samples = kNumCubeSamples;
00583         trans.SetSize(samples, from->NumCoeffs());
00584 
00585         // sample transport factors to our set of sample points
00586         from->EltSampleTransport(samples, p, n, trans);
00587 
00588         error = VecError(col(trans, 0));
00589         DBG_COUT << "cluster sample error: " << error << endl;
00590 
00591         coeffs[0] = trans[0];
00592         for (i = 1; i < trans.Rows(); i++)
00593             coeffs[0] += trans[i];
00594         coeffs[0] /= trans.Rows();
00595         Assert(vl_is_finite(coeffs[0][0]), "TC: bad transport coeff!!!");
00596 #endif
00597     }
00598 
00599     DBG_COUT << "ClusECT: coeffs = " << coeffs << endl;
00600 
00601     return(error);
00602 }
00603 
00604 // --- visibility estimation --------------------------------------------------
00605 
00606 
00607 Void Cluster::EltSetVisPoints(HRElem *to, Point *pts)
00608 {
00609     Int         i;
00610     Point       dstPoint[16];
00611     Vector      d, r;
00612     Vector      *samples;
00613 
00614     EltGetSamples(16, pts);
00615     
00616 #ifdef RAD_PTB
00617     // proj samples to sides of volume facing the source/dest
00618     if (to && to != this)
00619     {
00620         r = to->EltCentre() - centre;
00621         for (i = 0; i < 16; i++)
00622             pts[i] += ProjectToBox(min, max, pts[i], r) * r;
00623     }       
00624 #endif
00625 
00626     if (gRadControl->jitterRot)
00627         if (++gRotPick == kNumSampArrays)
00628             gRotPick = 0;
00629 }
00630 
00631 Void Cluster::AddIrradiance(const Colour &srcR, const Vector &r)
00632 {
00633     Int     i;
00634     
00635     for (i = 0; i < elems.NumItems(); i++)
00636         elems[i]->AddIrradiance(srcR, r);
00637 
00638     for (i = 0; i < 8; i++)
00639         if (child[i])
00640             child[i]->AddIrradiance(srcR, r);
00641 }
00642 
00643 Colour Cluster::GetPower(const Vector &m)
00644 {
00645     return(B * EltProjArea(m));
00646 }
00647 
00648 GCLReal Cluster::EltProjArea(const Vector &n)
00650 {
00651 #ifdef RAD_NON_ISO_DEST
00652     Int         i;
00653     GCLReal     eltArea = 0.0;
00654 
00655     for (i = 0; i < elems.NumItems(); i++)
00656     {
00657         eltArea += elems[i]->EltProjArea(n);
00658         Assert(vl_is_finite(eltArea), "FPA: proj area is NAN");
00659     }
00660 
00661     for (i = 0; i < 8; i++)
00662     {
00663         if (child[i])
00664             eltArea += child[i]->EltProjArea(n);
00665 
00666         Assert(vl_is_finite(eltArea), "FPA: proj area is NAN");
00667     }
00668 
00669 #ifdef DEBUG
00670     if (elems.NumItems() > 0 && elems[0]->IsFaceClus())
00671     {
00672         DBG_COUT << "min eltArea " << n << " = " << eltArea << endl;
00673     }
00674 #endif
00675 
00676     return(eltArea);
00677 #else
00678     return(0.25 * clusterArea)
00679 #endif
00680 }
00681 
00682 GCLReal Cluster::EltMaxProjArea(const Vector &n)
00684 {
00685     Int         i;
00686     GCLReal     eltArea = 0.0;
00687 
00688     for (i = 0; i < elems.NumItems(); i++)
00689     {
00690         eltArea += elems[i]->EltMaxProjArea(n);
00691         Assert(vl_is_finite(eltArea), "FPA: proj area is NAN");
00692     }
00693 
00694     for (i = 0; i < 8; i++)
00695     {
00696         if (child[i])
00697             eltArea += child[i]->EltMaxProjArea(n);
00698 
00699         Assert(vl_is_finite(eltArea), "FPA: proj area is NAN");
00700     }
00701 
00702 #ifdef DEBUG
00703     if (elems.NumItems() > 0 && elems[0]->IsFaceClus())
00704     {
00705         DBG_COUT << "max eltArea " << n << " = " << eltArea << endl;
00706         DBG_COUT << "rho = " << EltRho() << endl;
00707     }
00708 #endif
00709 
00710     return(eltArea);
00711 }
00712 
00713 Void Cluster::DistributeColours()
00714 {
00715     Int     i;
00716 
00717     for (i = 0; i < elems.NumItems(); i++)
00718         elems[i]->DistributeColours();
00719 
00720     for (i = 0; i < 8; i++)
00721         if (child[i])
00722             child[i]->DistributeColours();
00723 }
00724 
00725 Void Cluster::DistributeColoursBest(ShadeInfo &shadeInfo)
00726 {
00727     Int     i;
00728 
00729     if (!links.IsEmpty())
00730         shadeInfo.linkStack.Push(&links);
00731 
00732     for (i = 0; i < elems.NumItems(); i++)
00733         elems[i]->DistributeColoursBest(shadeInfo);
00734 
00735     for (i = 0; i < 8; i++)
00736         if (child[i])
00737             child[i]->DistributeColoursBest(shadeInfo);
00738 
00739     if (!links.IsEmpty())
00740         shadeInfo.linkStack.Pop();
00741 }

Generated at Sat Aug 5 00:26:50 2000 for Radiator by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000