效果预览
按钮或物体上出现扫光效果可以体现改物品的珍贵性,比如我们在SSR卡片或者付费按钮上加一个扫光效果可以增加玩家付费的欲望,而这个效果要是美术去做的话,需要大量序列帧,而用shader可以轻松的定制出各种各样的效果。
核心思路
让2条斜率相同的斜线中间夹住的部分变亮,并让这两条线保持相同的速度进行位移。然后周期回归到原点重新扫一遍。
实现过程
本demo是基于ccc2.4.8开发的。
首先我们先画一条线出来,斜率的方程是:y=k*x+b
我们只需要让2个斜线中间的区域变亮一点就可以了。对于不等式方程就是y > kx + b1 和 y < kx + b2;设变亮强度为flowStrength,那核心算法如下:
void main() {
...
if ((y > k * x + b1) && (y < k * x + b2)) {
o.rgb *= flowStrength;
}
...
gl_FragColor = o.rgb;
}
其次,我们要让线动起来,cocos内置的cc-global.chunk中的cc_time参数记录着游戏运行时间.
那上述的b1和b2需要跟随cc_time的变化而变化。
我们设扫光速度为flowSpeed,单次扫光周期为flowCycle,两条斜线之间的距离是flowWidth,就有下面两个公式:
b1 = (cc_time.x * flowSpeed) % flowCycle; (%是求模)
b2 = b1 + flowWidth;
在glsl中取模有个api是mod,而cc_time是不能直接用的,需要从顶点着色器传到片段着色器来,具体操作可以看我前面的文章。
最后要做的就是将坐标映射进去,我们设斜率为flowK,将uv对应的x和y代进去就有如下代码:
float b1 = mod(v_time.x * flowSpeed, flowCycle);
float b2 = b1 + flowWidth;
if ((uv.y > flowK * uv.x + b1) && (uv.y < flowK * uv.x + b2)) {
o.rgb *= flowStrength;
}
到这里调好材质球的参数(斜率、周期、线宽、扫光速度)就能得到单张图的扫光效果啦!
运行效果:
改良一下
实际装载到项目中发现,同一个材质球,宽高比不一样的图跑扫光效果的斜率不一样,这是因为uv没有去乘宽高比的系数问题导致的。这个的解决方案可以参考上一篇文章《CocosCreator追光效果+多相机RenderTexture应用》中,在代码里将图片的宽高比传进去(没办法,uv只是0~1,没有宽高信息)。但实际开发会觉得应用很麻烦,不仅要挂材质球,还要获取宽高传进去,所以就在想啊,有没有办法做一个全局扫光,一道光扫过来,有需求的图片依次做个扫光效果?
答案肯定是有的。
首先,在顶点着色器中,顶点经过矩阵变换获得世界坐标的顶点,将其传到片段着色器中
在片段着色器中我们做如下测试:
o.rgba = vec4(v_pos.xyz, 1.0);
将一张铺满全屏的图片应用这个shader我们将得到如下效果:
x方向是红(r),y方向是绿(g),2D不考虑z,看得出从左到右x是从-1到1的,从下到上y也是从-1到1的,在两者叠加的部分r+g就成了黄色(右上角),将坐标收缩到0~1试试?
o.rgba = vec4((v_pos.x + 1.0)*0.5, (v_pos.y + 1.0)*0.5, (v_pos.z + 1.0)*0.5, 1.0);
嗯,整个画面就类似uv一样,左下是原点,从0~1的渐变,对应将上面代码的uv改成v_pos得到如下代码
void main() {
...
float tx = (v_pos.x + 1.0)*0.5;
float ty = (v_pos.y + 1.0)*0.5;
if ((ty > flowK * tx + b1) && (ty < flowK * tx + b2))
{
o.rgb *= flowStrength;
}
...
}
运行效果如下:
我们得到了一个全屏的扫光,嗯,将这个材质球拖到各个小图片上面,再将背景图缩小做对比试试?
最终效果
最终代码
完整工程如下:
git@gitee.com:onion92/cocos2d-shader-effect.git
down下来后运行这个场景即可。
小结
今天的扫光就暂时告一段落了,期间也参考了一下异名大佬的扫光效果,2d的shader会暂停告一段落,后续几篇文章会为大家带来3d的一些效果。
感谢各位的观看,希望在渲染的道路上与君共勉,相互成长!