Shader编程之地标特效_游戏开发

如图,这种地图上经常出现的地标特效,我们用shader做一个,记录一下源码。这种特效有以下几个特征:


  • 分为上下2个sprite:上面的半透明图标和下面的同心圆环。

  • 特效发光发热。

  • 特效不参与光照、没有碰撞属性、没有阴影。

  • 上面图标以弦函数的速率上下运动,这样看上去有惯性。

  • 上面图标运动到最低位置时,下面最小的圆环刚刚生成,还是一个圆点,这样看上去好像是上面图标触发了下面圆环的生成,更加带感、拟物。

  • 上面图标永远对准相机,下面同心圆不动。

  • 上面图标(为了对准相机而运动)的支点(pivot point,或者叫中心点、枢点)在sprite的正下方。

  • 下面同心圆从两侧均可看见(禁用三角朝向剔除)。


关于什么是sprite(二维小精灵),可以参考​​《静态特效组成原理》​​​​《雷达图生成算法》​

Shader编程之地标特效_java_02


  • circle材质:下方的同心圆动画材质

  • plane网格体:下面同心圆的载体

  • icon纹理:上方的图标

  • mark材质:上面的动画材质

  • landmark蓝图类:成品


之所以选择UE4,是因为UE4提供了现成的编辑器,可以方便地编辑预览shader代码。首先我们landmark蓝图类继承自actor,其中有2个组件:MaterialBillboard和plane,很显然分别是特效上下2个部分。至于plane有没有更好的sprite选择,尚不知道,目前只能用一个静态网格体来做。

Shader编程之地标特效_webgl_03

对于上方的billboard,我们做以下设置:主要关联一下材质资产,并且设置尺寸。这里Base Size即方形的边长的一半,要和动画中的世界位置偏移保持一致,这样才能模拟正下方的pivot point。

Shader编程之地标特效_shader_04

然后图标的化我们准备一张透明png就可以了,四周trim以下,这张图主要记录了哪些像素是透明的。可以选择任何应景的图标哦~

Shader编程之地标特效_webgl_05

然后在材质中定义一下Opacity Mask为png的alpha值,Emissive Color设置为任意的发光色都可以。

Shader编程之地标特效_游戏开发_06

由于只有alpha剔除,我们选用masked材质,特效一般不需要参与光照,所以选择unlit模式提升性能。

Shader编程之地标特效_slam_07

由于虚幻的billboard没法设置支点,所以我们只能在材质中模拟了,利用World Position Offset,沿着屏幕方向(或者正方形上方)偏移前面的Base Size即可,也就是我们设置的30,因此我们需要利用TransformVector函数将视口坐标转换成世界坐标。细心的小伙伴应该发现了,图标上下摆动的方向也是支点偏移的方向,所以2者可以叠加。

Shader编程之地标特效_游戏开发_08

根据叠加公式,偏移值 =(边长 + 振幅 )/ 2 + 当前偏振,其中边长就是之前设置的Base Size = 30的2倍,振幅=20略小于边长的一半,因此得到30+10=40。注意之所以选用cosine而不是sine是为了同步上下2个动画时间,使得上面图标触底的时候,小圆环正好出生,从而实现拟物的视觉效果。下面的同心圆,也是先要关掉所有物理属性,选择双面材质,然后关联plane网格体以及circle材质。

Shader编程之地标特效_shader_09

同心圆算法在上一次的​​雷达图生成算法​

Shader编程之地标特效_java_10

注意,Opacity Mask Clip Value决定了圆环的宽度,所以要设定为一个合适的值。

Shader编程之地标特效_slam_11

‍于是就做完成了,是不是很简单呢?很多人疑惑为什么做特效要编程,然后害怕就完了,其实面向GPU的特效编程并没有想象中的那么难,依据当然有很多,但只要知道:既然有那么多人都在做特效,其中还有很多女生,说明特效编程并不是需要太多基础的。

Shader编程之地标特效_java_12

一般的canvas算法比较符合直觉,要画圆形或方形都有直接的函数可调,但shader算法是遍历每个像素,依次着色,最终形成想要的图形,比较抽象,但也正是这种着色模型可以借助现代GPU数千个物理核心的高并发能力,实现更高级的效果。

Shader编程之地标特效_shader_13

苟日新,日日新,又日新。