Shaders for Game Programmers and Artists(8) - Fog

简介

在水汽充足、微风及大气层稳定的情况下,气温接近零点,相对湿度达到100%时,空气中的水汽便会凝结成细微的水滴悬浮于空中,使地面水平的能见度下降,这种天气现象称为雾。
光线在照射到这些小颗粒的时候,方向发生改变,一些光被挡掉了,所有光的强度发生了改变,另一方面本不应该射向观察者的光线射向了观察者。

线性雾/指数雾/对数雾


如今的显卡对雾已经有了硬件级别的支持,所以性能上的损耗非常小。通常硬件都会提供几种基础的雾的实现。




1意味着没有fog,0表示全是fog
雾的实现也可分为per vertex的和per pixel的。Per vertex的只计算顶点的fog,其他的地方用插值来处理,perpixel每个pixel都计算一次,稍微耗一些。

After you determine the regular rendering
result of the object, the fog thickness is determined and used to blend the object color
with the fog color based on the fog progression mode chosen

使用fog的话也不用写什么shader,只要设置对应api的相关的state就可以了。

float4x4 view_proj_matrix;
struct VS_OUTPUT 
{
   float4 Pos:     POSITION;
   float2 Txr1:    TEXCOORD0;
   float1 Fog:     FOG;
};

VS_OUTPUT vs_main( 
   float4 inPos: POSITION, 
   float2 Txr1: TEXCOORD0
)
{
   VS_OUTPUT Out;

   float4 Pos = mul(view_proj_matrix, inPos);
   Out.Pos = Pos;
   Out.Txr1 = Txr1;

   // Set the fog based on a fixed end distance
   Out.Fog = pow(1-((Pos.z)/650),4);

   return Out;
}


Ps中并没有什么特殊处理,因为直接交给硬件处理了。
sampler Texture0;
float4 ps_main( 
   float4 inDiffuse: COLOR0, 
   float2 inTxr1: TEXCOORD0
) : COLOR0
{
   return tex2D(Texture0,inTxr1);
}



垂直雾

垂直雾在现实生活中就像下面这种情况一样



在计算的时候只要根据y值来设置雾的浓度就好了

float4x4 view_proj_matrix;
struct VS_OUTPUT 
{
   float4 Pos:     POSITION;
   float2 Txr1:    TEXCOORD0;
   float1 Fog:     FOG;
};

VS_OUTPUT vs_main( 
   float4 inPos: POSITION, 
   float2 Txr1: TEXCOORD0
)
{
   VS_OUTPUT Out;

   float4 Pos = mul(view_proj_matrix, inPos);
   Out.Pos = Pos;
   Out.Txr1 = Txr1;

   // Set the fog proportional to the Y height.
   // With a vertex shader, the fog can be set to
   // any value you wish.
   Out.Fog = (2*Pos.y/Pos.w)+1;

   return Out;
}




圆形雾

还是计算fog值
Out.Fog = 1-sqrt(dot(Pos.xy/Pos.w,Pos.xy/Pos.w));

vs如下

Out.Fog = 1-sqrt(dot(Pos.xy/Pos.w,Pos.xy/Pos.w));

float4x4 view_proj_matrix;
struct VS_OUTPUT 
{
   float4 Pos:     POSITION;
   float2 Txr1:    TEXCOORD0;
   float1 Fog:     FOG;
};

VS_OUTPUT vs_main( 
   float4 inPos: POSITION, 
   float2 Txr1: TEXCOORD0
)
{
   VS_OUTPUT Out;

   float4 Pos = mul(view_proj_matrix, inPos);
   Out.Pos = Pos;
   Out.Txr1 = Txr1;

   // Set the fog proportional to the Y height.
   // With a vertex shader, the fog can be set to
   // any value you wish.
   Out.Fog = 1-sqrt(dot(Pos.xy/Pos.w,Pos.xy/Pos.w));

   return Out;
}



体积雾

基于顶点的雾效,由于计算的雾色最终是叠加到模型上渲染出来,无法表达出体积感。所以需要一种新的可以表达体积的雾效,我们把它称之为体积雾,能够控制位置,形状,密度。

实现体积雾需要用到深度信息。在计算某一点fog浓度的时候,需要两个pass,两个RT,一个pass绘制正面的深度,另一个pass绘制背面的深度,fog的浓度等于这两个深度值相减。

想绘制模型的背面只需要将RenderState中CULLMODE换成CW就可以了。
深度绘制的vs

float4x4 view_proj_matrix;
struct VS_OUTPUT 
{
   float4 Pos:     POSITION;
   float Depth:   TEXCOORD0;
};

VS_OUTPUT vs_main(float4 inPos: POSITION)
{
   VS_OUTPUT Out;

   float4 Pos = mul(view_proj_matrix, inPos);
   Out.Pos = Pos;
   Out.Depth= (Pos.z/800);

   return Out;
}



深度绘制的ps
sampler Texture0;
float4 ps_main( 
   float Depth: TEXCOORD0
) : COLOR0
{
   return Depth;
}



最后一个pass采样之前绘制的两个pass,将深度值相减,得到雾的厚度
sampler Front;
sampler Back;
const float off = 1.0 / 128.0;

float4 ps_main( float2 TexCoord : TEXCOORD0 ) : COLOR
{
   float4 F = tex2D(Front,TexCoord);
   float4 B = tex2D(Back,TexCoord);
   return (F-B)*16;
}



猜你喜欢

转载自blog.csdn.net/qp120291570/article/details/54885724