本章为大家带来内发光特效。
2d-sprite-glow-inner.gif
一、内发光原理
学习 Shader 过程中,偶然在网上看到一句的内发光原理,十分精辟受用:
采样周边像素alpha取平均值,叠加发光效果
事实上,根据这句精辟的原理,就可以实现内发光了,你也试试吧?
以下为我的实现过程。
二、采样周边像素Alpha取平均值
怎么采集某个点的周边像素呢?这里我们可以用 「按圆采样」 算法
2.1 采样圆边上某点的 Alpha 值
如果我们已知圆的半径 radius ,已经某个角度 angle ,那么这个点的坐标就很好计算了,其上的 Alpha 值就不再话下 :
Step 1
x = radius * cos(angle);
y = radius * sin(angle);
在 Cocos Creator 的 Shader 中,代码如下:
/**
* 获取指定角度方向,距离为xxx的像素的透明度
*
* @param angle 角度 [0.0, 360.0]
* @param dist 距离 [0.0, 1.0]
*
* @return alpha [0.0, 1.0]
*/
float getColorAlpha(float angle, float dist) {
// 角度转弧度,公式为:弧度 = 角度 * (pi / 180)
// float radian = angle * 0.01745329252; // 这个浮点数是 pi / 180
float radian = radians(angle);
vec4 color = getTextureColor(texture, v_uv0 + vec2(dist * cos(radian), dist * sin(radian)));
return color.a;
}
PS:
这里我们用到了 sin 和 cos 函数,函数接受的参数是弧度制,因此我们要实现角度转弧度
// 角度转弧度,公式为:弧度 = 角度 * (pi / 180)
float radian = angle * 0.01745329252; // 这个浮点数是 pi / 180
但实际上,GLSL ES 语言已然存在内置函数 radians(float degree):将角度值转化为弧度值,因此我们就用内置函数即可。
2.2 采样圆边上所有点的 Alpah 平均值
上面我们已经实现了获取圆上某点的颜色 Alpha 值。那么,我们只需要来一个 for 循环,遍历 0 到 360 度,那这个圆上所有点的颜色 Alpha 平均值就很容易算出来了。
但是,这样子可能会有两个问题:
计算量可能会太多,导致我们的性能低下
半径很少的时候,相邻的两个或多个角度的点可能很近,或者甚至重合,此时这两个点的 Alpha 值有可能相差不大,那么此时分别计算这些角度的 Alpha 值,就可能显得有点冗余了,取其一即可
基于以上考虑,最终我采用的是圆采样方式为:
以某个角度作为间隔,遍历由此产生的各个方向的Alpha值,将这些值的和的平均值近似看作这个圆的Alpha值
比如:
假设以 45° 角间隔,那么我只需要计算下图的 [10, 17] 共计 8 个点的 Alpha 平均值,那么这个值我就可以近似看作这个圆上所有点的 Alpha 平均值了
Step2
在 Cocos Creator 的 Shader 中,代码如下:
/**
* 获取指定距离的周边像素的透明度平均值
*
* @param dist 距离 [0.0, 1.0]
*
* @return average alpha [0.0, 1.0]
*/
float getAverageAlpha(float dist) {
float totalAlpha = 0.0;
// 以30度为一个单位,那么「周边一圈」就由0到360度中共计12个点的组成
totalAlpha += getColorAlpha(0.0, dist);
totalAlpha += getColorAlpha(30.0