体积雾(dx9)

1.什么是体积雾?

         这个问题通过图片来解答再合适不过了,下面是本文利用体积雾做的一个结果

        

         体积雾(dx9)_第1张图片
         所谓体积雾:顾名思义就是被限制了形状的雾,本文表述如何通过ImageProcess(图象处理)的方式实现体积雾。
   2.常规雾原理
       雾效最终体现在雾颜色与场景色的混合上。决定雾的浓度的关键就在这个混合因子上。下面我们给出公式.
        float4   finalColor = factor * fogColor + ( 1 - factor) * sceneColor; ( !提取公因式,减少计算量)
                                   = factor(  fogColor - sceneColor) + sceneColor;   ( factor>=0 && factor<=1)
       (雾化公式)  finalColor   :混合后颜色
                          sceneColor:场景象素色
                           factor         :混合因子
  3.体积雾原理
     雾效关键在于如何求得每个场景可见象素点的混合因子!
     float  factor = fogDepth / ( fogEnd - fogStart);
    也就是视点与目标象素点的距离上雾所占的距离 fogDepth。根据Z Buffer,我们可以获取每帧每个象素到视点的距离。
     于是,我们同样可以通过渲染FogVolume的正面与反面的深度到两张贴图上。这样我们就可以根据当前场景深度信息以及前面的两张贴图,获得FogDepth,
 4.实现步骤
    1.首先渲染所有场景物体, 此处我们需要FrameBuffer, 与  Z Buffer信息
    2.渲染所有物模型的背面的深度到一张纹理上
    3.渲染所有雾模型的正面的尝试到一张纹理上
    4.利用场景的ZBuffer信息, 雾的两张深度纹理, 雾参数  处理 场景的FrameBuffer
5.具体步骤
  1.获取场景的ZBuffer, 与 FrameBuffer
  因为dx9无法直接获取场景的ZBuffer信息,所以我们要采用别的方式,
          1.把所有的场景多渲染一次,把深度信息渲染到一张纹理上;
          2.使用MultiRenderTarget 渲染场景的同时把深度信息保存到一张纹理上
 下面我们只介绍MultiRenderTarget的方式。
 MultiRenderTarget 是 Ps 2.0 即支持的渲染方式。其实现方法比较简单,只需更改PS( pixel shader)的返回值
例(这里使用使用两个RenderTarget):
   struct PS_OUTPUT
   {
        float4   Target0  : COLOR0;
        float4   Target1  : COLOR1;
    };
  硬件支持的RenderTarget数可以通过 D3DCaps.NumSimultaneousRTs 查看, 一般显卡:4
  代码部分:
  // 设置多RenderTarget
  g_pDevice->SetRenderTarget( 0, m_pMainRenderTarget);
  g_pDevice->SetRenderTarget( 1, m_pDepthTexture->GetSurface());
 
  //  渲染调用代码  
 
  g_pDevice->SetRenderTarget( 0, m_pMainRenderTarget);
  g_pDevice->SetRenderTarget( 1, NULL);
 
 注意:使用MultiRenderTarget 不能开启反锯齿
 
 // 拷贝FrameBuffer到一张动态纹理上
  IDirect3DSurface9* pSurface = NULL;
  g_pDevice->GetRenderTarget( 0, &pSurface);
 
  // copy back buffer into refraction map texture
  g_pDevice->StretchRect( pSurface, 0, m_pTextureSrc->GetSurface(), 0, D3DTEXF_NONE);
  SAFE_RELEASE( pSurface);
 
    2.渲染所有物模型的背面的深度到一张纹理上 
    3.渲染所有雾模型的正面的尝试到一张纹理上
   
体积雾(dx9)_第2张图片 
  4最后利用所有的数据更改FrameBuffer
  Shader 代码:
 
uniform float2  g_fogParam;   // x: fogStart  y: fogEnd
uniform float3  g_fogColor;   // FogColor

// vertexInput
struct VS_INPUT
{
 float3 Position : POSITION0;
 float2 Texcoord : TEXCOORD0;
};
// Vertex OutPut
struct VS_OUTPUT
{
 float4 Position : POSITION;
 float2 Texcoord : TEXCOORD1;
};
// Vertex Shader
VS_OUTPUT VS(VS_INPUT In)
{
 VS_OUTPUT Out;
 
 Out.Position = float4(In.Position, 1.0f);
 Out.Texcoord = In.Texcoord;
 return Out;
}
texture  texSrc;
texture  texSceneDepth;
texture  texFogFront;
texture  texFogBack;
// 纹理采样
sampler2D RGBSampler = sampler_state
{
    texture   = <texSrc>;
};
sampler2D DepthSampler = sampler_state
{
 texture   = <texSceneDepth>;
};
sampler2D FogFrontSampler = sampler_state
{
 texture   = <texFogFront>;
};
sampler2D FogBackSampler = sampler_state
{
 texture   = <texFogBack>;
};
// Pixel Shader
float4 PS(VS_OUTPUT In) : COLOR
{
 float depth    = tex2D( DepthSampler,    In.Texcoord).r;
 float fogFront = tex2D( FogFrontSampler, In.Texcoord).r;
 float fogBack  = tex2D( FogBackSampler,  In.Texcoord).r;
 float dis = 0.f;

 if( depth > fogBack)
  dis = fogBack - fogFront;
 else if( depth > fogFront)
  dis = depth - fogFront;
 
 float factor = max(( dis - g_fogParam.x), 0.f) / ( g_fogParam.y - g_fogParam.x);

 
 float3 rgb   = tex2D(RGBSampler, In.Texcoord);
 float3 color = rgb + factor * ( g_fogColor - rgb);
 return float4( color, 1.f);
}
technique technique0
{
 pass p0
 {    
  VertexShader = compile vs_3_0 VS();
  PixelShader  = compile ps_3_0 PS();
 }
}
 
