在实践中使用 VertexArrayObjects 吗?

Posted

技术标签:

【中文标题】在实践中使用 VertexArrayObjects 吗?【英文标题】:Are VertexArrayObjects used in practice? 【发布时间】:2014-01-03 16:58:33 【问题描述】:

我目前正在学习 OpenGL,而 VAO 让我感到困惑。据我了解,VAO 只是封装了 VBO 的状态。

Bind VAO
load buffer data
Disable VAO

然后你就可以画出来了

activate VAO
DrawArray ...
deactivate VAO

但我不确定这在实践中是否真的有用。假设我有一个非常大的场景要渲染。也许 10 平方公里,我显然不想一次将每个对象加载到 GPU,我可能想将场景分成不同的块。

现在我四处走动,有一次我必须将另一块对象加载到 GPU 上,对吗?但据我所知,我无法更改 VAO,而且每次我的场景发生变化时,我都必须创建一个新的 VAO。

那么在我的场景中什么是 VAO?整个场景会是 VAO 吗?还是每个对象都是 VAO?

对我来说,拥有多个 VAO 并没有多大意义,因为我无法将 VAO 组合在一起,我只能像这样将它们叠加在一起

activate VAO1
DrawArray ...
deactivate VAO1

activate VAO2
DrawArray ...
deactivate VAO2

【问题讨论】:

【参考方案1】:

您无法启用或禁用 VAO,它们是 OpenGL 中的一类对象,称为 容器(与 FBO 相同)。它们为顶点数组绘制操作提供上下文以及描述它们所需的状态。您肯定可以更改 VAO,它们只是状态容器...绑定它,然后更改它存储的状态之一。是否为整个场景使用一个 VAO 或多个 VAO 取决于您,但请记住,在核心 OpenGL 3.2 上下文中,您不能在没有 at 的情况下发出 任何 顶点绘制命令至少有一些 VAO 约束。

此外,除了元素数组缓冲区之外,VAO 与 当前绑定 缓冲区对象 per-se 无关。 VAO 存储顶点数组指针,可能直接或间接(参见:GL_ARB_vertex_attrib_binding)绑定到 VBO,但 VAO 根本不关心 VBO 当前绑定到 GL_ARRAY_BUFFER。正如我提到的,元素数组缓冲区不同,VAO do 跟踪 当前绑定 元素数组缓冲区,因此对 glDrawElements (...) 的调用将仅通过绑定具有一致的行为一个VAO。如果没有此属性,您必须先绑定一个 VAO,然后再绑定一个元素数组缓冲区,然后才能发出索引绘图操作。

【讨论】:

抱歉,您的回复中有一些错误。 VAO 在 OpenGL 3.1 核心配置文件中成为强制性的。此外,VAO 将绑定存储到顶点处理所需的任何类型的缓冲区对象,并且不会像您建议的那样对元素数组缓冲区执行任何特殊操作。假设 VAO 包含所有 VBO,一个 EBO(一次只能绑定一个元素数组缓冲区,而一次至少可以激活 16 个 VBO),绑定 VAO 将绑定其所有附加缓冲区。很抱歉纠正你,Andon,通常你的答案是正确的。 @radical7:没有 3.1 核心配置文件这样的东西,核心/兼容性是在 GL 3.2 中引入的。此外,VAO 不存储顶点缓冲区绑定;它们存储指针(可能与 VBO 相关)。但是,它们确实记住绑定了哪个元素缓冲区。在任何给定时间,您只能绑定一种类型的缓冲区对象,这正是 VAO 不跟踪 VBO 绑定的原因,VBO 绑定唯一重要的时间是在glVertexAttribPointer (...) 和朋友被调用之前(再次,因为指针的地址空间由绑定的VBO定义当时) @radical7:我相信您对 VBO 绑定的一些困惑与 glVertexAttribPointer (...) 的行为有关。通常,当需要在 OpenGL 中绑定对象才能进行 API 调用时,这是因为该 API 调用会在您刚刚绑定的对象中设置一些状态。 VBO 颠覆了这种范式,因为在调用 glVertexAttribPointer (...) 之前必须绑定 VBO 的唯一原因是因为您传递的 offset 与绑定的 VBO 相关。这整个混乱实际上源于重用旧的客户端内存顶点指针系统。【参考方案2】:

你的第一句话:

据我了解,VAO 只是封装了 VBO 的状态。

大部分是正确的,因为 VBO 是 VAO 中存储最多的缓冲区类型,但与顶点处理相关的任何类型的缓冲区(即元素数组、间接绘制缓冲区等取决于您的支持的缓冲区) OpenGL 版本)也包含在 VAO 中。

将 VAO 添加到 API 的原因是为了减少为不同对象交换数据所需的函数调用次数。在具有多个需要不同顶点属性集的对象的应用程序中,在 VAO 之前,您需要为渲染该对象所需的每个 VBO(包括元素数组缓冲区)调用 glBindBuffer(顶点属性位置的关联和缓冲区是该缓冲区的属性,而不是 VAO 的属性,以防您有这个问题)。正如您提到的,VAO 允许将所有这些绑定封装到单个对象中,该对象可以通过对 glBindVertexArray 的单个调用进行绑定。

在 VAO 之间进行交换时,您也走在了正确的轨道上。在应用程序的初始化中(或当您需要添加更多对象时),您将根据需要创建和初始化尽可能多的 VAO,并为每个 VAO 绑定它,并使用其所有相关缓冲区填充它。当你想使用一个时,你只需绑定它。还值得注意的是,您始终可以使用 glBufferData 或类似调用更新 VBO 中的数据,并且该操作不会影响与该缓冲区关联的 VAO 中包含的绑定。

【讨论】:

我建议您查看 OpenGL wiki 的 this 部分。如果您不想深入了解官方 OpenGL 规范以了解为什么 VAO 不存储 VBO 绑定但存储元素数组缓冲区绑定(有时称为 IBO)。但是,我强烈建议您查看官方规范,因为 Wiki 中该部分的语言非常不专业(例如 “我知道这很混乱,但事实就是如此。”)。 Wiki 中的信息准确无误,只是呈现不佳。

以上是关于在实践中使用 VertexArrayObjects 吗?的主要内容,如果未能解决你的问题,请参考以下文章

绑定到“顶点数组对象”后,我应该删除“顶点缓冲区对象”吗?

在 .Net 中使用扩展方法的最佳实践是啥?

在多个项目中使用相同模型的最佳实践是啥?

在 vue 组件中使用样式的最佳实践是啥?

在 UITableViewCell 中使用 UIImages 的最佳实践

在 SQL 2005 中使用模式的最佳实践?