Unity Shader - 深度图基础及应用

2024-05-17 09:13

1. Unity Shader - 深度图基础及应用

 深度图里存放了 [0,1] 范围的 非线性分布 的深度值,这些深度值来自 NDC 坐标。   在延迟渲染中,深度值默认已经渲染到G-buffer;而在前向渲染中,你需要去 申请 ,以便Unity在背后利用Shader Replacement将RenderType为Opaque、渲染队列小于等于 2500 并且有 ShadowCaster Pass 的物体的深度值渲染到深度图中。
   第一步:在C#中设置Camera.main.depthTextureMode = DepthTextureMode.Depth;
   可以在主摄像机的Camera组件下看见提示:
                                           这表明了主摄像机渲染了深度图
   第二步:在Shader中声明_CameraDepthTexture
   第三步:访问深度图
   利用覆盖屏幕的uv值和深度图中的深度,我们可以重建出物体在世界空间中的坐标。   主要有以下两种方法:
   首先要在C#脚本中传递当前的VP逆矩阵:
   然后在Shader中首先制造NDC坐标:
   利用当前的VP逆矩阵将NDC坐标转换到世界空间:
   具体用法可以到下面的MotionBlur例子中查看。
   首先需要知道,Post Process实际上是渲染一个覆盖屏幕的Quad,因此屏幕四个角对应摄像机的视椎体四个角。   首先是算出摄像机到四个角的向量:
                                                                                                                           假设有个绿点在toTopLeft所在线上,利用相似三角形,可以得到:
   而depth是能够在Shader中获得的,因此我们只需要传递toTopLeft / near到Shader中就能计算出toGreen:
   在Vertex中判断出对应顶点所在的向量:
                                           可以看到uv值和对应的索引值正好是二进制的关系,所以可以如下求出:
   你可能奇怪这样只能求到4个角线上的点,但vertex到fragment的过程中是有个东西叫插值的,这个 插值 正好能把每个像素所在的向量求出。   然后我们就能在fragment中求出世界坐标了:
   具体的用法可以到下面的垂直雾效例子中找到。
   输出[0,1]范围的深度值即可,如下:
                                           思路是判断当前物体的深度值与深度图中对应的深度值是否在一定范围内,如果是则判定为相交。   首先访问当前物体的深度值:
   然后访问深度图。由于此时不是Post Process,因此需要利用投影纹理采样来访问深度图:
   最后就是进行相交判断:
                                           在相交高亮效果的基础上,加上 半透明 和 边缘高亮 ,就能制造出一个简单的能量场效果:
                                           思路是让雾的浓度随着深度值的增大而增大,然后进行的原图颜色和雾颜色的插值:
                                           思路与相交高亮效果类似,只是这里是Post Process。自定义一个[0,1]变化的值_CurValue,根据_CurValue与深度值的差进行颜色的插值:
                                           利用上面提到的第二种重建世界空间坐标的方法得到世界空间坐标,判断该坐标的Y值是否在给定阈值下,如果是则混合原图颜色和水的颜色:
                                           利用上面提到的第二种重建世界空间坐标的方法得到世界空间坐标,让雾的浓度随着Y值变化:
                                           思路是取当前像素的附近4个角,分别计算出两个对角的深度值差异,将这两个差异值相乘就得到我们判断边缘的值。   首先是得到4个角:
   然后是得到这4个角的深度值:
   最后就是根据对角差异来得到判断边缘的值:
                                                                                   运动模糊主要用在竞速类游戏中用来体现出速度感。这里介绍的运动模糊只能用于 周围物体不动,摄像机动 的情景。   思路是利用上面提到的重建世界坐标方法得到世界坐标,由于该世界坐标在摄像机运动过程中都是不动的,因此可以将该世界空间坐标分别转到摄像机运动前和运动后的坐标系中,从而得到两个NDC坐标,利用这两个NDC坐标就能得到该像素运动的轨迹,在该轨迹上多次取样进行模糊即可。   首先是得到世界坐标(这里使用提到的第一种重建方法):
   然后是计算出运算前后的NDC坐标:
   最后就是在轨迹上多次取样进行模糊:
                                           景深是一种聚焦处清晰,其他地方模糊的效果,在摄影中很常见。   思路是首先渲染一张模糊的图,然后在深度图中找到聚焦点对应的深度,该深度附近用原图,其他地方渐变至模糊图。   第一步是使用SimpleBlur Shader渲染模糊的图,这里我只是简单地采样当前像素附近的9个点然后平均,你可以选择更好的模糊方式:
   第二步就是传递该模糊的图给DepthOfField Shader:
   第三步就是在DepthOfField Shader中根据焦点来混合原图颜色和模糊图颜色:
    https://github.com/KaimaChen/Unity-Shader-Demo/tree/master/UnityShaderProject 
    Unity Docs - Camera’s Depth Texture     Unity Docs - Platform-specific rendering differences     神奇的深度图:复杂的效果,不复杂的原理     SPECIAL EFFECTS WITH DEPTH     GPU Gems - Chapter 27. Motion Blur as a Post-Processing Effect    《Unity Shader 入门精要》   《Unity 3D ShaderLab 开发实战详解》

Unity Shader - 深度图基础及应用