抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

原理

根据传入的进度[0,1]剔除对应颜色值 RGB 之一的像素,上图为进度条所需的从颜色值 0 到颜色值 1 的贴图(透明底图,进度条的圈为从白到黑的不透明圆环)。

此代码负责剔除一定颜色值的像素,利用 step 函数的原理(step(a,b),当 b>=a 时返回 1,否则返回 0),其中 1.0-col.r 决定进度条动画的方向,代表从白向黑,也可以直接使用 col.r 从黑向白。

1
float colorMinus = step(1.0-col.r,u_progress);

这段代码包括两个部分,前面的部分决定进度条的颜色,后面的部分决定背景的颜色,我们可以从加号的地方拆开来看。前面的部分构造了一个三维向量,假如 colorMinus 为 1,则前面的向量就是全 1,此时和传入的进度条颜色值相乘可得进度条的颜色。后面构造了一个和前面相反的三维向量,此时后面的向量为全 0,和传入的背景颜色相乘依然是 0。

由此可得,当此处的像素筛选为进度条的时候,进度条的颜色值发挥作用,而背景颜色值不发挥作用;相反,此处像素筛选为背景时,进度条颜色值不发挥作用而背景颜色值发挥作用。为什么要这么做呢,因为 GPU 运算的时候是大量并行的,条件判断语句对于 GPU 来说每个分支都要执行,性能会有损失。

1
2
vec4 final = vec4(colorMinus);
final.xyz = vec3(colorMinus) * u_edgeColor.xyz + vec3(1.0-colorMinus) * u_bgColor.xyz;

只有上述代码的话,运行时的效果并不能符合我们的需要,进度条之外的像素也会有填充。因此我们需要对透明度进行剔除。

1
final.a = (step(1.0-col.a,0.0) * colorMinus * u_edgeColor.a) + step(colorMinus,0.0) * u_bgColor.a;

由于我们支持自定义进度条和进度条背景的透明度,因此这两个部分也需要进行处理。

关于进度条的透明度,起判断的部分只有 colorMinus * u_edgeColor.a。为什么要乘上 step(1.0-col.a,0.0)呢,主要是为了筛去透明的部分,col.a 是原材质贴图的透明度,当其为 1 的时候(不透明)所得值为 0,step(1.0-col.a,0.0)的值才为 1,进度条的颜色才生效。当然这里可以设置为你所需要的任意值。

关于背景的透明度,和进度条同理可得 step(colorMinus,0.0) * u_bgColor.a。

进度条 shader 代码

片元着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifdef FSHIGHPRECISION
precision highp float;
#else
precision mediump float;
#endif

uniform sampler2D u_DiffuseTexture;
uniform float u_progress;
uniform vec4 u_edgeColor;
uniform vec4 u_bgColor;

varying vec2 v_Texcoord0;

void main()
{
vec4 col = texture2D(u_DiffuseTexture, v_Texcoord0);
float colorMinus = step(1.0-col.r,u_progress);
vec4 final = vec4(colorMinus);
final.xyz = vec3(colorMinus) * u_edgeColor.xyz + vec3(1.0-colorMinus) * u_bgColor.xyz;
final.a = (step(1.0-col.a,0.0) * colorMinus * u_edgeColor.a) + step(colorMinus,0.0) * u_bgColor.a;
gl_FragColor = final;
}

顶点着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Lighting.glsl";
attribute vec4 a_Position;
attribute vec2 a_Texcoord0;

varying vec2 v_Texcoord0;

uniform mat4 u_MvpMatrix;
uniform vec4 u_TilingOffset;

void main()
{
v_Texcoord0=TransformUV(a_Texcoord0,u_TilingOffset);
gl_Position=remapGLPositionZ(gl_Position);
}

评论