雾 : 说白了就是一层有颜色的(一般是白色,灰色) 蒙蒙的感觉 混在光线里面。 不管是白天还是黑天。
龙书里面是这样实现的:
1. 给雾定义一个颜色 float3 gFogColor={0.7f,0.7f,0.7f};
2. 然后呢在顶点着色器里面计算出 顶点级别的雾化需要的颜色加成比例
加成比例: 意思是当距离摄像机,就是你的眼睛越远,雾的浓度越大,就是颜色越深。 根据这个得出一个(0,1)的和距离有关的比例系数
vout.fogLerp = saturate((d-gFogStart)/gFogRange) ; 其中 gFogStart是可见范围,没有雾的范围,gFogRange是不可见范围,超出这个范围就全是雾
saturate是强制为(0,1)这个区间。
3. 在像素着色器像素级别的融合 纹理颜色和雾的颜色
float3 floggedColor = lerp(litColor,gFogColor,pIn.fogLerp);
具体fx代码为:
//============================================================================= // fog.fx by Frank Luna (C) 2008 All Rights Reserved. // // Same as clip.fx, but adds fog in the vertex shader. // Note that we could do fog in the pixel shader, but if the scene // has sufficient triangle density, not much is gained. //============================================================================= #include "lighthelper.fx" cbuffer cbPerFrame { Light gLight; float3 gEyePosW; }; cbuffer cbPerObject { float4x4 gWorld; float4x4 gWVP; float4x4 gTexMtx; }; cbuffer cbFixed { // For this demo, we hardcode the fog values. However, in a real // application, the program may want to change the fog settings // at runtime; for example, to fade the fog in and out based on // the time of day or the location of the game player. float gFogStart = 5.0f; float gFogRange = 140.0f; float3 gFogColor = {0.7f, 0.7f, 0.7f}; }; // Nonnumeric values cannot be added to a cbuffer. Texture2D gDiffuseMap; Texture2D gSpecMap; SamplerState gTriLinearSam { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_IN { float3 posL : POSITION; float3 normalL : NORMAL; float2 texC : TEXCOORD; }; struct VS_OUT { float4 posH : SV_POSITION; float3 posW : POSITION; float3 normalW : NORMAL; float2 texC0 : TEXCOORD0; float2 texC1 : TEXCOORD1; float fogLerp : FOG; }; VS_OUT VS(VS_IN vIn) { VS_OUT vOut; // Transform to world space space. vOut.posW = mul(float4(vIn.posL, 1.0f), gWorld); vOut.normalW = mul(float4(vIn.normalL, 0.0f), gWorld); // Transform to homogeneous clip space. vOut.posH = mul(float4(vIn.posL, 1.0f), gWVP); // Output vertex attributes for interpolation across triangle. vOut.texC0 = vIn.texC; vOut.texC1 = mul(float4(vIn.texC, 0.0f, 1.0f), gTexMtx); float d = distance(vOut.posW, gEyePosW); vOut.fogLerp = saturate( (d - gFogStart) / gFogRange ); return vOut; } float4 PS(VS_OUT pIn) : SV_Target { // Get materials from texture maps. float alpha = gDiffuseMap.Sample( gTriLinearSam, pIn.texC0 ).a; // Discard pixel if texture alpha < 0.1. Note that we do this // test as soon as possible so that we can potentially exit the shader // early, thereby skipping the rest of the shader code. clip(alpha - 0.1f); float4 diffuse = gDiffuseMap.Sample( gTriLinearSam, pIn.texC1 ); float4 spec = gSpecMap.Sample( gTriLinearSam, pIn.texC1 ); // Map [0,1] --> [0,256] spec.a *= 256.0f; // Interpolating normal can make it not be of unit length so normalize it. float3 normalW = normalize(pIn.normalW); // Compute the lit color for this pixel. SurfaceInfo v = {pIn.posW, normalW, diffuse, spec}; float3 litColor = ParallelLight(v, gLight, gEyePosW); // Blend the fog color and the lit color. float3 foggedColor = lerp(litColor, gFogColor, pIn.fogLerp); return float4(foggedColor, alpha); } technique10 FogTech { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }