
本来是打算做成视频的,但发现1分钟可能不够就改成文章的形式了。

风格化尝试
线框的效果我们肯定都不陌生,在unity scene窗口我们选中物体的时候便会看见。从美术的角度上看,看到这类效果,实现上可能会直接考虑直接建模出线框框架或者配合相应的贴图控制alpha来制作,当然这是一种可行的做法,而且可以更加自由的控制线框粗细来达到更好的效果。但同时这对美术大大们会产生额外的工作量,我们可以尝试从渲染的角度直接来绘制效果。
这里我使用的是几何着色器(Geometry shader)的方法来实现这种效果,关于几何着色器的相关概念还请自行查阅,注意使用gs需要保证平台支持sm4.0.我们利用几何着色器获取mesh中的三角面,并尝试在三角边中内侧画线来达成效果。为了在三角形内侧画线,我们需要得到片元在视口空间中与每个三角边的距离并根据这个距离去绘制靠近三角边的片元。我们可以通过重心坐标插值(barycentric coordinates)后的数据来实现,关于这个插值过程的相应资料我将放在文末,想了解的可以去看看。

barycentric coordinates
我们利用gs指定输入图元类型为三角形,并输出相应的三角形带。注意指定最多的输出顶点数,我们仅仅绘制以3个顶点组成的三角形带,所以只需要指定顶点数为3即可。接下来在gs中向每个三角形添加此坐标信息,表示三角形的三个高,插值到片元着色器后我们便可以得到此片元和三边的距离。


Geometry shader
我们在ps输出插值后的结果确认一下。

好啦到这一步我们已经得到了片元与三角边的距离,接下来我们取片元离最近的边的距离并通过阈值去控制片元的显示,这样我们就可以得到一个基本的线框效果。

wireframe1
我们可发现背面被剔除了,这样不符合心中的理想效果,于是再添加一个pass剔除正面渲染一遍。

wireframe2
但是我们可以发现这锯齿感也太明显了吧,虽然对于细线条来说锯齿感难免,我们还是要试着去aa一下。

aa

wireframe3

OK,到目前为止一个基本的线框渲染效果就已经完善了,我们可以将它应用其他模型上去做很多特殊的效果。接下来我们尝试着去完善和改进下效果,可以发现线框组成都是三角面,看起来不太干净,那如果想要像建模软件那样展现四边面该如何做呢?
首先gs中我们是无法获得四边面的,要展现四边面我们需要想办法剔除掉对角线。查询资料发现一种trick的方法,那就是寻找三角形最长的边然后剔除掉这个边(仔细想想就会发现这个做法的不正确,他默认了三角形最长边就是组成四边面的对角线)但是这个做法对于大部分模型拓扑都还是适用的。

剔除对角线

wireframe4
看起来还不错是不是,现在我们尝试着去拉伸这个球看一下结果。

scale后的错误剔除
可以看见在我们缩放球体后,剔除的对角线判断发生了错误。我们不想要这个结果,在上面代码中我们使用的是世界坐标判断的边长度,其会受到缩放影响,我们传入模型坐标来计算保持缩放前的剔除即可。

模型坐标计算边长

修正后的结果
目前为止大体已经实现完了,接下来我们考虑去加入一些风格化元素来提升效果。
虚线效果:

dotted line

dotted line
噪波叠加:

noise

noise
控制背面透明度:

backface alpha
项目地址:https://github.com/mxrhyx233/Unity-stylized-wireframe-rendering
参考文档:
https://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf
https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/rasterization-stage
https://github.com/mattdesl/webgl-wireframes
https://catlikecoding.com/unity/tutorials/advanced-rendering/flat-and-wireframe-shading/