体积雾(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.渲染所有雾模型的正面的尝试到一张纹理上
   
 
  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(0000), 0.00);

    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/ 

posted @ 2011-02-23 17:47  oayx  阅读(3763)  评论(1编辑  收藏  举报