【可视化学习】12-WEBGL与GPU渲染原理
发表于:2023-05-28 |

webgl是什么我这里不多说,大家自己去查阅文档之类的东西,自行去了解

用webgl绘制一个三角形

新建一个html

1
2
3
4
5
6
7
8
9
10
11
12
<!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>Document</title>
</head>
<body>

</body>
</html>

添加canvas标签,并配置基本样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!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>Document</title>
</head>
<style>
body{
margin: 0;
padding: 0;
}
canvas{
width:100%;
height:100%;
}
</style>
<body>
<canvas id="canvas"></canvas>
</body>
</html>

接下来部分都是js的部分

获取canvas元素并设置宽高

1
2
3
4
5
// 获取canvas元素
var canvas = document.getElementById('canvas');
// canvas宽高
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

获取webgl上下文

1
2
3
4
// 获取webgl绘图上下文
var gl = canvas.getContext('webgl');
// 第一次创建webgl绘图上下文,需要设置视口大小
gl.viewport(0, 0, canvas.width, canvas.height);

创建顶点着色器

这里预留了一个变量a_position

1
2
3
4
5
6
7
8
9
10
11
12
// 创建顶点着色器
var vertexShader=gl.createShader(gl.VERTEX_SHADER);
// 创建顶点着色器的源代码,需要编写glsl代码
gl.shaderSource(vertexShader,`
attribute vec4 a_position;
void main(){
gl_Position=a_position;
}
`
);
// 编译顶点着色器
gl.compileShader(vertexShader);

创建片元着色器

1
2
3
4
5
6
7
8
9
10
11
// 创建片元着色器
var fragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
// 创建片元着色器的源代码,需要编写glsl代码
gl.shaderSource(fragmentShader,`
void main(){
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}
`
);
// 编译片元着色器
gl.compileShader(fragmentShader);

创建程序连接

1
2
3
4
5
6
7
8
9
10
11
12
// 创建程序连接顶点着色器和片元着色器
var program=gl.createProgram();
// 链接顶点着色器和片元着色器
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);

// 链接程序
gl.linkProgram(program);

// 使用程序进行渲染
gl.useProgram(program);

使用缓冲区对象并渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 创建顶点缓冲区对象
var vertexBuffer=gl.createBuffer();
// 绑定顶点缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
// 向顶点缓冲区对象中写入数据
var vertices=new Float32Array([
0.0,0.5,
-0.5,-0.5,
0.5,-0.5
]);
//gl.STATIC_DRAW表示数据不会或几乎不会改变,gl.DYNAMIC_DRAW表示数据会被改变很多,gl.STREAM_DRAW表示数据每次绘制时都会改变
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
// 获取顶点着色器中的a_position变量的地址
var a_position=gl.getAttribLocation(program,'a_position');
// 将顶点缓冲区对象分配给a_position变量
// 告诉openGL如何解析顶点数据
gl.vertexAttribPointer(a_position,2,gl.FLOAT,false,0,0);
// 启用顶点着色器中的a_position变量
gl.enableVertexAttribArray(a_position);

// 绘制三角形
gl.drawArrays(gl.TRIANGLES,0,3);

完整代码

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
95
<!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>Document</title>
</head>
<style>
body{
margin: 0;
padding: 0;
}
canvas{
width:100%;
height:100%;
}
</style>
<body>
<canvas id="canvas"></canvas>

<script>
// 获取canvas元素
var canvas = document.getElementById('canvas');
// canvas宽高
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 获取webgl绘图上下文
var gl = canvas.getContext('webgl');
// 第一次创建webgl绘图上下文,需要设置视口大小
gl.viewport(0, 0, canvas.width, canvas.height);


// 创建顶点着色器
var vertexShader=gl.createShader(gl.VERTEX_SHADER);
// 创建顶点着色器的源代码,需要编写glsl代码
gl.shaderSource(vertexShader,`
attribute vec4 a_position;
void main(){
gl_Position=a_position;
}
`
);
// 编译顶点着色器
gl.compileShader(vertexShader);

// 创建片元着色器
var fragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
// 创建片元着色器的源代码,需要编写glsl代码
gl.shaderSource(fragmentShader,`
void main(){
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}
`
);
// 编译片元着色器
gl.compileShader(fragmentShader);

// 创建程序连接顶点着色器和片元着色器
var program=gl.createProgram();
// 链接顶点着色器和片元着色器
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);

// 链接程序
gl.linkProgram(program);

// 使用程序进行渲染
gl.useProgram(program);

