项目需求要做类似炉石卡牌边缘发光的效果:
结果找了半天都没找到个现成的,只能自己写了,先来看看实现的效果:
思路来源:https://www.shadertoy.com/view/XdV3Dc
大致原理:对于每个透明的点都用圆来检测其周围的点是否有不透明的,如果有则说明该点为边缘点,涂上边缘的颜色即可。
核心代码:
CCProgram fs %{
precision lowp float;
#include <texture>
#define SAMPLE 16
#define PI 3.14159265359
in vec4 v_color;
#if USE_TEXTURE
in vec2 v_uv0;
uniform sampler2D texture;
uniform myUniform{
vec4 hightlightColor;
vec2 textureSize;
float radius;
};
#endif
vec4 getColorFromTexture(sampler2D texture,vec2 uv){
vec4 color=vec4(1,1,1,1);
CCTexture(texture,uv,color);
return color;
}
void main () {
vec4 o = vec4(1, 1, 1, 1);
float unitWidth=1.0/textureSize.x; //单个像素的宽占uv.x的百分比
float unitHeight=1.0/textureSize.y; //单个像素的高占uv.y的百分比
float width=radius*unitWidth; //radius为边缘高光的半径
float height=radius*unitHeight;
float angle=0.0; //角度
float maxAlpha=0.0; //透明度,经过下面的循环后,如果透明度为0则说明该像素周围没有颜色,即它不是图像的边缘;反之则是图像的边缘
for(int i=0;i<SAMPLE;i++){
angle+=1.0/float(SAMPLE)*2.0*PI; //角度每个循环增加一次,循环结束时角度为2PI,整好一个圆的角度,圆的精度由SAMPLE决定,SAMPLE越高圆越精细,但运算量也会增加
vec2 testPoint_uv=vec2(width*cos(angle),height*sin(angle));//该点的圆上该角度的相对UV坐标
testPoint_uv=clamp(v_uv0+testPoint_uv,vec2(0,0),vec2(1,1));//加上该点的UV坐标变为绝对UV坐标
float tempAlpha=getColorFromTexture(texture,testPoint_uv).a;//用绝对UV坐标从texture读取颜色,看它的透明度
maxAlpha=max(maxAlpha,tempAlpha);//把透明度结果保存起来
}
vec4 finalColor=mix(vec4(0.0),hightlightColor,maxAlpha);//根据检测后的透明度决定该点最终的颜色
o=getColorFromTexture(texture,v_uv0);//读取该点本来的颜色
o*=v_color;//乘上顶点颜色,如果想要边缘高光也受node.color的影响,那么也要finalColor*=v_color;
gl_FragColor = mix(finalColor,o,o.a);//最后按透明度的占比给这俩颜色混合起来
}
}%
有几个uniform变量要单独设置一下,尤其是textureSize最好用脚本把数据传进去:
effect文件:
edgeHighlight.zip (1.6 KB)