目录

01UV坐标操控

目录

03外描边

这里的外描边其实就是outline。这里的描边实际上主要指2D图形的描边,使用教程中的资源,最终效果如下:

2D图形的描边,常用的方式简单描述就是:将原始图形渲染成纯色后,四周偏移一定像素作为背景跟原图形混合。具体来说可以分为以下一系列步骤:

  • 偏移一定像素采样原图案,使用alpha值和原图形将alpha值叠加作为采样用mask值。
  • 将纯色背景图样跟原始图片根据上述mask值进行叠加。

根据步骤可以看到,这个方式其实暗含了一定限制。

  • 原图形周边应当有一圈透明像素。其实这也是自然要求。如果没有透明像素,一是说明偏移之后会出边框,二是不能产生有效的mask值。
  • 这个方式实际上是将原图形采样之后位移产生。如果位移距离过大,实际上会产生一个脱离原位置的图形。跟描边效果相背离。

现在根据这一系列步骤来看具体实现:

  • 偏移采样

向四周偏移采样,使用alpha值生成mask值。其代码如下


uniform float outline_thick = 4.0;
uniform vec3 outline_color : source_color;
uniform int iteration = 1;

void fragment() {
    // 原始贴图采样
    vec4 ori = texture(TEXTURE,UV);

    float outline_mask = ori.a;

    // 设置一个基础偏移角度 后续均匀的向每个角度偏移采样叠加获取mask值
    float angle_base = PI/(2.0*float(iteration));
    for(int i=0;i<iteration*4;i++)
    {
        float angle = angle_base*float(i);
        vec2 direction = vec2(cos(angle),sin(angle));
        // TEXTURE_PIXEL_SIZE表示单个像素在UV空间下的大小
        // 换句话说 就是 1/贴图大小
        // TEXTURE_PIXEL_SIZE*outline_thick就表示在这个方向上偏移的像素个数
        outline_mask += texture(TEXTURE,UV+direction*TEXTURE_PIXEL_SIZE*outline_thick).a;
    }
}

这里的主要思想就是使用alpha值来作为需要采样图案的区域,一般称这样的值为mask,标记需要操作设置的区域。

这里之所以需要叠加原始图样的alpha,主要是为了方便后面扣除原始区域获得描边区域。对于原始区域则使用原图案。另一方面是,因为采样都向四周偏移了,如果偏移距离较大,中心会产生一系列空相素,这些区域反而会无法覆盖原图案而造成一些图案缺失,所以需要补足。

  • 叠加

叠加实际所面临的问题,就是如何区分原始图案区域,以及应该渲染为描边图形的区域。这里所用的想法就是:

  • 采样原始图案时,也就是ori,其alpha值标记了原始图案的区域。
  • 前面偏移采样时,生成的outline_mask,既包含了描边区域,也包含了原始图案区域。

两者相减,扣除原始图案即可得到描边区域。而原始区域直接使用原始像素即可。这个可以通过mix函数来实现。其函数描述如下:

  • mix(a,b,c)根据$c$的值来输出$a$或者$b$。当$c=1$时使用$b$,$c=0$时使用$a$细节来说,其输出数值相当于
$$f_{mix}(a,b,c)=a*(1-c)+b*c$$

所以这段代码如下:

void fragment() {
    // 前面反复叠加outline_mask 重复区域 其值远大于1.0 需要约束一下
    outline_mask = min(outline_mask,1.0)

    // 使用outlinemask-ori.a 来作为mix采样因子
    COLOR = mix(ori,vec4(outline_color,1.0),outline_mask-ori.a);
}

对于原始图案区域,该值为0,使用ori。这个时候ori即原始图案 对于需要描边区域,该值为1,使用outline_color。此即为描边区域 对于其他区域,该值也为0,只用ori。但是这些区域根据前面算法,也都是原始图案中的透明区域。所以得到透明像素。显示透明。

由此完成一个2D的描边效果。