高级计算机图形学网格,计算机图形学(OPENGL):高级数据

该篇博客探讨了OpenGL中管理缓冲的多种方法,包括使用glBufferSubData填充特定区域,通过glMapBuffer获取内存指针直接写入数据,以及如何实现顶点属性的批处理定制。此外,还介绍了如何使用glCopyBufferSubData复制缓冲数据到另一个缓冲对象,以及在不同缓冲对象间进行数据迁移的技巧。
摘要由CSDN通过智能技术生成

高级数据

在之前的章节中,我们广泛的使用了OpenGL中的缓冲来在GPU上存储数据,这一章来讨论一下管理缓冲的其它方法。

缓冲在OpenGL中,是一个管理一片GPU内存空间的对象,我们将其绑定到特定的缓冲区来赋予缓冲对象意义。

到目前为止,我们使用glBufferData来填充缓冲的内存空间,这个方法会分配一片GPU内存,并将数据存储到这片内存。如果我们传入NULL,则只会分配内存空间。

其实我们可以只填充缓冲的特定区域,使用glBufferSubData。这个方法要求一个缓冲区参数,一个偏移参数,一个数据大小的参数,以及要传入的数据。我们使用这个偏移参数来指定要填充数据的位置。注意,为了确保缓冲有足够的内存空间,最好在调用glBufferSubData前调用glBufferData,下面是glBufferSubData的一个例子:

glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // 范围: [24, 24 + sizeof(data)]

当然,填充数据还有另一种方法,我们可以创建指向一块缓冲内存的指针,然后将数据复制到这块区域。我们可以使用glMapBuffer创建一块缓冲内存区域并返回一个指针。下前面是一个例子:

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));

// 我们不再需要这个指针

glUnmapBuffer(GL_ARRAY_BUFFER);

我们使用glUnmapBuffer来结束指针的操作。使用glMapBuffer的优势是不需要使用中转内存区域。

批处理顶点属性

使用glVertexAttribPointer我们可以对VAO中的顶点属性进行位置分配,但之前我们都是使用glBufferData一次传入数据,所以是按照位置、法线、纹理坐标的顺序来紧密排列每个顶点,我们可以使用glBufferSubData来自定义顺序。

我们可以单独定义顶点的位置,法线和纹理坐标,并按照顺序传入缓冲区的内存中,内存中存储的顺序为:所有顶点的位置--所有顶点的法线--所有顶点的纹理坐标。例子如下:

float positions[] = { ... };

float normals[] = { ... };

float tex[] = { ... };

// fill buffer

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的配置:

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和witetarget分别代表贡献数据的缓冲区和获得数据的缓冲区,readoffset和writeoffset代表两个缓冲区执行操作开始的位置,size代表复制数据的大小。例如,我们可以将VERTEX_ARRAY_BUFFER上的数据复制到VERTEX_ELEMENT_ARRAY_BUFFER上。但如果想要在两个同一缓冲区上的缓冲对象之间进行复制操作呢?基于这一问题,OpenGL提供了两个缓冲区:GL_COPY_READ_BUFFER和GL_COPY_WRITE_BUFFER,我们只需要在进行复制操作前将两个缓冲对象绑定至这两个缓冲区就行:

glBindBuffer(GL_COPY_READ_BUFFER, vbo1);

glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);

glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, 8 * sizeof(float));

我们也可以只将待写入的缓冲对象绑定至GL_COPY_WRITE_BUFFER:

float vertexData[] = { ... };

glBindBuffer(GL_ARRAY_BUFFER, vbo1);

glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);

glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, 8 * sizeof(float));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值