WebGL
能够绘制三种基本的图形,点、线、三角形。其他图形都是由这三种基本图形组装成的。
# 1、绘制正方形点图形
<canvas id="canvas" width="500" height="500"></canvas>
1
下面是着色器语言。一般会写成一段单独的js
代码。当然也可以在js
代码中写成一段字符串的形式。
注意: gl.POINTS
模式点渲染的方形区域,方形中心是 0.5,0.5
,左上角是坐标原点,右下角是 1.0,1.0
,
- 顶点着色器
<script type="shader-source" id="vertexShader">
void main(){
//顶点的位置
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
//顶点的像素大小
gl_PointSize = 40.0;
}
</script>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 片元着色器
<script type="shader-source" id="fragmentShader">
// 数据类型为低精度浮点型
precision lowp float;
void main(){
// 设置片元着色器的颜色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
</script>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
javascript
代码部分
//获取canvas
let canvas = document.getElementById("canvas");
//获取绘图上下文
let gl = canvas.getContext("WebGL");
//创建着色器程序
initShader(gl);
//设置清屏颜色为黑色。
gl.clearColor(0, 0, 0, 1.0);
//清屏
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制一个点。
gl.drawArrays(gl.POINTS, 0, 1);
//声明初始化着色器函数
function initShader(gl) {
//创建定点着色器
const vertexShaderSource = document.querySelector("#vertexShader").innerText;
//创建片元着色器
const fragmentShaderSource = document.querySelector("#fragmentShader")
.innerText;
//创建顶点着色器对象
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
//创建片元着色器对象
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
//引入顶点、片元着色器源代码
gl.shaderSource(vertexShader, vertexShaderSource);
gl.shaderSource(fragmentShader, fragmentShaderSource);
//编译顶点、片元着色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
//创建程序对象program
const program = gl.createProgram();
//附着顶点着色器和片元着色器到program
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
//链接program
gl.linkProgram(program);
//使用program
gl.useProgram(program);
//返回程序program对象
return program;
}
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
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
# 2、绘制圆形点图形
圆点的绘制主要用到了两个内置函数distance
和discard
。distance
用于计算两个顶点坐标之间的距离。discard
函数用于舍弃一些不要的片元。
- 顶点着色器
<script type="shader-source" id="vertexShader">
void main(){
//顶点的位置
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
//顶点的像素大小
gl_PointSize = 40.0;
}
</script>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 片元着色器
<script type="shader-source" id="fragmentShader">
// 数据类型为低精度浮点型
precision lowp float;
void main(){
//gl_PointCoord是内置变量,表示顶点坐标 gl_PointCoord的最大值是(1.0,1.0)
//gl_FragColor 也是内置变量,表示顶点坐标对应的像素的颜色值
//计算顶点坐标到指定点(0.5,0.5)之间的距离,
float r = distance(gl_PointCoord, vec2(0.5, 0.5));
//根据距离设置片元
if(r < 0.5){
// 方形区域片元距离几何中心半径小于0.5,像素颜色设置红色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}else {
// 方形区域距离几何中心半径大于等于0.5的片元剪裁舍弃掉:
discard;
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
javascript
代码部分 这部分代码跟绘制正方形点图形的代码是一样的。
下面是使用 gl_pointCoord
裁剪成 圆形 的图片和没有被裁减的 正方形 的图片对比情况。
# 3、动态绘制点
通过用户的点击来实现动态添加点。
- 顶点着色器
<script type="shader-source" id="vertexShader">
//浮点数设置为中等精度
precision mediump float;
//接收 JavaScript 传递过来的点的坐标(X, Y)
attribute vec2 a_Position;
// 接收canvas的尺寸。
attribute vec2 a_Screen_Size;
void main(){
// 将 canvas 的坐标值 转换为 [-1.0, 1.0]的范围。
vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0;
// canvas的 Y 轴坐标方向和 设备坐标系的相反。
position = position * vec2(1.0, -1.0);
// 最终的顶点坐标。
gl_Position = vec4(position, 0.0, 1.0);
// 点的大小。
gl_PointSize = 10.0;
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 片元着色器
<script type="shader-source" id="fragmentShader">
//浮点数设置为中等精度
precision mediump float;
//全局变量,用来接收 JavaScript传递过来的颜色。
uniform vec4 u_Color;
void main(){
// 将颜色处理成 GLSL 允许的范围[0, 1]。
vec4 color = u_Color / vec4(255, 255, 255, 1);
gl_FragColor = color;
}
</script>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
javascript
代码部分
//获取canvas
let canvas = document.getElementById("canvas");
//获取绘图上下文
let gl = canvas.getContext("WebGL");
//创建着色器程序
let program = initShader(gl);
//获取顶点着色器中的变量a_Position的位置。
let a_Position = gl.getAttribLocation(program, "a_Position");
//获取顶点着色器中的变量a_Screen_Size的位置。
let a_Screen_Size = gl.getAttribLocation(program, "a_Screen_Size");
//获取片元着色器中的变量u_Color的位置。
let u_Color = gl.getUniformLocation(program, "u_Color");
//向顶点着色器的 a_Screen_Size 传递 canvas 尺寸信息。
gl.vertexAttrib2f(a_Screen_Size, canvas.width, canvas.height);
//声明初始化着色器函数
function initShader(gl) {
//创建定点着色器
const vertexShaderSource = document.querySelector("#vertexShader").innerText;
//创建片元着色器
const fragmentShaderSource = document.querySelector("#fragmentShader")
.innerText;
//创建顶点着色器对象
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
//创建片元着色器对象
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
//引入顶点、片元着色器源代码
gl.shaderSource(vertexShader, vertexShaderSource);
gl.shaderSource(fragmentShader, fragmentShaderSource);
//编译顶点、片元着色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
//创建程序对象program
const program = gl.createProgram();
//附着顶点着色器和片元着色器到program
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
//链接program
gl.linkProgram(program);
//使用program
gl.useProgram(program);
//返回程序program对象
return program;
}
//存储区顶点信息的容器
const points = [];
const random = Math.random;
canvas.addEventListener("click", (e) => {
const x = e.pageX;
const y = e.pageY;
const color = randomColor();
//存储新的点的坐标和颜色。
points.push({ x: x, y: y, color: color });
render(gl);
});
//绘制函数
function render(gl) {
//清除屏幕
gl.clear(gl.COLOR_BUFFER_BIT);
for (let i = 0; i < points.length; i++) {
const color = points[i].color;
//向片元着色器传递颜色信息
gl.uniform4f(u_Color, color.r, color.g, color.b, color.a);
//向顶点着色器传递坐标信息。
gl.vertexAttrib2f(a_Position, points[i].x, points[i].y);
//绘制点。
gl.drawArrays(gl.POINTS, 0, 1);
}
}
function randomColor() {
return {
r: random() * 255,
g: random() * 255,
b: random() * 255,
a: random() * 1,
};
}
//设置屏幕清除颜色为黑色。
gl.clearColor(0, 0, 0, 1.0);
//绘制
render(gl);
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
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
# 4、渐变色
- 顶点着色器
<script type="shader-source" id="vertexShader">
void main(){
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 100.0;
}
</script>
1
2
3
4
5
6
2
3
4
5
6
- 片元着色器
<script type="shader-source" id="fragmentShader">
void main(){
// 根据片元的x坐标,来设置片元的像素值
// 片元沿着x方向渐变
gl_FragColor = vec4(gl_FragCoord.x/500.0*1.0,0.0,0.0,1.0);
}
</script>
1
2
3
4
5
6
7
2
3
4
5
6
7
javascript
代码部分 这部分代码跟绘制正方形点图形的代码是一样的。
# 5、颜色分区
- 顶点着色器
<script type="shader-source" id="vertexShader">
void main(){
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 200.0;
}
</script>
1
2
3
4
5
6
2
3
4
5
6
- 片元着色器
<script type="shader-source" id="fragmentShader">
void main(){
// 根据片元的x坐标,来设置片元的像素值
if(gl_FragCoord.x < 200.0){
//默认为 canvas原来的颜色
}
else if (gl_FragCoord.x < 250.0) {
// canvas画布上[0,300)之间片元像素值设置
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
} else if (gl_FragCoord.x <= 300.0) {
// canvas画布上(300,400]之间片元像素值设置 绿色
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
} else {
// canvas画布上(400,500]之间片元像素值设置 蓝色
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
javascript
代码部分 这部分代码跟绘制正方形点图形的代码是一样的。
参考
WebGL零基础入门教程(郭隆邦) (opens new window) WebGL 入门与实践 (opens new window) WebGL官方文档 (opens new window)