对实现动画的前端同学们来说,canvas能够说是最自在,最能全面管制的一个动画实现载体。岂但能通过javascript控制点、线、面的绘制,应用图片资源填充;还能扭转输出参数作出交互动画,齐全管制动画过程中的动作轨迹、速度、弹性等因素。

但应用canvas开发过较简单一点的动画的同学,可能会发现,齐全应用javascript绘制、管制的动画,某些成果不太好实现(这篇文章只探讨2D),像含糊,光照,水滴等成果。尽管用逐像素解决的办法也能够实现,但javascript对这类型大量数据的计算并不善于,实现进去每一帧绘制的工夫非常感人,用他实现动画并不事实。

canvas除了最罕用的javascript API绘制形式(getContext('2d')),还有WebGL的形式(getContext(webgl)),对后面说到的大量数据计算的场景,能够说是最适宜施展的中央。WebGL对很多同学来说就是实现3D场景的,其实对2D绘图来说,也有很大的施展场景。

为什么WebGL会比拟厉害

咱们来看看javascript API绘制和webGL绘制原理上的不同之处:

如果应用javascript对画布的一一像素进行解决,那这部分解决工作就须要在javascript的运行环境里进行,咱们晓得javascript的执行是单线程的,所以只能一一一一像素进行计算和绘制。就像一个修长的漏斗,一滴一滴水的往下漏。

而WebGL的解决形式,是用GPU驱动的,对每一个像素的解决,都是在GPU上执行,而GPU有许多渲染管道,这些解决能够在这些管道中并行执行,这就是WebGL善于这种大量数据计算场景的起因。

WebGL那么厉害,都用它绘图就好喇

WebGL尽管有下面说的长处,但也有个致命的毛病:不好学,想要简略画根线也要费一番力量。

GPU并行管道之间是不晓得另一个管道输入的是什么,只晓得本人管道的输出和须要执行的程序;而且不保留状态,管道本人并不知道在这次工作之前执行过什么程序,有什么输入输出值,相似当初纯函数的概念。这些观点上的不同就晋升了应用WebGL绘图的门槛。

另外这些跑在GPU里的程序不是javascript,是一品种C语言,这也须要前端同学们另外再学习。

Hello, world

那门槛再高也总有须要跨过来的一天的,上面一步一步管制WebGL去一点图案,大家也能够领会一下,适宜在什么时候应用这一门技术。

根底环境——大荧幕

为尽快进入GLSL着色器的阶段,这里根底WebGL环境搭建用了Three.js,大家能够钻研下这个根底环境的搭建,不必第三方库其实也用不了多少代码量。

以下是根底环境的搭建:

