ShaderOne的体积雾
ShaderOne的体积雾
ShaderOne 是Unity商店的一个shader资源,作者期望把所有的渲染特性集合到一个shader上去,所以起个名字叫 ShaderOne。
本人其实比较反对这种 All In One 的shader,因为变种实在太多,优化起来比较蛋疼,不过作为一个学习资料还是挺好的。
今天我们来看一下他的 体积雾 的实现,先上截图:
核心代码
说到体积雾,大家的第一个印象就是费。
没错了,指望 ShaderOne 的 体积雾 能在手机上跑得飞起是有点强人所难的,因为计算涉及到 射线步进 和 3d纹理采样。
不过如果射线数设置的不那么高,高端手机还是可以一战的,文章的最后会给出一个测试。
在介绍 体积雾 之前,我们先看一下 ShaderOne 提供的全部雾效类型,应用雾效的入口代码如下:
inline void FogApply ( inout SOLightingData i_sold, in v2f i )
{#ifdef SO_GD_BASE_PASS#ifdef SO_GD_FOG_SOLIDFogApplySolid ( i_sold, i );#endif#ifdef SO_GD_FOG_VOLUMETRICFogApplyVolumetric ( i_sold, i );#endif#ifdef SO_GD_FOG_VOLUMETRIC_3DFogApplyVolumetric3D ( i_sold, i );#endif#endif
}
可以看到 ShaderOne 提供了3种雾:
- FogApplySolid:线性雾
- FogApplyVolumetric:线性雾 + 指数高度雾
- FogApplyVolumetric3D: 线性雾 + 3d指数高度雾
FogApplySolid
FogApplySolid 就是最简单的 线性雾,提供的参数就三个:颜色、开始距离、结束距离。
代码简单到不想废话:
inline void FogApplySolid ( inout SOLightingData i_sold, in v2f i )
{
#ifdef SO_GD_BASE_PASS
#ifdef SO_SF_FOG_ON
#ifdef SO_GD_FOG_SOLIDhalf dist = distance ( _WorldSpaceCameraPos.xyz , i.positionWorld );half distFade = 1.0 - clamp ( ( _FogEndDistance - dist ) / _FogSolidDistance, 0.0, 1.0 );i_sold.finalRGBA.rgb = lerp ( i_sold.finalRGBA.rgb, _FogColorFade, distFade );
#endif
#endif
#endif
}
FogApplyVolumetric
FogApplyVolumetric 是 指数高度雾 再混合之前的 线性雾。
这里除了之前的线性雾参数之外,又加了高度雾参数。可以看到雾有高低和远近的过渡,并且有2种雾色。
关于指数高度雾,这里的计算公式如下:
fogAmount = 1.0 - exp ( -dist * ( fogHeightIntensity * _FogDensity ) );
这里的公式和Unity的 Exponential 雾类似,只是多了一个 fogHeightIntensity 这个高度因子。
fogHeightIntensity 的计算公式类似线性雾,不过是算的是高度:
fogHeightIntensity = ( 1.0 - min ( ( length ( i.positionWorld.y - _FogHeight ) / _FogHeightSize ), 1.0 ) );
最后雾效和场景颜色的混合计算,是先算指数高度雾,后算线性雾,代码如下:
i_sold.finalRGBA.rgb = lerp ( i_sold.finalRGBA.rgb, fogColor, fogAmount );
i_sold.finalRGBA.rgb = lerp ( i_sold.finalRGBA.rgb, _FogColorFade, distFade );
代码还是比较清楚的,市面上大部分手游的雾效和这个类似,只是计算公式可能有一点差别。
FogApplyVolumetric3D
最后来看一下 FogApplyVolumetric3D,也就是 体积雾。
FogApplyVolumetric3D 和 FogApplyVolumetric 的设置差不多,多了一些体积雾相关的参数,还有一个全局的射线数量需要设置:
两者的计算流程也非常相似,指数雾部分的公式如下:
fogAmount = 1.0 - exp ( -dist * fogAmount );
不过这里 fogAmount 的计算和 FogApplyVolumetric 相比就比较复杂了:为了平滑的勾勒出体积,这里需要依靠 射线步进,主要代码如下:
fogAmount = 0;for ( int i = 0; i < SO_GD_FOG_RAYCOUNT; i++ )
{rayPos += viewDir * stepSize;fogValue = tex3D ( _FogTexture3D, ( rayPos * _FogScale ) + fogUVOffset ).a;#ifdef SO_GD_FOG_ROUGHNESS_ONfogYLength = length ( rayPos.y - ( _FogHeight + ( ( fogValue - 0.5 ) * _FogVerticalRoughness ) ) );#elsefogYLength = length ( rayPos.y - _FogHeight );#endifheightIntensity = 1.0 - min ( ( fogYLength / _FogHeightSize ), 1.0 );fogAmount += fogValue * heightIntensity;
}fogAmount = ( fogAmount / SO_GD_FOG_RAYCOUNT ) * _FogDensity;
上述代码的大致计算流程如下:
从摄像机向场景发射 SO_GD_FOG_RAYCOUNT 条射线,这里的 SO_GD_FOG_RAYCOUNT 即前面的全局射线数,这个值越高效果越好,当然也越费。
每一条射线从摄像机点沿着 viewDir 方向逐步向前探测 stepSize 段距离,并且从一个预定的3d纹理 _FogTexture3D 去采样雾的密度。
最后把这么多根射线的采样结果加权平均,得出 fogAmount。
关于_FogTexture3D
可以看到,雾的体积由 _FogTexture3D 这张3d纹理决定。
_FogTexture3D 是一个3维的噪声图,如果我们想要自己调整噪音参数,可以借由作者提供的一个工具:Fog Texture Designer。
这个工具依赖另一个Unity的插件:FastNoise,具体细节可以参考插件源码,这个不是本文的重点。
关于stepSize的计算
前文提到 射线步进 的步长是 stepSize,stepSize 的计算方式如下:
dist = length ( _WorldSpaceCameraPos.xyz - i.positionWorld ) - _FogOffset;
distFade = 1.0 - clamp ( ( _FogEndDistance - dist ) / _FogSolidDistance, 0.0, 1.0 );
stepSize = dist / (float)SO_GD_FOG_RAYCOUNT;
这里比较简单,把dist按照射线数等分即可。
关于SO_GD_FOG_RAYCOUNT
SO_GD_FOG_RAYCOUNT 控制射线的数量,这个参数对体积雾的质量影响较大,下图是只发3条射线的计算结果:
可以看到之前的平滑过渡出现了断裂。
关于Fog Roughness
Fog Roughness 通过给高度增加扰动来增加雾的高低起伏,计算代码如下:
#ifdef SO_GD_FOG_ROUGHNESS_ONfogYLength = length ( rayPos.y - ( _FogHeight + ( ( fogValue - 0.5 ) * _FogVerticalRoughness ) ) );
#elsefogYLength = length ( rayPos.y - _FogHeight );
#endifheightIntensity = 1.0 - min ( ( fogYLength / _FogHeightSize ), 1.0 );
下图是 Fog Roughness 设置为0和设置为16的效果对比:
移动设备的帧率
体积雾就介绍到这里了。
最后,看看哥的 小米MIX2 是否可以一战。
24条射线,Roughness不开很高的情况下,稳稳60帧,效果也能接受,如下图:
个人主页
本文的个人主页链接:https://baddogzz.github.io/2020/01/06/Volumetric-Fog/
好了,拜拜。
ShaderOne的体积雾相关推荐
- 【Shader特效10】体积雾特效的使用
说在开始 这里主要讲解一下体积雾的算法和相关的知识.在许多大型游戏中都可以看到体积雾的身影,体积雾是飘动的,实现的效果也是距离摄像机越远雾的浓度也就越大.这里介绍一套数学模型相对比较简单的体积雾,可以 ...
- unity沙子堆积_unity游戏动态体积雾沙尘暴管理渲染插件Dynamic Fogamp;Mist 6.5 - 素材巷...
unity游戏动态体积雾沙尘暴管理渲染着色器Dynamic Fog&Mist 6.5,是一种相机脚本和全屏图像后处理效果,可在游戏场景中添加实时的.移动的雾和天空薄雾,使其不那么枯燥乏味. D ...
- Unity-VolumeLighting组件(体积雾/光效果)使用小记
Unity的实例<Neno>就使用了VolumeLighting 组件 突然发现了Unity提供的一个开源组件VolumeLighting ,简单记一下用法. 下载地址:https://g ...
- 体积光,体积雾——链接
http://www.lsngo.net/2017/10/22/unityshader_volumetriclight/?gqfwls=qb0ac3 https://zhuanlan.zhihu.co ...
- Unity实现体积雾与体积光
Unity实现体积雾与体积光 大家好,这次给大家分享在Unity中实现体积雾与体积光,先来看一下效果
- ue4 体积光与体积雾 快速入门
因为最近项目上需要用到体积雾气 所以看了下ue4 4.16的新特性,如果项目上有这种需求,强烈建议最低版本4.16 当然如果项目要求更高建议上4.18有对光雾效果有更好的控制(这里就不展开了,用的 ...
- 3dmax:3dmax经典案例详细步骤图文教程之环境特效大气效果体积雾效果
3dmax:3dmax经典案例详细步骤图文教程之环境特效大气效果体积雾效果 目录 环境特效大气效果体积雾效果 环境特效大气效果体积雾效果
- 10_ue4丁达尔效应(光束)与体积雾
1.先看光束遮挡 对比效果: 无光束遮挡 有光束遮挡 可以调节遮挡暗度来变换效果. 2.丁达尔效应(光束): 通过增加遮挡暗度参数值,来显现光束 第二种方法: 增大体积散射强度. 3.光束泛光: ...
- Vulkan_片元着色器特效1(体积雾)
我们在之前做过的案例:Vulkan_动态地形细分(Tessellation Shader)(本次特效也是基于此场景实现)中介绍过简单的雾特效,通过它可以模拟很多现实世界中与雾.烟等相关的场景.但是简单 ...
最新文章
- CCD工业相机、镜头倍率及相关参数计算方法
- java 隐藏参数,如何在没有JVM参数的情况下隐藏java 9中的“...
- 探讨ASP.NET 2.0中的Web控件改进技术(3)
- 软件工程第二次作业——模仿主流网站:搜狗输入法
- 代理模式——静态代理,动态代理(JDK代理和CGLib代理)
- java单元测试总结
- 《伟大的小细节:互联网产品设计中的微创新思维》——
- lstm原始论文_有序的神经元——ON-LSTM模型浅析
- linux mysql-5.7.13 源码安装,Linux下安装-配置-mysql-5.7.13
- Android-JNI开发系列《一》-动态库的函数注册
- Sicily 1029. Rabbit 解题报告
- Gazbo下的无人车集群导航仿真
- (转)开源GIS总结(一)——总结
- Centos 7环境MySql8.0.28源码安装
- 具体案例 快速原型模型_快速原型模型
- 关于java一些星号三角形的实现
- 控件库中的Botton控件简述
- AD软件自动添加原理图标注
- Vue使用Router报错:ncaught ReferenceError: VueRouter is not defined
- 有自学能力的人,赚钱极其简单—来福宝盒