本文介绍一个简单的WebGL程序,与canvas2D相比,除了代码量剧增,需要掌握的相关知识也多了很多
试读
##一.canvas 2D绘制矩形
用canvas 2D绘制一个矩形很容易,几行代码轻松搞定:
<!-- html -->
<h5>canvas2d</h5>
<canvas id="canvas2d" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
// js
// 获取元素引用
var canvas2d = document.getElementById('canvas2d');
// 获取2D context
var ctx = canvas2d.getContext('2d');
// 设置填充色
ctx.fillStyle = 'rgba(255, 0, 255, 0.75)';
// 绘制矩形块
ctx.fillRect(100, 100, 200, 200);
实际效果就是一个200x200px淡紫色矩形块,周围一圈宽度100px的透明环。从代码的角度来看,应该是:400x400px的透明canvas中心被涂上了一个不透明度为0.75的200x200px的紫色矩形块
从ctx.fillRect(100, 100, 200, 200);可以看出canvas 2D的坐标系与屏幕坐标系一样,左上角是(0, 0),x轴向右为正,y轴向下为正
从ctx.fillStyle = 'rgba(255, 0, 255, 0.75)';可以看出rgba()与CSS一样,rgb值为0255,a为01表示不透明度
##二.WebGL绘制矩形
###1.获取context
类似于canvas2d.getContext('2d'),WebGL需要获取专用的context:
var webgl = document.getElementById('webgl');
var gl = webgl.getContext('webgl');
这里习惯把WebGL的context命名为gl,是为了以后调用API时与OpenGL调用方式保持一致,嗯,就图个好看
###2.清空canvas
类似于canvas 2D提供的clearRect方法,WebGL也有橡皮擦一样的东西,而且更强大,可以指定擦除后的颜色:
// 指定清空canvas的颜色
// 参数是rgba,范围0.0~1.0
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 清空canvas
// gl.COLOR_BUFFER_BIT颜色缓存,默认清空色rgba(0.0, 0.0, 0.0, 0.0) 透明黑色,通过gl.clearColor指定
// gl.DEPTH_BUFFER_BIT深度缓存,默认深度1.0,通过gl.clearDepth指定
// gl.STENCIL_BUFFER_BIT模板缓存,默认值0,通过gl.clearStencil()指定
gl.clear(gl.COLOR_BUFFER_BIT);
对于本例而言,清空canvas不是必须的,但一定要会用这种方法,不然就疯了,因为在canvas 2D中,如果要设置黑色背景,我们会这样做:
// 黑色背景
ctx.fillStyle = 'rgba(0, 0, 0, 1)';
ctx.fillRect(0, 0, canvas2d.width, canvas2d.height);
同样的思路,画一个黑块铺满整个canvas,在WebGL中当然也可以,但会相当麻烦
###3.绘制矩形
为了绘制一个矩形,我们需要先做8件事情:
- 编写着色器源程序
使用着色器语言(GLSL ES)编写着色器源程序,再以字符串形式传入WebGL系统内部编译执行:
// 0.着色器源程序
// 顶点着色器源程序
var vsSrc = 'void main() {' +
'gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' + // 设置坐标
'gl_PointSize = 200.0;' + // 设置尺寸
'}';
// 片元着色器源程序
var fsSrc = 'void main() {' +
'gl_FragColor = vec4(1.0, 0.0, 1.0, 0.75);' + // 设置颜色
'}';
GLSL ES的语法和C语言比较像,具体语法规则在以后的笔记里再说
- 创建着色器对象
没什么好说的,游戏规则
// 1.创建着色器对象
var vs = gl.createShader(gl.VERTEX_SHADER);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
// 检查创建结果
if (vs === null) {
log('gl.createShader(gl.VERTEX_SHADER) failed');
}
if (fs === null) {
log('gl.createShader(gl.FRAGMENT_SHADER) failed');
}
3. 填充源程序
有了着色器对象,就可以把着色器源程序塞进去了
// 2.填充源程序
gl.shaderSource(vs, vsSrc);
gl.shaderSource(fs, fsSrc);
4. 编译
有了源码,赶紧编译,看报不报错
// 3.编译
gl.compileShader(vs);
gl.compileShader(fs);
// 检查编译错误
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
log('gl.compileShader(vs) failed');
log(gl.getShaderInfoLog(vs)); // 输出错误信息
}
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
log('gl.compileShader(fs) failed');
log(gl.getShaderInfoLog(fs)); // 输出错误信息
}
5. 创建程序对象
除了着色器对象,还需要程序对象,js与WebGL内部交流主要通过这个程序对象,先做一个出来
// 4.创建程序对象
var prog = gl.createProgram();
// 检查创建结果
if (prog === null) {
log('gl.createProgram() failed');
}
注意:上面4步都是一个顶点XX和一个片元XX,而这一步只需要1个prog对象
- 为程序对象分配着色器
每个prog都需要2个着色器(1个顶点着色器,1个片元着色器),所以检查分配错误时要与2比较,看prog身上是不是绑了2个shader
// 5.为程序对象分配着色器
gl.attachShader(prog, vs);
gl.attachShader(prog, fs);
// 检查分配错误
if (gl.getProgramParameter(prog, gl.ATTACHED_SHADERS) !== 2) {
log('gl.getProgramParameter(prog, gl.ATTACHED_SHADERS) failed');
}
7. 连接程序对象
类似于C语言程序的compile -> link -> run
// 6.连接程序对象
gl.linkProgram(prog);
// 检查连接错误
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
log('gl.linkProgram(prog) failed');
log(gl.getProgramInfoLog(prog));
}
8. 使用程序对象
不做错误检查,因为没有返回值
// 7.使用程序对象
gl.useProgram(prog);
至此,为绘制一个矩形做的准备工作就完成了
最后当然是draw点什么
// 绘制矩形(一个点,但点的尺寸略大)
gl.drawArrays(gl.POINTS, 0, 1);
##三.DEMO
包含上述代码的完整的例子,请查看:http://www.ayqy.net/temp/webgl/hoho/index.html
##四.WebGL与canvas 2D的差异
###1.坐标系不同
在WebGL中,canvas的中心是(0, 0),x轴向右为正,y轴向上为正,z轴从屏幕射出指向脸为正(右手坐标系)
###2.坐标值不同
WebGL中,整个画布是Rect(-1.0, 1.0, 2, 2),也就是说canvas左上角坐标是(-1.0, 1.0),右上角坐标为(1.0, 1.0),画布尺寸是2x2,如果canvas本身是400x400px的,那么WebGL中坐标值的单位就是200px
注意:对于非坐标值属性,比如上面着色器源程序中的gl_PointSize,其单位仍然是px
###3.rgb值不同
片元着色器中有用到色值,vec4(r, g, b, a),与CSS的rgba()不同,WebGL中rgb值范围是0.0~1.0,而且必须是带小数的形式,因为vec4构造函数只接受float型参数,int不会被隐式转换为float
###4.颜色叠加规则不同
运行DEMO能够发现canvas 2D与Web GL画出的紫色矩形颜色不同,canvas 2D中我们先绘制了黑色背景,再画上了紫色矩形,紫色矩形有0.25的透明,最终显示的颜色是紫色与黑色的叠加。
而WebGL中,紫色矩形的颜色没有与黑色叠加(body背景色就是我们给紫色矩形指定的颜色,能清楚地看到WebGL中没有发生紫黑叠加)。尝试在紫色矩形背后(z坐标为-0.1)再绘制一个黑色矩形,发现颜色仍然没有叠加,这需要特别注意
##五.总结
从API使用步骤上来看WebGL就是这么麻烦,画一个矩形都要写这么多代码,实际上我们只绘制了一个点(略大只的点),绘制矩形还要更麻烦些,需要用4个顶点确定2个三角片,再分别填色
至于顶点着色器,片元着色器是什么?有什么作用?需要一个稍微复杂一点的例子来说明,我们在以后的笔记里再解释
###参考资料
- 《WebGL编程指南》
评论
暂无评论