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_

template
struct 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_