00001 /* 00002 File: Haar.cc 00003 00004 Function: Implementation of the Haar basis 00005 00006 Author: Andrew Willmott 00007 00008 Notes: 00009 */ 00010 00011 #include "Haar.h" 00012 #include "RadMethod.h" 00013 #include "gcl/Draw.h" 00014 00015 #define DBG_COUT if (0) cerr 00016 00017 #define RAD_SAMPLE_ERROR 00018 00019 // --- HaarLink methods ------------------------------------------------------- 00020 00021 00022 Bool HaarLink::CalcTransport() 00023 { 00024 if (gRadControl->quadLevel > 3) 00025 transport = From()->SampledFormFactor(8, To(), error); 00026 else 00027 { 00028 transport = From()->EstFormFactor(To()); 00029 error = transport; 00030 } 00031 00032 if (transport == 0.0 && error == 0.0) 00033 return(false); 00034 00035 return(true); 00036 } 00037 00038 Bool HaarLink::CalcVisibility(HRLink *parent, Bool reuse) 00039 { 00040 if (parent && (reuse || !NeedVisibility(parent))) 00041 visibility = parent->visibility; 00042 else 00043 visibility = From()->Visibility(To()); 00044 00045 transport *= visibility; 00046 00047 return(true); 00048 } 00049 00050 Void HaarLink::Gather() 00051 { 00052 To()->R += transport * From()->B; 00053 } 00054 00055 GCLReal HaarLink::Error() 00056 { 00057 return(error); 00058 } 00059 00060 GCLReal HaarLink::BFAError() 00061 { 00062 return(To()->area * error * 00063 dot(kRadRGBToLum, To()->Reflectance() * From()->B)); 00064 } 00065 00066 Void HaarLink::Print(ostream &s) 00067 { 00068 HRLink::Print(s); 00069 s << transport << ' ' << visibility << ' '; 00070 } 00071 00072 Void HaarLink::DrawLink(Renderer &r, GCLReal left, GCLReal top, 00073 GCLReal right, GCLReal bottom, GCLReal weight) 00074 { 00075 r.SetColour(To()->Reflectance() * transport * visibility * weight); 00076 00077 PaintRect(r, Coord(left, top), Coord(right, bottom)); 00078 } 00079 00080 00081 // --- HaarElem methods ------------------------------------------------------- 00082 00083 00084 Colour HaarElem::lastB; 00085 00086 Void HaarElem::Add() 00087 { 00088 B += R; 00089 } 00090 00091 Void HaarElem::Push() 00092 { 00093 Int i; 00094 00095 for (i = 0; i < 4; i++) 00096 Child(i)->B = B; 00097 } 00098 00099 Void HaarElem::Pull() 00100 { 00101 Int i; 00102 00103 B = vl_0; 00104 for (i = 0; i < 4; i++) 00105 B += Child(i)->B; 00106 B /= 4.0; 00107 } 00108 00109 Void HaarElem::ClearB() 00110 { 00111 // Save B for comparison to post push/pull B 00112 lastB = B; 00113 // Initialise B to emittance of this patch. 00114 B = vl_0; 00115 } 00116 00117 GCLReal HaarElem::Error() 00118 { 00119 return(dot(kRadRGBToLum, B - lastB)); 00120 } 00121 00122 Void HaarElem::ClearR() 00123 { 00124 R = vl_0; 00125 } 00126 00127 Void HaarElem::CalcLeafRadiosity() 00128 { 00129 B = Emittance() + Reflectance() * B; 00130 } 00131 00132 Void HaarElem::Print(ostream &s) 00133 { 00134 s << " + haar "; 00135 PrintRec(s); 00136 } 00137 00138 Void HaarElem::PrintSelf(ostream &s) 00139 { 00140 HRMeshElem::PrintSelf(s); 00141 s << B << ' '; 00142 } 00143 00144 Void HaarElem::ParseSelf(istream &s) 00145 { 00146 HRMeshElem::ParseSelf(s); 00147 s >> B; 00148 } 00149 00150 Void HaarElem::SetParent(HierElem &itsParent) 00151 { 00152 HierElem::SetParent(itsParent); 00153 00154 B = ((HaarElem &) itsParent).B; 00155 } 00156 00157 Colour HaarElem::SampleLeaf(Coord c) 00158 { 00159 00160 if (gRadControl->gouraud) 00161 { 00162 Colour c1, c2; 00163 00164 c1 = Mix(VtxClr(0), VtxClr(3), c[0]); 00165 c2 = Mix(VtxClr(1), VtxClr(2), c[0]); 00166 return(Mix(c2, c1, c[1])); 00167 } 00168 else 00169 return(B); 00170 } 00171 00172 Void HaarElem::EltSampleTransport( 00173 Int numSamples, 00174 Point p[], 00175 Vector n[], 00176 Matd &coeffs 00177 ) 00178 // find coeffs s.t. dot(from->B, coeffs) = irradiance 00179 // at p, n. 00180 { 00181 Int i; 00182 00183 for (i = 0; i < numSamples; i++) 00184 coeffs[i][0] = ApproxPatchFactor(p[i], n[i]); 00185 DBG_COUT << "haar: sample coeffs = " << coeffs << endl; 00186 } 00187 00188 GCLReal HaarElem::EltCalcTransport(HRElem *from, Matd &coeffs) 00189 { 00190 if (from == this) 00191 { 00192 // no self-reflection for haar... 00193 coeffs = vl_0; 00194 return(0.0); 00195 } 00196 00197 #ifndef RAD_SAMPLE_ERROR 00198 from->EltSampleTransport(1, ¢re, &normal, coeffs); 00199 DBG_COUT << "haar: transport coeffs = " << coeffs << endl; 00200 return(coeffs[0][0]); 00201 #else 00202 GCLReal error; 00203 Point p[16]; 00204 Vector n[16]; 00205 static Matd t; 00206 Int i, samples; 00207 00208 #ifdef RAD_SC 00209 // sample at 3 or 4 corners and centre. 00210 00211 for (i = 0; i < Sides(); i++) 00212 { 00213 p[i] = Vertex(i); 00214 n[i] = normal; 00215 } 00216 p[i] = centre; 00217 n[i] = normal; 00218 samples = i + 1; 00219 #else 00220 samples = 16; 00221 SetVisPoints(p); 00222 for (i = 0; i < 16; i++) 00223 n[i] = normal; 00224 #endif 00225 t.SetSize(samples, from->NumCoeffs()); 00226 00227 from->EltSampleTransport(samples, p, n, t); 00228 00229 // find (Linf) error in samples 00230 error = VecError(col(t, 0)); 00231 // average samples to get coeffs... 00232 coeffs[0] = t[0]; 00233 for (i = 1; i < t.Rows(); i++) 00234 coeffs[0] += t[i]; 00235 coeffs[0] /= t.Rows(); 00236 00237 return(error); 00238 #endif 00239 } 00240 00241 Void HaarElem::AddIrradiance(const Colour &E, const Vector &m) 00242 { 00243 GCLReal temp; 00244 00245 temp = dot(m, normal); 00246 if (temp > 0.0) 00247 R += temp * E; 00248 } 00249 00250 Colour HaarElem::GetPower(const Vector &m) 00251 { 00252 return(B * EltProjArea(m)); 00253 } 00254 00255 Void HaarElem::DistributeColours() 00256 { 00257 SetColour(B); 00258 00259 if (HasChildren()) 00260 { 00261 Child(0)->DistributeColours(); 00262 Child(1)->DistributeColours(); 00263 Child(2)->DistributeColours(); 00264 Child(3)->DistributeColours(); 00265 } 00266 } 00267 00268 Void HaarElem::DistributeColoursBest(ShadeInfo &shadeInfo) 00269 { 00270 if (gRadControl->bestLevels == 0) 00271 { 00272 // for now we return. eventually would like to resample at vertices 00273 // same as the clusters. (only perhaps avoiding duplicate samples.) 00274 DistributeColours(); 00275 return; 00276 } 00277 00278 // Here we apply the leaf element irradiances to the leaf face clusters 00279 00280 if (!links.IsEmpty()) 00281 shadeInfo.linkStack.Push(&links); 00282 00283 if (IsLeaf() && shadeInfo.level >= gRadControl->bestLevels) 00284 { 00285 Int i, nlinks = 0; 00286 HRLinkIter l; 00287 00288 Point centreOff, srcPt; 00289 Vector r; 00290 GCLReal dp, r2; 00291 Colour E; 00292 00293 // find face's normal, pos & area in WCS 00294 00295 centreOff = centre; 00296 centreOff += 1e-6 * normal; 00297 colour = cBlack; 00298 00299 // traverse all links, do final gather 00300 for (i = 0; i < shadeInfo.linkStack.NumItems(); i++) 00301 for (l.Begin(*shadeInfo.linkStack[i]); !l.AtEnd(); l.Inc()) 00302 { 00303 HRElem *src = l.Data().from; 00304 00305 nlinks++; 00306 srcPt = src->EltCentre(); 00307 r = srcPt - centre; 00308 dp = dot(r, normal); 00309 r2 = sqrlen(r); 00310 00311 if (dp > 0 && r2 > 0) 00312 { 00313 E = src->GetPower(-r); 00314 E *= dp / (sqr(r2) * vl_pi + src->EltArea()); 00315 00316 if (!gRadControl->bestVisPass) 00317 E *= l.Data().visibility; 00318 else 00319 { 00320 dp = l.Data().visibility; 00321 if (dp == 0.0) 00322 E = vl_0; 00323 else if (dp < 1.0) // dot(kRadRGBToLum, E) > 0.01 00324 { 00325 r /= sqrt(r2) * 1e6; 00326 srcPt -= r; 00327 if (gRadControl->radObject-> 00328 IntersectsWithRay(srcPt, centreOff)) 00329 E = vl_0; 00330 gRadControl->rays++; 00331 } 00332 else 00333 E *= dp; 00334 } 00335 colour += E * Reflectance(); 00336 } 00337 } 00338 00339 colour += Emittance(); 00340 } 00341 else 00342 { 00343 Bool amSubdividing = IsLeaf(); 00344 00345 if (amSubdividing) 00346 { 00347 shadeInfo.level++; 00348 00349 flags.Set(hrIntNode); 00350 if (!HasChildren()) 00351 Subdivide(); 00352 } 00353 00354 Child(0)->DistributeColoursBest(shadeInfo); 00355 Child(1)->DistributeColoursBest(shadeInfo); 00356 Child(2)->DistributeColoursBest(shadeInfo); 00357 Child(3)->DistributeColoursBest(shadeInfo); 00358 00359 if (amSubdividing) 00360 shadeInfo.level--; 00361 } 00362 00363 if (!links.IsEmpty()) 00364 shadeInfo.linkStack.Pop(); 00365 }