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;
}
}