www.pudn.com > Samples-latest.zip > ReconstructSH.h
// TReconstructSH: Spherical Function to reconstruct an sh-compressed function // - created for illustration #ifndef _INCLUDE_RECONSTRUCTSH_H_ #define _INCLUDE_RECONSTRUCTSH_H_ templatestruct TReconstructSH : public ZFXMath::SphericalHarmonics::TSphericalFunction { typedef ZFXMath::SphericalHarmonics::TSample Sample; TReconstructSH() {} // Construct from SH coefficients TReconstructSH(const ZFXMath::SphericalHarmonics::TCoeffs & coeffs) : m_Coeffs(coeffs) { } FuncValueType EvalFunction(const Sample& s) const { int nb_bands = m_Coeffs.GetNbBands(); // Calculate a coeff-weighted sum of all the SH bases FuncValueType value = FuncValueType(0.0); for (int l = 0, i = 0; l < nb_bands; l++) for (int m = -l; m <= l; m++, i++) value += m_Coeffs(i) * FuncValueType( ZFXMath::SphericalHarmonics::y (l, m, s.theta, s.phi) ); return (value); } // Copy of the SH list ZFXMath::SphericalHarmonics::TCoeffs m_Coeffs; // Map from spherical co-ordinates onto the sphere using the unsigned sample as the radius D3DXVECTOR3 ToVector(const Sample& s) const { PrecisionType r = (PrecisionType)fabs( double( EvalFunction(s) ) ); return D3DXVECTOR3( (float)(r * s.x), (float)(r * s.y), float(r * s.z) ); } // Helper for constructing sample type D3DXVECTOR3 ToVector(const PrecisionType u, const PrecisionType v) const { return ToVector( Sample(u, v) ); } // draw method void Reconstruct( float* pBuffer, int numSamples, bool toSphere ) const { // Steps along the sphere PrecisionType du = PrecisionType( ZFXMath::PI / numSamples ); PrecisionType dv = PrecisionType( 2 * ZFXMath::PI / numSamples ); PrecisionType ddu = du / 10; PrecisionType ddv = dv / 10; PrecisionType u = 0; for ( int l = 0; l < numSamples; l++ ) { PrecisionType v = 0; for ( int k = 0; k < numSamples; k++ ) { // Sample 4 points in the neighbourhood D3DXVECTOR3 p[4]; D3DXVECTOR3 n[4]; FuncValueType c[4]; if ( toSphere ) { Sample s = Sample(u, v); p[0] = D3DXVECTOR3( (float)s.x, (float)s.y, (float)s.z ); s = Sample(u + du, v); p[1] = D3DXVECTOR3( (float)s.x, (float)s.y, (float)s.z ); s = Sample(u + du, v + dv); p[2] = D3DXVECTOR3( (float)s.x, (float)s.y, (float)s.z ); s = Sample(u, v + dv); p[3] = D3DXVECTOR3( (float)s.x, (float)s.y, (float)s.z ); n[0] = p[0]; n[1] = p[1]; n[2] = p[2]; n[3] = p[3]; c[0] = EvalFunction(Sample(u, v)); c[1] = EvalFunction(Sample(u + du, v)); c[2] = EvalFunction(Sample(u + du, v + dv)); c[3] = EvalFunction(Sample(u, v + dv)); } else { p[0] = ToVector(u, v); p[1] = ToVector(u + du, v); p[2] = ToVector(u + du, v + dv); p[3] = ToVector(u, v + dv); // Sample the normals as even smaller patches in the neighbourhood n[0] = CalculateNormal(p[0], ToVector(u + ddu, v), ToVector(u, v + ddv)); n[1] = CalculateNormal(p[1], ToVector(u + du + ddu, v), ToVector(u + du, v + ddv)); n[2] = CalculateNormal(p[2], ToVector(u + du + ddu, v + dv), ToVector(u + du, v + dv + ddv)); n[3] = CalculateNormal(p[3], ToVector(u + ddu, v + dv), ToVector(u, v + dv + ddv)); // Positive SH samples are green, negative are red c[0] = (EvalFunction(Sample(u, v)) > 0) ? 1.0f : -1.0f; c[1] = (EvalFunction(Sample(u + du, v)) > 0) ? 1.0f : -1.0f; c[2] = (EvalFunction(Sample(u + du, v + dv)) > 0) ? 1.0f : -1.0f; c[3] = (EvalFunction(Sample(u, v + dv)) > 0) ? 1.0f : -1.0f; } // put this quad into the buffer AddVertex( pBuffer, p[0], n[0], c[0] ); pBuffer += 6 + sizeof(FuncValueType)/4; AddVertex( pBuffer, p[1], n[1], c[1] ); pBuffer += 6 + sizeof(FuncValueType)/4; AddVertex( pBuffer, p[2], n[2], c[2] ); pBuffer += 6 + sizeof(FuncValueType)/4; AddVertex( pBuffer, p[0], n[0], c[0] ); pBuffer += 6 + sizeof(FuncValueType)/4; AddVertex( pBuffer, p[2], n[2], c[2] ); pBuffer += 6 + sizeof(FuncValueType)/4; AddVertex( pBuffer, p[3], n[3], c[3] ); pBuffer += 6 + sizeof(FuncValueType)/4; v += dv; } u += du; } } protected: static void AddVertex( float* pBuffer, D3DXVECTOR3 pos, D3DXVECTOR3 normal, FuncValueType funcValue ) { pBuffer[0] = pos.x; pBuffer[1] = pos.y; pBuffer[2] = pos.z; pBuffer[3] = normal.x; pBuffer[4] = normal.y; pBuffer[5] = normal.z; pBuffer += 6; *(FuncValueType*)pBuffer = funcValue; } static D3DXVECTOR3 CalculateNormal(const D3DXVECTOR3& a, const D3DXVECTOR3& b, const D3DXVECTOR3&c ) { // Get edges D3DXVECTOR3 e0 = b - a; D3DXVECTOR3 e1 = c - a; // Get perpendicular D3DXVECTOR3 out; D3DXVec3Cross( &out, &e0, &e1 ); D3DXVec3Normalize( &out, &out ); return out; } }; #endif //_INCLUDE_RECONSTRUCTSH_H_