将两个不同的网格放在同一个顶点 VBO 中的 OpenGL 最佳实践

Posted

技术标签:

【中文标题】将两个不同的网格放在同一个顶点 VBO 中的 OpenGL 最佳实践【英文标题】:OpenGL best practice for putting two different mesh in the same vertex VBO 【发布时间】:2021-06-19 07:37:15 【问题描述】:

经过一番搜索,据说分离的VAO共享完全相同的着色器属性布局,将它们合并到一个VAO中并将所有这些数据放入一个VBO中,这样我就可以只用一个draw call来绘制这个对象。

这完全有道理,但是统一变量呢?假设我想画树和球。它们具有不同的顶点数,具有不同的变换,但共享完全相同的着色器程序。

到目前为止,我的程序是这样的

// generate VAOs, called only once

glGenVertexArray(1, &treeVaoId);
// generate VBO and bind tree vertices
// enabled vertex attribute and set it for shader program

glGenVertexArray(1, &ballVaoId);
// repeat for ball


// draw, called each frame

// give the tree's transform to shader as uniform
glDrawArrays(...) // first draw call

// repeat for ball
glDrawArrays(...) // second draw call

将这些顶点连接到一个 VAO 和 VBO,例如:

glGenVertexArray(1, &treeBallId);
// generate enough size of VBO and bind tree vertices and ball vertices after it.
// enabled vertex attribute and set it for shader program

// to draw, I have to separately give transform to it's uniform to each tree and ball, but how?
glDrawArrays(...)

对不起,这个例子很糟糕,但重点是,有没有办法在绘制一个 VAO 时给出不同的统一变量?或者,我的方法完全错误吗?

【问题讨论】:

您可以将所有制服存储在 UBO 中。然后,您需要对该缓冲区的索引,或者一个附加属性,或者您也可以查看间接绘制命令。与发出两个单独的绘图调用相比,这是否会给您带来更好的性能:取决于您的具体情况。 【参考方案1】:

batching 的目的是通过最小化绘图调用之间的状态变化来提高性能(批处理将它们减少到 0,因为绘图调用之间没有任何内容)。然而,性能提升是有一定程度的,并不是所有的状态变化都是平等的。

在costs of state changes 的规模上,更改程序制服是最不昂贵的状态更改。这并不是说它没有意义,但是您应该考虑与您从中获得的结果相比,您真正想要花费多少精力。特别是如果您尽可能快地推动硬件。

VAO 更改(即非仅缓冲更改)属于成本更高的状态更改,因此消除它们会收获很多。

顾名思义,uniform 变量不能在一次绘制调用中从一个着色器实例更改为另一个。甚至是多次绘制调用。但这并不意味着没有什么可以做的。

Multi-draw functionality 允许您在单个函数调用中发出多个绘制调用。这些单独的绘制可以从顶点和索引缓冲区的不同部分获取它们的顶点数据。您需要一种与您的顶点着色器进行通信的方法,它正在参与哪个绘制调用,以便它可以索引某种数组以提取该绘制调用的每个对象数据。

半近期硬件has access to gl_DrawID,它是正在执行的特定绘图调用的多绘图命令的索引。 ARB_shader_draw_parameters 扩展名是fairly widely implemented。您可以使用该索引从 UBO 或 SSBO 获取每个对象的数据。

【讨论】:

以上是关于将两个不同的网格放在同一个顶点 VBO 中的 OpenGL 最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

多个网格、多个 VBO、多个 VAO、OpenGL 4.1

如何使用 VBO 进行变形?

OpenGL顶点数组对象不记录VBO和IBO绑定

OpenGL ES:一个 VBO 中的多个网格

使用 VBO 在 OpenGL 中渲染人群

当在两个不同的vbo之间进行插值时,网格面向迷失方向