Unity

用Shader绘制攻击范围的圆环

游戏中经常会有如下图所示的表示攻击范围的圆环,圆环是由渐变色绘制而成。无论圆环的直径多大,圆环的宽度都是不变的。这一特点决定了无法用图片实现,只能通过程序绘制。

yuanhuan

在Unity中,我们可以用Shader来绘制这个圆环。代码如下:

 

 

 

我们用这段Shader来渲染一个1×1的正方形面片,可以通过_Object2World[0][0]来获取矩阵中的Scale,也就是面片的实际边长。然后在Fragment Shader中通过计算每个像素到面片中心的距离,来计算是否绘制以及像素的透明度。就可以实现图上的效果。

当然,在Unity中遇到了一个小坑,有一些炮塔是需要有两个攻击范围的。如下图:

yuanhuan2

但当我们加入两个面片时,发现都画不出来。而单独显示一个的时候就没问题。这是由于Unity中的Dynamic Batching导致的,Dynamic Batching的原理是将一些顶点少的,使用相同材质的面片,合成一个批次,送入到渲染管线中,从而减少DrawCall。而在合成批次的时候,就要提前用变换矩阵将所有的顶点展开。

在我们的例子中,如果同时渲染两个圆环,这两个圆环的面片顶点就会被换算成实际的坐标位置。也就是已经乘了Scale。这样我们在Shader中假设变换前的每一个像素坐标都<=0.5就错了。所以导致两个圆圈都画不出来。

所以就需要在绘制圆圈的时候关闭Unity中的Dynamic Batching。在文档中,提供了一个开启Dynamic Batching的条件列表,其中有一条是这样的:

  • Multi-pass shaders will break batching. Almost all unity shaders supports several lights in forward rendering, effectively doing additional pass for them. The draw calls for “additional per-pixel lights” will not be batched.

多个Pass的Shader将不会被纳入到Dynamic Patching中,所以我们在代码中加入了这样一个没有任何卵用的Pass,来避开Dynamic Patching:

另外一个问题,就是在老型号手机上,不支持shader中的if 和 discard语句,因此,做一些修改,绕开这两种语句: