📄 ca_water.cpp
字号:
// no need to clear temporary target
// even if wireframe mode, render to texture as solid
m_pD3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID );
DWORD wrapval = m_bWrap ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
m_pD3DDev->SetTextureStageState(0, D3DTSS_ADDRESSU, wrapval);
m_pD3DDev->SetTextureStageState(0, D3DTSS_ADDRESSV, wrapval);
m_pD3DDev->SetTextureStageState(1, D3DTSS_ADDRESSU, wrapval);
m_pD3DDev->SetTextureStageState(1, D3DTSS_ADDRESSV, wrapval);
m_pD3DDev->SetTextureStageState(2, D3DTSS_ADDRESSU, wrapval);
m_pD3DDev->SetTextureStageState(2, D3DTSS_ADDRESSV, wrapval);
m_pD3DDev->SetTextureStageState(3, D3DTSS_ADDRESSU, wrapval);
m_pD3DDev->SetTextureStageState(3, D3DTSS_ADDRESSV, wrapval);
for(i = 0; i < 4; i++ )
{
m_pD3DDev->SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
m_pD3DDev->SetTextureStageState(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
}
/////////////////////////////////////////////////////////////
// Render first 3 components of force from three neighbors
// Offsets selected are 1 center texel for center height
// and 3 of the 4 nearest neighbors. Texture selected
// is same for all stages as we're turning height difference
// of nearest neightbor texels into a force value.
hr = m_pD3DDev->SetPixelShader( m_dwNeighborForceCalc_1 );
ASSERT_IF_FAILED( hr );
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nForceStepOne], NULL);
ASSERT_IF_FAILED( hr );
// write first part of force calc
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, false );
hr = m_pD3DDev->SetTexture(0, m_pTex_HeightSrc );
ASSERT_IF_FAILED(hr);
hr = m_pD3DDev->SetTexture(1, m_pTex_HeightSrc );
ASSERT_IF_FAILED(hr);
hr = m_pD3DDev->SetTexture(2, m_pTex_HeightSrc );
ASSERT_IF_FAILED(hr);
hr = m_pD3DDev->SetTexture(3, m_pTex_HeightSrc );
ASSERT_IF_FAILED(hr);
// Render using offset set 1
offset.x = 1.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
// draw the quad with texture coords doing difference of
// nearby texels for force calc.
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
////////////////////////////////////////////////////////////////
// Now add in last component of force for the 4th neighbor
// that we didn't have enough texture lookups to do in the
// first pass
hr = m_pD3DDev->SetPixelShader( m_dwNeighborForceCalc_2 );
ASSERT_IF_FAILED( hr );
// Cannot use additive blending as the force contribution might
// be negative and would have to subtract from the dest.
// We must instead use an additional texture as target and read
// the previous partial 3-neighbor result into the pixel shader
// for possible subtraction
// Alphablend must be false
//; t0 = center
//; t1 = 2nd axis final point
//; t2 = previous partial result texture sampled at center
//; t3 = not used
m_pD3DDev->SetTexture(0, m_pTex_HeightSrc );
m_pD3DDev->SetTexture(1, m_pTex_HeightSrc );
m_pD3DDev->SetTexture(2, mpTextureFiltered[m_nForceStepOne] );
// Render to the final force texture
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nForceTexture], NULL);
ASSERT_IF_FAILED( hr );
offset.x = 2.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
/////////////////////////////////////////////////////////////////
// Apply the force with a scale factor to reduce it's magnitude.
// Add this to the current texture representing the water height.
hr = m_pD3DDev->SetPixelShader( m_dwApplyForceShader );
ASSERT_IF_FAILED( hr );
// use offsets of zero
offset.x = 0.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
m_pD3DDev->SetTexture(0, mpTextureFiltered[m_nTex_VelSrc] );// 1st is offset to 0 with offsets 1.0
m_pD3DDev->SetTexture(1, mpTextureFiltered[m_nForceTexture] ); // stage 2,3 not used
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nTex_VelTarg], NULL);
ASSERT_IF_FAILED( hr );
// no more additive blending - math for signed values has to be
// done in the pixel shader
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, false );
// Set constant at which to apply force to velocity
float pix_force_mult[4] = { m_fBlend, m_fBlend, m_fBlend, 1.0f }; // RGBA
hr = m_pD3DDev->SetPixelShaderConstant( PCN_MULTFACTOR_1, &pix_force_mult, 1 );
ASSERT_IF_FAILED(hr);
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
///////////////////////////////////////////////////////////////////
// With velocity texture selected, render new excitation droplets
// at random freq.
float rnd_freq;
rnd_freq = (float)rand()/((float)RAND_MAX);
if( m_fDropletFreq > rnd_freq )
{
// a drop falls - decide where
float x = (float)rand()/((float)RAND_MAX);
float y = (float)rand()/((float)RAND_MAX);
// pick a droplet size at random:
float scale = 10.0f;
scale += 25.0f * ((float)rand()/((float)RAND_MAX));
AddDroplet( x, y, scale );
}
// Now draw the droplets:
DrawDroplets();
//////////////////////////////////////////////////////////////////////
// Apply velocity to position
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nTex_HeightTarg], NULL);
ASSERT_IF_FAILED( hr );
hr = m_pD3DDev->SetPixelShader( m_dwApplyVelocityShader );
ASSERT_IF_FAILED( hr );
m_pD3DDev->SetTexture(0, m_pTex_HeightSrc );
m_pD3DDev->SetTexture(1, mpTextureFiltered[m_nTex_VelTarg] );
m_pD3DDev->SetTexture(2, 0);
m_pD3DDev->SetTexture(3, 0);
// no more additive blending - math for signed values has to be
// done in the pixel shader
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, false );
// Set constant at which to apply velocity to height
float pix_vel_mult[4] = { m_fVelFactor, m_fVelFactor, m_fVelFactor, 1.0f }; // RGBA
hr = m_pD3DDev->SetPixelShaderConstant( PCN_MULTFACTOR_1, &pix_vel_mult, 1 );
ASSERT_IF_FAILED(hr);
// use offsets of zero
offset.x = 0.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
ASSERT_IF_FAILED(hr);
///////////////////////////////////////////////////////////////////
// blur positions to smooth noise & generaly dampen things
// degree of blur is controlled by magnitude of 4 neighbor texel
// offsets with bilinear on
// Swap height targ & src
tmp = m_nTex_HeightTarg;
m_nTex_HeightTarg = m_nTex_HeightSrc;
m_nTex_HeightSrc = tmp;
m_pTex_HeightSrc = mpTextureFiltered[m_nTex_HeightSrc];
// Now blur height
m_pD3DDev->SetTexture(0, m_pTex_HeightSrc );
m_pD3DDev->SetTexture(1, m_pTex_HeightSrc );
m_pD3DDev->SetTexture(2, m_pTex_HeightSrc );
m_pD3DDev->SetTexture(3, m_pTex_HeightSrc );
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, false );
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nTex_HeightTarg], NULL);
ASSERT_IF_FAILED( hr );
hr = m_pD3DDev->SetPixelShader( m_dwEqualWeight_PostMultShader );
ASSERT_IF_FAILED( hr );
offset.x = 3.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
ASSERT_IF_FAILED(hr);
////////////////////////////
// Draw fixed objects within the texture
if( m_bApplyInteriorBoundaries )
{
DrawInteriorBoundaryObjects();
}
///////////////////////////////////////////////////////////////////
// If selected, create a normal map from the height
if( m_bCreateNormalMap )
{
Do_CreateNormalMapSteps();
}
// Flip the state variable for the next round of rendering
switch( m_nFlipState )
{
case 0:
m_nFlipState = 1;
break;
case 1:
m_nFlipState = 2;
break;
case 2:
m_nFlipState = 1;
break;
}
return hr;
}
IDirect3DTexture8 * CA_Water::GetOutputTexture()
{
int texture_index;
switch( m_SimulationMode )
{
case SM_NORMAL_GRAY:
texture_index = m_nTex_NrmlTarg;
break;
case SM_RGB_GLOW:
texture_index = m_nTex_HeightTarg;
break;
case SM_HUE_DROPLETS:
texture_index = m_nTex_HeightTarg;
break;
}
assert( mpTextureFiltered[texture_index] != NULL );
return( mpTextureFiltered[texture_index] );
}
void CA_Water::CreateAndWriteUVOffsets(int width, int height)
{
// This sets vertex shader constants used to displace the
// source texture over several additive samples. This is
// used to accumulate neighboring texel information that we
// need to run the simulation.
// Label the texels as follows, with the source texel being
// rendered as "e"
// (0.0)
// abc
// def
// ghi
// (1,1)
m_fPerTexelWidth = 1.0f/static_cast<float>(width);
m_fPerTexelHeight = 1.0f/static_cast<float>(height);
// A multiplier for sampling beyond the 8 nearest neighbors
// For this, we don't use the multiplier, so it is just 1.0
m_fPerTexelWidth *= 1.0f; // 1 = no change - run standard game of life
m_fPerTexelHeight *= 1.0f;
// Half-texel width and height offsets for sampling from the
// exact center of a texel when rendering a full-coverage quad
// to a texture target. Without these, a full-coverage quad with
// texture coords from 0 to 1.0 would sample from the lower corner
// of each source texel in rendering to a texture target of the
// same resolution as the source texture.
float woff, hoff;
woff = m_fPerTexelWidth/2.0f;
hoff = m_fPerTexelHeight/2.0f;
// Offsets set 0 - all zeros for center of texel sampling.
// first the easy one: no offsets for sampling the center
// 'e' texel
// Use index offset value 0.0 to access these in the
// vertex shader.
float noOffsetX[4] = { 0.0f + woff, 0.0f + woff, 0.0f + woff, 0.0f + woff};
float noOffsetY[4] = { 0.0f + hoff, 0.0f + hoff, 0.0f + hoff, 0.0f + hoff};
// Offset set 1: For use with neighbor force pixel shader 1
// samples center with 0, +u, -u, and +v,
// ie the 'e','f','d', and 'h' texels
float type1OffsetX[4] = { 0.0f + woff,
- m_fPerTexelWidth + woff,
m_fPerTexelWidth + woff,
0.0f + woff };
float type1OffsetY[4] = { 0.0f + hoff,
0.0f + hoff,
0.0f + hoff,
m_fPerTexelHeight + hoff };
// Offset set 2: for use with neighbor force pixel shader 2
// samples center with 0, and -v texels
// ie the 'e' and 'b' texels
// This completes a pattern of sampling center texel and it's
// 4 nearest neighbors to run the height-based water simulation
// 3rd must be 0 0 to sample texel center from partial result
// texture.
float type2OffsetX[4] = { 0.0f + woff,
0.0f + woff,
0.0f + woff,
0.0f + woff };
float type2OffsetY[4] = { 0.0f + hoff,
- m_fPerTexelHeight + hoff,
0.0f + hoff,
0.0f + hoff };
// Now we change all that & instead of sampling 1 texel from center, we
// sample 1.5 texels from center and use bilinear sampling. This reduces
// some of the noise and high-frequency oscillation from sampling the
// exact texel neighbor only, giving smoother results in the height field
// and smoother water ripples
// Displacements 1.5 texels from center texel
//
// 0 = 0 0
// 1 = -s -t
// 2 = +s -t
// 3 = +s +t
// /*
type1OffsetX[0] = 0.0f + woff;
type1OffsetX[1] = - m_fPerTexelWidth ;
type1OffsetX[2] = m_fPerTexelWidth + 2.0f * woff;
type1OffsetX[3] = m_fPerTexelWidth + 2.0f * woff;
type1OffsetY[0] = 0.0f + hoff;
type1OffsetY[1] = - m_fPerTexelHeight;
type1OffsetY[2] = - m_fPerTexelHeight;
type1OffsetY[3] = m_fPerTexelHeight + 2.0f * woff;
// Displacements 1.5 texels from center texel
// 0 = 0 0
// 1 = -s +t
// 2 = 0 0
type2OffsetX[0] = 0.0f + woff;
type2OffsetX[1] = - m_fPerTexelWidth;
type2OffsetX[2] = 0.0f + woff;
type2OffsetX[3] = 0.0f + woff;
type2OffsetY[0] = 0.0f + hoff;
type2OffsetY[1] = m_fPerTexelHeight + 2.0f * hoff;
type2OffsetY[2] = 0.0f + hoff;
type2OffsetY[3] = 0.0f + hoff;
// */
// Offsets 3 are set in separate function
//////////////////////////////////////////////////////////////
// Nearest neighbor offsets:
float type4OffsetX[4] = { - m_fPerTexelWidth + woff,
m_fPerTexelWidth + woff,
0.0f + woff,
0.0f + woff };
float type4OffsetY[4] = { 0.0f + hoff,
0.0f + hoff,
m_fPerTexelHeight + hoff,
- m_fPerTexelHeight + hoff };
int i;
// write all these offsets to constant memory
for ( i = 0; i < 4; ++i)
{
D3DXVECTOR4 noOffset( noOffsetX[i], noOffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 type1Offset(type1OffsetX[i], type1OffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 type2Offset(type2OffsetX[i], type2OffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 type4Offset(type4OffsetX[i], type4OffsetY[i], 0.0f, 0.0f);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_NO_OFFSET + 5*i, &noOffset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE1 + 5*i, &type1Offset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE2 + 5*i, &type2Offset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE4 + 5*i, &type4Offset, 1);
}
// Set offsets set 3.0 used to further filter the high-frequency
// oscillations
UpdateBlurVertOffset();
}
void CA_Water::SetSimMode( int simmode )
{
m_SimulationMode = simmode;
if( m_SimulationMode >= SM_LAST )
m_SimulationMode = 0;
switch( m_SimulationMode )
{
case SM_NORMAL_GRAY:
m_fEqRestore_factor = 0.5f;
m_fBlurDist = 0.5f;
UpdateBlurVertOffset();
m_eRenderMode = FULLSCREEN_RESULT;
m_bDrawOutput = false;
m_fBlend = 0.25f;
m_fVelFactor = 0.5;
m_fDropletFreq = 0.1750f;
m_bCreateNormalMap = true;
FDebug("Set sim mode to NORMAL_GRAY\n");
break;
case SM_RGB_GLOW:
m_fEqRestore_factor = 0.0f;
m_fBlurDist = 0.01f;
UpdateBlurVertOffset();
m_eRenderMode = FULLSCREEN_FINALOUT;
m_bDrawOutput = true;
m_fBlend = 0.25f;
m_fVelFactor = 0.5;
m_fDropletFreq = 0.0f;
m_bCreateNormalMap = false;
m_bApplyInteriorBoundaries = true;
FDebug("Set sim mode to RGB_GLOW\n");
break;
case SM_HUE_DROPLETS:
m_fEqRestore_factor = 0.0f;
m_fBlurDist = 0.01f;
UpdateBlurVertOffset();
m_fBlend = 0.02f;
m_fVelFactor = 0.082994f;
m_fDropletFreq = 0.0f;
m_eRenderMode = FULLSCREEN_FINALOUT;
m_bDrawOutput = true;
m_bCreateNormalMap = false;
m_bApplyInteriorBoundaries = false;
FDebug("Set sim mode to HUE_DROPLETS\n");
m_fBlurDist = 0.020f;
m_fVelFactor = 0.0637f;
m_fBlend = 0.01158f;
break;
default:
FDebug("weird sim mode!\n");
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -