PISCOnoob

导航

Unity PostProcessing with Depth Texture

写在前面:

本文章为个人学习笔记,方便以后自己复习,也希望能帮助到他人。

由于本人水平有限难免出现错误,还请评论区指出,多多指教。

部分图元和素材来源于网络,如有侵权请联系本人删除。

参考资料与链接会在文章末尾贴出。

=======================================================================

1.Read Depth

首先我们需要camera生成depth buffer给我们使用,可以通过depthtexture mode flags来完成。不过我们不想改写一些由其他effect设置flags(翻译成标志位?),即保留现有的flags/values,同时生成新的效果,我们需要用到 | (bitwise or),简单来说就是两个数做bitwise or只要有一个是1结果就是1.

(1011)|(0101)=1111

more info about depth texture:

然后我们来写shader:

我们可以创建新的texture sampler来获取depth texture,像正常纹理一样采样即可,要注意的是depth texture是single value存储在r通道,其他通道为空。

       sampler2D _CameraDepthTexture;
            float4 frag (v2f i) : SV_Target
            {
               
               float finalCol = tex2D(_CameraDepthTexture,i.uv).r;
               
               return finalCol;
            }

我们摆好物体按下start后有可能game窗口会非常暗,甚至是黑色,这是因为这里的depth并非线性encode至1-0之间(物体越近相机值越大,亮度更高),而是近处的精度比远处更高(精度为32bit,平台不同可能会有差异)。因此当我们把镜头拉近物体时就会亮很多(如果仍然是漆黑一片可能你需要调整一下你camera的near clipping distance)。

接下来我们需要改变一下encode的方式,越靠近相机深度值越小,越暗,远处反之,线性encode至0-1。unity已经内置了这种encode的方法:

若出现下面这样所有物体一片黑,可以尝试降低camera far clipping plane的值

下一步我们将深度信息与相机设置分离开来,这样我们就可以再次更改它们而不会改变效果的结果。我们可以简单地将我们现在拥有的线性深度与远裁剪平面的距离相乘来实现这一点。在unity built-in shader variable里面有

_ProjectionParams, z分量就是远裁剪平面。

因为大多数物体与相机的距离超过一个单位,屏幕上的图像可能会将再次被白色占满,但我们现在可以使用一个独立于相机裁剪平面的值,且用我们可以理解的测量单位(unity单位)。

2.Generate Wave

这部分我们将会尝试制作一种扫描地形,或者说一种像波浪来回的效果。我们先定义wave与玩家的距离,wave的宽度以及波浪的颜色。

我们先粗略地把画面硬切为waveFront(画面上部)和waveRear(画面下部)。这里我们用step函数,如果第1个参数比较大则返回0,否则返回1。

 

 

然后定义waveRear,这里我们用smoothstep函数,有三个参数,如果第三个参数小于第一个参数则返回0,如果第三个参数大于第二个参数则返回1,其他情况则返回0-1之间。代码如下,因此,waveWidth这个部分效果是比较平滑的,而不是像之前一样硬切(hardcut)。

 

 

可以观察到,wave的前后部分是相反的,如果把值相乘,则前后部分都为0,只剩下waveWidth这部分是>0的,这里我们把waveWidth设为1。

 
 

现在我们已经定义了我们的wave,我们可以为图像带回颜色。为此,我们首先必须再次对源图像进行采样,然后根据刚刚计算的wave参数从源图像到waveColor进行线性插值。

 

如您所见,当距离到达远剪裁平面时,我们使用这种方法会产生伪影。尽管天空盒在技术上与远剪裁平面的距离很远,但我们不想在波到达它时显示它。

为了解决这个问题,我们在计算深度后立即读取源颜色,如果深度在远裁剪平面上,则立即返回它。

 

不过目前还有点小问题,到wave到达远裁剪平面时会有artifact。我们可以在计算深度后立即采样源图像,如果深度在远裁剪平面上就返回采样值。

我想做的最后一件事是扩展 C# 脚本以自动为我们设置距离并使其慢慢远离玩家。我想控制波浪的传播速度以及波浪是否处于活动状态。我们还必须记住波的当前距离。为此,我们在脚本中添加了一些新的类变量。

最后,我们来扩张一下C#脚本使其帮我们移动wave:

posted on 2022-11-02 09:33  PISCOnoob  阅读(52)  评论(0编辑  收藏  举报