Shader入门学习案例,描边效果

在学习 Shader 的过程中做的小案例,在 Creator v2.4.10 实现2D物体的描边效果。

outline.mtloutline.effect用于描边效果

创建 SpriteNode 节点, 给其添加上图和outline.mtl材质。

参考自:

f6b26d870a1504f46459ff360d47830

effect

CCEffect 中添加 propertie:

properties:
        outlineWidth: { value: 0.01, editor: { tooltip: '描边宽度' }}
        outlineColor: { value: [1,1,1,1], editor: { type: color ,tooltip: '描边颜色' }}

修改片段着色器fs:

声明:

uniform Outline {
    vec4 outlineColor;
    float outlineWidth;
  };

入口函数:

void main () {
    vec4 o = vec4(1, 1, 1, 1);

    #if USE_TEXTURE
      CCTexture(texture, v_uv0, o);

      // 计算周围像素的 alpha 值
      float alphaLeft = texture2D(texture, v_uv0 + vec2(outlineWidth, 0)).a;
      float alphaRight = texture2D(texture, v_uv0 - vec2(outlineWidth, 0)).a;
      float alphaTop = texture2D(texture, v_uv0 + vec2(0, outlineWidth)).a;
      float alphaBottom = texture2D(texture, v_uv0 - vec2(0, outlineWidth)).a;

      // 计算描边的 alpha 值
      float outlineAlpha = alphaLeft + alphaRight + alphaTop + alphaBottom;

      vec4 finalColor = mix(outlineColor, o.rgba, o.a);

      finalColor.a = outlineAlpha;

      gl_FragColor = finalColor;

    #endif
  }

vec4 finalColor = mix(outlineColor, o.rgba, o.a);

  • o.a == 1,说明纹理图该位置有颜色,采用纹理图的原色
  • o.a == 0,说明纹理图该位置没有颜色,采用描边颜色
  • o.a介于中间,根据纹理图的Alpha值使用混合颜色

float outlineAlpha = alphaLeft + alphaRight + alphaTop + alphaBottom; 记录周围像素的alpha。如果 outlineAlpha == 0,说明附近都是透明的;

finalColor.a = outlineAlpha;,令周围都是透明的地方的保持透明。

最终效果:

01

11赞

good,上下左右偏移再叠加到一起,丝滑点可以八方向 :joy:

确实,可以再加四个方向

mark!!!学习

6666,能用到,感谢

666,学习了

像这种尖锐处容易叉毛了咋搞 :face_with_raised_eyebrow:
image

这种是不是只支持周围留有透明像素的图片呐

可以再加四个方向,这个只写了上下左右。把左上、右上、左下、右下也加上,这种地方就能连贯起来了。

修改一下 fs 入口函数:

void main () {
    vec4 o = vec4(1, 1, 1, 1);

    #if USE_TEXTURE
      CCTexture(texture, v_uv0, o);

      vec4 finalColor = mix(outlineColor, o.rgba, o.a);

      // 计算周围像素的 alpha 值
      float alpha_Left = texture2D(texture, v_uv0 + vec2(outlineWidth, 0)).a;
      float alpha_Right = texture2D(texture, v_uv0 + vec2(-outlineWidth, 0)).a;
      float alpha_Top = texture2D(texture, v_uv0 + vec2(0, outlineWidth)).a;
      float alpha_Bottom = texture2D(texture, v_uv0 + vec2(0, -outlineWidth)).a;
      
      float alpha_LeftTop = texture2D(texture, v_uv0 + vec2(outlineWidth, outlineWidth)).a;
      float alpha_RightTop = texture2D(texture, v_uv0 + vec2(-outlineWidth, outlineWidth)).a;
      float alpha_RightBottom = texture2D(texture, v_uv0 + vec2(-outlineWidth, -outlineWidth)).a;
      float alpha_LeftBottom = texture2D(texture, v_uv0 + vec2(outlineWidth, -outlineWidth)).a;

      // 计算描边的 alpha 值
      float outlineAlpha = alpha_Left + alpha_Right + alpha_Top + alpha_Bottom 
      + alpha_LeftTop + alpha_RightTop + alpha_RightBottom + alpha_LeftBottom;

      finalColor.a = outlineAlpha;

      gl_FragColor = finalColor;

    #endif
  }

效果:

01

1赞

嗯,应该是的

大佬,为什么我把fs的main方法复制进去了报错啊,运行不了

报错,报的什么呀?

4a67cb648f035c11f7bc30e32834ed4

就是复制这一段,覆盖了原来的fs中的main()

引用
void main () {
vec4 o = vec4(1, 1, 1, 1);
#if USE_TEXTURE
CCTexture(texture, v_uv0, o);
vec4 finalColor = mix(outlineColor, o.rgba, o.a);
// 计算周围像素的 alpha 值
float alpha_Left = texture2D(texture, v_uv0 + vec2(outlineWidth, 0)).a;
float alpha_Right = texture2D(texture, v_uv0 + vec2(-outlineWidth, 0)).a;
float alpha_Top = texture2D(texture, v_uv0 + vec2(0, outlineWidth)).a;
float alpha_Bottom = texture2D(texture, v_uv0 + vec2(0, -outlineWidth)).a;
float alpha_LeftTop = texture2D(texture, v_uv0 + vec2(outlineWidth, outlineWidth)).a;
float alpha_RightTop = texture2D(texture, v_uv0 + vec2(-outlineWidth, outlineWidth)).a;
float alpha_RightBottom = texture2D(texture, v_uv0 + vec2(-outlineWidth, -outlineWidth)).a;
float alpha_LeftBottom = texture2D(texture, v_uv0 + vec2(outlineWidth, -outlineWidth)).a;
// 计算描边的 alpha 值
float outlineAlpha = alpha_Left + alpha_Right + alpha_Top + alpha_Bottom
+ alpha_LeftTop + alpha_RightTop + alpha_RightBottom + alpha_LeftBottom;
finalColor.a = outlineAlpha;
gl_FragColor = finalColor;
#endif
}

报错展开,看看详细信息,看一下具体是哪里的原因?

找到问题了 是
uniform Outline {
vec4 outlineColor;
float outlineWidth;
};
这段代码放错位置了,现在不报错了,感谢大佬 :joy:

拿来就用 非常感谢

大佬 我设置描边宽度为0.01后,编辑器预览正常,但是网页运行,出来的描边就会变得非常宽,修改为0.001后,描边看起来才正常,这是什么原因,

可以看一下你贴图属性的 Packable 有没有勾选,

00

勾选的话,引擎会自动合图,合图有可能影响uv的像素检测,会出一些问题。

!解决了,感谢大佬解答,大佬牛

爱了爱了!