webgl滤镜--旋转的三原色

1,003 阅读4分钟

今天我们一起来做一个三原色的旋转,为了更好的体现效果呢,我没有使用图片作为背景,闲言少叙,我们直接看效果。

图中就是我们要实现的效果,有红蓝绿三种颜色的圆圈在旋转,我们需要解决的主要问题有如何使用webgl来画一个模糊的圆圈,如何使三个圆圈绕一点旋转。
同时如果你喜欢的话还可以自己做一个延伸,例如时刻更改旋转的中心等等,这样效果会更佳的丰富,我在这里呢就不做延伸了。

基础的构建我在这里就不在赘述了,你可以看一下我的另一篇基础构建的文章,在此我们直接进入最核心的webgl的片元着色器代码。

一 webgl画出一个圆圈

precision mediump float;
varying vec2 uv;
uniform float time;

void main(){
	vec3 color;
	float blur = 15.0;
	
	color.b =  1.0 - (pow(uv.x - 0.5,2.0) + pow(uv.y - 0.8,2.0))*blur;

	gl_FragColor = vec4(color, 1.0 );
}

我们使用上面的代码就轻松的构建出了一个圆,接下来我们就看一下这个轻松画出圆的原理。
首先我们定义了一个vec3类型的变量,这个变量的作用就是用来存储我们改变以后的色值的。
接着我们定义了一个float类型的blur变量,此变量的作用是用来控制画出圆的模糊距离。

color.b =  1.0 - (pow(uv.x - 0.5,2.0) + pow(uv.y - 0.8,2.0))*blur;

这句代码是画出圆的关键点,我们使用具体的坐标事例来说明。

图中的坐标系中我们定义了我们想要画圆的点A(0.5,0.8),其坐标你可以在上面的公式找到。
我们分别将W,X,U点带入公式看一下。
pow函数是平方函数,pow(x,y)会返回x的y次方。

W => 1.0-(pow(0.5 - 0.5, 2.0) + pow(0.77 - 0.8, 2.0))*15.0 => 0.865
X => 1.0-(pow(0.5 - 0.5, 2.0) + pow(0.4 - 0.8, 2.0))*15.0 => -1.4 U => 1.0-(pow(0.1 - 0.5, 2.0) + pow(0.1 - 0.8, 2.0))*15.0 => -8.75

我们在整个二维平面上面,距离A点越远的点最后计算出来的值就越大。
在webgl中rgba的取值范围是在0.0~1.0。

也就是说从A点为圆心,距离A越远的点计算出来的值会越小,也就会呈现黑色,距离A点越近的点就会月靠近1.0这个数值,也就会呈现蓝色。

二 画出三色圆

一个圆的画法我们已经知道了,那么我们画出来三个圆。

precision mediump float;
varying vec2 uv;
uniform float time;

void main(){
	vec3 color;
	float blur = 15.0;
	
	color.r =  1.0 - (pow(uv.x - 0.24,2.0) + pow(uv.y - 0.35,2.0))*blur;
	color.g =  1.0 - (pow(uv.x - 0.75,2.0) + pow(uv.y - 0.35,2.0))*blur;
	color.b =  1.0 - (pow(uv.x - 0.5,2.0) + pow(uv.y - 0.8,2.0))*blur;

	gl_FragColor = vec4(color, 1.0 );
}


上面我们使用和画蓝色圆同样的方式画出了三色圆,那么接下来就是让三色圆进行转动了。

三 转动三色圆

precision mediump float;
varying vec2 uv;
uniform float time;

void main(){
	vec3 color;
	float blur = 15.0;
	vec2 rotateCenter = vec2(0.5, 0.5);

	vec2 circleA = vec2(rotateCenter.x + 0.3*cos(radians(90.0+time)), rotateCenter.y + 0.3*sin(radians(90.0+time)));
	vec2 circleB = vec2(rotateCenter.x + 0.3*cos(radians(210.0+time)), rotateCenter.y + 0.3*sin(radians(210.0+time)));
	vec2 circleC = vec2(rotateCenter.x + 0.3*cos(radians(-30.0+time)), rotateCenter.y + 0.3*sin(radians(-30.0+time)));

	color.r =  1.0 - (pow(uv.x - circleB.x,2.0) + pow(uv.y - circleB.y,2.0))*blur;
	color.g =  1.0 - (pow(uv.x - circleC.x,2.0) + pow(uv.y - circleC.y,2.0))*blur;
	color.b =  1.0 - (pow(uv.x - circleA.x,2.0) + pow(uv.y - circleA.y,2.0))*blur;

	gl_FragColor = vec4(color, 1.0 );
}

我们首先定义三色圆的旋转中心,我定义的是rotateCenter(0.5,0.5),接下来我们要将三色圆的圆心和这个点关联起来。


上面图中A点是蓝色圆的圆心,B点是红色圆的圆心,C点是绿色圆的圆心,O点是圆的圆心,同时也是三角形的中心。
我们可以根据初高中的知识知道: A(x1,y1),o(x0,y0)
x1 = x0 + r*cos(degrees*PI/180)
y1 = y0 + r*sin(degrees*PI/180)

vec2(rotateCenter.x + 0.3*cos(radians(90.0)), rotateCenter.y + 0.3*sin(radians(90.0)))

在代码中rotateCenter.x就是x0
rotateCenter.y就是y0
0.3就是r也就是圆的半径
degrees*PI/180我们使用webgl的内置三角函数radians(90.0)进行计算,其中90.0就是A点相对于O点的角度。
这样我们就将ABC三个点和O点关联上了,此时只要我们再时时的改变ABC三点相对于O点的角度值,这样就可以达到旋转的效果了。

vec2 circleA = vec2(rotateCenter.x + 0.3*cos(radians(90.0+time)), rotateCenter.y + 0.3*sin(radians(90.0+time)));

在上面我们在radians(90.0+time)的参数中添加了一个变量time,这个time会从0开始一直加1,这样ABC三个点就会时时的改变相对于O点的角度,进而完成旋转。

color.b =  1.0 - (pow(uv.x - circleA.x,2.0) + pow(uv.y - circleA.y,2.0))*blur;

最后我们将时时旋转的三色圆中心坐标传给颜色画圆的计算公式,这样就完成了。

旋转的方式你可以自己手动的更改,并且画圆那里使用2次方还是1次方你都可以进行更改,你会得到不一样的效果,篇幅的原因我就不一个个举例子了。

color.b =  1.0 - (pow(uv.x - circleA.x,2.0) + pow(uv.y - circleA.x,2.0))*blur;

嗯,怕你感觉对实现的效果失望,你只需要将color.b那里的旋转中新都设置成x就会出现上面的效果,更多的效果你可以自己尝试一下。

最后附上代码地址:gitee.com/wangtao_it_…
此次的代码是项目下面的rotateRGB.html