高级数据
撰写于 2016-09-10 修改于 2018-01-29 分类 OpenGL
在这之前,我们操作缓冲对象的方法很简单,首先生成缓冲区,然后绑定到缓冲区对象上,然后填充数据。这个缓冲区只可以存储该目标类型的数据。下面会有几个特殊的API,来更深入的操作缓冲区。
glBufferSubData
函数原型为:1
2/*tartget: 目标, offset: 起始位置 到 写入位置偏移量 ,size: 数据大小,date: 数据*/
void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);
glBufferSubData可以填充一定区域内的缓冲区。用法示例:1
2glBufferDate(GL_ARRAY_BUFFER, 256, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // 范围: [24, 24 + sizeof(data)];
注意,glBufferSubData只是使用已经创建好的缓冲区,并不会创建缓冲区,所以使用glBufferSubData之前一定要为当前目标的缓冲区分配足够的空间,在调用glBufferSubData 之前一定要调用glBufferDate分配缓冲区,并指定大小。(glBufferDate中的数据设置为NULL时,缓冲区还是会被创建,大小为设定的,内容空)
glMapBuffer,glUnmapBuffer
glMapBuffer,glUnmapBuffer是配套使用的,也是向缓冲区中填充数据的一种方式,但它不是直接填充数据,只是获得了对应目标的缓冲区指针,然后可以通过该指针向缓冲区中填充数据。
glMapBuffer获取对应的缓冲区指针。
glUnmapBuffer解映射(指针使用完毕)。
函数原型为:1
2
3
4
5
6
7
8
9/*
target:
Specifies the target to which the buffer object is bound for glMapBuffer
access:
Specifies the access policy for glMapBuffer, indicating whether it will be possible to read from, write to, or both read from and write to the buffer object's mapped data store. The symbolic constant must be GL_READ_ONLY, GL_WRITE_ONLY, or GL_READ_WRITE.
*/
void *glMapBuffer(GLenum target, GLenum access);
GLboolean glUnmapBuffer(GLenum target);
注意:glMapBuffer也只是使用已经创建好的缓冲区,也需要提前创建好缓冲区。
用法示例(没有过多的研究,都是照搬教程的):1
2
3
4
5
6
7
8
9
10
11
12float data[] = {
0.5f, 1.0f, -0.35f
...
};
glBindBuffer(GL_ARRAY_BUFFER, buffer);
/* 获取当前绑定缓存buffer的内存地址 */
void* ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
/* 向缓冲中写入数据 */
memcpy(ptr, data, sizeof(data));
/* 完成够别忘了告诉OpenGL我们不再需要它了 */
glUnmapBuffer(GL_ARRAY_BUFFER);
glVertexAttribPointer
这个函数前面一直使用,就是用来指定缓冲区中顶点数组的属性布局,可以让一个数组里面放置位置,法线,纹理坐标等数据。不在详细描述。详细用法参考文档 glVertexAttribPointer。
函数原型为:1
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer);
示例用法:1
2
3
4
5
6
7
8
9
10
11
12GLfloat positions[] = { ... };
GLfloat normals[] = { ... };
GLfloat tex[] = { ... };
/*填充缓冲*/
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);
/*使用*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)(sizeof(positions)));
glVertexAttribPointer(
2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)(sizeof(positions) + sizeof(normals)));
glCopyBufferSubData
从名字就可以看出来,这个函数的作用的就是复制一个缓冲区的区域到另一个缓冲区的区域。函数的原型是:1
void glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
用法从参数就可以看出来,从目标readTarget的缓冲区中偏移readOffset的位置处读取size大小的数据,复制到目标writeTarget的缓冲区中偏移writeOffset的位置处。
特殊用法:如果 readTarget 和 writeTarget 是同一个目标,是不是就没办法,当然有,OpenGL给了我们另外两个缓冲目标叫做:GL_COPY_READ_BUFFER和GL_COPY_WRITE_BUFFER。这样我们就可以把我们选择的缓冲,用上面二者作为readtarget和writetarget的参数绑定到新的缓冲目标上了。
用法示例:1
2
3
4
5
6
7
8
9GLfloat vertexData[] = { ... };
glBindBuffer(GL_COPY_READ_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));
/*还可以这样使用*/
GLfloat vertexData[] = { ... };
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));
最后附上OpenGL文档,随手查文档,养成好习惯。
参考教程:https://learnopengl-cn.github.io/
学习交流:我的OpenGL工程