【WebGL之巅】15-颜色与纹理-将非坐标数据传入顶点着色器

By yesmore on 2021-07-28
阅读时间 7 分钟
文章共 1.6k
阅读量

对应《WebGL编程指南》代码:16-MultiAttributeSize、17-MultiAttributeSize_Interleaved

要点:绘制三个不同size的点、交错组织

知识点

一、回顾—将顶点坐标传入着色器步骤

1.创建缓冲区对象

2.将缓冲区对象绑定到target上

3.向缓存对象写入数据

4.将缓冲区对象分配给a_Postion变量(attribute变量)

5.连接a_Postion变量与分配给它的缓冲区对象(开启attribute变量)

二、交错组织

一般思维,通过创建多个缓冲区对象,可以实现传入顶点不同数据,但是当顶点数量庞大起来时,代码冗余增大。

WebGL允许我们把顶点坐标和尺寸数据打包到同一个缓冲区对象中,并通过某种机制分别访问缓冲区对象中不同种类的数据。比如,可以将顶点的坐标和尺寸数据按照如下方式交错组织

1
2
3
4
5
var verticesSizes = new Float32Array(
[0.0, 0.5, 10.0,
-0.5, -0.5, 10.0,
0.5, -0.5, 30.0]
);

可见,一旦将几种顶点数据交叉存储在一个数组中,WebGL就需要有差别的从缓冲区对象中获取某种特定的数据,即使用gl.vertexAttribPointer函数的第5个参数stride和第6个参数offset。

三、步进参数

gl.vertexAttribPointer(location, size, type, normalized, stride, offset);

1.将缓冲区对象分配给a_Postion变量

1
2
3
4
5
...
var FSIZE = verticesSizes.BYTES_PER_ELEMENT;
...
//将缓冲区对象分配给a_Postion变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE*3, 0);

​ 参数stride表示:在缓冲区对象中,单个顶点的所有数据(坐标和大小)的字节数,也就是相邻两个顶点间的距离,即步进参数。之前的缓冲区只含有一种数据即坐标,将其设置为0即可。

stride和offset如图:

1

​ 如图所示,每个顶点有3个数据值(两个坐标一个尺寸数据),因此stride应该设置为每项数据大小的三倍,即3 x FSIZE(Float32Array中每个元素所占的字节数)。

​ 参数offset表示当前考虑的数据项距离首个元素的距离,即偏移参数。在verticesSizes数组中,顶点的坐标数据是放在最前面的,所有offset为0。

2.将缓冲区对象分配给a_Postion变量

​ 接下来对顶点尺寸数据采取同样操作:将缓冲区对象分配给a_PointSize变量。缓冲区对象还是原来的那一个,改变的是关注的数据不同,需要将offset参数设置为顶点尺寸数据在缓冲区对象中的初始位置。由前面可以知道,前两个数据是顶点坐标,后一个是顶点尺寸,因此offset设置为FSIZE * 2

1
2
3
4
var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');

gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, FSIZE*3, FSIZE*2);
gl.enableVertexAttribArray(a_PointSize);

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>rotate triangle</title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
Please use the browser supporting "canvas".
</canvas>

<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>
<script src="MultiAttributeSize.js"></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
//MultiAttributeSize.js
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute float a_PointSize;\n' +
'void main() {\n' +
'gl_Position = a_Position;\n' +
'gl_PointSize = a_PointSize;\n' +
'}\n';

var FSHADER_SOURCE=
'void main(){'+
'gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);'+
'}';

function main() {

var canvas = document.getElementById("webgl");
if (!canvas) {
console.log("Failed to retrieve the <canvas> element");
return;
}

var gl = getWebGLContext(canvas);
if (!gl) {
console.log("Failed to get the rendering context for WebGL");
return;
}

if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log("Failed to initialize shaders.");
return;
}

//设置顶点位置
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}

//指定清空<canvas>颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);

//清空<canvas>
gl.clear(gl.COLOR_BUFFER_BIT);

gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
var vertices = new Float32Array(
[0.0, 0.5, -0.5, -0.5, 0.5, -0.5]
);
var n=3; //点的个数

var sizes = new Float32Array(
[10.0, 20.0, 30.0]
);

//创建多个缓冲区对象
var vertexBuffer = gl.createBuffer();
var sizeBuffer = gl.createBuffer();
//将缓冲区对象保存到目标上
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//向缓存对象写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
//将缓冲区对象分配给a_Postion变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
//连接a_Postion变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);

gl.bindBuffer(gl.ARRAY_BUFFER, sizeBuffer);
gl.bufferData(gl.ARRAY_BUFFER, sizes, gl.STATIC_DRAW);
var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_PointSize);

return n;
}
方法二、使用交错组织配合gl.vertexAttribPointer的步进和偏移量
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
/**
* Created by hushhw on 17/12/14.
*/
//MultiAttributeSize.js
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute float a_PointSize;\n' +
'void main() {\n' +
'gl_Position = a_Position;\n' +
'gl_PointSize = a_PointSize;\n' +
'}\n';

var FSHADER_SOURCE=
'void main(){'+
'gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);'+
'}';

function main() {

var canvas = document.getElementById("webgl");
if (!canvas) {
console.log("Failed to retrieve the <canvas> element");
return;
}

var gl = getWebGLContext(canvas);
if (!gl) {
console.log("Failed to get the rendering context for WebGL");
return;
}

if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log("Failed to initialize shaders.");
return;
}

//设置顶点位置
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}

//指定清空<canvas>颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);

//清空<canvas>
gl.clear(gl.COLOR_BUFFER_BIT);

gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
var verticesSizes = new Float32Array(
[0.0, 0.5, 10.0,
-0.5, -0.5, 20.0,
0.5, -0.5, 30.0]
);
var n=3; //点的个数


//创建缓冲区对象
var vertexSizeBuffer = gl.createBuffer();
if(!vertexSizeBuffer){
console.log("Failed to create thie buffer object");
return -1;
}
//将缓冲区对象保存到目标上
gl.bindBuffer(gl.ARRAY_BUFFER, vertexSizeBuffer);

//向缓存对象写入数据
gl.bufferData(gl.ARRAY_BUFFER, verticesSizes, gl.STATIC_DRAW);

var FSIZE = verticesSizes.BYTES_PER_ELEMENT;

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;
}
//将缓冲区对象分配给a_Postion变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE*3, 0);
//连接a_Postion变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);

var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
if(a_Position < 0){
console.log("Failed to get the storage location of a_Position");
return -1;
}

gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, FSIZE*3, FSIZE*2);
gl.enableVertexAttribArray(a_PointSize);

return n;
}

效果

1


Tips: Please indicate the source and original author when reprinting or quoting this article.