【雾】初探雾效果!shader 源码分析与讲解!

初探雾效果!shader 源码分析与讲解! Cocos Creator 3D Shader Fog !

随便讲讲雾的原理以及旧版本的使用雾的方法。

效果

原理

雾效(fog)是游戏中常用的一种效果,根据远近产生不同的深度的雾效果。

这个效果涉及两个关键字。

  • 距离
  • 颜色

在着色器中,雾效的距离,一般转成换计算雾效因素(factor_fog),这个数字范围是0-1

  • 1 表示完全不受雾影响
  • 0 表示完全被雾笼罩

接着再根据这个雾效因素去计算颜色,混合当前颜色color和雾factor_fog的颜色即可。

mix(cc_fogColor.rgb, color.rgb, factor_fog)

接下来就是如何去计算这个雾效因素了。

雾效因素一般是通过由摄像机位置(cc_cameraPos)和当前点位置(世界坐标,由世界空间矩阵和模型坐标计算的wPos)的距离去计算的。

float cam_dis = distance(cc_cameraPos, wPos);

不同的雾效果,采用不同的方式去计算雾效因素。

线性雾

线性一般会有两个参数去计算。雾开始的地方fogStart和雾最远的地方fogEnd

  • 当距离小于雾开始的地方,表示没有雾,即雾效因素为1
  • 当距离大于雾最远的地方,完全被雾给覆盖了,即雾效因素为0

factor_fog = clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);

当然也可以改造一下,在0-1之间平滑一些。

factor_fog = 1.0 - smoothstep(fogStart, fogEnd, fogDistance);

指数雾

指数雾就是用指数函数根据距离计算雾效因素。

一般会有一个雾浓度fogDensity去控制这个指数函数。

一般指数雾:

factor_fog = exp(-cam_dis * fogDensity);

平方指数雾:

factor_fog = exp(-cam_dis * cam_dis * fogDensity * fogDensity);

层级雾

层级雾计算过程相对复杂,大致过程就是计算水平面的距离和高度距离以及浓度参数,具体实现过程可以参考源代码 cc-fog.chunk

fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;

factor_fog = exp(-fDensity);

移植

Cocos Creator 3D v1.2 版本之前还未提供雾效果,那么该如何移植或定制呢?

把控一个重点,雾效果的关键就是计算雾效因素。

因为材质默认使用的是 builtin-standard.effect,可以拷贝一份重新写个build-in-fog.effect,然后再将需要雾化的材质选择这个effect

先在顶点着色器中加一个雾效因素的计算方法。

out float v_fogFactor;
float computeFogFactor(float fogDistance){
    const float start = 1000.0;
    const float end = 3000.0;
    const float density = 0.0002;
    // return clamp((end-fogDistance)/(end-start), 0.0, 1.0); //雾化因子线性变化
    return 1.0 - smoothstep(start,end,fogDistance); //雾化因子非线性变化
    // return exp(-(density*fogDistance)); // 指数雾
    // return exp(-density*density*fogDistance*fogDistance); // 指数雾2
}

把雾效因素传给片元着色器。

v_fogFactor = computeFogFactor(length(cc_cameraPos.xyz - pos.xyz));

在片元着色器中接收雾效因素。

in float v_fogFactor;

计算混合颜色。

color.rgb = mix(fogColor, color.rgb, v_fogFactor); 

效果预览(示例项目 CCC_3D_v1.1.2_雾 @白玉无冰.zip (2.0 MB) ):

小结

fog ! 计算雾效系数 !混合颜色 !shader

以上为白玉无冰讲解 Cocos Creator 3D v1.2 中的 "雾效果(fog)原理解析" 的技术分享。欢迎分享给身边的朋友!

天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。人之为学有难易乎?学之,则难者亦易矣;不学,则易者亦难矣。

相关帖子

3d 版本雾

2.x 版本雾

更多论坛分享

更更更多分享导航

更多(点图片直达)

噪声纹理之消融效果
流体之 LiquidFun 流体纹理 shader
3D瞄准器
gizmo与多边形裁剪
3D摇杆
两种方法实现亮度/饱和度/对比度的调整
物理挖洞系列
四叉树与碰撞检测 !
shader顶点动画之旗子水纹
2D实现背景图3D滚动效果
画线纹理之绳子
█ 原创文章导航 █

11赞

老弟 :ox:

优秀优秀优秀

mark!

:ox::beer:mark

优秀优秀优秀

不知道这样的思路可行吗?

  1. 先将3D场景渲染到RenderTexture,
  2. 再将RenderTexture以Sprite渲染到Canvas中
  3. 因为看到RenderTexture中,有DepthStencilFormat,所以想问下,有没有办法,在Sprite的shader中获取深度缓冲的数据,以在Sprite中实现雾效

(不知道怎么在Sprite的Shader里获取RenderTexture的深度信息)

mark!!!

白玉无冰的理解是 RenderTexture 已经变成了像一张纸的图片了,没有原来的顶点那些数据了,就像你拍了一张照片一样。

DepthStencilFormat 猜测是深度测试和模板测试 用来裁剪用的,并没有原先场景中的信息了。

:joy:个人看法,欢迎讨论。