www.pudn.com > fluid.rar > FluidAnimator2D.cpp, change:2006-10-27,size:15928b


#include "stableHeader.h" 
#include "FluidAnimator2D.h" 
#include "DTKUtil.h" 
#include "DTKScreenAlignedQuad.h" 
 
 
//Debug 
#include "DTKTextureViewer.h" 
 
namespace DTK 
{ 
 
FluidAnimator2D::FluidAnimator2D(uint uWidth, uint uHeight,TexturePrecision texPrec) 
:m_texPrec(texPrec), 
m_pD3DDevice(NULL), 
m_d(1.0f), 
m_dis(0.99f), 
m_v(0.2f), 
m_vorCoe(0.5f), 
m_bAdvection(true), 
m_bDiffuse(true), 
m_bProject(true), 
m_bVelocityBoundary(true), 
m_bPressureBoundary(true), 
m_bVorticityConfinement(true), 
m_uWidth(uWidth), 
m_uHeight(uHeight), 
m_uSrcVelField(0), 
m_uActiveVelField(0), 
m_uSrcScalarField(0), 
m_uActiveScalarField(0), 
m_uNumItr(5), 
m_pForceTex(NULL), 
m_pForceSurf(NULL), 
m_pVorticityTex(NULL), 
m_pVorticitySurf(NULL), 
m_extForce(), 
m_pShader(NULL) 
{ 
	for (int iBuf=0; iBuf BUFFER_NUM; ++iBuf) 
	{ 
		m_apVelFieldTex[iBuf]  = NULL; 
		m_apVelFieldSurf[iBuf] = NULL; 
 
		m_apScalarFieldTex[iBuf]  = NULL; 
		m_apScalarFieldSurf[iBuf] = NULL; 
 
	} 
} 
 
 
 
void FluidAnimator2D::clearRenderTarget(IDirect3DSurface9* pSurf) 
{ 
	assert(m_pD3DDevice); 
	DTK::RenderTargetStateBlock rtsb; 
	rtsb.capture(m_pD3DDevice,1); 
	HRESULT hr; 
 
	V(m_pD3DDevice->SetRenderTarget(0,pSurf)); 
	V(m_pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_RGBA(0,0,0,1),1,0)); 
 
	rtsb.restore(m_pD3DDevice); 
} 
void FluidAnimator2D::reset() 
{ 
	clearRenderTarget(m_apVelFieldSurf[u0()]); 
	clearRenderTarget(m_apScalarFieldSurf[s0()]); 
	clearRenderTarget(m_pVorticitySurf); 
	clearRenderTarget(m_pForceSurf); 
} 
 
void FluidAnimator2D::addExternalForce(const FluidAnimator2D::ExternalForce& force) 
{ 
	m_extForce = force; 
} 
 
void FluidAnimator2D::setParticleDistance(float fD) 
{ 
	if(fD >0.0f) 
	{ 
		m_d = fD; 
	} 
 
} 
float FluidAnimator2D::getParticleDistance() 
{ 
	return m_d; 
} 
void FluidAnimator2D::setDissipation(float dis) 
{ 
	m_dis = dis; 
} 
float FluidAnimator2D::getDissipation() 
{ 
	return m_dis; 
} 
void FluidAnimator2D::setViscous(float fV) 
{ 
	m_v =( fV>0.0f )?fV:m_v; 
} 
float FluidAnimator2D::getViscous() 
{ 
	return m_v; 
} 
void FluidAnimator2D::setVorticityConfinementCoefficient(float vorCoe) 
{ 
	m_vorCoe = vorCoe; 
} 
float FluidAnimator2D::getVorticityConfinementCoefficient() 
{ 
	return m_vorCoe; 
} 
void FluidAnimator2D::setIterateNumber(uint uNum) 
{ 
	m_uNumItr = (uNum > 0)? uNum:m_uNumItr; 
} 
uint FluidAnimator2D::getIterateNumber() 
{ 
	return m_uNumItr; 
} 
 
Vector2 FluidAnimator2D::getSize() 
{ 
	return Vector2(m_uWidth,m_uHeight); 
} 
 
