描边Shader

写一个使3D物体带描边的shader是基于GPU的渲染的一项作业,关于这个作业有一些思考。

描边shader有很多种写法,最常见最通用的是法线外拓的方法,就是用两个pass,第一个pass渲染红色的放大版模型(之后用A pass表示),第二个pass渲染正常的物体(之后用B pass表示),这样正常物体渲染结果会盖住A pass的结果,但由于A pass把模型放大了,所以会露出旁边的一圈“描边”。

而如何放大模型?就是把模型顶点沿法线向外移动(移动距离用offset表示)。
为了方便看到A pass的情况,互换了两个pass的位置,用立方体做模型,得到如下情况。

发现A pass的前面在最顶层,接下来是B pass,最后是A pass的背面。因为默认开了Zwrite和Ztest,所以会根据顶点坐标的前后渲染。

那么给A pass设置剔除正面只渲染背面(Cull Front):

会发现因为顶点沿法线向外移动导致面片分开,使得描边不连续。(这个问题可以通过在模型导入面板中把法线设置为calculate解决)

换个复杂的模型:

由于模型复杂,有些面片虽然是背面的,但还是会穿透B pass的面片。
试想如果B pass能把A pass完全盖住就解决这个问题了。

于是把A pass移到B pass之前,同时设置Zwrite off,也就是说不管A pass的顶点在哪里,都会被B pass的渲染结果盖住,这样就解决了这个问题。