### 创建 WebGL上下文
1 2 3 4 5 6 7 8 9
| <canvas id='glcanvas' width='600' height='600'></canvas>
<script> var canvas = document.getElementById('glcanvas'); var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
</script>
|
创建顶点着色器和片段着色器
所有的 WebGL 程序都必须有一个顶点着色器和一个片段着色器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <script id="vertexShader" type="x-shader/x-vertex">
attribute vec3 a_position;
void main(){ gl_Position = vec4(a_position,1.0); gl_PointSize = 10.0; } </script>
<script id="fragmentShader" type="x-shader/x-fragment"> void main(){ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } </script>
<script>
var vertexShaderSource = document.getElementById('vertexShader').innerText;
var fragShaderSource = document.getElementById('fragmentShader').innerText;
</script>
|
### 编译着色器
1 2 3 4
| gl.shaderSource(vShader, vertexShaderSource); gl.shaderSource(fShader, fragShaderSource); gl.compileShader(vShader); gl.compileShader(fShader);
|
### 创建程序对象和链接着色器
1 2 3 4 5
| var shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vShader); gl.attachShader(shaderProgram, fShader); gl.linkProgram(shaderProgram); gl.useProgram(shaderProgram);
|
建立缓冲
1 2 3 4 5 6 7 8 9 10 11
| var vertices = [ 0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0 ];
var vertex_buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
|
调用 gl.bufferData()
方法,把顶点数据写入当前绑定的 WebGLBuffer 对象中。这个调用告诉 WebGL,哪些数据保存在用 gl.createBuffer()
创建的缓冲对象中。这样子会导致丢失上下文。
清空面板
1 2 3
| gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
gl.clear()
方法通过参数 gl.COLOR_BUFFER_BIT
指示 WebGL 把颜色缓冲清除为事先用gl.clearColoro()
函数定义的颜色。本例用 gl.clearColor()
把黑色定义为清除颜色。因此,当调用 gl.clear()
方法时,颜色缓冲清除为黑色。
clearColor
1
| void gl.clearColor(red, green, blue, alpha);
|
参数
- red 一个 GLclampf 类型的值,指定清除缓冲时的红色值。默认值:0。
- green 一个 GLclampf 类型的值,指定清除缓冲时的绿色值。默认值:0。
- blue 一个 GLclampf 类型的值,指定清除缓冲时的蓝色值。默认值:0。
- alpha 一个 GLclampf 类型的值,指定清除缓冲时的不透明度。默认值:0
绘制场景
1 2 3 4 5 6 7 8 9 10 11
| var a_position = gl.getAttribLocation(shaderProgram, "a_position");
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(a_position);
gl.drawArrays(gl.TRIANGLES, 0, 3)
|
vertexAttribPointer
1
| void gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
|
index 指定要修改的顶点属性的索引 , 可以通过 gl.getAttribLocation
获取
size 表示每个属性的大小或分量数。在本例中,每个属性的分量是3(因为每个顶点位置用x、y、z坐标表示)。
type 指定数组中每个元素的数据类型。gl.FLOAT
表示要把顶点缓冲对象中的值当作浮点数。如果我们传入的数据不是浮点数,则在顶点着色器中使用它之前,必须将其转换为浮点数
gl.BYTE
: 有符号的8位整数,范围[-128, 127]
gl.SHORT
: 有符号的16位整数,范围[-32768, 32767]
gl.UNSIGNED_BYTE
: 无符号的8位整数,范围[0, 255]
gl.UNSIGNED_SHORT
: 无符号的16位整数,范围[0, 65535]
gl.FLOAT
: 32位IEEE标准的浮点数normalized
normalized 当转换为浮点数时是否应该将非浮点数统一转化成特定范围的浮点数。
- 对于类型
gl.BYTE
和gl.SHORT
,如果是true则将值归一化为[-1, 1]
- 对于类型
gl.UNSIGNED_BYTE
和gl.UNSIGNED_SHORT
,如果是true则将值归一化为[0, 1]
- 对于类型
gl.FLOAT
和gl.HALF_FLOAT
,此参数无效
stride 当这个参数取值0时,就相当于 $ size * sizeof(type) $ 表示数据在内存中顺
序存放
offset 表示缓冲中的偏移值。如果数据从缓冲的开始位置存放,那么这个参数也设置为 0。
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| <html> <head> <meta charset="utf-8"> <title></title>
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec3 a_position; void main(){ gl_Position = vec4(a_position,1.0); gl_PointSize = 10.0; } </script>
<script id="fragmentShader" type="x-shader/x-fragment"> void main(){ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } </script>
</head> <body>
<canvas id='glcanvas' width='600' height='600'></canvas>
<script> var canvas = document.getElementById('glcanvas'); var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
var vertexShaderSource = document.getElementById('vertexShader').innerText;
var fragShaderSource = document.getElementById('fragmentShader').innerText;
var vShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vShader, vertexShaderSource); gl.compileShader(vShader); var fShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fShader, fragShaderSource); gl.compileShader(fShader);
var shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vShader); gl.attachShader(shaderProgram, fShader); gl.linkProgram(shaderProgram); gl.useProgram(shaderProgram);
var vertices = [ 0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0 ];
var vertex_buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var a_position = gl.getAttribLocation(shaderProgram, "a_position");
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(a_position);
gl.drawArrays(gl.TRIANGLES, 0, 3) </script>
</body> </html>
|
类型化数组
上面代码中 Float32Array 到底是什么,以及为什么要用这个类型?
C和C++等程序设计语言是可以直接操作二进制数据。但是 JavaScript 语言并没有内置二进制数据的处理功能。js开发人员如果需要处理二进制数据,则要把数据转化成字符串,然后用JavaScript的charCodeAt()
方法和位操作运算符(&、、<<和>>)进行处理。
下面这个示例说明如何获得用字符串表示的数据中某个位置的特定字节∶
1
| var oneByte = str.charCodeAt(index) & 0xFF;
|
这个过程的开销太大,不是一个切实可行的解决方法。因此,引入了 JavaScript类型化数组类型,它是一个更为有效的二进制处理方法。
ArrayBuffer
new ArrayBuffer(length)
- length 表示要创建的 ArrayBuffer 的大小,单位为字节。
类型化数组是建立在ArrayBuffer对象的基础上的。它的作用是,分配一段可以存放数据的连续内存区域。
1 2
| var buf = new ArrayBuffer(32);
|
视图
ArrayBuffer作为内存区域,是不带类型的。需要为创建的ArrayBuffer指定一个类型,才能对其进行读写操作 ,这就叫做“视图”。
JavaScript 提供类型视图如下:
TYPE |
Description |
Value Range |
Size in bytes |
Int8Array |
8位有符号整数 |
-128 to 127 |
1字节 |
Uint8Array |
8位无符号整数 |
0 to 255 |
1字节 |
Uint8ClampedArray |
8位浮点数 |
0 to 255 |
1字节 |
Int16Array |
16位有符号整数 |
-32768 to 32767 |
2字节 |
Uint16Array |
16位无符号整数 |
0 to 65535 |
2字节 |
Int32Array |
32位有符号整数 |
-231 to 231-1 |
4字节 |
Uint32Array |
32位无符号整数 |
0 to 232 |
4字节 |
Float32Array |
32位浮点数 |
“Isn’t this fun?” |
4字节 |
Float64Array |
64位浮点数 |
– is en-dash, — is em-dash |
8字节 |
如果创建了一个 ArrayBuffer,并且以它为基础又创建了一个 Uint8Array、一个Uint16Array、一个 Uint32Array、一个 Float64Array 视图,他们之间的对应关系如下:
数组缓冲区中的值的类型 与 ArrayBuffer 的 对应关系
ArrayBuffer |
数组缓冲区类型 |
Uint8Array |
gl.UNSIGNED_BYTE |
Uint16Array |
gl.UNSIGNED_SHORT_5_6_5 gl.UNSIGNED_SHORT_4_4_4_4 gl.UNSIGNED_SHORT_5_5_5_1 gl.UNSIGNED_SHORT ext.HALF_FLOAT_OES |
Uint32Array |
gl.UNSIGNED_INT ext.UNSIGNED_INT_24_8_WEBGL |
Float32Array |
gl.FLOAT |