三维世界
# 概念理解
前面几章主要了解了WebGL系统的工作原理、着色器的作用、矩阵变换(平移和旋转)、动画和纹理映射等等。
绘制三维物体时需要考虑其深度信息。
定义一个观察者需要考虑以下两点:
- 观察方向,即观察者自己在什么位置,在看场景的哪一部分
- 可视距离,即观察者能够看多远
视点:观察者所在的三维空间中的位置,视线的起点。用(eyeX,eyeY,eyeZ)
表示。
视线:观察者所处的位置,从视点出发沿着观察者方向的射线称作视线 (viewing direction)。
观察目标点:被观察目标所在的点。视线从视点触发,穿过观察目标点并继续延伸。只有同时知道观察目标点和视点,才能算出视线方向。用(atX,atY,atZ)
表示。
WebGL系统中,默认情况下的视点处于原点(0,0,0)
,视线为Z轴负半轴(指向屏幕内部)
为了确定观察者的状态,需要我们获取两项信息:视点,即观察者的位置;观察目标点,即被观察目标所在的点,它可以用来确定视线。最后我们要把 观察到的景象绘制到屏幕上,还需知道上方向(up direction)。有了这三项信息就可以确定观察者的状态了。用(upX,upY,upZ)
表示。


上图中的三个矢量
创建了一个视图矩阵(view matrix)
,然后将该矩阵传递给顶点着色器。视图矩阵可以表示观察者的状态,含观察者的视点、观察目标点、上方向等信息。之所以被称作视图矩阵
,是因为它最终影响了显示在屏幕上的视图
,也就是观察者观察到的场景。
# 例子:三维世界中画三个三角形
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>走进三维世界:视图矩阵</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_ViewMatrix * a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
let u_ViewMatrix_Location = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
let matrix = new Matrix4();
matrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0);
gl.uniformMatrix4fv(u_ViewMatrix_Location, false, matrix.elements);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
//顶点+颜色
let verticesColors = new Float32Array([
0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
-0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
0.5, -0.5, -0.4, 1.0, 0.4, 0.4,
0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
-0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
0.0, -0.6, -0.2, 1.0, 1.0, 0.4,
0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
-0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
0.5, -0.5, 0.0, 1.0, 0.4, 0.4
]);
let n = 9;
let vertexColorbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
let a_Color_location = gl.getAttribLocation(gl.program, 'a_Color');
gl.vertexAttribPointer(a_Color_location, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color_location);
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

# 视图矩阵
实际上根据自定义的观察者状态,绘制观察者看到的景象,与使用默认的观察者状态,但对三维对象进行平移、旋转等变换,在绘制观察者看到的景象,这两种行为是等价的。

场景中的物体旋转、平移、缩放以及他们的组合变换都是来操作场景模型的,所以也称之为模型变换
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>模型矩阵与视图矩阵</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;
uniform mat4 u_modelMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_ViewMatrix * u_modelMatrix * a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
let u_ViewMatrix_Location = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
let matrix = new Matrix4();
matrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0);
gl.uniformMatrix4fv(u_ViewMatrix_Location, false, matrix.elements);
let u_ModelMatrix_Location = gl.getUniformLocation(gl.program, 'u_modelMatrix');
let m_matrix = new Matrix4();
m_matrix.setRotate(-60, 0, 0, 1);
gl.uniformMatrix4fv(u_ModelMatrix_Location, false, m_matrix.elements);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
//顶点+颜色
let verticesColors = new Float32Array([
0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
-0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
0.5, -0.5, -0.4, 1.0, 0.4, 0.4,
0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
-0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
0.0, -0.6, -0.2, 1.0, 1.0, 0.4,
0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
-0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
0.5, -0.5, 0.0, 1.0, 0.4, 0.4
]);
let n = 9;
let vertexColorbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
let a_Color_location = gl.getAttribLocation(gl.program, 'a_Color');
gl.vertexAttribPointer(a_Color_location, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color_location);
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


