绘制变换三角形
# 三角形绘制和多边形
缓冲区对象(buffer object) 它可以一次性地向着色器中传入多个顶点的数据。缓冲区对象是webgl系统中一块内存区域,我们可以一次性地向缓冲区对象中填充大量的顶点数据,然后将这些数据保存在其中,供顶点着色器使用。
使用缓冲区对象向顶点着色器传入多个顶点数据,需要遵循五个步骤
- 创建缓冲区对象(gl.createBuffer)
- 绑定缓冲区对象(gl.bindBuffer) 绑定到webgl已经存在的目标上,这个目标表示缓冲区对象的用途,这样webgl才能正确处理其中的内容。
- 将数据写入缓冲区对象(gl.bufferData)
- 将缓冲区对象分配给一个attribute变量(gl.vertexAttribPointer)
- 开启attribute变量(gl.enableVertexAttribArray),使分配到attribute变量真生生效,顶点着色器可以访问缓冲区中的数据。
提示
gl.deleteBuffer(buffer)删除缓冲区对象 gl.disableVertexAttribArray()关闭缓冲区分配
提示
为了绘制三维图形,webgl通常需要同时处理大量相同类型的数据,为了优化性能,webgl为每种基本数据类型引入了一种特殊的数组(类型化数组),浏览器事先知道数组中的数据类型,所以处理起来也更加有效率。
提示
gl.vertexAttribPointer(location,size,type,normalized,stride,offset)


例子一:使用缓冲区对象中的数据绘制三个点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用缓冲区对象绘制多点</title>
<script src="./lib/cuon-matrix.js"></script>
<script src="./lib/cuon-utils.js"></script>
<script src="./lib/webgl-debug.js"></script>
<script src="./lib/webgl-utils.js"></script>
</head>
<body onload="main()">
<canvas width="400" height="400" id="mulitiPoint"></canvas>
<script>
let VSHADER_SOURCE =
`attribute vec4 a_Position;
void main(){
gl_Position=a_Position;
gl_PointSize=10.0; //该句只有在绘制单个点的时候才起作用
}`;
let FSHADER_SOURCE =
`void main(){
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}`;
function main() {
let canvas = document.querySelector('#mulitiPoint');
let gl = getWebGLContext(canvas);
if (!gl) {
console.info('failed to initalize gl.');
return;
}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.info('failed to initalize shaders.');
return;
}
let n = initVertextBuffers(gl);
if (n < 0) {
console.info('failed to set the position of the vertices');
return;
}
gl.clearColor(1.0, 1.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, n);//绘制3个点
//gl.drawArrays(gl.LINE_STRIP, 0, n);//绘制两条线
//gl.drawArrays(gl.LINES, 0, n);//绘制线段
//gl.drawArrays(gl.LINE_LOOP, 0, n); //绘制空心三角形
//gl.drawArrays(gl.TRIANGLES, 0, n); //绘制实心三角形
//gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); //绘制实心三角形
//gl.drawArrays(gl.TRIANGLE_FAN, 0, n); //绘制实心三角形
}
function initVertextBuffers(gl) {
let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
let n = 3;
let vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.info('failed to create the buffer object');
return -1;
}
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//向缓冲区写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
//将缓冲区对象分配给a_Position
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
//连接a_Position变量与分配给他的缓冲区对象
gl.enableVertexAttribArray(a_Position);
return n;
}
</script>
</body>
</html>
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






<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制多边形</title>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script src="../lib/cuon-matrix.js"></script>
</head>
<body onload="main()">
<canvas width="400" height="400" id='Rect'>
请使用支持的浏览器来实现
</canvas>
<script>
let VSHADER_SOURCE =
`attribute vec4 a_Position;
void main(){
gl_Position=a_Position;
}`;
let FSHADER_SOURCE =
`void main(){
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}`;
function main() {
let canavas = document.querySelector('#Rect');
let gl = getWebGLContext(canavas);
if (!gl) {
console.info('failed initalized gl.');
return;
}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.info('failed initalized shaders.');
return;
}
let n = initVertexBuffer(gl);
if (n < 0) {
console.info('failed initalized vertexBuffer.');
return;
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_FAN, 0, n);
}
function initVertexBuffer(gl) {
let vertices = new Float32Array([-0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5]);
let n = 4;
let vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.info('failed initaized vertexBuffer.');
return -1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STREAM_DRAW);
let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
return n;
}
</script>
</body>
</html>
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

