描边效果

本文简单归纳总结整理了关于各种思路的ShaderLab中的描边效果的实现。

描边效果常见于一些非真实感的渲染中。下图是本人在测试各种描边方法实现时在Unity中的表现:

第一行:Back Facing描边

这种方法的思路十分简单,将每个顶点的位置沿着法线的方向进行扩展。

过程实现非常简单,理论上讲,先把顶点坐标转换到裁剪空间,然后将法线坐标变换到视角空间后,直接讲顶点的位置的xy分量(xyz也行)加上对应的法线坐标。这个加法的结果就是所有的点沿着法线方向”膨胀”了一定的位移。然后把膨胀后的模型直接渲染成纯色,之后再正常的渲染模型,这样两层叠加后看起来就是喵了个边。

.

此处实例是将模型简单设置成了白色 描边设置为黑色。如果想要控制描边的粗细,其实就是控制模型膨胀的程度,那么定义一个变量与计算膨胀的顶点坐标中的法线参数相乘,就可以通过这个参数的大小控制描边粗细。

但是这个描边效果有两个问题:
1、对于正方体这种,转角处法线方向突变的情况,相当于周围面片飘了起来
2、随着摄像机靠近物体,会发现描边也是跟着变粗的,当然这个不能算问题,可以作为一种特性。

第一个图的第二行就是解决了上述两个问题的情况

第二行:临时更改法线信息

对于第一个问题,很清楚是因为法线完全垂直于平面,往外扩张之后还是垂直的,然后出现转角的时候就出现了断裂。正方体甚至正面完全看不见,因为就是渲染了一个平面。

所以我们可以临时修改法线的信息来实这种情况的描边。将每个顶点在同一个位置的不同的法线信息数据进行平均计算,计算出新的临时法线信息。

此处牵涉到一个新的问题,如果模型有骨骼动画,那么法线的数据会随着骨骼动画变化。如果模型使用了骨骼动画,那么需要将法线和切线数据写进mesh。如果不需要可以直接在顶点着色器中进行变化。如果要对mesh进行改变需要脚本进行。此处选择在脚本中操作。

实现的主要思路是通过Unity的API读取到mesh的顶点相关信息,然后自定义一个字典来进行每个顶点对应的法线向量的判断,将一个顶点的不同面的法线进行相加然后标准化(此处的几何意义很明显不解释了)。这样可以得到一个比较”温和”的转折处的法线,然后再进行扩张,可以得到很好的效果。

关于第二个问题其实很简单,因为是在视角空间进行的操作,随意会对摄像机产生随距离变化的情况。如果把描边改成NDC空间就会解决这个问题。

转换到NDC空间会遇到新的问题,众所周知Unity采用OpenGL的NDC空间,是个标准正方体,但是屏幕一般是16比9,所以我们要对x坐标进行修正。具体实现就是x坐标乘屏幕宽高比。

完成上述的操作后就获得了比较好的描边效果,这种描边不是完全的轮廓边界,因为在渲染描边的时候Z缓冲写入没有关闭。

第三行:关闭Z缓冲的Back Facing

如果我不想要前面的部分会出现局部描边,而是完全的只有外部轮廓有描边的话,就需要关闭描边的Z缓冲写入,这样就会被后渲染的图形完全遮挡,就会得到想要的效果。

第四行:关闭Z缓冲的法线修改

这个是在临时修改法线的基础上关闭了描边的Zbuffer写入。

此外需要注意,在进行Z缓冲关闭的时候,由于默认 的渲染顺序是先于skybox的顺序的,所以渲染skybox后会遮掉描边,需要更改渲染队列的顺序,放在skybox之后。

源码地址:https://github.com/muchenhen/MyUnityShaders/tree/master/Assets/Unreality/01%E6%8F%8F%E8%BE%B9%E6%95%88%E6%9E%9C%20%E5%90%84%E7%A7%8D%E5%B0%9D%E8%AF%95

Author: 木尘痕
Link: https://muchenhen.com/2020/03/07/%E6%8F%8F%E8%BE%B9%E6%95%88%E6%9E%9C/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.