// 创建顶点缓冲区对象
var vertexBuffer=gl.createBuffer();
// 绑定顶点缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
// 向顶点缓冲区对象中写入数据
var vertices=new Float32Array([
0.0,0.5,
-0.5,-0.5,
0.5,-0.5
]);
//gl.STATIC_DRAW表示数据不会或几乎不会改变,gl.DYNAMIC_DRAW表示数据会被改变很多,gl.STREAM_DRAW表示数据每次绘制时都会改变
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
// 获取顶点着色器中的a_position变量的地址
var a_position=gl.getAttribLocation(program,'a_position');
// 将顶点缓冲区对象分配给a_position变量
// 告诉openGL如何解析顶点数据
gl.vertexAttribPointer(a_position,2,gl.FLOAT,false,0,0);
// 启用顶点着色器中的a_position变量
gl.enableVertexAttribArray(a_position);

// 绘制三角形
gl.drawArrays(gl.TRIANGLES,0,3);
</script>
</body>
</html>

效果图

缩放矩阵与uniform变量和varying变量

完整代码

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
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
<!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>Document</title>
</head>
<style>
body{
margin: 0;
padding: 0;
}
canvas{
width:100%;
height:100%;
}
</style>
<body>
<canvas id="canvas"></canvas>

<script>
// 获取canvas元素
var canvas = document.getElementById('canvas');
// canvas宽高
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 获取webgl绘图上下文
var gl = canvas.getContext('webgl');
// 第一次创建webgl绘图上下文,需要设置视口大小
gl.viewport(0, 0, canvas.width, canvas.height);


// 创建顶点着色器
var vertexShader=gl.createShader(gl.VERTEX_SHADER);
// 创建顶点着色器的源代码,需要编写glsl代码
// uniform mat4 u_Mat,接收矩阵变量,uniform(全局)
// varying vec4 v_Color,传递顶点着色器的颜色数据给片元着色器,varying(着色器之间)
gl.shaderSource(vertexShader,`
attribute vec4 a_position;
uniform mat4 u_Mat;
varying vec4 v_Color;
void main(){
gl_Position=u_Mat*a_position;
v_Color=gl_position;
}
`
);
// 编译顶点着色器
gl.compileShader(vertexShader);

// 创建片元着色器
var fragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
// 创建片元着色器的源代码,需要编写glsl代码
gl.shaderSource(fragmentShader,`
precision mediump float;
varying vec4 v_Color;
void main(){
gl_FragColor=v_Color;
}
`
);
// 编译片元着色器
gl.compileShader(fragmentShader);

// 创建程序连接顶点着色器和片元着色器
var program=gl.createProgram();
// 链接顶点着色器和片元着色器
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);

// 链接程序
gl.linkProgram(program);

// 使用程序进行渲染
gl.useProgram(program);

// 创建顶点缓冲区对象
var vertexBuffer=gl.createBuffer();
// 绑定顶点缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
// 向顶点缓冲区对象中写入数据
var vertices=new Float32Array([
0.0,0.5,
-0.5,-0.5,
0.5,-0.5
]);
//gl.STATIC_DRAW表示数据不会或几乎不会改变,gl.DYNAMIC_DRAW表示数据会被改变很多,gl.STREAM_DRAW表示数据每次绘制时都会改变
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
// 获取顶点着色器中的a_position变量的地址
var a_position=gl.getAttribLocation(program,'a_position');
// 将顶点缓冲区对象分配给a_position变量
// 告诉openGL如何解析顶点数据
gl.vertexAttribPointer(a_position,2,gl.FLOAT,false,0,0);
// 启用顶点着色器中的a_position变量
gl.enableVertexAttribArray(a_position);
// 清除canvas
gl.clearColor(0.0,0.0,0.0,0.0);
gl.clear(gl.COLOR_BUFFER_BIT);

const scale={
x:1.5,
y:1.5,
z:1.5
}

// 渲染动画
function animate(){
scale.x-=0.01;
const mat=new Float32Array([
scale.x,0.0,0.0,0.0,
0.0,scale.x,0.0,0.0,
0.0,0.0,scale.x,0.0,
0.0,0.0,0.0,1.0
]);
// 传矩阵值进去
const u_Mat=gl.getUniformLocation(program,'u_Mat');
gl.uniformMatrix4fv(u_Mat,false,mat);
gl.drawArrays(gl.TRIANGLES,0,3);
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>

glsl语法细节

  • 有全局预设变量,如gl_Position
  • 需要提前指定参数类型
  • 不能忘记;
  • 注意浮点数便需要有精度
上一篇:
手撸编辑器
下一篇:
【可视化学习】11-Three.js物理引擎