问题表现
很多特效都会用叠加的渲染方式,如果面片出现重叠,那么这个特效就可能会叠加两次或以上。下面以贪吃蛇的蛇身体上的加速特效为例进行说明。
图1 重复叠加现象示意图
上图中放射状的黄色尖刺就是重复叠加特效的结果。
原因
直接原因是:
1, 有面片重叠
2, 使用叠加方式渲染
3, 关闭ZTest
在蛇身体的例子中,面片重叠的原因是蛇身弯曲的程度过大。
图2 未弯曲时的网格示意图
图 3 过度弯曲时的网格示意图
蛇身体在未弯曲时的网格如图 2所示。从图 3可以看到过度弯曲的时候,蓝色三角面片和黑色三角面片出现重叠。
常规解决方案
多次重复叠加的常规解决方案是:
1. ZWrite设为On
2. 所有面片在同一深度
3. 深度相同时不绘制
在蛇身体的例子中尝试这种常规解决方案如下图所示。
图4 常规解决方案
可以看到由于重复叠加产生的黄色尖刺确实没有了,但是有些区域的特效感觉莫名消失了。
究其原因,先看网格图:
图5 网格示意图
为了避免特效出现锐利的边缘,在身体左右两侧的特效需要有渐变,所以特效的网格比身体要宽很多。图中特效莫名消失的区域都是蛇身重叠的区域,有两层网格。在绘制渐变部分的时候,已经写入深度缓存了,导致在绘制第二层的时候,由于深度相同而选择不绘制。
可见常规解决方案并不能很好的解决问题。
分段式解决方案
现在出现了两种情况:
1. 蛇身过度弯曲的区域,重叠的特效需要只绘制一次
2. 蛇身重叠的区域,重叠的特效需要都绘制
在这个例子里,能用来区分到底是蛇身过度弯曲的区域还是蛇身重叠的区域的东西是,面片在蛇身上的序号。如果是序号相邻的面片重叠,就是蛇身过度弯曲,否则就是蛇身重叠。我们可以令面片的深度随着序号增加而增加,那么对于两个重叠的面片,如果深度差异小,则可以认为是蛇身过度弯曲的区域,否则就是蛇身重叠的区域。
因此我们可以在depth test阶段判断当前深度和已绘制的深度的差异,如果小于一定阈值,depth testfail即可。然而我们并不能自定义这样的depth test,我们最多只能做到,ZTest设为NotEqual。这意味着序号相邻的面片深度相同,序号差别大的面片深度不同。然而这是件不可能完成的任务,我们可以退而求其次,把蛇分成n个片段,每个片段由m个面片组成,片段内的面片深度相同,不同片段的深度不同。
图6 分段式解决方案
从上图可以看到,虽然还是会出现黄色尖刺,但是黄色尖刺已经大幅度减少,达到可以接受的程度,同时不会引发其他问题。