您的位置:首页 > 其它

Directx11教程十五之Fog(雾)

2016-10-13 16:01 369 查看
首先的本节教程旨在实现雾的特效,程序结构跟SpecularMap那节教程差不多,如下所示:



第一,雾的简介和原理。

雾的实现能帮助游戏实现一种朦朦胧胧的感觉,并且由于视锥体的存在,有些靠近视锥体但是没在视锥体内的物体,进入视锥体后在视觉上有种非常突兀的感觉,如果能在远处附着上一些雾,可减弱物体突然进入视锥体的突兀感。
来看看雾的计算原型模型:



假设雾气因子为FogFactor,E点位摄像机的位置,P点位看到的点的位置,dis(P,E)为相机和看到的点之间的距离。

则存在三种雾模型:

(1)线性雾:线性雾指的的以眼睛(Camera)和看那到的点之间的距离为计算,雾的强度是随距离的距离变换而呈现线性变换。

线性雾的计算公式

                 FogFactor=(FogEnd-dis(P,E))/(FogEnd-FogStart);
               其中FogEnd=FogStart+FogRange;

(2)指数雾:线性雾指的的以眼睛(Camera)和看那到的点之间的距离为计算,雾的强度是随距离的距离变换而呈现指数变化

指数雾的计算公式

                  FogFator=1.0/2.71828power(dis(P,E)*FogDensity);
                其中FogDensity为雾的密度。

(3)指数平方雾:跟指数雾差不多

指数平方雾的计算公式

     FogFator=1.0/2.71828power((dis(P,E)*FogDensity)*(dis(P,E)*FogDensity));

                           其中FogDensity为雾的密度。

计算出雾气因子(FogFactor)之后,将计算场景颜色,假设场景物体的颜色为SceneColor,最终输出的颜色为color

           color=FogFactor*SceneColor+(1-FogFactor)*FogColor;

            其中FogColor为雾气的颜色

下面看看我的shader代码:
Texture2D ShaderTexture[3];  //纹理资源数组
SamplerState SampleType:register(s0);   //采样方式

//VertexShader
cbuffer CBMatrix:register(b0)
{
matrix World;
matrix View;
matrix Proj;
matrix WorldInvTranpose;
};

cbuffer CBLight:register(b1)
{
float4 SpecularColor;
float4 AmbientColor;
float4 DiffuseColor;
float3 LightDirection;
float SpecularPow;
};

cbuffer CBCamera:register(b2)
{
float3 CameraPos;
float Pad;
};

cbuffer CBFog:register(b3)
{
float FogStart;
float FogEnd;
float pad1;
float pad2;
};

struct VertexIn
{
float3 Pos:POSITION;
float2 Tex:TEXCOORD0;  //多重纹理可以用其它数字
float3 Normal:NORMAL;
float3 Tangent:TANGENT;
float3 Binormal:BINORMAL;
};

struct VertexOut
{
float4 Pos:SV_POSITION;
float3 Pos_W:POSITION;
float2 Tex:TEXCOORD0;
float3 Normal_W:NORMAL;
float3 Tangent_W:TANGENT;
float3 Binormal_W:BINORMAL;
float3 LookDirection:NORMAL1;
};

VertexOut VS(VertexIn ina)
{
VertexOut outa;

//变换坐标到齐次裁剪空间(CVV)
outa.Pos = mul(float4(ina.Pos,1.0f), World);
outa.Pos = mul(outa.Pos, View);
outa.Pos = mul(outa.Pos, Proj);
outa.Tex= ina.Tex;

//将法线量由局部空间变换到世界空间,并进行规格化
outa.Normal_W = mul(ina.Normal, (float3x3)WorldInvTranpose);
outa.Normal_W = normalize(outa.Normal_W);

//将切向量由局部空间变换到世界空间,并且进行规格化
outa.Tangent_W = mul(ina.Tangent,(float3x3)World);
outa.Tangent_W = normalize(outa.Tangent_W);

//将切向量由局部空间变换到世界空间,并且进行规格化
outa.Binormal_W = mul(ina.Binormal, (float3x3)World);
outa.Binormal_W = normalize(outa.Binormal_W);

//求出顶点在世界空间的位置
float3 worldPos= (float3)mul(float4(ina.Pos, 1.0f), World);
outa.Pos_W = worldPos;

//计算出每个顶点到相机的单位向量,之后在光栅化阶段进行插值
outa.LookDirection =CameraPos.xyz - worldPos.xyz;
outa.LookDirection = normalize(outa.LookDirection);

return outa;
}

