www.pudn.com > Samples-latest.zip > CubeMapFunction.h



// Evaluates a complex light environment by a given CubeMap
template
struct TCubeMapFunction : public ZFXMath::SphericalHarmonics::TSphericalFunction< PrecisionType, FuncValueType >
{
	typedef ZFXMath::SphericalHarmonics::TSample Sample;

	struct TLVertex
	{
		float x, y, z, rhw;
		DWORD color;			// for 32 Byte Stride
		float u, v, w;			// Lookup for Cube Map
	};

	TCubeMapFunction( LPDIRECT3DDEVICE9 pD3DDevice, int numSamples )
	{
		m_pD3DDevice = pD3DDevice;
		m_NumSamples = numSamples;

		m_FuncValue = new FuncValueType[m_NumSamples * m_NumSamples * 2];

		// Steps along the sphere
		PrecisionType du = PrecisionType( ZFXMath::PI / m_NumSamples );
		PrecisionType dv = PrecisionType( 2 * ZFXMath::PI / (m_NumSamples * 2) );

		m_Theta = 1 / du;
		m_Phi = 1 / dv;

		m_Vertex = new TLVertex[m_NumSamples * m_NumSamples * 2];

		// each pixel in the render target becomes a point
		// on a sphere to lookup the cubemap
		PrecisionType v = 0;
		for ( int m = 0; m < m_NumSamples * 2; m++ )
		{
			PrecisionType u = 0;
			for ( int n = 0; n < m_NumSamples; n++ )
			{
				// compute spherical coordinates (for texture lookup)
				Sample s( u, v );

				m_Vertex[ m * m_NumSamples + n ].x = float( n );
				m_Vertex[ m * m_NumSamples + n ].y = float( m );
				m_Vertex[ m * m_NumSamples + n ].z = 0.0f;
				m_Vertex[ m * m_NumSamples + n ].rhw = 1.0f;

				m_Vertex[ m * m_NumSamples + n ].color = 0; //n + (m << 16);

				m_Vertex[ m * m_NumSamples + n ].u = s.x;
				m_Vertex[ m * m_NumSamples + n ].v = s.y;
				m_Vertex[ m * m_NumSamples + n ].w = s.z;

				u += du;	
			}
			v += dv;
		}


		m_pD3DDevice->CreateRenderTarget( numSamples, numSamples * 2, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, true, &m_pSphericalRT, NULL );
		m_pD3DDevice->CreateOffscreenPlainSurface( numSamples, numSamples * 2, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &m_pSphericalSurface, NULL );
	}

	~TCubeMapFunction()
	{
		m_pSphericalRT->Release();
		m_pSphericalSurface->Release();
		

		// clean up
		delete[] m_Vertex;
		delete[] m_FuncValue;
	}


	void EvaluateCubeMap( LPDIRECT3DCUBETEXTURE9 pCubeMap )
	{
		LPDIRECT3DSURFACE9 pBackBuffer = NULL;
		LPDIRECT3DSURFACE9 pDepthStencil = NULL;

		m_pD3DDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
		m_pD3DDevice->GetDepthStencilSurface( &pDepthStencil );

		m_pD3DDevice->SetRenderTarget( 0, m_pSphericalRT );
		m_pD3DDevice->SetDepthStencilSurface( NULL );

		m_pD3DDevice->SetTexture( 0, pCubeMap );
		m_pD3DDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0) );

		m_pD3DDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
		m_pD3DDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); 
		m_pD3DDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );

		m_pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
		m_pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );

		m_pD3DDevice->BeginScene();

			//------------------------------
			// Rendering
			int primitiveCount = 65535;
			int primitiveIndex = 0;
			while ( m_NumSamples * m_NumSamples * 2 - primitiveIndex )
			{
				primitiveCount = ZFXMath::Min( ( m_NumSamples * m_NumSamples * 2 - primitiveIndex ), primitiveCount );

				m_pD3DDevice->DrawPrimitiveUP( D3DPT_POINTLIST, primitiveCount, &m_Vertex[primitiveIndex], 32 );

				primitiveIndex += primitiveCount;
			}
			//------------------------------

		m_pD3DDevice->EndScene();

		m_pD3DDevice->SetRenderTarget( 0, pBackBuffer );
		m_pD3DDevice->SetDepthStencilSurface( pDepthStencil );

		pBackBuffer->Release();
		pDepthStencil->Release();

		m_pD3DDevice->GetRenderTargetData( m_pSphericalRT, m_pSphericalSurface );		


		std::ostringstream oss;
		std::string str;
		oss << "C:/sphere" << timeGetTime() << ".bmp";
		str = oss.str();

		//D3DXSaveSurfaceToFile( str.c_str(), D3DXIFF_BMP, m_pSphericalSurface, NULL, NULL );

		// put the created spherical map into the phi-theta array
		D3DLOCKED_RECT LockedRect;
		m_pSphericalSurface->LockRect( &LockedRect, NULL, D3DLOCK_READONLY );

		const int SURFACE_BYTE_DEPTH = 4;

		ARGB* pColor = (ARGB*)LockedRect.pBits;
		for ( int m = 0; m < m_NumSamples * 2; m++ )
		{
			for ( int n = 0; n < m_NumSamples; n++ )
			{
				ARGB& Color = pColor[ ( LockedRect.Pitch / SURFACE_BYTE_DEPTH ) * m + n ];
				m_FuncValue[ m * m_NumSamples + n ] = FuncValueType( Color.R,
																	 Color.G,
																	 Color.B ) / 255.0f ;
			}
		}

		m_pSphericalSurface->UnlockRect();
	}
	

	FuncValueType EvalFunction(const ZFXMath::SphericalHarmonics::TSample& s) const
	{
		FuncValueType ret;

		// 00 10
		// 01 11

		PrecisionType u = PrecisionType( ZFXMath::Min( s.theta, PrecisionType(PI) ) * m_Theta );
		PrecisionType v = PrecisionType( ZFXMath::Min( s.phi, PrecisionType(2 * PI) ) * m_Phi );

		int pX0 = ZFXMath::Min( int( u ), m_NumSamples - 1 );
		int pY0 = ZFXMath::Min( int( v ), m_NumSamples * 2 - 1 );

		u -= pX0;
		v -= pY0;

		int pX1 = ZFXMath::Min( pX0 + 1, m_NumSamples - 1 );
		int pY1 = ZFXMath::Min( pY0 + 1, m_NumSamples * 2 - 1 );

		FuncValueType& p00 = m_FuncValue[ pY0 * m_NumSamples + pX0 ];
		FuncValueType& p10 = m_FuncValue[ pY0 * m_NumSamples + pX1 ];
		FuncValueType& p01 = m_FuncValue[ pY1 * m_NumSamples + pX0 ];
		FuncValueType& p11 = m_FuncValue[ pY1 * m_NumSamples + pX1 ];

		ret = ZFXMath::Interpolate( ZFXMath::Interpolate( p00, p10, u ),
									ZFXMath::Interpolate( p01, p11, u ), v );

		return ret;
	}

private:

	int						m_NumSamples;

	PrecisionType			m_Theta;
	PrecisionType			m_Phi;

	FuncValueType*			m_FuncValue;
	TLVertex*				m_Vertex;

	LPDIRECT3DDEVICE9		m_pD3DDevice;
	LPDIRECT3DSURFACE9		m_pSphericalRT;
	LPDIRECT3DSURFACE9		m_pSphericalSurface;
};