一、高级数据
下面,我们将使用纹理对象来存储大量的数据。OpenGL中的缓冲只是一个管理特定内存块的对象,在我们将它绑定到一个缓冲目标时,便赋予了意义。
当绑定到GL_ARRAY_BUFFER
时,就是一个顶点数组缓冲(或者GL_ELEMENT_ARRAY_BUFFER
)。
到目前为止,我们一直调用glBufferData
函数填充缓存对象管理的内存,这个函数会分配一块内存,然后将数据添加到这块内存中去(如果参数data
设置为NULL
,也就是说这个函数只会分配内存,不进行填充)。
除了调用一次函数填充整个缓冲外,也可以使用glBufferSubData
,填充缓冲的特定区域。其参数列表为一个缓冲目标,一个偏移量,数据大小,和数据本身。与上面的填充函数不同的是,我们可以指定是从哪一个位置开始填充内存。
glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // 范围: [24, 24 + sizeof(data)]
将数据导入缓冲的另外一种方法是,请求缓冲内存的指针,直接将数据复制到缓冲当中。
通过调用glMapBuffer
函数,OpenGL会返回当前绑定缓冲的内存指针。
float data[] = {
0.5f, 1.0f, -0.35f
...
};
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// 获取指针
void *ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// 复制数据到内存
memcpy(ptr, data, sizeof(data));
// 记得告诉OpenGL我们不再需要这个指针了
glUnmapBuffer(GL_ARRAY_BUFFER);
二、分批顶点属性
使用glVertexAttribPointer
,可以指定顶点数组缓冲内容的属性布局。在顶点属性中,对属性进行了交错处理,也就是将每一个顶点的位置,或纹理坐标紧密放置在一起。
能做的是将每一个属性类型的向量数据打包为一个大的区块,而不是进行交错存储。与交错布局123123123不同,将采用分批的方式111222333。
当从文件中加载顶点数据时,获取到的是一个顶点坐标,一个纹理坐标,需要将这些数组结合为一个大的交错坐标数据数组,使用分批glBufferSubData
可以很容易实现:
float positions[] = { ... };
float normals[] = { ... };
float 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);
这样我们可以直接将属性数组作为一个整体传递给缓冲,不需要事先进行处理。
可以先合并为一个大的数组,然后使用glBufferData
来填充。
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
能让我们容易将一个缓冲复制到另一个缓冲。
void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset,
GLintptr writeoffset, GLsizeiptr size);
readtarget
和writetarget
参数需要填入复制源和复制目标的缓冲目标。
接下来glCopyBufferSubData
会从readtarget中读取size大小的数据,并将其写入writetarget缓冲的writeoffset偏移量处。
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));