float4 PS(VertexOut outa) : SV_Target
{
float4 BasePixel;
float3 BumpNormal;  //隆起法向量
float4 color;
float DiffuseFactor;  //漫反射因子
float SpecularFactor; //镜面反射因子
float4 Specular; //镜面反射颜色
float4 SpecularIntensity; //镜面强度
float FogFactor;

//增加漫反射光颜色
color = AmbientColor;

//求每个像素的纹理像素颜色
BasePixel = ShaderTexture[0].Sample(SampleType, outa.Tex);

//求每个像素的隆起法向量(切线空间)
BumpNormal=(float3)ShaderTexture[1].Sample(SampleType, outa.Tex);
BumpNormal = (2.0f*BumpNormal) - 1.0f;

//-----求出TBN矩阵(已经和世界变换矩阵结合在一起)--------
float3 N = outa.Normal_W;
float3 T = outa.Tangent_W;
float3 B = outa.Binormal_W;

//将隆起法向量由切线空间变换到局部空间,再到世界空间,然后规格化
//BumpNormal= mul(BumpNormal,float3x3(T,B,N));
BumpNormal = N + BumpNormal.x*T + BumpNormal.y*B;
BumpNormal = normalize(BumpNormal);

//求出漫反射因子
float3 InvLightDirection = -LightDirection;
DiffuseFactor = saturate(dot(BumpNormal, InvLightDirection));
color += DiffuseColor*DiffuseFactor;
color = saturate(color);

//乘以基础纹理颜色
color = color*BasePixel;

//如果漫射因子为正时,漫反射光和镜面才存在意义
if (DiffuseFactor > 0)
{

//求出入射光的反射向量,此时的法线量应该为法线贴图的法向量,别把参数位置搞反了
float3 ReflectLightDir = normalize(reflect(LightDirection,BumpNormal));
//float3 ReflectLightDir = normalize(2 * DiffuseFactor*BumpNormal - InvLightDirection);
//求每个像素的镜面强度
SpecularIntensity = ShaderTexture[2].Sample(SampleType, outa.Tex);

//求出镜面反射因子
SpecularFactor = pow(saturate(dot(outa.LookDirection, ReflectLightDir)), SpecularPow);

//求出镜面颜色,为什么这里用不上SpecularColor??
Specular = SpecularFactor  *SpecularIntensity;
color = color + Specular;  //确实只有镜面光被计算 才加上

}
color = saturate(color);

//求出相机到像素点的距离
float EyeToPixelDistance = length(CameraPos - outa.Pos_W);

//计算出线性雾气因子
FogFactor = (FogEnd - EyeToPixelDistance) / (FogEnd - FogStart);

//计算融合雾气后的颜色
float4 FogColor = float4(0.5f, 0.5f, 0.5f, 1.0f);
color = FogFactor*color + (1 - FogFactor)*FogColor;

return color;
}


其中背后缓存清除为灰色背景(0.5f,0.5f,0.5f,1.0f);
//第一,清除缓存开始绘制场景,清除背后缓存为灰色,模拟雾的背景
mD3D->BeginScene(0.5f, 0.5f, 0.5f, 1.0f);


我的程序运行图:




你看距离立方体我们近处部分看的比远处部分要清楚。不过最后得记得清楚背景为灰色,要不输出的效果不够模拟雾天气,
如图:背景颜色为黑色的



最后我的源代码链接如下:

点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: