我用的是corona的引擎,所以有点GLSL用法有些不同,不过语言还是相同的。
先放代码:
category = "filter",
name = "outline",
isTimeDependent = true,
vertexData = {
--CoronaVertexUserData.x //宽度
{
name = "width",
default = 1,
index = 0,
},
--CoronaVertexUserData.y //颜色
{
name = "color",
default = 0,
index = 1,
},
--CoronaVertexUserData.z //闪烁速度 0为不闪烁
{
name = "flashSpeed",
default = 0,
index = 2,
},
--CoronaVertexUserData.w //检测精度
{
name = "accuracy",
default = 1,
index = 3,
},
},
fragment =
[[
vec2 textureSize = vec2(CoronaTexelSize.x*1334.0,CoronaTexelSize.y*750.0);
//红
vec3 red = vec3(1,0,0);
//绿
vec3 green = vec3(0,1,0);
//蓝
vec3 blue = vec3(0,0,1);
vec3 outlineColor = vec3(0,0,0);
float outlineSize = CoronaVertexUserData.x;
float getIsStrokeWithAngel(float angel,vec2 v_texCoord)
{
float stroke = 0.0;
float rad = angel * 0.01745329252; // 这个浮点数是 pi / 180,角度转弧度
vec2 unit = 1.0 / textureSize.xy;//单位坐标
vec2 offset = vec2(outlineSize * cos(rad) * unit.x, outlineSize * sin(rad) * unit.y); //偏移量
float a = texture2D(CoronaSampler0, v_texCoord + offset).a;
if (a >= 0.5)// 我把alpha值大于0.5都视为不透明,小于0.5都视为透明
{
stroke = 1.0;
}
return stroke;
}
P_COLOR vec4 FragmentKernel( P_UV vec2 texCoord )
{
outlineColor = red;
if (CoronaVertexUserData.y==0.0)
{
outlineColor = red;
}
if(CoronaVertexUserData.y==1.0)
{
outlineColor = green;
}
if(CoronaVertexUserData.y==2.0)
{
outlineColor = blue;
}
vec4 texColor = texture2D(CoronaSampler0, texCoord); // 正在处理的这个像素点的颜色
if (texColor.a >= 0.5) // 不透明,不管,直接返回
{
return CoronaColorScale(texColor);
}
float strokeCount = 0.0;
float onceAngel = CoronaVertexUserData.w;//每次检测的角度
for(float angel = 0.0; angel < 360.0; angel += onceAngel)
{
strokeCount += getIsStrokeWithAngel(angel,texCoord);
}
if (strokeCount > 0.0) // 四周围至少有一个点是不透明的,这个点要设成描边颜色
{
texColor.rgb = outlineColor;
texColor.a = 1.0;
float sumCount = 360.0/onceAngel;
texColor.rgba = texColor.rgba*(strokeCount/sumCount);
}
texColor.rgba = texColor.rgba*cos(CoronaTotalTime*CoronaVertexUserData.z);
return CoronaColorScale(texColor );
}
]]
先解释一下corona引擎可直接获取到变量的意思:
CoronaTexelSize为纹理的大小,范围是0-1,所以真正大小是CoronaTexelSize.x*屏幕高=真实高,CoronaTexelSize.y*屏幕宽=真实宽
CoronaTotalTime为打开应用到现在的运行时间
CoronaVertexUserData.xyzw为外部传入的参数
CoronaSampler0为纹理采样
我是参考了别人用cocos shader写的单纯描边,并且在基础思路上修改。
这个shader的大致思路是:
1.在片段着色器 检测每个像素点的透明度是否大于0.5,如果大于0.5则不处理像素点的颜色。
2.如果检测到像素点的透明度小于0.5,就以该像素点为圆心,outlineSize为半径,检测该圆周上透明度大于0.5的像素点有几个。(检测的精度和onceAngel有关,onceAngel每次检测的角度)。如果该圆周上有透明度大于0.5的像素点,(strokeCount为这个圆周上,像素点透明度为0.5的个数),就说明该像素点(圆心)在图片的边缘,可以为他设置边缘的颜色。
到此为止是设置单纯描边的思路。接下来是让描边又内二外有渐变的效果,类似外发光。
3.所以当strokeCount越大,我们是不是可以认为,该像素点离图像越近,反之则相反。所以利用
float sumCount = 360.0/onceAngel;
strokeCount/sumCount为百分比,去设置透明度。
这样越边缘的透明度就越低。
4.并且根据CoronaTotalTime和正余弦函数控制外边缘发光的闪烁速度。