7 - 进阶缓冲操作
本文将讨论有关OpenGL缓冲的一些高级操作。
缓冲的高级操作
OpenGL的缓冲就是一个管理特定显存的对象,当我们用GL_ARRAY_BUFFER
或GL_ELEMENT_ARRAY_BUFFER
等将其绑定时,就有了不同的意义。
glBufferSubData()
之前我们创建一块缓冲用的都是glBufferData()
,可以对他进行填充,也能只分配内存后续再填充。这都是对一整块缓冲进行操作的,有没有只对缓冲中一小块区域进行操作的函数,有,就是glBufferSubData()
。
该函数需要一个缓冲目标,一个偏移量,数据大小和数据本身的地址:
glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // 范围: [24, 24 + sizeof(data)]
gl(Un)mapBuffer()
当然,为了获得更多灵活性,可以用glMapBuffer()
请求当前缓冲目标的指针,对其操作后使用glUnmapBuffer()
解除当前指针的可用性,解除成功会返回GL_TRUE
。
一段示例如下:
// 获取当前缓冲目标
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// 获取当前缓冲的指针
void* ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// 对缓冲指向的内存进行操作
// ......
// 解绑指针
glUnmapBuffer(GL_ARRAY_BUFFER);
如果直接从文件中读数据,然后放到缓冲中,这两个函数会很有用,因为省的再开辟一段临时空间了。
分配顶点属性
之前使用glVertexAttribPointer()
分配顶点属性时,都是按照顶点位置、法向量、纹理坐标等属性 交错存储 的。这样做不是很好,我们更希望这些属性可以被 批处理,从而优化程序效率。
可以用glBufferSubData()
打包这些顶点属性,然后再用glVertexAttribPointer()
来分配顶点属性:
float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// 使用 glBufferSubData() 往缓冲中打包顶点属性
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(float), 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(sizeof(positions)));
glVertexAttribPointer(
2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(sizeof(positions) + sizeof(normals)));
glCopyBufferSubData()
可以通过glCopyBufferSubData()
来将缓冲中部分内容复制到另一个缓冲中,它的函数原型如下:
void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size);
其中,各参数的释义如下:
readtarget
:要读取的缓冲,可以将要读取的缓冲绑定至GL_COPY_READ_BUFFER
然后使用该参数writetarget
:要写入的缓冲,可以将要读取的缓冲绑定至GL_COPY_WRITE_BUFFER
然后使用该参数read/writeoffset
:偏移量size
:要复制内容的大小
例如要处理两个VBO的代码如下:
float 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));
参考资料
- 高级数据 - LearnOpenGL CN (learnopengl-cn.github.io)