什么是WebGL?
WebGL是一种可以在网页上绘制渲染3D图形,并允许用户与之交互的技术。浏览器内置了WebGL,可以搭配HTML5和JavaScript使用。
WebGL的优势?
充分利用前端开发与浏览器的优势,不需要复杂的开发环境,可以轻松开发可移植性强、兼容性强的三维图形程序。WebGL程序使用三种语言开发:HTML、JavaScript、GLSL ES(OpenGL ES)着色器代码内嵌在JavaScript中,以字符串形式在JavaScript中编写。
例2.1 DrawRectangle 绘制一个实心蓝色矩形
目标: 了解canvas标签与绘图上下文
步骤:
- 获取canvas元素
var canvas = document.getElementById('canvas');
- 向该元素请求二维图形的绘图上下文
var ctx = canvas.getContext('2d');
- 使用绘图上下文的绘图函数,绘制二维图形
// 设置填充颜色为蓝色
ctx.fillStyle = 'rgba(0, 0, 255, 1.0)';
// 使用填充颜色填充指定大小和位置的矩形
ctx.fillRect(120, 10, 150, 150);
fillRect函数前两个参数是位置,后两个参数是宽高。
例2.2 HelloCanvas 清空/使用指定颜色填充canvas
目标: 使用指定颜色清空画布
步骤:
获取canvas元素
获取WebGL绘图上下文
var gl = getWebGLContext(canvas);
- 设置背景色,设置的背景色会常驻系统,待下一次调用前不会改变
gl.clearColor(0.0, 0.0, 1.0, 1.0);
- 清空canvas,用背景色填充,擦除已经绘制的内容
gl.clear(gl.COLOR_BUFFER_BIT);
gl.COLOR_BUFFER_BIT指的是颜色缓冲区(color buffer),除此之外还有深度缓冲区和模板缓冲区。
例2.3 HelloPoint1 绘制一个点(版本1)
目标: 学习编写着色器代码,初始化着色器并绘制图形
着色器是WebGL的绘图机制,着色器包括顶点着色器和片元着色器两种,顶点着色器是用于描述顶点特性(如位置、颜色等)的程序,顶点指的是图形的端点和交点,片元着色器是进行逐片元处理过程(如光照等)的程序,片元是WebGL术语,可以理解为像素。
步骤:
获取canvas元素
获取WebGL绘图上下文
初始化着色器
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)
着色器初始化之前,顶点和片元着色器都是空白的,函数将字符串形式的着色器代码从JavaScript传给WebGL系统并建立着色器。
设置背景色
清空canvas
绘制一个点
gl.drawArrays(gl.POINTS, 0, 1);
调用该函数,顶点着色器被执行count次,每次处理一个顶点。
着色器代码:
// 顶点着色器程序
var VSHADER_SOURCE =
'void main() {\n' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' + // 设置坐标
' gl_PointSize = 10.0;\n' + // 设置尺寸
'}\n';
// 片元着色器程序
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // 设置颜色
'}\n';
在着色器代码中,gl_Position必填,指定顶点位置,vec4表示4个浮点数矢量,gl_PointSize为顶点尺寸,gl_FragColor为片元颜色。
WebGL坐标为右手坐标系统,并且在二维平面中与canvas坐标系统也不一致。
例2.4 HelloPoint2 绘制一个点(版本2)
目标: 使用attribute变量,使用attribute或uniform变量将位置信息从JavaScript程序中传给顶点着色器,attribute变量传输与顶点相关的数据,uniform变量传输与顶点无关的数据
步骤:
- 在顶点着色器代码中,声明attribute变量,并赋值给gl_Position变量
'attribute vec4 a_Position;\n' +
···
' gl_Position = a_Position;\n' + // 设置坐标
- 着色器初始化后,获取attribute变量的存储位置
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
- 向attribute变量传递数据
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
gl.vertexAttrib?f(?=1/2/3/4)的任务是从JavaScript向顶点着色器中的attribute变量传值。
例2.5 ClickedPoints 通过鼠标点击绘点
目标: 加入鼠标交互,通过鼠标点击绘点,了解浏览器、canvas、webgl坐标系统与相互转换
步骤:
- 为鼠标点击事件绑定回调函数click
canvas.onmousedown = function(ev) {
click(ev, gl, canvas, a_Position);
}
- 通过event可以获得鼠标点击的位置(浏览器页面坐标),该坐标需要转换到canvas坐标系统下,再转换到webgl坐标系统下
var x = ev.clientX; // 鼠标点击处的x坐标
var y = ev.clientY; // 鼠标点击处的y坐标
var rect = ev.target.getBoundingClientRect();
ev.target表示canvas元素,getBoundingClientRect用于获取某个元素相对于视窗的位置集合,返回包含top、left、bottom、right、width和height属性的对象。
坐标转换代码如下:
x = ((x - rect.left) - canvas.width/2)/(canvas.width/2);
y = (canvas.height/2 - (y - rect.top))/(canvas.height/2);
- 清空canvas,根据数组的每个元素,在相应位置绘制点:点位置传递给变量,并绘制
// 清空canvas
gl.clear(gl.COLOR_BUFFER_BIT);
var len = g_points.length;
for (var i = 0; i < len; i += 2) {
// 将点的位置传递到变量a_Position中
gl.vertexAttrib3f(a_Position, g_points[i], g_points[i+1], 0.0);
// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);
}
存储点坐标的数组会存储所有点坐标,每次点击后指定canvas背景颜色(设置颜色缓冲区),再把数组中的所有点绘制出来。若注释清空canvas代码,在第一次点击后canvas背景色变为白色,因为绘制点后,颜色缓冲区会被重置为默认颜色。
例2.6 ColoredPoints 改变点的颜色
目标: 熟悉uniform变量的使用
步骤:
- 在片元着色器中定义并使用uniform变量,注意在片元着色器中使用变量时需要使用精度限定词指定变量的范围和精度,否则程序会报错
var FSHADER_SOURCE =
'precision mediump float;\n' + // 精度限定词
'uniform vec4 u_FragColor;\n' + // uniform变量
'void main() {\n' +
' gl_FragColor = u_FragColor;\n' + // 设置颜色
'}\n';
- 获取uniform变量地址
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
- 向uniform变量传递数据
gl.uniform4f(u_FragColor, rgba[0], rgba[1], rgba[2], rgba[3]);