另:为了减少判断量, 需把所有的图片 Clear为黑色
Please help to write shaders  for  volumetric fog. I have an error. But I  do  not know  where .

float4x4 g_wvp;
// depth.vsh  m_pFogShaderDepth
void  vs_depth( inout float4 pos   : POSITION  ,
                 
out   float   depth : TEXCOORD0 )
{
    pos 
=  mul( pos, g_wvp );
    depth 
=  pos.z;
}

// depth.psh  m_pFogShaderDepth
float4 ps_depth(  in   float  depth : TEXCOORD0 ) : COLOR
{
    
return  float4( depth,  0 .f,  0 .f,  0 .f );
}

    sampler2D s_fog_back;
    sampler2D s_fog_front;
    sampler2D s_scene_depth;

// fog.ps  m_pPixShader
float4 Main_ps(  in  float2 tex : TEXCOORD0 ) : COLOR
{

    
float  fog_back     =  tex2D( s_fog_back    , tex ).r;
    
float  fog_front    =  tex2D( s_fog_front   , tex ).r;
    
float  scene_depth  =  tex2D( s_scene_depth , tex ).r;
    
    
float  k  =  fog_back  -  fog_front;
    k 
-=  fog_back  -  clamp( scene_depth,  0 , fog_back );

    
return  float4( 0.5f , 0.5f , 0.5f , k * 0.5f  );
}

Code C
++

p_d3d_Device
-> SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);

    p_d3d_Device
-> SetTexture( 0 ,m_pEndFogTexture);
// ********************************
    D3DXMATRIX V;
    TheCamera.getViewMatrix(
& V);

    D3DXMATRIX matRes;
    
// matRes=mxWorld*mxView*mxProj;
    matRes = mxWorld * V * mxProj;

    VertShaderConstTable
-> SetMatrix(p_d3d_Device, MatrixHandle,  & matRes);
    
// ------------------------------
    p_d3d_Device -> SetPixelShader( NULL );
    
// reverse the culling order to get the back side
    
    
    p_d3d_Device
-> SetRenderState( D3DRS_ZFUNC , D3DCMP_GREATER  );

    p_d3d_Device
-> Clear(NULL, NULL, D3DCLEAR_TARGET |  D3DCLEAR_ZBUFFER , D3DCOLOR_ARGB( 0 0 0 0 ),  0.0 0 );

    p_d3d_Device
-> SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);

    p_d3d_Device
-> SetTexture( 0 ,m_pEndFogTexture);

    p_d3d_Device
-> SetVertexShader( m_pFogShaderDepth );


    

    
for ( DWORD i = 0 ; i < g_dwNumMaterials; i ++  )
     {
     m_pMeshFloor
-> DrawSubset( i );
     }

    p_d3d_Device
-> SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);

    p_d3d_Device
-> SetTexture( 1 ,m_pStartFogTexture);
    

    p_d3d_Device
-> SetVertexShader( m_pFogShaderDepth );


    
for ( DWORD i = 0 ; i < g_dwNumMaterials; i ++  )
     {
     m_pMeshFloor
-> DrawSubset( i );
     }
    p_d3d_Device
-> SetRenderState( D3DRS_CULLMODE,         D3DCULL_NONE );


    p_d3d_Device
-> SetVertexShader( NULL);
    p_d3d_Device
-> SetPixelShader( m_pPixShader );

    

    
for ( DWORD i = 0 ; i < g_dwNumMaterials; i ++  )
     {
     m_pMeshFloor
-> DrawSubset( i );
     }

    
    

    
// ---------------------------------
    p_d3d_Device -> SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE); 
   
// **********************************

    p_d3d_Device
-> EndScene ();
    p_d3d_Device
-> Present (NULL, NULL, NULL, NULL);

as  a result I have displayed a blue cube, textured very wrong, on a gray background. Read the article Russian programmer http: // timai-ru.blogspot.com/ 

你可能感兴趣的:(体积雾(dx9))