void FluidAnimator2D::timeStep(float dt) 
{ 
	assert(m_pD3DDevice); 
	assert(m_pShader); 
	 
	HRESULT hr; 
 
 
 
	//backup render target 
	DTK::RenderTargetStateBlock rtsb; 
	rtsb.capture(m_pD3DDevice,2); 
 
	updateSharedParam(dt); 
	 
	V(m_pShader->SetTechnique(m_hTimeStepTech)); 
	V(m_pShader->Begin(0,0)); 
	//add force term 
	addForceTerm(dt); 
 
	//add diffuse term 
	if (m_bDiffuse) 
	{ 
		diffuse(dt); 
	} 
 
	//add advect term 
	if (m_bAdvection) 
	{ 
		advection(dt); 
	} 
 
 
	 
	//compute pressure and project velocity field 
	if (m_bProject) 
	{ 
		project(); 
	} 
	 
	//apply boundary condition 
	boundary(); 
 
    //compute vorticity confinement 
	computeVorticityConfinement(); 
	 
	//clear external force 
	m_extForce=ExternalForce(); 
 
	V(m_pShader->End()); 
 
	//restore render target 
	rtsb.restore(m_pD3DDevice); 
 
	 
 
} 
 
 
void FluidAnimator2D::addForceTerm(float dt) 
{ 
	assert(m_pShader); 
	HRESULT hr; 
     
	V(m_pD3DDevice->SetRenderTarget(0,m_apVelFieldSurf[u1()])); 
 
	//update param 
	V(m_pShader->SetFloat(m_hRf_rt,m_extForce.m_r)); 
	V(m_pShader->SetFloatArray(m_hPosf_rt,reinterpret_cast<const float*>(& (m_extForce.m_p_rt)),2)); 
	V(m_pShader->SetFloatArray(m_hForce_rp,reinterpret_cast<const float*>(& (m_extForce.m_f_rp)),2)); 
	V(m_pShader->SetTexture(m_hForceFieldTex,m_pForceTex)); 
	V(m_pShader->SetTexture(m_hVelFieldTex,m_apVelFieldTex[u0()])); 
 
	V(m_pShader->BeginPass(TSP_ADD_FORCE)); 
     
	DTK::ScreenAlignedQuad::instance().draw(); 
 
	V(m_pShader->EndPass()); 
 
 
	loop_u0(u1()); 
 
} 
 
void FluidAnimator2D::enableDiffuse(bool bEnable) 
{ 
	m_bDiffuse = bEnable; 
} 
void FluidAnimator2D::enableAdvection(bool bEnable) 
{ 
	m_bAdvection = bEnable; 
} 
void FluidAnimator2D::enableProject(bool bEnable) 
{ 
	m_bProject = bEnable; 
} 
void FluidAnimator2D::enableVelocityBoundary(bool bEnable) 
{ 
	m_bVelocityBoundary = bEnable; 
} 
void FluidAnimator2D::enablePressureBoundary(bool bEnable) 
{ 
	m_bPressureBoundary = bEnable; 
} 
void FluidAnimator2D::enableVorticityConfinement(bool bEnable) 
{ 
	m_bVorticityConfinement = bEnable; 
} 
 
void FluidAnimator2D::advection(float dt) 
{ 
	assert(m_pShader); 
	HRESULT hr; 
	//update param 
	V(m_pD3DDevice->SetRenderTarget(0,m_apVelFieldSurf[u1()])); 
   
	V(m_pShader->SetTexture(m_hVelFieldTex,m_apVelFieldTex[u0()])); 
	V(m_pShader->BeginPass(TSP_ADVECTION)); 
 
	DTK::ScreenAlignedQuad::instance().draw(); 
 
	V(m_pShader->EndPass()); 
 
	loop_u0(u1()); 
} 
 
