Hauptseite | Liste aller Namensbereiche | Klassenhierarchie | Auflistung der Klassen | Auflistung der Dateien | Elemente eines Namensbereiches | Klassen-Elemente | Datei-Elemente

SphericalHarmonics.h

gehe zur Dokumentation dieser Datei
00001 00002 00003 00004 00005 00006 00007 00008 00009 #ifndef _ZFXMATH_INCLUDE_SH_H_ 00010 #define _ZFXMATH_INCLUDE_SH_H_ 00011 00012 namespace ZFXMath 00013 { 00014 00029 namespace SphericalHarmonics 00030 { 00031 00037 template<class PrecisionType> 00038 struct TSample 00039 { 00040 // Default constructor 00041 TSample() { }; 00042 00043 // Construct from spherical co-ordinates 00044 TSample( const PrecisionType u, const PrecisionType v ) : 00045 theta(u), 00046 phi(v) 00047 { 00048 x = PrecisionType( sin(theta) * cos(phi) ); 00049 y = PrecisionType( sin(theta) * sin(phi) ); 00050 z = PrecisionType( cos(theta) ); 00051 } 00052 00054 PrecisionType theta, phi; 00055 00057 PrecisionType x, y, z; 00058 }; 00059 00069 template<class PrecisionType, class FuncValueType> 00070 struct TSphericalFunction 00071 { 00077 virtual FuncValueType EvalFunction(const TSample<PrecisionType>& s) const = 0; 00078 }; 00079 00089 template<class T> 00090 class TCoeffs 00091 { 00092 public: 00098 template<class TAlloc> 00099 class TAllocator 00100 { 00101 public: 00102 TAllocator( int size ) 00103 { 00104 m_Size = size; 00105 m_pMemory = new TAlloc[size]; 00106 m_pNextMem = m_pMemory; 00107 } 00108 00109 ~TAllocator() 00110 { 00111 delete[] m_pMemory; 00112 } 00113 00114 TAlloc* GetMem( int amount ) 00115 { 00116 m_Size -= amount; 00117 assert( m_Size >= 0 ); 00118 00119 TAlloc* pMem = m_pNextMem; 00120 m_pNextMem += amount; 00121 00122 return pMem; 00123 } 00124 00125 private: 00126 TAlloc* m_pMemory; 00127 TAlloc* m_pNextMem; 00128 int m_Size; 00129 }; 00130 typedef TAllocator<T> Allocator; 00131 00132 TCoeffs() : m_Coeffs(0), m_NbBands(0), m_NbCoeffs(0) { } 00133 00134 TCoeffs(const int nb_bands) : 00135 m_Coeffs(0), 00136 m_NbBands(nb_bands), 00137 m_NbCoeffs(m_NbBands * m_NbBands), 00138 m_FromAllocator(false) 00139 { 00140 // Allocate the coeff list 00141 m_Coeffs = new T[m_NbCoeffs]; 00142 } 00143 00144 TCoeffs(const int nb_bands, Allocator* pAlloc) : 00145 m_Coeffs(0), 00146 m_NbCoeffs(nb_bands * nb_bands), 00147 m_FromAllocator(true) 00148 { 00149 // Allocate the coeff list 00150 m_Coeffs = pAlloc->GetMem( m_NbCoeffs ); 00151 } 00152 00153 ~TCoeffs() 00154 { 00155 // Stack allocator cleans itself up 00156 if (!m_FromAllocator) 00157 delete [] m_Coeffs; 00158 } 00159 00160 TCoeffs(const TCoeffs& other) : 00161 m_Coeffs(0), 00162 m_NbBands(other.m_NbBands), 00163 m_NbCoeffs(other.m_NbCoeffs), 00164 m_FromAllocator(other.m_FromAllocator) 00165 { 00166 // Just copy the pointer in this case 00167 if (m_FromAllocator) 00168 m_Coeffs = other.m_Coeffs; 00169 00170 else 00171 { 00172 // Make a copy when not using the stack allocator 00173 m_Coeffs = new T[m_NbCoeffs]; 00174 for (int i = 0; i < m_NbCoeffs; i++) 00175 m_Coeffs[i] = other.m_Coeffs[i]; 00176 } 00177 } 00178 00179 // Const/non-const accessors for band/arg 00180 T operator () (const int l, const int m) const 00181 { 00182 return (m_Coeffs[Check(l * (l + 1) + m)]); 00183 } 00184 T& operator () (const int l, const int m) 00185 { 00186 return (m_Coeffs[Check(l * (l + 1) + m)]); 00187 } 00188 00189 // Const/non-const accessors by index 00190 T operator () (const int i) const 00191 { 00192 return (m_Coeffs[Check(i)]); 00193 } 00194 T& operator () (const int i) 00195 { 00196 return (m_Coeffs[Check(i)]); 00197 } 00198 00199 int GetNbBands(void) const 00200 { 00201 return (m_NbBands); 00202 } 00203 00204 int GetSize(void) const 00205 { 00206 return (m_NbCoeffs); 00207 } 00208 00209 private: 00210 inline int Check(const int index) const 00211 { 00212 // Check bounds in debug build 00213 assert(index >= 0 && index < m_NbCoeffs); 00214 00215 return (index); 00216 } 00217 00218 // List of SH coefficients 00219 T* m_Coeffs; 00220 00221 // Number of bands used 00222 int m_NbBands; 00223 00224 // Number of coefficients (=bands^2) 00225 int m_NbCoeffs; 00226 00227 // Allocated from a special-purpose allocator? 00228 bool m_FromAllocator; 00229 00230 }; 00231 00232 00236 // http://www.research.scea.com/gdc2003/spherical-harmonic-lighting.html 00237 // Project a spherical function onto the spherical harmonic bases 00238 // 00239 // a. Spherical Function to project 00240 // b. List of sample locations on the sphere 00241 // c. List of y(l,m,theta,phi) for each sample 00242 // d. Number of samples on the sphere 00243 // e. Destination projection 00245 template<class PrecisionType, class FuncValueType> 00246 void Project(const TSphericalFunction<PrecisionType,FuncValueType>& func, 00247 const TSample<PrecisionType>* samples, 00248 const TCoeffs<PrecisionType>* coeffs, 00249 const int nb_samples, 00250 TCoeffs<FuncValueType>& dest ) 00251 { 00252 int nb_coeffs = dest.GetSize(); 00253 00254 // Check input 00255 assert(samples && coeffs); 00256 assert(nb_samples >= 0); 00257 assert(coeffs[0].GetSize() == nb_coeffs); 00258 00259 // Clear out sums 00260 for (int i = 0; i < nb_coeffs; i++) 00261 dest(i) = 0; 00262 00263 for (int i = 0; i < nb_samples; i++) 00264 { 00265 // Take the sample at this point on the sphere 00266 const TSample<PrecisionType>& s = samples[i]; 00267 const TCoeffs<PrecisionType>& c = coeffs[i]; 00268 FuncValueType sample = func.EvalFunction(s); 00269 00270 // Sum the projection of this sample onto each SH basis 00271 for (int j = 0; j < nb_coeffs; j++) 00272 dest(j) += sample * FuncValueType( c(j) ); 00273 } 00274 00275 // Divide each coefficient by the number of samples and multiply by weights 00276 for (int i = 0; i < nb_coeffs; i++) 00277 dest(i) = dest(i) * FuncValueType( PrecisionType( (4 * PI) / nb_samples ) ); 00278 } 00279 00280 //--------------------------------------------------------------------------------------- 00281 // Evaluate Associated Legendre Polynomial 00282 template<class PrecisionType> 00283 PrecisionType P(const int l, const int m, const PrecisionType x) 00284 { 00285 // Start with P(0,0) at 1 00286 PrecisionType pmm = 1; 00287 00288 // First calculate P(m,m) since that is the only rule that requires results 00289 // from previous bands 00290 // No need to check for m>0 since SH function always gives positive m 00291 00292 // Precalculate (1 - x^2)^0.5 00293 PrecisionType somx2 = (PrecisionType)sqrt(1 - x * x); 00294 00295 // This calculates P(m,m). There are three terms in rule 2 that are being iteratively multiplied: 00296 // 00297 // 0: -1^m 00298 // 1: (2m-1)!! 00299 // 2: (1-x^2)^(m/2) 00300 // 00301 // Term 2 has been partly precalculated and the iterative multiplication by itself m times 00302 // completes the term. 00303 // The result of 2m-1 is always odd so the double factorial calculation multiplies every odd 00304 // number below 2m-1 together. So, term 3 is calculated using the 'fact' variable. 00305 PrecisionType fact = 1; 00306 for (int i = 1; i <= m; i++) 00307 { 00308 pmm *= -1 * fact * somx2; 00309 fact += 2; 00310 } 00311 00312 // No need to go any further, rule 2 is satisfied 00313 if (l == m) 00314 return (pmm); 00315 00316 // Since m<l in all remaining cases, all that is left is to raise the band until the required 00317 // l is found 00318 00319 // Rule 3, use result of P(m,m) to calculate P(m,m+1) 00320 PrecisionType pmmp1 = x * (2 * m + 1) * pmm; 00321 00322 // Is rule 3 satisfied? 00323 if (l == m + 1) 00324 return (pmmp1); 00325 00326 // Finally, use rule 1 to calculate any remaining cases 00327 PrecisionType pll = 0; 00328 for (int ll = m + 2; ll <= l; ll++) 00329 { 00330 // Use result of two previous bands 00331 pll = PrecisionType( (x * (2.0f * ll - 1.0f) * pmmp1 - (ll + m - 1.0f) * pmm) / (ll - m) ); 00332 00333 // Shift the previous two bands up 00334 pmm = pmmp1; 00335 pmmp1 = pll; 00336 } 00337 00338 return (pll); 00339 } 00340 00341 // Evaluate Real Spherical Harmonic 00342 template<class PrecisionType> 00343 PrecisionType y(const int l, const int m, const PrecisionType theta, const PrecisionType phi) 00344 { 00345 if (0 == m) 00346 return (PrecisionType(K<PrecisionType>(l, 0) * P(l, 0, (PrecisionType)cos(theta)))); 00347 00348 if (m > 0) 00349 return PrecisionType(sqrt(2.0) * K<PrecisionType>(l, m) * cos(m * phi) * P(l, m, (PrecisionType)cos(theta))); 00350 00351 // m < 0, m is negated in call to K 00352 return PrecisionType(sqrt(2.0) * K<PrecisionType>(l, -m) * sin(-m * phi) * P(l, -m, (PrecisionType)cos(theta))); 00353 } 00354 00355 00356 // Re-normalisation constant for SH function 00357 template<class PrecisionType> 00358 PrecisionType K(const int l, const int m) 00359 { 00360 struct FactorialGen 00361 { 00362 FactorialGen(const int count) : 00363 factorials(0), 00364 nb_factorials(count) 00365 { 00366 factorials = new int[nb_factorials]; 00367 00368 // Build a factorial LUT 00369 factorials[0] = 1; 00370 for (int i = 1; i < nb_factorials; i++) 00371 factorials[i] = i * factorials[i - 1]; 00372 } 00373 00374 ~FactorialGen(void) 00375 { 00376 delete [] factorials; 00377 } 00378 00379 int operator () (const int i) const 00380 { 00381 // Check input for debug builds 00382 assert(i >= 0 && i < nb_factorials); 00383 return (factorials[i]); 00384 } 00385 00386 int* factorials; 00387 int nb_factorials; 00388 }; 00389 00390 // Generate lut the first time this function is called 00391 // Note that this method doesn't interact well with explicit init/shutdown memory managers 00392 // Additionally, 32-bits is not enough to store any higher bands (7 max) !!! 00393 static FactorialGen factorial(14); 00394 00395 // Note that |m| is not used here as the SH function always passes positive m 00396 return PrecisionType(sqrt(((2 * l + 1) * factorial(l - m)) / (4 * PI * factorial(l + m)))); 00397 } 00398 00399 00400 }; // namespace SphericalHarmonics 00401 00402 }; // namespace ZFXMath 00403 00404 #endif //_ZFXMATH_INCLUDE_SH_H_ 00405 00406

Erzeugt am Thu Nov 25 04:02:55 2004 für ZFX-Math Library von doxygen 1.3.8