# 模型视图矩阵
模型视图矩阵 = 视图矩阵 * 模型矩阵
上例改进版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>模型矩阵与视图矩阵的性能优化版本</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
//uniform mat4 u_ViewMatrix;
//uniform mat4 u_modelMatrix;
uniform mat4 u_modelviewMatrix;
varying vec4 v_Color;
void main(){
//gl_Position = u_ViewMatrix * u_modelMatrix * a_Position;
gl_Position = u_modelviewMatrix * a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
let u_modelviewMatrix = gl.getUniformLocation(gl.program, 'u_modelviewMatrix');
// let mMatrix = new Matrix4();
// let vMatrix = new Matrix4();
// vMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0);
// mMatrix.setRotate(-60, 0, 0, 1);
// let mvMatrix = vMatrix.multiply(mMatrix);
//上面注释的代码就是下面一行代码的拆分
let mvMatrix = new Matrix4();
mvMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0).rotate(-60, 0, 0, 1);
gl.uniformMatrix4fv(u_modelviewMatrix, false, mvMatrix.elements);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
//顶点+颜色
let verticesColors = new Float32Array([
0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
-0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
0.5, -0.5, -0.4, 1.0, 0.4, 0.4,
0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
-0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
0.0, -0.6, -0.2, 1.0, 1.0, 0.4,
0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
-0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
0.5, -0.5, 0.0, 1.0, 0.4, 0.4
]);
let n = 9;
let vertexColorbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
let a_Color_location = gl.getAttribLocation(gl.program, 'a_Color');
gl.vertexAttribPointer(a_Color_location, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color_location);
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
# 可视空间
人类可以观察的眼前可视范围大概是水平方向200
度内东西。除了水平和垂直范围内的限制,webgl
还限制观察者的可视深度,即能看多远。所有这些限制,包括水平视角、垂直视角和可视深度,定义了可视空间(view volume)
。
如果想绘制任何东西,必须将其置于可视空间
中。
例子:正射投影矩阵
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>正射投影矩阵</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<p id="nearFar">显示近裁剪和远裁剪顶点值</p>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ProjectMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_ProjectMatrix * a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let nf = document.querySelector('#nearFar');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
let u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjectMatrix');
let projMatrix = new Matrix4();
document.onkeydown = function (ev) { keydown(ev, gl, n, u_ProjMatrix, projMatrix, nf); };
draw(gl, n, u_ProjMatrix, projMatrix);
}
let g_near = 0.0, g_far = 0.5;
function keydown(ev, gl, n, u_ProjMatrix, projMatrix, nf) {
switch (ev.keyCode) {
case 39: g_near += 0.01; break;
case 37: g_near -= 0.01; break;
case 38: g_far += 0.01; break;
case 40: g_far -= 0.01; break;
default: return;
}
draw(gl, n, u_ProjMatrix, projMatrix, nf);
}
function draw(gl, n, u_ProjMatrix, projMatrix, nf) {
projMatrix.setOrtho(-1, 1, -1, 1, g_near, g_far);
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
nf.innerHTML = 'near:' + Math.round(g_near * 100) / 100 + ',far:' + Math.round(g_far * 100) / 100;
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
//顶点+颜色
let verticesColors = new Float32Array([
0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
-0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
0.5, -0.5, -0.4, 1.0, 0.4, 0.4,
0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
-0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
0.0, -0.6, -0.2, 1.0, 1.0, 0.4,
0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
-0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
0.5, -0.5, 0.0, 1.0, 0.4, 0.4
]);
let n = 9;
let vertexColorbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
let a_Color_location = gl.getAttribLocation(gl.program, 'a_Color');
gl.vertexAttribPointer(a_Color_location, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color_location);
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
例子:键盘控制视图矩阵并显示在投影矩阵内
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>使用键盘控制视图方向</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_ProjMatrix * u_ViewMatrix * a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
let u_ViewMatrix_Location = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
let viewMatrix = new Matrix4();
let u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
let projMatrix = new Matrix4();
projMatrix.setOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 2.0);
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
document.onkeydown = function (ev) { keydown(ev, gl, n, u_ViewMatrix_Location, viewMatrix); };
draw(gl, n, u_ViewMatrix_Location, viewMatrix);
}
let g_eyeX = 0.20, g_eyeY = 0.25, g_eyeZ = 0.25;
function keydown(ev, gl, n, u_ViewMatrix_Location, viewMatrix) {
if (ev.keyCode == 39) {
g_eyeX += 0.01;
} else if (ev.keyCode == 37) {
g_eyeX -= 0.01;
} else {
return;
}
draw(gl, n, u_ViewMatrix_Location, viewMatrix);
}
function draw(gl, n, u_ViewMatrix_Location, viewMatrix) {
viewMatrix.setLookAt(g_eyeX, g_eyeY, g_eyeZ, 0, 0, 0, 0, 1, 0);
gl.uniformMatrix4fv(u_ViewMatrix_Location, false, viewMatrix.elements);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
//顶点+颜色
let verticesColors = new Float32Array([
0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
-0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
0.5, -0.5, -0.4, 1.0, 0.4, 0.4,
0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
-0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
0.0, -0.6, -0.2, 1.0, 1.0, 0.4,
0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
-0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
0.5, -0.5, 0.0, 1.0, 0.4, 0.4
]);
let n = 9;
let vertexColorbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
let a_Color_location = gl.getAttribLocation(gl.program, 'a_Color');
gl.vertexAttribPointer(a_Color_location, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color_location);
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
117
118
拉伸与缩放的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>使用键盘控制视图方向</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_ProjMatrix * u_ViewMatrix * a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
let u_ViewMatrix_Location = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
let viewMatrix = new Matrix4();
let u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
let projMatrix = new Matrix4();
// projMatrix.setOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 2.0);//原来的投影矩阵
projMatrix.setOrtho(-0.5, 0.5, -0.5, 0.5, 0.0, 1.0);//缩小一半后的投影矩阵
//projMatrix.setOrtho(-0.3, 0.3, -1.0, 1.0, 0.0, 0.5);//不成比例变化后图形出现拉伸现象
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
document.onkeydown = function (ev) { keydown(ev, gl, n, u_ViewMatrix_Location, viewMatrix); };
draw(gl, n, u_ViewMatrix_Location, viewMatrix);
}
let g_eyeX = 0.20, g_eyeY = 0.25, g_eyeZ = 0.25;
function keydown(ev, gl, n, u_ViewMatrix_Location, viewMatrix) {
if (ev.keyCode == 39) {
g_eyeX += 0.01;
} else if (ev.keyCode == 37) {
g_eyeX -= 0.01;
} else {
return;
}
draw(gl, n, u_ViewMatrix_Location, viewMatrix);
}
function draw(gl, n, u_ViewMatrix_Location, viewMatrix) {
viewMatrix.setLookAt(g_eyeX, g_eyeY, g_eyeZ, 0, 0, 0, 0, 1, 0);
gl.uniformMatrix4fv(u_ViewMatrix_Location, false, viewMatrix.elements);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
//顶点+颜色
let verticesColors = new Float32Array([
0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
-0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
0.5, -0.5, -0.4, 1.0, 0.4, 0.4,
0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
-0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
0.0, -0.6, -0.2, 1.0, 1.0, 0.4,
0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
-0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
0.5, -0.5, 0.0, 1.0, 0.4, 0.4
]);
let n = 9;
let vertexColorbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
let a_Color_location = gl.getAttribLocation(gl.program, 'a_Color');
gl.vertexAttribPointer(a_Color_location, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color_location);
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
117
118
119
120


# 透视投影可视空间
定义了透视投影可视空间的矩阵被称为透视投影矩阵。(perspective projection matrix)
。
Matrix4.setPerspective(fov,aspect,near,far);
fov
:指定垂直视角,即可视空间顶面和底面的夹角,必须大于0。
aspect
:指定近裁剪面的宽高比。
near,far
:指定近裁剪面和远裁剪面的位置,即可视空间近边界和远边界。
例子:透视投影矩阵
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>透视投影矩阵</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_ProjMatrix * u_ViewMatrix * a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
gl.clearColor(0, 0, 0, 1);
let u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
let u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
let viewMatrix = new Matrix4();
let projMatrix = new Matrix4();
viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1, 0);
projMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
// Draw the triangles
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
var verticesColors = new Float32Array([
// Three triangles on the right side
0.75, 1.0, -4.0, 0.4, 1.0, 0.4, // The back green one
0.25, -1.0, -4.0, 0.4, 1.0, 0.4,
1.25, -1.0, -4.0, 1.0, 0.4, 0.4,
0.75, 1.0, -2.0, 1.0, 1.0, 0.4, // The middle yellow one
0.25, -1.0, -2.0, 1.0, 1.0, 0.4,
1.25, -1.0, -2.0, 1.0, 0.4, 0.4,
0.75, 1.0, 0.0, 0.4, 0.4, 1.0, // The front blue one
0.25, -1.0, 0.0, 0.4, 0.4, 1.0,
1.25, -1.0, 0.0, 1.0, 0.4, 0.4,
// Three triangles on the left side
-0.75, 1.0, -4.0, 0.4, 1.0, 0.4, // The back green one
-1.25, -1.0, -4.0, 0.4, 1.0, 0.4,
-0.25, -1.0, -4.0, 1.0, 0.4, 0.4,
-0.75, 1.0, -2.0, 1.0, 1.0, 0.4, // The middle yellow one
-1.25, -1.0, -2.0, 1.0, 1.0, 0.4,
-0.25, -1.0, -2.0, 1.0, 0.4, 0.4,
-0.75, 1.0, 0.0, 0.4, 0.4, 1.0, // The front blue one
-1.25, -1.0, 0.0, 0.4, 0.4, 1.0,
-0.25, -1.0, 0.0, 1.0, 0.4, 0.4,
]);
var n = 18; // Three vertices per triangle * 6
// Create a buffer object
var vertexColorbuffer = gl.createBuffer();
if (!vertexColorbuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Write the vertex coordinates and color to the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// Assign the buffer object to a_Position and enable the assignment
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// Assign the buffer object to a_Color and enable the assignment
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if (a_Color < 0) {
console.log('Failed to get the storage location of a_Color');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

透视矩阵的作用:作用1对场景的物体做缩放变换,作用2对场景的物体进行平移变换使其贴近视线。

有了投影矩阵、视图矩阵、模型矩阵就能够处理顶点所需要的所有几何变换。最终达到具有深度感的视觉效果。
# MVP模型视图投影矩阵
模型矩阵
定义了模型空间变换
;
视图矩阵
定义了观察者
;
投影矩阵
定义了可视空间
;
<投影矩阵> * <视图矩阵> * <模型矩阵> * <顶点坐标> 计算出来的坐标最终显示在规范立方体内
。
例子:MVP矩阵
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>MVP</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix *a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
gl.clearColor(0, 0, 0, 1);
let u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
let u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
let u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
let viewMatrix = new Matrix4();
let projMatrix = new Matrix4();
let modelMatrix = new Matrix4();
modelMatrix.setTranslate(0.75, 0.0, 0.0);
viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1, 0);
projMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
// Draw the triangles
gl.drawArrays(gl.TRIANGLES, 0, n);
modelMatrix.setTranslate(-0.75, 0.0, 0.0);
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
var verticesColors = new Float32Array([
// Vertex coordinates and color
0.0, 1.0, -4.0, 0.4, 1.0, 0.4, // The back green one
-0.5, -1.0, -4.0, 0.4, 1.0, 0.4,
0.5, -1.0, -4.0, 1.0, 0.4, 0.4,
0.0, 1.0, -2.0, 1.0, 1.0, 0.4, // The middle yellow one
-0.5, -1.0, -2.0, 1.0, 1.0, 0.4,
0.5, -1.0, -2.0, 1.0, 0.4, 0.4,
0.0, 1.0, 0.0, 0.4, 0.4, 1.0, // The front blue one
-0.5, -1.0, 0.0, 0.4, 0.4, 1.0,
0.5, -1.0, 0.0, 1.0, 0.4, 0.4,
]);
var n = 9;
// Create a buffer object
var vertexColorbuffer = gl.createBuffer();
if (!vertexColorbuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Write the vertex information and enable it
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// Assign the buffer object to a_Position and enable the assignment
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// Assign the buffer object to a_Color and enable the assignment
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if (a_Color < 0) {
console.log('Failed to get the storage location of a_Color');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
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
117
118
119
120
121
122
123
124
125
126
127
128
129

例子:MVP矩阵优化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>MVP改进版</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_MVPMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_MVPMatrix *a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
gl.clearColor(0, 0, 0, 1);
let u_MVPMatrix = gl.getUniformLocation(gl.program, 'u_MVPMatrix');
let viewMatrix = new Matrix4();
let projMatrix = new Matrix4();
let modelMatrix = new Matrix4();
let mvpMatrix = new Matrix4();
modelMatrix.setTranslate(0.75, 0.0, 0.0);
viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1, 0);
projMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
gl.uniformMatrix4fv(u_MVPMatrix, false, mvpMatrix.elements);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
// Draw the triangles
gl.drawArrays(gl.TRIANGLES, 0, n);
modelMatrix.setTranslate(-0.75, 0.0, 0.0);
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
gl.uniformMatrix4fv(u_MVPMatrix, false, mvpMatrix.elements);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
var verticesColors = new Float32Array([
// Vertex coordinates and color
0.0, 1.0, -4.0, 0.4, 1.0, 0.4, // The back green one
-0.5, -1.0, -4.0, 0.4, 1.0, 0.4,
0.5, -1.0, -4.0, 1.0, 0.4, 0.4,
0.0, 1.0, -2.0, 1.0, 1.0, 0.4, // The middle yellow one
-0.5, -1.0, -2.0, 1.0, 1.0, 0.4,
0.5, -1.0, -2.0, 1.0, 0.4, 0.4,
0.0, 1.0, 0.0, 0.4, 0.4, 1.0, // The front blue one
-0.5, -1.0, 0.0, 0.4, 0.4, 1.0,
0.5, -1.0, 0.0, 1.0, 0.4, 0.4,
]);
var n = 9;
// Create a buffer object
var vertexColorbuffer = gl.createBuffer();
if (!vertexColorbuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Write the vertex information and enable it
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// Assign the buffer object to a_Position and enable the assignment
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// Assign the buffer object to a_Color and enable the assignment
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if (a_Color < 0) {
console.log('Failed to get the storage location of a_Color');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
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
117
118
119
120
121
122
123
124
125
126
127

webgl
渲染图形是按照由远及近的顺序来绘制的。默认情况下webgl
会按照顶点在缓冲区中的顺序绘制图形,而且后绘制的图形会覆盖先绘制的图形,因为这样会提高效率。这只是针对场景中的物体没有移动,视点也固定的情况下。
# 隐藏面消除
步骤:
- 开启隐藏面消除功能:
gl.enable(gl.DEPTH_TEST)
; - 在绘制前,清除深度缓冲区:
gl.clear(gl.DEPTH_BUFFER_BIT)
;
在任何三维场景都应该开启隐藏面消除功能,并在适当时候(通常是绘制每一帧之前)清除深度缓冲区。
所谓深度检测DEPTH_TEST
,实际上是因为该机制是通过检测物体的每个像素的深度
来决定是否将其画出来的。
同时清除任意多个缓冲区对象都可以使用"|"符号来操作 gl.enable(gl.DEPTH_BUFFER_BIT|gl.COLOR_BUFFER_BIT)
;
例子:开启深度缓冲区
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>深度缓冲区</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_MVPMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_MVPMatrix *a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);
let u_MVPMatrix = gl.getUniformLocation(gl.program, 'u_MVPMatrix');
let viewMatrix = new Matrix4();
let projMatrix = new Matrix4();
let modelMatrix = new Matrix4();
let mvpMatrix = new Matrix4();
modelMatrix.setTranslate(0.75, 0.0, 0.0);
viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1, 0);
projMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
gl.uniformMatrix4fv(u_MVPMatrix, false, mvpMatrix.elements);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the triangles
gl.drawArrays(gl.TRIANGLES, 0, n);
modelMatrix.setTranslate(-0.75, 0.0, 0.0);
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
gl.uniformMatrix4fv(u_MVPMatrix, false, mvpMatrix.elements);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
var verticesColors = new Float32Array([
// Vertex coordinates and color
0.0, 1.0, -4.0, 0.4, 1.0, 0.4, // The back green one
-0.5, -1.0, -4.0, 0.4, 1.0, 0.4,
0.5, -1.0, -4.0, 1.0, 0.4, 0.4,
0.0, 1.0, -2.0, 1.0, 1.0, 0.4, // The middle yellow one
-0.5, -1.0, -2.0, 1.0, 1.0, 0.4,
0.5, -1.0, -2.0, 1.0, 0.4, 0.4,
0.0, 1.0, 0.0, 0.4, 0.4, 1.0, // The front blue one
-0.5, -1.0, 0.0, 0.4, 0.4, 1.0,
0.5, -1.0, 0.0, 1.0, 0.4, 0.4,
]);
var n = 9;
// Create a buffer object
var vertexColorbuffer = gl.createBuffer();
if (!vertexColorbuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Write the vertex information and enable it
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// Assign the buffer object to a_Position and enable the assignment
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// Assign the buffer object to a_Color and enable the assignment
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if (a_Color < 0) {
console.log('Failed to get the storage location of a_Color');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
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
117
118
119
120
121
122
123
124
125
126
127
128


# 深度冲突(Z-fighting)
之所以会产生这个现象是因为两个表面过于接近,深度缓冲区有限的精度已经不能区分哪个在前,哪个在后了。
解决办法:多边形偏移(polygon offset)
步骤:
- 启用多边形偏移:
gl.enable(gl.POLYGON_OFFSET_FILL)
; - 在绘制之前指定用来计算偏移量的参数:
gl.polygonOffset(1.0,1.0)
;
例子:深度冲突
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>深度冲突</title>
</head>
<body onload="main();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
// Vertex shader program
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'uniform mat4 u_ViewProjMatrix;\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_Position = u_ViewProjMatrix * a_Position;\n' +
' v_Color = a_Color;\n' +
'}\n';
// Fragment shader program
var FSHADER_SOURCE =
'#ifdef GL_ES\n' +
'precision mediump float;\n' +
'#endif\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_FragColor = v_Color;\n' +
'}\n';
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('test');
// Get the rendering context for WebGL
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// Set the vertex coordinates and color (the blue triangle is in the front)
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the vertex information');
return;
}
//Set clear color and enable the hidden surface removal function
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);
// Get the storage locations of u_ViewProjMatrix
var u_ViewProjMatrix = gl.getUniformLocation(gl.program, 'u_ViewProjMatrix');
if (!u_ViewProjMatrix) {
console.log('Failed to get the storage locations of u_ViewProjMatrix');
return;
}
var viewProjMatrix = new Matrix4();
// Set the eye point, look-at point, and up vector.
viewProjMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
viewProjMatrix.lookAt(3.06, 2.5, 10.0, 0, 0, -2, 0, 1, 0);
// Pass the view projection matrix to u_ViewProjMatrix
gl.uniformMatrix4fv(u_ViewProjMatrix, false, viewProjMatrix.elements);
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Enable the polygon offset function
//gl.enable(gl.POLYGON_OFFSET_FILL);
// Draw the triangles
gl.drawArrays(gl.TRIANGLES, 0, n / 2); // The green triangle
gl.polygonOffset(1.0, 1.0); // Set the polygon offset
gl.drawArrays(gl.TRIANGLES, n / 2, n / 2); // The yellow triangle
}
function initVertexBuffers(gl) {
var verticesColors = new Float32Array([
// Vertex coordinates and color
0.0, 2.5, -5.0, 0.4, 1.0, 0.4, // The green triangle
-2.5, -2.5, -5.0, 0.4, 1.0, 0.4,
2.5, -2.5, -5.0, 1.0, 0.4, 0.4,
0.0, 3.0, -5.0, 1.0, 0.4, 0.4, // The yellow triagle
-3.0, -3.0, -5.0, 1.0, 1.0, 0.4,
3.0, -3.0, -5.0, 1.0, 1.0, 0.4,
]);
var n = 6;
// Create a buffer object
var vertexColorbuffer = gl.createBuffer();
if (!vertexColorbuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Write the vertex coordinates and color to the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// Assign the buffer object to a_Position and enable the assignment
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// Assign the buffer object to a_Color and enable the assignment
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if (a_Color < 0) {
console.log('Failed to get the storage location of a_Color');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139


# 顶点索引缓冲区
例子:绘制立方体
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>绘制立方体</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_MVPMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_MVPMatrix *a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);
let u_MVPMatrix = gl.getUniformLocation(gl.program, 'u_MVPMatrix');
let mvpMatrix = new Matrix4();
mvpMatrix.setPerspective(30, 1, 1, 100).lookAt(3, 3, 7, 0, 0, 0, 0, 1, 0);
gl.uniformMatrix4fv(u_MVPMatrix, false, mvpMatrix.elements);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}
function initVertexBuffers(gl) {
// Create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
var verticesColors = new Float32Array([
// Vertex coordinates and color
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // v0 White
-1.0, 1.0, 1.0, 1.0, 0.0, 1.0, // v1 Magenta
-1.0, -1.0, 1.0, 1.0, 0.0, 0.0, // v2 Red
1.0, -1.0, 1.0, 1.0, 1.0, 0.0, // v3 Yellow
1.0, -1.0, -1.0, 0.0, 1.0, 0.0, // v4 Green
1.0, 1.0, -1.0, 0.0, 1.0, 1.0, // v5 Cyan
-1.0, 1.0, -1.0, 0.0, 0.0, 1.0, // v6 Blue
-1.0, -1.0, -1.0, 0.0, 0.0, 0.0 // v7 Black
]);
// Indices of the vertices
var indices = new Uint8Array([
0, 1, 2, 0, 2, 3, // front
0, 3, 4, 0, 4, 5, // right
0, 5, 6, 0, 6, 1, // up
1, 6, 7, 1, 7, 2, // left
7, 4, 3, 7, 3, 2, // down
4, 7, 6, 4, 6, 5 // back
]);
// Create a buffer object
var vertexColorBuffer = gl.createBuffer();
var indexBuffer = gl.createBuffer();
if (!vertexColorBuffer || !indexBuffer) {
return -1;
}
// Write the vertex coordinates and color to the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// Assign the buffer object to a_Position and enable the assignment
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// Assign the buffer object to a_Color and enable the assignment
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if (a_Color < 0) {
console.log('Failed to get the storage location of a_Color');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
// Write the indices to the buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;
}
</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
117
118
119
120
121
122
123
124


例子:表面着不同颜色的立方体
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<title>不同颜色表面的立方体</title>
</head>
<body onload="lookAtTriangles();">
<canvas id="test" width="400" height="200">浏览器不支持webgl</canvas>
<script>
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_MVPMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_MVPMatrix *a_Position;
v_Color = a_Color;
}
`;
let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
function lookAtTriangles() {
let canvas = document.querySelector('#test');
let gl = getWebGLContext(canvas, true);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
let n = initVertexBuffers(gl);
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);
let u_MVPMatrix = gl.getUniformLocation(gl.program, 'u_MVPMatrix');
let mvpMatrix = new Matrix4();
mvpMatrix.setPerspective(30, 1, 1, 100).lookAt(3, 3, 7, 0, 0, 0, 0, 1, 0);
gl.uniformMatrix4fv(u_MVPMatrix, false, mvpMatrix.elements);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}
function initVertexBuffers(gl) {
// Create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
var vertices = new Float32Array([ // Vertex coordinates
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, // v0-v1-v2-v3 front
1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, // v0-v3-v4-v5 right
1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up
-1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, // v1-v6-v7-v2 left
-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, // v7-v4-v3-v2 down
1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0 // v4-v7-v6-v5 back
]);
var colors = new Float32Array([ // Colors
0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, // v0-v1-v2-v3 front(blue)
0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, // v0-v3-v4-v5 right(green)
1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, // v0-v5-v6-v1 up(red)
1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, // v1-v6-v7-v2 left
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // v7-v4-v3-v2 down
0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0 // v4-v7-v6-v5 back
]);
var indices = new Uint8Array([ // Indices of the vertices
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9, 10, 8, 10, 11, // up
12, 13, 14, 12, 14, 15, // left
16, 17, 18, 16, 18, 19, // down
20, 21, 22, 20, 22, 23 // back
]);
// Create a buffer object
var indexBuffer = gl.createBuffer();
if (!indexBuffer)
return -1;
// Write the vertex coordinates and color to the buffer object
if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position'))
return -1;
if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color'))
return -1;
// Write the indices to the buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;
}
function initArrayBuffer(gl, data, num, type, attribute) {
var buffer = gl.createBuffer(); // Create a buffer object
if (!buffer) {
console.log('Failed to create the buffer object');
return false;
}
// Write date into the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// Assign the buffer object to the attribute variable
var a_attribute = gl.getAttribLocation(gl.program, attribute);
if (a_attribute < 0) {
console.log('Failed to get the storage location of ' + attribute);
return false;
}
gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
// Enable the assignment of the buffer object to the attribute variable
gl.enableVertexAttribArray(a_attribute);
return true;
}
</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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

如果物体各表面颜色相同就会使其失去立体感。而现实中确能分辨出各个表面的轻微差异是因为有环境光照在产生作用。
