目录
WebGL
类型化数组
WebGL 涉及的复杂计算需要提前知道数值的精度,而标准的 JavaScript 数值无法满足需要。为此,WebGL 引入了一个概念,叫类型化数组(typed arrays)。类型化数组也是数组,只不过其元素被设置为特定类型的值。
类型化数组的核心就是一个名为 ArrayBuffer 的类型。每个 ArrayBuffer 对象表示的只是内存中指定的字节数,但不会指定这些字节用于保存什么类型的数据。通过 ArrayBuffer 所能做的,就是为了将来使用而分配一定数量的字节。
视图
使用 ArrayBuffer(数组缓冲器类型)的一种特别的方式是用它创建数组缓冲器视图。最常见的视图是 DataView,通过它可以选择 ArrayBuffer 中一小段字节。为此,可以在创建 DataView实例的时候传入一个 ArrayBuffer、一个可选的字节偏移量(从该字节开始选择)和一个可选的要选择的字节数。
//基于整个缓冲器创建一个新视图
var view = new DataView(buffer);
//创建一个开始于字节 9 的新视图
var view = new DataView(buffer, 9);
//创建一个从字节 9 开始到字节 18 的新视图
var view = new DataView(buffer, 9, 10);
alert(view.byteOffset);//字节偏移量
alert(view.byteLength);//字节长度
var buffer = new ArrayBuffer(20),
view = new DataView(buffer),
value;
view.setUint16(0, 25);
view.setUint16(2, 50); //不能从字节 1 开始,因为 16 位整数要用 2B
value = view.getUint16(0);
var buffer = new ArrayBuffer(20),
view = new DataView(buffer),
value;
view.setUint16(0, 25);//存25即0000 0000 0001 1001
value = view.getInt8(0);//读 0000 0000 即0
alert(value); //0
类型化视图
类型化视图一般也被称为类型化数组,因为它们除了元素必须是某种特定的数据类型外,与常规的数组无异。类型化视图也分几种,而且它们都继承了 DataView。
Int8Array:表示 8 位二补整数。
Uint8Array:表示 8 位无符号整数。
Int16Array:表示 16 位二补整数。
Uint16Array:表示 16 位无符号整数。
Int32Array:表示 32 位二补整数。
Uint32Array:表示 32 位无符号整数。
Float32Array:表示 32 位 IEEE 浮点值。
Float64Array:表示 64 位 IEEE 浮点值。
WebGL上下文
Insert IconMargin [download]var drawing = document.getElementById("drawing"),gl;
//确定浏览器支持<canvas>元素
if (drawing.getContext){
try {
gl = drawing.getContext("experimental-webgl");
} catch (ex) {
//什么也不做
}
if (gl){
//使用 WebGL
} else {
alert("WebGL context could not be created.");
}
}
WebGLExample01.ht
常量
常量在 OpenGL 中都带前缀GL_ 。 在WebGL中 ,保存在上下文对象中的这些常量都没有GL_ 前缀 。比如说,GL_COLOR_BUFFER_BIT 常量在 WebGL 上下文中就是 gl.COLOR_BUFFER_BIT。 WebGL 以这种方式支持大多数 OpenGL 常量。
方法命名
OpenGL(以及 WebGL)中的很多方法都试图通过名字传达有关数据类型的信息。如果某方法可以接收不同类型及不同数量的参数,看方法名的后缀就可以知道。方法名的后缀会包含参数个数(1 到 4)和接收的数据类型(f 表示浮点数, i 表示整数)。例如, gl.uniform4f()意味着要接收 4 个浮点数,而 gl.uniform3i()则表示要接收 3 个整数。
也有很多方法接收数组参数而非一个个单独的参数。这样的方法其名字中会包含字母 v(即 vector,矢量)。因此, gl.uniform3iv()可以接收一个包含 3 个值的整数数组。
准备绘图
在实际操作 WebGL 上下文之前,一般都要使用某种实色清除<canvas>,为绘图做好准备。首先必须使用clearColor()方法来指定要使用的颜色值,该方法接收 4 个参数:红、绿、蓝和透明度。每个参数必须是一个 0 到 1 之间的数值,表示每种分量在最终颜色中的强度。
gl.clearColor(0,0,0,1); //black
gl.clear(gl.COLOR_BUFFER_BIT);
视口与坐标
开始绘图之前,通常要先定义 WebGL 的视口(viewport)。
//视口是<canvas>左下角的四分之一区域
gl.viewport(0, 0, drawing.width/2, drawing.height/2);
//视口是<canvas>左上角的四分之一区域
gl.viewport(0, drawing.height/2, drawing.width/2, drawing.height/2);
//视口是<canvas>右下角的四分之一区域
gl.viewport(drawing.width/2, 0, drawing.width/2, drawing.height/2);
缓冲区
顶点信息保存在 JavaScript 的类型化数组中,使用之前必须转换到 WebGL 的缓冲区。
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.5, 1]), gl.STATIC_DRAW);
gl.deleteBuffer(buffer);
错误
JavaScript 与 WebGL 之间的一个最大的区别在于, WebGL 操作一般不会抛出错误。为了知道是否有错误发生,必须在调用某个可能出错的方法后,手工调用 gl.getError()方法。这个方法返回一个表示错误类型的常量。
var errorCode = gl.getError();
while(errorCode){
console.log("Error occurred: " + errorCode);
errorCode = gl.getError();
}
着色器
着色器(shader)是 OpenGL 中的另一个概念。WebGL中有两种着色器:顶点着色器和片段(或像素)着色器。顶点着色器用于将 3D 顶点转换为需要渲染的2D点。片段着色器用于准确计算要绘制的每个像素的颜色。 WebGL 着色器的独特之处也是其难点在于,它们并不是用 JavaScript 写的。这些着色器是使用 GLSL(OpenGL Shading Language,OpenGL 着色语言)写的, GLSL 是一种与 C 和 JavaScript完全不同的语言。
编写着色器
GLSL 是一种类 C 语言,专门用于编写 OpenGL 着色器。因为 WebGL 是 OpenGL ES 2.0 的实现,所以 OpenGL 中使用的着色器可以直接在 WebGL 中使用。这样就方便了将桌面图形应用移植到浏览器中。
每个着色器都有一个 main()方法,该方法在绘图期间会重复执行。为着色器传递数据的方式有两种: Attribute 和 Uniform。通过 Attribute 可以向顶点着色器中传入顶点信息,通过 Uniform 可以向任何着色器传入常量值。 Attribute 和 Uniform 在 main()方法外部定义,分别使用关键字 attribute 和uniform。在这两个值类型关键字之后,是数据类型和变量名。
编写着色器程序
浏览器不能理解 GLSL 程序,因此必须准备好字符串形式的 GLSL 程序,以便编译并链接到着色器程序。为便于使用,通常是把着色器包含在页面的<script>标签内,并为该标签指定一个自定义的 type属性。由于无法识别 type 属性值,浏览器不会解析<script>标签中的内容,但这不影响你读写其中的代码。
为着色器传入值
为了给着色器传入这个值,必须先找到要接收这个值的变量。对于 Uniform 变量,可以使用 gl.getUniformLocation(),这个方法返回一个对象,表示Uniform 变量在内存中的位置。然后可以基于变量的位置来赋值。
调试着色器和程序
与 WebGL 中的其他操作一样,着色器操作也可能会失败,而且也是静默失败。如果你想知道着色器或程序执行中是否发生了错误,必须亲自询问 WebGL 上下文。
绘图
WebGL 只能绘制三种形状:点、线和三角。其他所有形状都是由这三种基本形状合成之后,再绘制到三维空间中的。执行绘图操作要调用 gl.drawArrays()或 gl.drawElements()方法,前者用于数组缓冲区,后者用于元素数组缓冲区。
纹理
WebGL 的纹理可以使用 DOM 中的图像。要创建一个新纹理,可以调用 gl.createTexture(),然后再将一幅图像绑定到该纹理。如果图像尚未加载到内存中,可能需要创建一个 Image 对象的实例,以便动态加载图像。图像加载完成之前,纹理不会初始化,因此,必须在 load 事件触发后才能设置纹理。
读取像素
与 2D 上下文 类似,通过 WebGL 上下文也能读取像素值。读取像素值的方法 readPixels()与OpenGL 中的同名方法只有一点不同,即最后一个参数必须是类型化数组。像素信息是从帧缓冲区读取的,然后保存在型化数组中。 readPixels()方法的参数有: x、 y、宽度、高度、图像格式、数据类型和类型化数组。前 4 个参数指定读取哪个区域中的像素。图像格式参数几乎总是 gl.RGBA。数据类型参数用于指定保存在类型化数组中的数据的类型。