雾化这一节本应该放在局部光照那里的后面。
不过鉴于博客更新断了两个月,我觉得有必要跟着书动动手复习一下,雾化在原博客中没有提到,不过代码也非常简单,赶紧水一篇笔记。
代码承接Blending的工程
雾化
我们可以将雾化计算简化成两个半圆,分为内径和外径,内径为雾开始距离,外径为雾结束距离,两者之差为雾范围,只有在fogRange内才会计算雾的效果。
因此再定义一个float4:雾的颜色,只需要再添加这三个变量即可,不过别忘了内存对齐。
计算公式为C = lerp(C,gFogColor,saturate((disToEye - fogStart)/fogRange))
PS代码
// 像素着色器(3D)
float4 PS_3D(VertexPosHWNormalTex pIn) : SV_Target
{
// 提前进行裁剪,对不符合要求的像素可以避免后续运算
float4 texColor = g_Tex.Sample(g_SamLinear, pIn.Tex);
clip(texColor.a - 0.1f);
// 标准化法向量
pIn.NormalW = normalize(pIn.NormalW);
// 顶点指向眼睛的向量
float3 toEyeW = normalize(g_EyePosW - pIn.PosW);
// 初始化为0
float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 A = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 D = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 S = float4(0.0f, 0.0f, 0.0f, 0.0f);
int i;
// 强制展开循环以减少指令数
[unroll]
for (i = 0; i < g_NumDirLight; ++i)
{
ComputeDirectionalLight(g_Material, g_DirLight[i], pIn.NormalW, toEyeW, A, D, S);
ambient += A;
diffuse += D;
spec += S;
}
[unroll]
for (i = 0; i < g_NumPointLight; ++i)
{
ComputePointLight(g_Material, g_PointLight[i], pIn.PosW, pIn.NormalW, toEyeW, A, D, S);
ambient += A;
diffuse += D;
spec += S;
}
[unroll]
for (i = 0; i < g_NumSpotLight; ++i)
{
ComputeSpotLight(g_Material, g_SpotLight[i], pIn.PosW, pIn.NormalW, toEyeW, A, D, S);
ambient += A;
diffuse += D;
spec += S;
}
float4 litColor = texColor * (ambient + diffuse) + spec;
float disToEye = length(g_EyePosW - pIn.PosW);
float fogLerp = saturate((disToEye - g_FogStart) / g_FogRange);
litColor = lerp(litColor, g_FogColor, fogLerp);
litColor.a = texColor.a * g_Material.Diffuse.a;
return litColor;
}
别忘了在cpp中补齐对应的常量缓冲区变量。