Opengles学习2-Vextex attributes,Vextex array,VBO

1. Vextex attributes

一个顶点基本上有postion,color,normal,texture coordinate等数据。
vextex attribute 分两种: 一种是所有顶点的数据都一样,比如color都是白色;相应的另一种就是有不一样的值,所有需要用array保存每个顶点的数据。

1.1 const vextex attribute

设置const attribute

1
2
3
void glVertexAttrib1f(GLuint index, GLfloat x); void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y); void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
stride : 代表指针位置幅度,the components of vertex attribute specified by size are stored sequentially for each vertex. stride specifies the delta between data for vertex index I and vertex (I + 1). If stride is 0, attribute data for all vertices are stored sequentially. If stride is > 0, then we use the stride value as the pitch to get vertex data for next index

1.2 vertex arrays

1
glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr)

保存顶点数据数组的两种方式:

  • 每个顶点的所有属性保存在一个struct中,然后有一个保存每个顶点struct的数组。array of structs
  • 每个顶点同样属性保存在一个数组中,然后一个struct里面保存全部属性的数组。struct of arrays

假如每个顶点的属性只有postion ,normal ,两个textcoord。
两种方式代码书写的区别:

  • array of structs
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
// 每个属性的大小(几个float 组成)
#define VERTEX_POS_SIZE 3
#define VERTEX_NORMAL_SIZE 3
#define VERTEX_TEXCOORD0_SIZE 2
#define VERTEX_TEXCOORD1_SIZE 2
// 属性的下标
#define VERTEX_POS_INDX 0
#define VERTEX_NORMAL_INDX 1
#define VERTEX_TEXCOORD0_INDX 2
#define VERTEX_TEXCOORD1_INDX 3
// the following 4 defines are used to determine location of various // attributes if vertex data is are stored as an array of structures
#define VERTEX_POS_OFFSET 0
#define VERTEX_NORMAL_OFFSET 3
#define VERTEX_TEXCOORD0_OFFSET 6
#define VERTEX_TEXCOORD1_OFFSET 8
// 一个顶点strcut 的大小
#define VERTEX_ATTRIB_SIZE VERTEX_POS_SIZE + \
VERTEX_NORMAL_SIZE + \
VERTEX_TEXCOORD0_SIZE + \
VERTEX_TEXCOORD1_SIZE
// array of structs,创建
float *p = malloc(numVertices * VERTEX_ATTRIB_SIZE * sizeof(float));
// 设置每个属性
// position is vertex attribute 0
glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,GL_FLOAT, GL_FALSE, VERTEX_ATTRIB_SIZE * sizeof(float), p);
// normal is vertex attribute 1
glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE, GL_FLOAT, GL_FALSE, VERTEX_ATTRIB_SIZE * sizeof(float), (p + VERTEX_NORMAL_OFFSET));
// texture coordinate 0 is vertex attribute 2
glVertexAttribPointer(VERTEX_TEXCOORD0_INDX, VERTEX_TEXCOORD0_SIZE, GL_FLOAT, GL_FALSE, VERTEX_ATTRIB_SIZE * sizeof(float), (p + VERTEX_TEXCOORD0_OFFSET));
// texture coordinate 1 is vertex attribute 3
glVertexAttribPointer(VERTEX_TEXCOORD1_INDX, VERTEX_TEXCOORD1_SIZE, GL_FLOAT, GL_FALSE, VERTEX_ATTRIB_SIZE * sizeof(float), (p + VERTEX_TEXCOORD1_OFFSET));
  • struct of arrays
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 一个包含全部顶点position属性的数组
float *position = malloc(numVertices * VERTEX_POS_SIZE * sizeof(float));
// 一个包含全部顶点normal属性的数组
float *normal = malloc(numVertices * VERTEX_NORMAL_SIZE * sizeof(float));
// 一个包含全部顶点texcoord0属性的数组
float *texcoord0 = malloc(numVertices * VERTEX_TEXCOORD0_SIZE * sizeof(float));
// 一个包含全部顶点texcoord1属性的数组
float *texcoord1 = malloc(numVertices * VERTEX_TEXCOORD1_SIZE * sizeof(float));
// position is vertex attribute 0
glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,GL_FLOAT, GL_FALSE, VERTEX_POS_SIZE * sizeof(float), position);
// normal is vertex attribute 1
glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE,GL_FLOAT, GL_FALSE, VERTEX_NORMAL_SIZE * sizeof(float), normal);
// texture coordinate 0 is vertex attribute 2
glVertexAttribPointer(VERTEX_TEXCOORD0_INDX, VERTEX_TEXCOORD0_SIZE, GL_FLOAT, GL_FALSE, VERTEX_TEXCOORD0_SIZE * sizeof(float), texcoord0);
// texture coordinate 1 is vertex attribute 3
glVertexAttribPointer(VERTEX_TEXCOORD1_INDX, VERTEX_TEXCOORD1_SIZE, GL_FLOAT, GL_FALSE, VERTEX_TEXCOORD1_SIZE * sizeof(float), texcoord1);

