使用 glMapBuffer 用一个缓冲区渲染多个对象?

Posted

技术标签:

【中文标题】使用 glMapBuffer 用一个缓冲区渲染多个对象?【英文标题】:Render multiple objects with one buffer using glMapBuffer? 【发布时间】:2016-04-07 07:28:38 【问题描述】:

我对缓冲区的概念感到困惑。我了解 glBufferDataglBufferSubData 的基本知识。在主循环中的渲染函数之前使用 glBufferSubData,您可以使用 offsetsize 参数将多个模型对象存储在顶点缓冲区和索引缓冲区。然后在渲染时绑定单个顶点缓冲区并使用正确的偏移量和大小调用 glDrawElements 以渲染多个对象。

glMapBuffer 是这种情况吗?还是我想调用 glMapBuffer 在渲染时链接顶点和索引数据,然后绘制?

GLuint vertexArrayId;
GLuint verticesBufferId;
GLuint indicesBufferId;

void setupBuffers() 
    glGenVertexArrays(1, &vertexArrayId);
    glBindVertexArray(vertexArrayId);
    glGenBuffers(1, &verticesBufferId);
    glGenBuffers(1, &indicesBufferId);

    glBindBuffer(GL_ARRAY_BUFFER, verticesBufferId);
    glBufferData(GL_ARRAY_BUFFER, VERTICES_SIZE, NULL, GL_STATIC_DRAW);
    // glMapBuffer stuff here 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBufferId);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, INDICES_SIZE, NULL, GL_STATIC_DRAW);
    // glMapBuffer stuff here


void render() 
    glBindBuffer(GL_ARRAY_BUFFER, verticesBufferId);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)((sizeof(GLfloat) * 0)));

    glEnableVertexAttribArray(0);
    // glDrawElements stuff here
    glDisableVertexAttribArray(0);

    // Model, View, Projection transformations here
    // glUniformMatrix4fv 

【问题讨论】:

【参考方案1】:

您可以使用 glMapBuffer 将数据从 ram 上传到 GPU:

    glBindBuffer(GL_ARRAY_BUFFER, verticesBufferId);
    void *data = glMapBuffer( GL_ARRAY_BUFFER, ... );
    // copy vertex data from instance 
    ::memcpy( data, vertices, vertexSize );
    ...
    glUnmapBuffer( ... );

例如,当您想从模型上传顶点和索引数据时。您可以使用从 glMapBuffer 返回的指针,就像 raw-c-pointer 一样(只是为了方便)

记住:glMapBuffer 并不快,所以尽量避免在渲染循环中使用它。调用 glUnMap 后,数据将传输到 GPU。

当您必须定期将数据从 CPU 上传到 GPU 时,有更好的方法,例如使用 Uniform-Blocks。 我找到了这篇博文,其中对映射的解释非常好(有所有缺点):Mapping in OpenGL

【讨论】:

感谢您查看您的链接。出于学习目的,是否可以解释渲染多个对象模型(1 个顶点数组,每个对象的 1 个索引数据数组)的解决方案?如果我不应该在渲染期间调用 glMapBuffer 来指向数据,我如何告诉 glDrawElements 绘制什么? 你可以看看这个教程:mbsoftworks.sk/… 诀窍是:在渲染之前加载一次数据。在渲染过程中,只需说出应使用哪些缓冲区并调用 glDrawArray。 但这是否意味着我每个对象会有 2 个 VBO? 1个VBO用于顶点,1个用于索引?我认为最好为每种存储许多对象的数据类型配备 1 个大型 VBO glMapBuffer 也不一定很慢。 真正 减慢速度的原因是您正在修改可能需要完成 GPU 当前正在处理的帧的内存。映射和取消映射不是您应该避免的,而是需要避免的修改-使用循环;通常通过建立多个重复缓冲区或告诉 GL 使缓冲区中不需要持久化的区域无效。 正如我在这里所说的:记住:glMapBuffer 并不快,所以尽量避免在渲染循环中使用它。调用 glUnMap 后,数据将传输到 GPU。

以上是关于使用 glMapBuffer 用一个缓冲区渲染多个对象?的主要内容,如果未能解决你的问题,请参考以下文章

带有 glMapBuffer 的 Buffer 会被分配比 glBufferSubData 更慢的 VRAM 吗?

OpenGL:使用多个纹理渲染到 FBO

使用 OpenGL API 播放 BIK 视频

我可以为每个渲染目标指定一个视口吗?

从单个顶点缓冲区渲染多个图形

深度缓冲区不使用多个着色器程序