
对半透明与不透明物体相交部分进行一些效果处理也是比较常见的需求,在这里简单记录一下。
1.应用场景
- 下图中的半透明半球与不透明的圆柱,被圆柱穿过的边缘,半球会有紫色的效果。

2.下图中的右边半透明的河流与左边不透明的陆地,陆地边上的水会有边缘白沫和边缘白浪的效果。

2.原理
原理挺简单,想要实现上面提到的效果,就需要获得半透明和不透明物体相交的边界。所以用上面两个例子来说明。
- 将场景中的所有不透明物体全部渲染出来并进行深度写入。于是得到下面两张图。


- 渲染所有的半透明物体,例如场景1中的半球和场景2中的河流。由于目的是找到半透明物体和不透明物体的边界,常用的方法是通过线性深度来判断,通过比较场景中的半透明物体的线性深度与不透明物体的线性深度的差值,差值越小,越处于两者交界处。具体在Unity中,可以通过ComputeScreenPos获得齐次坐标系下的屏幕坐标值,范围是[0,w];再除以w之后,得到NDC下的屏幕坐标;再用这个坐标的xy逆变换到相机空间,对没有半透明物体的深度纹理进行采样并线性化,从而得到了不透明物体片元在相机空间的线性深度;然后对NDC下的屏幕坐标z值(半透明物体片元的非线性深度)线性化,得到半透明物体片元线性深度;最后,比较这两个线性深度的差值是否小于一个阈值即可找到边界。


3.示例代码
v2f
这个代码只是为了说明前面讲的原理,代码最后的distanceDepth即为线性深度差值。