# 变换
平移
x'=x+Tx
y'=y+Ty
z'=z+Tz
(x,y,z) 偏移了 (Tx,Ty,Tz) 后到达点 (x',y',z')
平移计算例子二:三角形平移
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>绘制三角形并且移动</title> <script src="./lib/cuon-matrix.js"></script> <script src="./lib/cuon-utils.js"></script> <script src="./lib/webgl-debug.js"></script> <script src="./lib/webgl-utils.js"></script> </head> <body onload="main();"> <canvas width="300" height="300" id="translate"> 请使用支持的浏览器查看 </canvas> <script> let VSHADER_SOURCE = `attribute vec4 a_Position; uniform vec4 u_Translation; void main(){ gl_Position=a_Position+u_Translation; }`; let FSHADER_SOURCE = `void main(){ gl_FragColor=vec4(1.0,0.5,0.5,1.0); }`; let Tx = 0.5, Ty = 0.5, Tz = 0.0; function main() { let canvas = document.querySelector('#translate'); let gl = getWebGLContext(canvas); if (!gl) { console.info('failed initalizead gl.'); return; } if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.info('failed initaized shaders.'); return; } let n = initVertexBuffer(gl); if (n < 0) { console.info('failed initalized buffer'); return; } let u_Translation = gl.getUniformLocation(gl.program, 'u_Translation'); gl.uniform4f(u_Translation, Tx, Ty, Tz, 0.0); gl.clearColor(0.0, 1.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, n); } function initVertexBuffer(gl) { let vertices = new Float32Array([0.0, 0.5, -0.5, 0.0, 0.5, 0.0]); let n = 3; let vertexBuffer = gl.createBuffer(); if (!vertexBuffer) { console.info('failed initalize vertexBuffer.'); return -1; } gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); let a_Position = gl.getAttribLocation(gl.program, 'a_Position'); gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(a_Position); return n; } </script> </body> </html>
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三角形平移旋转
- 描述旋转必须指明:旋转轴(图形将围绕旋转轴旋转)
- 旋转方向(顺时针旋转还是逆时针旋转)
- 旋转角度(图形旋转经过的角度)
提示
正旋转,观测者在Z轴正半轴某处,视线沿着Z轴负方向进行观察,那么看到的物体就是逆时针旋转的。遵循右手法则旋转。WebGL默认是右手旋转。
提示
sin(a+b) = sinacosb - cosasinb
sin(a-b) = sinacosb + cosasinb
cos(a+b) = cosacosb - sinasinb
cos(a-b) = cosacosb + sinasinb
例子三:三角形正旋转90度
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>三角形旋转</title> <script src="./lib/webgl-utils.js"></script> <script src="./lib/webgl-debug.js"></script> <script src="./lib/cuon-utils.js"></script> <script src="./lib/cuon-matrix.js"></script> </head> <body onload="main();"> <canvas width="300" height="300" id="webgl"> 请使用支持的浏览器查看这个效果 </canvas> <script> let VSHADER_SOURCE = `attribute vec4 a_Position; uniform float u_CosB,u_SinB; void main(){ gl_Position.x=a_Position.x*u_CosB-a_Position.y*u_SinB; gl_Position.y=a_Position.x*u_SinB+a_Position.y*u_CosB; gl_Position.z=a_Position.z; gl_Position.w=1.0; }`; let FSHADER_SOURCE = `void main(){ gl_FragColor=vec4(1.0,0.0,0.0,1.0); }`; let angle = 90.0; function main() { let canvas = document.querySelector('#webgl'); let gl = getWebGLContext(canvas); if (!gl) { console.info('failed initalized gl.'); return; } if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.info('failed initalized shaders.'); return; } let n = initVertexBuffer(gl); if (n < 0) { console.info('failed initalized vertexBuffer.'); return; } let radian = Math.PI * angle / 180.0; let cosB = Math.cos(radian); let sinB = Math.sin(radian); let u_CosB = gl.getUniformLocation(gl.program, 'u_CosB'); let u_SinB = gl.getUniformLocation(gl.program, 'u_SinB'); gl.uniform1f(u_CosB, cosB); gl.uniform1f(u_SinB, sinB); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, n); } function initVertexBuffer(gl) { let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]); let n = 3; let vertexBuffer = gl.createBuffer(); if (!vertexBuffer) { console.info('initalize vertexBuffer failed.'); return -1; } gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); let a_Position = gl.getAttribLocation(gl.program, 'a_Position'); if (a_Position < 0) { console.info('initalized position failed.'); return -1; } gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(a_Position); return n; } </script> </body> </html>
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三角形正旋转90度注意
对于简单的变换,可以使用数学表达式来实现。但是当遇到既有旋转又有平移的复杂情况时,数学表达式书写就变得比较繁琐。解决办法是用变换矩阵来代替数学表达式。
缩放
例子四:使用矩阵实现平移、旋转和缩放
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用矩阵实现平移、旋转、缩放</title>
<script src="./lib/cuon-matrix.js"></script>
<script src="./lib/cuon-utils.js"></script>
<script src="./lib/webgl-debug.js"></script>
<script src="./lib/webgl-utils.js"></script>
</head>
<body onload="test()">
<canvas width="200" height="200" id="webgl">
请使用支持的浏览器查看
</canvas>
<script>
let VSHADER_SOURCE =
`attribute vec4 a_Position;
uniform mat4 u_xformMatrix;
void main(){
gl_Position=u_xformMatrix*a_Position;
}`;
let FSHADER_SOURCE =
`void main(){
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}`;
let ANGLE = 90;
let Tx = 0.5;
let Ty = 0.5;
let Tz = 0.0;
let Sx = 1.0;
let Sy = 1.5;
let Sz = 1.0;
function test(){
let canvas = document.querySelector('#webgl');
let gl = getWebGLContext(canvas);
if (!gl) {
console.info('failed initalized gl.');
return;
}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.info('failed initalized shaders.');
return;
}
let n = initVertexBuffer(gl);
if (n < 0) {
console.info('failed initalized vertexBuffer.');
return;
}
let radian = Math.PI * ANGLE / 180.0;
let cosB = Math.cos(radian);
let sinB = Math.sin(radian);
//webgl矩阵是列主序的
let xformMatrix = new Float32Array([
cosB, sinB, 0.0, 0.0,
-sinB, cosB, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
]);
let xformMatrix1 = new Float32Array([
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
Tx, Ty, Tz, 1.0
]);
let xformMatrix2 = new Float32Array([
Sx, 0.0, 0.0, 0.0,
0.0, Sy, 0.0, 0.0,
0.0, 0.0, Sz, 0.0,
0.0, 0.0, 0.0, 1.0
]);
let u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
//给矩阵变量传值
//gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);
//gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix1);
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix2);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffer(gl) {
let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
let n = 3;
let vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.info('initalize vertexBuffer failed.');
return -1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.info('initalized position failed.');
return -1;
}
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
return n;
}
</script>
</body>
</html>
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
注意
WebGL和OpenGL一样,矩阵元素是按照列主序储存在数组中的。