1.3 选择使用const vextex 还是vextex array

1
2
void glEnableVertexAttribArray(GLuint index);
void glDisableVertexAttribArray(GLuint index);

2. VBO

为什么需要vbo,因为vextex data,vextex arrays 保存在应用内存中,当绘制的时候需要拷贝到GPU内存中,影响性能。
所以如果能把vextex data 直接放大GPU内存中就好了。

2.1 那什么是VBO?

Opengles 中有两种类型的buffer object:

  • array buffer object

GL_ARRAY_BUFFER 用来保存vextex data.

  • element buffer object

GL_ELEMENT_ARRAY_BUFFER用来保存 图元的indicts.

2.2 如何使用VBO?

1
2
3
4
5
6
7
8
// 创建
glGenBuffers(2, vboIds);
// 设置为当前的 array buffer
glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(vertex_t), vertexBuffer, GL_STATIC_DRAW);
// bind buffer object for element indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,numIndices * sizeof(GLushort),indices, GL_STATIC_DRAW);

看一下代码 绘制图元 不用VBO和使用VBOde 区别

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
// 每个属性的大小(几个float 组成)
#define VERTEX_POS_SIZE 3
#define VERTEX_NORMAL_SIZE 3
#define VERTEX_TEXCOORD0_SIZE 2
// 属性的下标
#define VERTEX_POS_INDX 0
#define VERTEX_NORMAL_INDX 1
#define VERTEX_TEXCOORD0_INDX 2
void drawPrimitiveWithoutVBOs(GLfloat *vertices, GLint vtxStride, GLint numIndices, GLushort *indices) {
GLfloat *vtxBuf = vertices;
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(VERTEX_POS_INDX);
glEnableVertexAttribArray(VERTEX_NORMAL_INDX);
glEnableVertexAttribArray{VERTEX_TEXCOORD0_INDX);
glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, vtxStride, vtxBuf);
vtxBuf += VERTEX_POS_SIZE;
glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE, GL_FLOAT, GL_FALSE, vtxStride, vtxBuf);
vtxBuf += VERTEX_NORMAL_SIZE;
glVertexAttribPointer(VERTEX_TEXCOORD0_INDX,VERTEX_TEXCOORD0_SIZE, GL_FLOAT, GL_FALSE, vtxStride, vtxBuf);
glBindAttribLocation(program, VERTEX_POS_INDX, "v_position");
glBindAttribLocation(program, VERTEX_NORMAL_INDX, "v_normal");
glBindAttribLocation(program, VERTEX_TEXCOORD0_INDX, "v_texcoord");
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices);
}
void drawPrimitiveWithVBOs(GLint numVertices, GLfloat *vtxBuf, GLint vtxStride, GLint numIndices, GLushort *indices)
{
GLuint offset = 0;
GLuint vboIds[2];// vboIds[0] – used to store vertex attribute data // vboIds[1] – used to store element indices glGenBuffers(2, vboIds);
glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, vtxStride * numVertices, vtxBuf, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * numIndices, indices, GL_STATIC_DRAW);
glEnableVertexAttribArray(VERTEX_POS_INDX);
glEnableVertexAttribArray(VERTEX_NORMAL_INDX);
glEnableVertexAttribArray{VERTEX_TEXCOORD0_INDX);
glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, vtxStride, (const void*)offset);
offset += VERTEX_POS_SIZE * sizeof(GLfloat);
glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE, GL_FLOAT, GL_FALSE, vtxStride, (const void*)offset);
offset += VERTEX_NORMAL_SIZE * sizeof(GLfloat);
glVertexAttribPointer(VERTEX_TEXCOORD0_INDX,VERTEX_TEXCOORD0_SIZE, GL_FLOAT, GL_FALSE, vtxStride, (const void*)offset);
glBindAttribLocation(program, VERTEX_POS_INDX, "v_position");
glBindAttribLocation(program, VERTEX_NORMAL_INDX, "v_normal");
glBindAttribLocation(program, VERTEX_TEXCOORD0_INDX, "v_texcoord");
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
glDeleteBuffers(2, vboIds);
}
文章目录
  1. 1. 1. Vextex attributes
    1. 1.1. 1.1 const vextex attribute
    2. 1.2. 1.2 vertex arrays
    3. 1.3. 1.3 选择使用const vextex 还是vextex array
  2. 2. 2. VBO
    1. 2.1. 2.1 那什么是VBO?
    2. 2.2. 2.2 如何使用VBO?
|