一个简单的自定义顶点雾Shader
本文首发于知乎专栏:MACK的游戏开发笔记,欢迎各位关注。
因为新手引导的需要,镜头会有些改变,某些时刻会看的比较远需要雾效来遮挡一下。因为场景使用了我们TA写的伪PBR Shader,因此不能使用Unity的雾效,实现了一个类似的基于深度和高度的顶点雾,并做了一些特殊修正。虽然相比与体积雾来说有些过时,但是在手机上效果还不错,性能开销也非常低,与像素雾相比效果也差不多。
补充:
关于Fixed的问题,官方的文档,关于shader性能里面有写:Fixed precision is generally only useful for older mobile GPUs. Most modern GPUs (the ones that can run OpenGL ES 3 or Metal) internally treat fixed and half precision exactly the same.
因此对于老的设备Fixed是有效的、支持的,新的设备Unity会自动转成half。我们的目标用户是千元机,有很多比较老的设备。另外实际使用下来Fixed也没有出现问题(老的设备会有fixed精度,不同设备还不一样,有10bit和12bit两种)。
没想到随手写了一个简单的shader也引起这么多讨论,都是就精益求精的人,魔鬼藏在细节中没一个细节都不放过。其实如果了解渲染管线的原理,找几篇paper很多功能效果都能实现,但真正难得是在在实际应用中使用,能高效稳定的运行,能极致优化,能集成到工作流中等等,需要极大的耐心和毅力去应对各种问题和繁琐的修改迭代。
我的理念是技术是为产品服务的,不一定要选择数学最正确最牛逼的技术,而是要选择适合自己的方案,满足产品的需要,首先实现出功能再不断迭代和打磨。而对技术本身是应该持有怀疑的态度球根问底。
代码如下,因为有多个版本的Shader,将雾效的代码封装成一个函数:
CGINCLUDE
uniform fixed _DepthFogStart;
uniform fixed _DepthFogRange;
uniform fixed _DepthFogDensity;
uniform fixed _HeightFogStart;
uniform fixed _HeightFogRange;
//************************************************************************
// Method : CalculateFog
// Description : 计算雾
// Parameter : float3 _f3WorldPos -> World空间坐标
// Returns : float 雾的系数
// Author : Mack Han
//************************************************************************
inline fixed CalculateFogVS(fixed3 _f3WorldPos)
{
fixed3 f3Distance = _f3WorldPos - _WorldSpaceCameraPos;
fixed fDepthFog = saturate((length(f3Distance) - _DepthFogStart) * _DepthFogRange);
fDepthFog *= _DepthFogDensity;
fixed fHeightFog = saturate((_HeightFogStart - f3Distance.y) * _HeightFogRange);
return saturate(fDepthFog + fHeightFog);
}
ENDCG
这里为了需要将深度雾和高度雾拆分出来,深度依据顶点到到摄像机的距离,根据传入的用户参数计算,而高度雾之考虑顶点和摄像机Y轴的距离,最后混合深度和高度雾效。
在VS里输出顶点雾效的参数:
o.uv.z = CalculateFogVS(wPos); //-计算雾效
在PS的最后一步使用雾效系数混合像素的颜色和雾效的颜色:
finalColor = lerp(finalColor, _sceneHeightFogColor, i.uv.z);
可以实时编辑,编辑模式如下:
最终效果如下: