高度雾、深度雾在Unity中的实现

好久没写新博客了,都是在老博客上修修补补,不能再这样划水了。今年在求职市场上兜兜转转了好久,腾讯网易进不去,那么还是老老实实做技术积累吧。。。

在CSDN上看到一篇做高度/深度雾的的博客,正好项目里也要用,所以想拿过来直接看看效果的,没想到大佬竟然放在百度云盘并且不给提取码。。。好吧,我自己来实现一遍吧= =

深度雾
顾名思义,根据深度的不同将雾的颜色不同程度的混合到场景颜色上,一般来说有三种不一样的混合公式,称之为Linear线性、Exp指数以及指数平方Exp2。Unity本身也实现了这三种雾,具体代码在UnityCG.cginc中。

#if defined(FOG_LINEAR)
    // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
    #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w
#elif defined(FOG_EXP)
    // factor = exp(-density*z)
    #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor)
#elif defined(FOG_EXP2)
    // factor = exp(-(density*z)^2)
    #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.x * (coord); unityFogFactor = exp2(-unityFogFactor*unityFogFactor)
#else
    #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = 0.0
#endif

自己来实现的话其实我们首先考虑的是后处理实现,毕竟要是用unity的方法处理,那么每个物体想混合雾的颜色就得去改每个物体的shader,这样实在太麻烦了,而且美术需求的定制化程度也不高,所以还是选择走后处理了。
后处理的话首先我们必须取到深度,开启深度图是必须的,然后进行采样并应用深度,关键代码如下

float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);

float dist = 0;
#if _DIST_TYPE_VIEWSPACE 
    dist = LinearEyeDepth(depth);;
#else
    dist = length(i.ray * Linear01Depth(depth));
#endif

float depthFactor = 0;
#if _FUNC_TYPE_LINEAR
    depthFactor = (_DepthEnd - dist) / (_DepthEnd - _DepthStart);
#elif _FUNC_TYPE_EXP
    depthFactor = exp(-(_Density * dist));
#else
    depthFactor = exp(-pow(_Density * dist, 2));
#endif

然后想让雾效动起来并且动的自然的话,添加噪声图和时间信息即可。

float noise = tex2D(_NoiseTex, wp.xz * _WorldPosScale + _Time.x * fixed2(_NoiseSpX, _NoiseSpY)).r;
depthFactor *= depthNoise;

这里的uv我使用的是通过屏幕像素还原出来的像素的世界坐标(当然读者在使用时也可以试试其他的uv),至于如何计算可以参考我的另一篇博客根据深度信息重建屏幕像素在世界中的坐标,核心代码就是

float3 wp = _WorldSpaceCameraPos.xyz + i.ray * Linear01Depth(depth);

这样depthFactor再乘上雾的颜色就得到了会流动的深度雾了。

视角和雾都调得丑了点,大家专注技术,无视美丑啊~

高度雾
既然有通过深度来将雾的颜色混合场景颜色的方法,那当然也有通过高度来做雾效的方法,关键是后处理时如何得到场景的高度。方法上面已经说了,核心就是这句代码

float3 wp = _WorldSpaceCameraPos.xyz + i.ray * Linear01Depth(depth);

得到世界坐标了那么y就是我们所需要的高度了。再按照上面的思路加上雾的流动效果就大功告成!关键代码如下

float noise = tex2D(_NoiseTex, wp.xz * _WorldPosScale + _Time.x * fixed2(_NoiseSpX, _NoiseSpY)).r;
float heightNoise = noise * _HeightNoiseScale;
float heightFactor = (_HeightEnd - wp.y - heightNoise) / (_HeightEnd - _HeightStart);
高度雾有点意思了

最后,我们希望雾不要去影响粒子特效这类半透明的物体,所以用了CommandBuffer来指定渲染的时机,代码如下

        cmd = new CommandBuffer();
        cmd.name = "Fog";

        int fogID = Shader.PropertyToID("_FogTex");
        cmd.GetTemporaryRT(fogID,-1,-1,24,FilterMode.Bilinear);
        int fogID2 = Shader.PropertyToID("_Temp");
        cmd.GetTemporaryRT(fogID2,-1,-1,24,FilterMode.Bilinear);
        cmd.Blit(BuiltinRenderTextureType.CurrentActive,fogID2);
        cmd.Blit(fogID2,fogID);
        
        cmd.Blit(fogID,fogID2,mat);
        cmd.SetGlobalTexture("_FogTex",fogID2);
        cmd.Blit(fogID, BuiltinRenderTextureType.CameraTarget,blend);
        cam.AddCommandBuffer(CameraEvent.BeforeForwardAlpha,cmd);

这里我本意是只想用一张RT来承载雾效的,不过试了一下在手机上会出现雾效不断叠加的效果,不是我想要的,不得已只好开了两张RT。。。
并且,初始化RT时要用cmd.Blit(BuiltinRenderTextureType.CurrentActive,fogID2);这句,不然你会深切感受到IMR和TBDR渲染机制的不同,各位可以把这句注释掉再在iPhone上打个包试试,就明白我在说什么了。

最后,放上项目地址,大家可以慢慢玩。

项目地址

参考
Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾
大萌喵的着色器特效第三发---垂直雾(Vertical Fog)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容