void FluidAnimator2D::diffuse(float dt) 
{ 
	assert(m_pShader); 
 
	DTK::ScreenAlignedQuad& quad = DTK::ScreenAlignedQuad::instance(); 
 
	HRESULT hr; 
	 
	//first iterate	 
	V(m_pShader->SetTexture(m_hVelFieldTex,m_apVelFieldTex[u0()])); 
	//use u0 as initial velocity for Jacobi iterate 
	//V(m_pShader->SetTexture(m_hActiveVelFieldTex,m_apVelFieldTex[u0()])); 
	V(m_pShader->SetTexture(m_hActiveVelFieldTex,NULL)); 
 
	//use u00 as render target 
	V(m_pD3DDevice->SetRenderTarget(0,m_apVelFieldSurf[u00()])); 
     
 
	V(m_pShader->BeginPass(TSP_DIFFUSE));	 
	quad.draw(); 
	V(m_pShader->EndPass()); 
 
	if (m_uNumItr == 1) 
	{ 
		loop_u0(u00()); 
		return; 
	} 
 
    for (uint itr = 1;itr<m_uNumItr; ++itr) 
    { 
		//swap iterate velocity texture 
		loop_u00(_u01()); 
		V(m_pShader->SetTexture(m_hActiveVelFieldTex,m_apVelFieldTex[u00()])); 
		V(m_pD3DDevice->SetRenderTarget(0,m_apVelFieldSurf[u01()])); 
		V(m_pShader->BeginPass(TSP_DIFFUSE)); 
		quad.draw(); 
		V(m_pShader->EndPass()); 
    } 
 
     
	loop_u0(u01()); 
 
} 
 
/*! project velocity field to zero divergence 
use u0 as source velocity field 
use u1 as temp velocity field 
\return 
u0 will keep the result 
*/ 
void FluidAnimator2D::project() 
{ 
	assert(m_pShader); 
	HRESULT hr; 
 
	 
 
	//compute divergence 
	//------------------------------------------------------------------------------ 
	//keep divergence in s00 
	V(m_pD3DDevice->SetRenderTarget(0,m_apScalarFieldSurf[s00()])); 
	//set source velocity field 
	V(m_pShader->SetTexture(m_hVelFieldTex,m_apVelFieldTex[u0()])); 
 
	V(m_pShader->BeginPass(TSP_COMPUTE_DIVERGENCE)); 
 
	DTK::ScreenAlignedQuad::instance().draw(); 
 
	V(m_pShader->EndPass()); 
 
 
	//compute pressure 
	//------------------------------------------------------------------------------ 
	computePressure(); 
 
	//project velocity field 
	//------------------------------------------------------------------------------ 
	//u0 is source velocity field 
	//s0 pressure field 
 
 
	V(m_pD3DDevice->SetRenderTarget(0,m_apVelFieldSurf[u1()])); 
 
	V(m_pShader->SetTexture(m_hScalarFieldTex,m_apScalarFieldTex[s0()])); 
 
	V(m_pShader->BeginPass(TSP_PROJECT)); 
	DTK::ScreenAlignedQuad::instance().draw(); 
	V(m_pShader->EndPass()); 
 
	loop_u0(u1()); 
 
 
 
} 
 
/* 
use s0 as initial pressure field for Jacobi iterate 
use s00 as divergence of source velocity field 
use s01 as temp pressure field 
\return 
result will be kept in s0 
*/ 
void FluidAnimator2D::computePressure() 
{ 
	assert(m_pShader); 
 
	DTK::ScreenAlignedQuad& quad = DTK::ScreenAlignedQuad::instance(); 
 
	HRESULT hr; 
 
	//first iterate	 
	//set divergence of source velocity field 
	V(m_pShader->SetTexture(m_hScalarFieldTex,m_apScalarFieldTex[s00()])); 
	//set as initial pressure for Jacobi iterate 
	V(m_pShader->SetTexture(m_hActiveScalarFieldTex,m_apScalarFieldTex[s0()])); 
	//use s01 as result pressure field 
	V(m_pD3DDevice->SetRenderTarget(0,m_apScalarFieldSurf[s01()])); 
 
 
	V(m_pShader->BeginPass(TSP_COMPUTE_PRESSURE));	 
	quad.draw(); 
	V(m_pShader->EndPass()); 
 
	if (m_uNumItr == 1) 
	{ 
		loop_s0(s01()); 
		return; 
	} 
 
	//map  
	//s0 : divergence of source velocity field 
	//s00 : initial pressure field 
	//s11 : result pressure field 
	uint u_s01 = s01(); 
	loop_s0(s00()); 
	set_s00(u_s01); 
 
 
	for (uint itr = 1;itr<m_uNumItr; ++itr) 
	{ 
 
		V(m_pShader->SetTexture(m_hActiveScalarFieldTex,m_apScalarFieldTex[s00()])); 
		V(m_pD3DDevice->SetRenderTarget(0,m_apScalarFieldSurf[s01()])); 
		V(m_pShader->BeginPass(TSP_COMPUTE_PRESSURE)); 
		quad.draw(); 
		V(m_pShader->EndPass()); 
 
		//swap iterate velocity texture 
		loop_s00(_s01()); 
	} 
 
	loop_s0(s00()); 
} 
 
void FluidAnimator2D::boundary() 
{ 
	assert(m_pShader); 
	HRESULT hr; 
 
	if (m_bVelocityBoundary) 
	{	 
		//apply velocity boundary 
	V(m_pD3DDevice->SetRenderTarget(0,m_apVelFieldSurf[u1()])); 
	V(m_pShader->SetTexture(m_hVelFieldTex,m_apVelFieldTex[u0()])); 
	V(m_pShader->BeginPass(TSP_VELOCITY_BOUNDARY)); 
 
	DTK::ScreenAlignedQuad::instance().draw(); 
	V(m_pShader->EndPass()); 
	loop_u0(u1()); 
	} 
 
 
	if (m_bPressureBoundary) 
	{ 
		//apply pressure boundary 
	V(m_pD3DDevice->SetRenderTarget(0,m_apScalarFieldSurf[s1()])); 
	V(m_pShader->SetTexture(m_hScalarFieldTex,m_apScalarFieldTex[s0()])); 
	V(m_pShader->BeginPass(TSP_PRESSURE_BOUNDARY)); 
	DTK::ScreenAlignedQuad::instance().draw(); 
	V(m_pShader->EndPass()); 
	loop_s0(s1()); 
	} 
 
} 
 
void FluidAnimator2D::computeVorticityConfinement() 
{ 
	assert(m_pShader); 
	HRESULT hr; 
 
	computeVorticity(); 
 
	V(m_pD3DDevice->SetRenderTarget(0,m_pForceSurf)); 
	if(m_bVorticityConfinement) 
	{ 
	//update param 
	V(m_pShader->SetFloat(m_hVorCoe,m_vorCoe)); 
	V(m_pShader->SetTexture(m_hScalarFieldTex,m_pVorticityTex)); 
	V(m_pShader->BeginPass(TSP_VORTICITY_CONFINEMENT)); 
	DTK::ScreenAlignedQuad::instance().draw(); 
	V(m_pShader->EndPass()); 
	} 
	else 
	{ 
		clearRenderTarget(m_pForceSurf); 
	} 
 
	 
 
	 
} 
void FluidAnimator2D::computeVorticity() 
{ 
	assert(m_pShader); 
	HRESULT hr; 
	//update param 
	V(m_pD3DDevice->SetRenderTarget(0,m_pVorticitySurf)); 
 
	V(m_pShader->SetTexture(m_hVelFieldTex,m_apVelFieldTex[u0()])); 
	V(m_pShader->BeginPass(TSP_COMPUTE_VORTICITY)); 
	DTK::ScreenAlignedQuad::instance().draw(); 
	V(m_pShader->EndPass()); 
 
} 
 
IDirect3DTexture9* FluidAnimator2D::getForceField() 
{ 
	return m_pForceTex; 
} 
 
IDirect3DTexture9* FluidAnimator2D::getVelocityField() 
{ 
	return m_apVelFieldTex[u0()]; 
} 
IDirect3DTexture9* FluidAnimator2D::getPressureField() 
{ 
	return m_apScalarFieldTex[s0()]; 
} 
IDirect3DTexture9* FluidAnimator2D::getVorticityField() 
{ 
	return m_pVorticityTex; 
} 
void FluidAnimator2D::createShader() 
{ 
	assert(m_pD3DDevice); 
	SAFE_RELEASE(m_pShader); 
 
	HRESULT hr; 
	DWORD dwShaderFlags = NULL; 
	//dwShaderFlags |= D3DXSHADER_NO_PRESHADER | D3DXSHADER_PREFER_FLOW_CONTROL; 
	//dwShaderFlags |= D3DXFX_NOT_CLONEABLE; 
	//dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT | D3DXSHADER_DEBUG; 
	//dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT | D3DXSHADER_DEBUG; 
	V(D3DXCreateEffectFromFile(m_pD3DDevice,L"../shader/fluidAnimator2D.fx",NULL,NULL, 
		dwShaderFlags,NULL,&m_pShader,NULL)); 
	m_hTexSize = m_pShader->GetParameterByName(NULL,"g_texSize"); 
	m_hDx = m_pShader->GetParameterByName(NULL,"g_dx"); 
	m_hDy = m_pShader->GetParameterByName(NULL,"g_dy"); 
	m_hD  = m_pShader->GetParameterByName(NULL,"g_d"); 
	m_hDis= m_pShader->GetParameterByName(NULL,"g_dis"); 
	m_hV  = m_pShader->GetParameterByName(NULL,"g_v"); 
	m_hVorCoe = m_pShader->GetParameterByName(NULL,"g_vorCoe"); 
	m_hDt = m_pShader->GetParameterByName(NULL,"g_dt"); 
	m_hRf_rt    = m_pShader->GetParameterByName(NULL,"g_rf_rt"); 
	m_hPosf_rt  = m_pShader->GetParameterByName(NULL,"g_posf_rt"); 
	m_hForce_rp = m_pShader->GetParameterByName(NULL,"g_force_rp"); 
	m_hForceFieldTex = m_pShader->GetParameterByName(NULL,"forceFieldTex"); 
	m_hVelFieldTex   = m_pShader->GetParameterByName(NULL,"velFieldTex"); 
	m_hActiveVelFieldTex   = m_pShader->GetParameterByName(NULL,"activeVelFieldTex"); 
	m_hScalarFieldTex   = m_pShader->GetParameterByName(NULL,"scalarFieldTex"); 
	m_hActiveScalarFieldTex   = m_pShader->GetParameterByName(NULL,"activeScalarFieldTex"); 
	m_hTimeStepTech  = m_pShader->GetTechniqueByName("timeStep"); 
 
} 
 
void FluidAnimator2D::updateSharedParam(float dt) 
{ 
	assert(m_pShader); 
	float texSize[2] = {static_cast<float>(m_uWidth),static_cast<float>(m_uHeight)}; 
	float dx = 1.0f/static_cast<float>(m_uWidth); 
	float dy = 1.0f/static_cast<float>(m_uHeight); 
 
 
	HRESULT hr; 
 
 
	V(m_pShader->SetFloat(m_hD,m_d)); 
	V(m_pShader->SetFloat(m_hDis,m_dis)); 
	V(m_pShader->SetFloat(m_hV,m_v)); 
	V(m_pShader->SetFloat(m_hDx,dx)); 
	V(m_pShader->SetFloat(m_hDy,dy)); 
	V(m_pShader->SetFloat(m_hDt,dt)); 
	V(m_pShader->SetFloatArray(m_hTexSize,texSize,2)); 
 
} 
 
void FluidAnimator2D::clearup() 
{ 
	SAFE_RELEASE(m_pShader); 
 
	for (uint i=0; i<BUFFER_NUM;++i) 
	{ 
		SAFE_RELEASE(m_apVelFieldTex[i]); 
		SAFE_RELEASE(m_apVelFieldSurf[i]); 
		SAFE_RELEASE(m_apScalarFieldTex[i]); 
		SAFE_RELEASE(m_apScalarFieldSurf[i]); 
	} 
} 
 
void FluidAnimator2D::onCreateDevice( IDirect3DDevice9* pd3dDevice,  
									 const D3DSURFACE_DESC* pBackBufferSurfaceDesc , void* pUserContext) 
{ 
	m_pD3DDevice = pd3dDevice; 
	assert(m_pD3DDevice); 
 
	createShader(); 
 
 
	 
} 
 