function init(canvas) {  const renderer = new THREE.WebGLRenderer({canvas});  renderer.autoClearColor = false;   const camera = new THREE.OrthographicCamera(    -1, // left     1, // right     1, // top    -1, // bottom    -1, // near,     1, // far  );  const scene = new THREE.Scene();  const plane = new THREE.PlaneGeometry(2, 2);  const fragmentShader = '............'  const uniforms = {    u_resolution:  { value: new THREE.Vector2(canvas.width, canvas.height) },    u_time: { value: 0 }  };  const material = new THREE.ShaderMaterial({    fragmentShader,    uniforms,  });  scene.add(new THREE.Mesh(plane, material));   function render() {    material.uniforms.u_time.value++;    renderer.render(scene, camera);    requestAnimationFrame(render);  }  render()}

解释一下下面这段代码做了什么:创立了一个3D场景(说好的2D呢?),把一个矩形立体糊在摄像机后面,占满摄像机视觉范畴,就像看IMAX坐最前排,你能看到的就只有背后的屏幕的感觉,屏幕上的画面就是你的整个世界。咱们的绘图就在这个屏幕上。

再阐明一下,着色器分为顶点着色器VERTEX_SHADER和片段着色器FRAGMENT_SHADER

顶点着色器对3D场景里物体的每个顶点计算值,如色彩、法线向量等,在这里咱们只探讨2D画面,顶点着色器的局部就由Three.js代劳了,实现的作用就是固定了场景中镜头和屏幕的地位。

而片段着色器的作用就是计算立体上每一个片段(在这里是屏幕上每一个像素)输入的色彩值,也是这篇文章钻研的对象。

片段着色器入参有varyinguniform两种,varying简略说一下是由顶点着色器传入的,每个片段输出的值由相干的顶点线性插值失去,所以每个片段上的值不一样,本文先不探讨这部分(不然写不完了)。uniform是对立值,由着色器内部传入,每个片段失去的值是一样的,在这里就是咱们从javascript输出变量的入口。下面的代码咱们就为片段着色器传入了u_resolution,蕴含画布的宽高值。

第一个着色器

fragmentShader为着色器的程序代码,个别的形成为:

#ifdef GL_ESprecision mediump float;#endifuniform vec2 u_resolution;void main() {  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}

在前3行查看了是否定义了GL_ES,这通常在挪动端或浏览器下会定义,第2行指定了浮点数float的精度为中等,也能够指定为低精度lowp或高精度highp,精度越低执行速度越快,但品质会升高。值得一提的是,同样的设置在不同的执行环境下可能会体现不一样,例如某些挪动端的浏览器环境,须要指定为高精度能力取得和PC端浏览器里中等精度一样的体现。

第5行指定了着色器能够接管哪些入参,这里就只有一个入参:类型为vec2的u_resolution

最初3行形容了着色器的主程序,其中能够对入参和其余信息作解决,最初输入色彩到gl_FragColor,代表这个片段显示的色彩,其中4个数值代表RGBA(红、绿、蓝、透明度),数值范畴为0.0 ~ 1.0

为什么要写0.0而不是0呢,因为GLSL里不像javascript数字只有一个类型,而是分成整形(int)和浮点数(float),而浮点数必须蕴含小数点,当小数点前是0的时候,写成.0也能够。

那大家看完这段讲解,应该能猜到下面的着色器会输入什么吧,对,就是全屏的红色。

这就是最根底的片段着色器。

应用uniform

大家应该留神到下面的例子没有用到传入的uniform值,上面来说一下这些值怎么用。

看之前搭建根底环境的javascript代码能够看到,u_resolution存储了画布的宽高,这个值在着色器有什么用呢?

这要说到片元着色器的另一个内建的值gl_FragCoord,这个值存储的是片段(像素)的座标xy值,应用这两个值就能够晓得以后着色器计算的是画布上哪个地位的色彩。举个例子:

#ifdef GL_ESprecision mediump float;#endifuniform vec2 u_resolution;void main() {  vec2 st = gl_FragCoord.xy / u_resolution;  gl_FragColor = vec4(st, 0.0, 1.0);}

能够看到这样的图像:

下面的着色器代码,应用归一化后的xy座标输入到gl_FragColor的红、绿色局部。

从图中能够看出,gl_FragCoord(0, 0)点在左下角,x轴和y轴方向别离为向右和向上。

另一个uniform值u_time就是一个随着工夫一直减少的值,利用这个值能够使图像随工夫变动,实现动画的成果。

下面的着色器再改写一下:

#ifdef GL_ESprecision mediump float;#endifuniform vec2 u_resolution;uniform float u_time;void main() {  vec2 st = gl_FragCoord.xy / u_resolution;  gl_FragColor = vec4(st, sin(u_time / 100.0), 1.0);}

能够看到下图的成果:

http://storage.360buyimg.com/element-video/QQ20210330-195823.mp4

着色器中应用三角函数sin,在色彩输入的蓝色通道做一个从0到1的周期变动。

还能做什么?

把握根本的原理后,就是开始从巨匠的作品中学习了。shadertoy是一个相似codepen的着色器playgroud,下面的着色器都是利用下面的根本工具,还有一些造型函数,造出各种目迷五色的特效、动画。

下面就是GLSL着色器根本的开发工具,当初就能够开始开发你本人的着色器,剩下就是应用数学方面的技能了。

欢送关注凹凸实验室博客:aotu.io

或者关注凹凸实验室公众号(AOTULabs),不定时推送文章。