还记得第一次看到canvas的粒子特效的时候,真的把我给惊艳到了,原来在浏览器也能做出这么棒的效果。结合《HTML5 Canvas核心技术》和网上的教程,经过半年断断续续的学习,对canvas的学习终于完结,对常用的canvas特效基本能做到信手拈来的。canvas特效请看:样例列表
众所周知,canvas是2D绘图技术,虽然可以通过坐标变换,位置计算也能做到3D的效果。但3D场景数据量毕竟比2D要高一个数量级的,纯粹用canvas的话,不管是性能和开发的复杂度会成为一个瓶颈。
这也是webGL出现的原因,解决web端3D渲染的场景。webGL会调用到GPU,处理大量重复的3D场景数据时,性能非常有优势。同时webGL是基于openGL ES 2.0, 因此它处理3D场景是非常成熟的。但为什么不直接学习three.js呢?因为本人对图形学感兴趣,只是希望做一些自己喜欢的效果的同时深入了解计算机图形学,没指望通过它做商业项目。
为了让学习更有动力和目的性,我们以实例为导向学习webGL,再从中展开到需要学习哪些知识点。这次我们来实现如下的动画,该教程参考了《WebGL编程指南》
实际效果请看:旋转的三角形
webGL渲染流程
webGL的渲染流程如下,其中第2,3,4步是重点,里面细节比较多。接着我们就按这个流程一步一步解决问题
- 获取webGL绘图上下文
- 初始化着色器
- 创建、绑定缓冲区对象
- 向顶点着色器和片元着色器写入数据
- 设置canvas背景色,清空canvas
- 绘制
webGL绘图上下文
webGL是canvas基础之上的3D绘图技术,只是上下文不同,get3DContext函数作用就是依次降级获取上下文。
var canvas = document.getElementById("canvas"), |
着色器
着色器就是嵌入到js中的webGL代码,是由GLSL语言编写的,可以把着色器看成是js代码连接webGL的中间件。顶点着色器和片元着色器分别用于操作顶点和颜色光照,《WebGL编程指南》中是把着色器写成字符串,但从可维护性考虑,还是写在script标签中比较好。GLSL语言与C语言非常像,只要熟悉了GLSL特有的部分,其实还是比较简单的。
限定符
限定符只能用于全局变量,有3种类型:
- attribute用于表示顶点信息
- uniform用于表示除顶点外的其他信息,可以是除结构体和数组之外的任意类型
- varying用于顶点着色器向片元着色器传输数据
GLSL特有的数据类型
向量:
vec2, vec3, vec4 : 表示有2,3,4个浮点数的向量
ivec2, ivec3, ivec4 : 表示有2,3,4个整形的向量
bvec2, bvec3, bvec4 : 表示有2,3,4个布尔值的向量矩阵:
mat2, mat3, mat4 : 表示有2x2,3x3,4x4的浮点数的矩阵
顶点着色器
<script type="x-shader/x-vertex" id="vs"> |
片元着色器
<script type="x-shader/x-fragment" id="fs"> |
接着就是创建着色器了,首先从页面script标签取出着色器代码,初始化着色器;接着创建程序对象,最后连接程序对象。中间的步骤其实非常的啰嗦,已经把这几个步骤封装,我们只需要调用createShaders就可以了。
/** |
缓冲区
创建好缓冲区对象后,需要把它分配给变量,然后使它生效。注意顶点数组使用的是类型化数组Float32Array,这样更加高效。vertexAttribPointer方法这里指定了每个顶点分量的个数为2,因为我们目前只定义x,y坐标,z坐标使用系统默认。
/** |
写入数据
首先要获取变量的地址,然后再给变量赋值,感觉挺麻烦的。attribute标记的变量使用getAttribLocation获取,同理uniform标记的变量使用getUniformLocation获取。
我们的动画要使图形绕坐标原点旋转,那么这就需要用到矩阵的变换,矩阵相关的知识就不详细说明了。要注意webGL使用的是列主序的矩阵,计算好变换矩阵后,把值赋予变量就ok。
// 获取 u_FragColor变量的存储地址并赋值 |
背景操作
每次执行动画前进行清屏,和canvas中的设置fillStyle,执行clearRect,效果一样。
// 设置清屏颜色 |
绘制
最后渲染图形,注意第一个参数,指定不同的值,它就渲染为不同的图形,大家可以用不同的值试试效果。
- POINTS 点
- LINES 线段
- LINE_STRIP 线条
- LINE_LOOP 回路
- TRIANGLES 三角形
- TRIANGLE_STRIP 三角带
- TRIANGLE_FAN 三角扇
// (基本图形,第几个顶点,执行几次),修改基本图形项可以生成点,线,三角形,矩形,扇形等 |
最后主体代码如下:
var canvas = document.getElementById("canvas"), |
总结
相比canvas,webGL的api要原始得多,涉及到很多底层的openGL细节,但经过封装后,我们可以把那部分细节看成一个黑箱。大部分的操作都是基于矩阵变换,尽管有很多方便的第三方矩阵库,但有牢固的线性代数基础还是大有裨益的,GLSL编程语言也是一样需要熟练掌握。