void FluidAnimator2D::onResetDevice( IDirect3DDevice9* pd3dDevice, 
									const D3DSURFACE_DESC* pBackBufferSurfaceDesc , void* pUserContext ) 
{ 
	HRESULT hr; 
 
	m_pShader->OnResetDevice(); 
 
	//create velocity field texture and 
	//------------------------------------------------------------------------------ 
	for (int iBuf=0; iBuf BUFFER_NUM; ++iBuf) 
	{ 
		SAFE_RELEASE(m_apVelFieldTex[iBuf]); 
		SAFE_RELEASE(m_apVelFieldSurf[iBuf]); 
	} 
 
	D3DFORMAT texFmt = D3DFMT_G32R32F; 
	if (m_texPrec == TP_16BIT) 
	{ 
		texFmt = D3DFMT_G16R16F; 
	} 
 
	for (int iBuf=0; iBuf BUFFER_NUM; ++iBuf) 
	{ 
		V(D3DXCreateTexture(m_pD3DDevice,m_uWidth,m_uHeight,1,D3DUSAGE_RENDERTARGET,texFmt,D3DPOOL_DEFAULT, 
			m_apVelFieldTex+iBuf)); 
		V(m_apVelFieldTex[iBuf]->GetSurfaceLevel(0,m_apVelFieldSurf+iBuf)); 
 
	} 
 
	//create force texture 
	//------------------------------------------------------------------------------ 
	V(D3DXCreateTexture(m_pD3DDevice,m_uWidth,m_uHeight,1,D3DUSAGE_RENDERTARGET,texFmt,D3DPOOL_DEFAULT, 
		&m_pForceTex)); 
	V(m_pForceTex->GetSurfaceLevel(0,&m_pForceSurf)); 
 
 
	//create scalar field texture 
	//------------------------------------------------------------------------------ 
	for (int iBuf=0; iBuf BUFFER_NUM; ++iBuf) 
	{ 
		SAFE_RELEASE(m_apScalarFieldTex[iBuf]); 
		SAFE_RELEASE(m_apScalarFieldSurf[iBuf]); 
	} 
 
	texFmt = D3DFMT_R32F; 
	if (m_texPrec == TP_16BIT) 
	{ 
		texFmt = D3DFMT_R16F; 
	} 
 
	for (int iBuf=0; iBuf BUFFER_NUM; ++iBuf) 
	{ 
		V(D3DXCreateTexture(m_pD3DDevice,m_uWidth,m_uHeight,1,D3DUSAGE_RENDERTARGET,texFmt,D3DPOOL_DEFAULT, 
			m_apScalarFieldTex+iBuf)); 
		V(m_apScalarFieldTex[iBuf]->GetSurfaceLevel(0,m_apScalarFieldSurf+iBuf)); 
	} 
     
	SAFE_RELEASE(m_pVorticityTex); 
	SAFE_RELEASE(m_pVorticitySurf); 
	V(D3DXCreateTexture(m_pD3DDevice,m_uWidth,m_uHeight,1,D3DUSAGE_RENDERTARGET,texFmt,D3DPOOL_DEFAULT, 
		&m_pVorticityTex)); 
	V(m_pVorticityTex->GetSurfaceLevel(0,&m_pVorticitySurf)); 
 
 
 
    reset(); 
 
 
} 
 
void FluidAnimator2D::onLostDevice( void* pUserContext ) 
{ 
	m_pShader->OnLostDevice(); 
 
	for (int iBuf=0; iBuf BUFFER_NUM; ++iBuf) 
	{ 
		SAFE_RELEASE(m_apVelFieldTex[iBuf]); 
		SAFE_RELEASE(m_apVelFieldSurf[iBuf]); 
		SAFE_RELEASE(m_apScalarFieldTex[iBuf]); 
		SAFE_RELEASE(m_apScalarFieldSurf[iBuf]); 
	} 
 
	SAFE_RELEASE(m_pForceTex); 
	SAFE_RELEASE(m_pForceSurf); 
	SAFE_RELEASE(m_pVorticityTex); 
	SAFE_RELEASE(m_pVorticitySurf); 
} 
 
void FluidAnimator2D::onDestroyDevice( void* pUserContext ) 
{ 
	clearup(); 
	m_pD3DDevice = NULL; 
} 
 
}