【问题标题】:Batching arbitrary vertex data in OpenGL batch renderer在 OpenGL 批处理渲染器中批处理任意顶点数据
【发布时间】:2013-08-07 10:26:32
【问题描述】:

我正在 OpenGL 中制作一个 2D 批处理渲染器,灵感来自 XNA/MonoGame 界面,但我遇到了一个小设计问题,我正在寻找一些输入。目前,您可以通过四种通用方式提交顶点数据:

void Render(const Sprite& sprite);
void Render(const Shape& shape);
void Render(const Vertex* vertices, unsigned int length);
void Render(const Vertex* vertices, unsigned int length, const Texture* texture);

一个精灵包含四个顶点、颜色和纹理坐标,而其他三个可以包含任意数字(精灵和形状具有唯一的变换)。一切都可以有纹理或无纹理。我想批量处理所有内容以减少状态更改和 OpenGL 绘制调用的数量。我认为可以合理地假设大多数提交将具有共享顶点,以便我可以使用 glDrawElements 而不是 glDrawArrays,但是鉴于我上面描述的内容,我无法弄清楚如何正确批处理。

XNA/MonoGame 精灵批处理器之所以有效,是因为它们仅适用于带纹理的四边形/三角形,而不是任意形状。或者,我可以像 SFML 渲染器一样为每个可绘制对象发出一次绘制调用,但这违背了批量渲染的目的。

我觉得我的渲染器正在尝试“做所有事情”,这是我想要避免的,因为根据我的经验,它通常很快就会变得过于复杂。

我要问的是:如何重新设计我的渲染器?我可以为不同的提交保留单独的批处理列表吗?我可以以某种方式模块化我的渲染器吗?我应该只允许 XNA/MonoGame 中的纹理对象吗?

【问题讨论】:

    标签: c++ opengl c++11 renderer


    【解决方案1】:

    好的,所以我们需要尽量减少状态更改和绘制调用的次数。我假设您使用的是现代 OpenGL,包括 Vertex Buffer Objects 和着色器。

    一种方法是确保所有顶点数据具有相同的格式。例如,每个顶点都有一个位置、颜色和纹理坐标(xyz、rgba、uv)。如果我们在 VBO 中交错顶点数据,我们只需要在渲染之前调用 glVertexAttribPointerglEnableVertexAttribArray

    这意味着未纹理对象的一些冗余数据,但我们可以将所有内容都塞进一个批次中,这很好。

    要处理无纹理的对象,您可以绑定一个空白的白色纹理并将其视为有纹理的对象。或者,您可以在片段着色器中使用统一变量(0 到 1 之间的浮点数),并使用 mix 函数在纹理颜色和顶点颜色之间进行混合。

    要批处理精灵和形状,我们应该首先在 CPU 上处理变换,以便我们始终将“世界”坐标上传到 GPU。这使我们不必为每个精灵设置一个转换统一,这将需要单独的绘制调用。

    此外,我们需要尽可能按纹理排序,因为纹理绑定是您可以执行的更昂贵的操作之一。

    我们的方法基本上可以归结为以下几点:

    • 维护单个顶点和索引缓冲区对象来存储数据
    • 将所有顶点数据保存在单一格式中,并在 VBO 中交错数据
    • 按纹理排序
    • 每当我们更改纹理(或设置纹理混合统一,如果我们使用该选项)时刷新缓冲区中的数据(绘制元素/数组)

    可以通过不同的方式将数据从 CPU 获取到 GPU 内存。例如,首先在 GPU 上分配一个足够大的空内存缓冲区,然后在每次执行 Render 调用时使用glBufferSubData 上传顶点/索引数据的子集。

    记得配置文件!

    在进行此类工作时进行分析非常重要。例如,比较批处理和单独绘制调用之间的性能,或者 glDrawArrays 与 glDrawElements。我推荐使用gDebugger,它是一个免费且非常好的 OpenGL 分析器。

    还要注意,太大的 VBO 可以hurt your performance。因此,请将其保持在合理的大小,并在其填满时使用绘图调用刷新它。

    【讨论】:

    • 这是一些非常可靠的信息,非常感谢。实际上,我总共创建了三个渲染器(支持不同版本用于教育目的),但据我所知,您的见解翻译得很好。我的顶点确实具有相同的格式。使用混合功能时,我只会使用值 0 和 1、全纹理颜色或全顶点颜色进行插值,对吗?转换的处理方式与您的建议完全相同。我还考虑在批量渲染之前的某个时间将无纹理的对象复制到批处理中。我不知道 gDebugger,谢谢你的链接!
    猜你喜欢
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多