Unity Shader——Wireframe

发表于2018-04-23
评论0 3.3k浏览
昨天无意中看到群里有个小伙伴发的一张截图中有个 VR/Wireframe 的 shader,晚上便抽空下载了5.6.3 的 bulit-in 看看源码,Unity 还是良心,直接把理论资料注释在了代码的开头,是NVIDIA的一篇文章,像DX11本身提供了FillMode = D3D11_FILL_WIREFRAME选项,可以直接渲染网格,但NVIDIA认为这样渲染有诸多问题,文章比较了该技术和以前的双 pass Wireframe 渲染在各方面的优劣。当然,文章里说自己的技术基本上各方面全面领先,我也没有再去找以前的双 pass 渲染相关资料了。

整体的思路很简单也很明确,只渲染离三角形边缘距离在一定范围内的像素,那么怎么知道像素离边缘的距离呢,NVIDIA 通过在Geometry Shader中计算三角形在裁减空间中每个顶点到对边的距离,即三角形三条边的高,高很容易得到,两条边叉乘得到两倍面积,两倍面积再除以边长即可得到高:

将三条边的高传入 fragment shader,则在光栅化插值后,我们便可得到任一像素离三条边的距离:

最后,在fragment shader中取最小距离与预先设置的阈值做比较即可得到下面的结果:

可以看到,锯齿感比较严重,因此 NVIDIA 又加了一个调和函数做插值:


NVIDIA 选择了
,得到的效果如下:

最后,如果我们不取离三条边距离最小值,相对的,我们将代码改成
float minDistanceToEdge = min(i.dist[0], max(i.dist[1], i.dist[2])) * i.dist[3]; 

便可以得到没有对角线的网格:

更新一波

之前写的不画斜线的算法确实比较蛋疼,而且画出来效果也很挫,斜线会有一小段留在那,特别难看,前段时间突然想到这个东西,决定改一改,但智商捉急,思路依旧简单粗暴:

既然斜线通常都是三角形中边长最长的一条线, 那么干脆就在GS阶段把它的 index 标记出来然后传到 FS, 然后在 FS 算最小距离的时候,根据 GS 传过来的 Index 将斜边排除在外,这样,我们就得到了干净利落的正方形框线效果:

不过代码实在是有点挫的没法看了,GS 本身性能就不高,被我这么一整性能更低了, 暂时没想到特别优雅的实现方法。
来自:https://blog.csdn.net/notmz/article/details/77676290

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引