C++ glBindVertexArrays 与 glBindBuffer 的作用是什么,它们的关系是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21652546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:45:07  来源:igfitidea点击:

What is the role of glBindVertexArrays vs glBindBuffer and what is their relationship?

c++opengl

提问by DashAnimal

I'm new to OpenGL and Graphics Programming. I've been reading a textbook which has been really thorough and well-written so far.However, I've hit a point in the code that I'm not quite understanding and I'd like to make sense of these lines before I move on.

我是 OpenGL 和图形编程的新手。到目前为止,我一直在阅读一本非常详尽且写得很好的教科书。但是,我在代码中遇到了一个我不太理解的地方,我想在我开始之前弄清楚这些行继续前行。

GLuint abuffer;

glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);


GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

The book explains that the first three lines are creating a vertex-array object, which is used to bundle associated data with a vertex array. The second line finds an unused name (I'm guessing an unsigned integer identifier stored in abuffer) and the third line creates the object / makes it active.

这本书解释说,前三行正在创建一个顶点数组对象,用于将关联数据与顶点数组捆绑在一起。第二行找到一个未使用的名称(我猜是一个存储在 中的无符号整数标识符abuffer),第三行创建对象/使其处于活动状态。

The book explains that the 4th-7th lines creating a buffer objectto store our data, with the 5th line giving us an unused identifier (similar to line 2 for the vertex array object?), the 6th line creating the buffer, and the 7th line allocating sufficient memory on the CPU and creating a pointer to our data (points) for GL_STATIC_DRAW.

这本书解释说,第 4-7 行创建了一个缓冲区对象来存储我们的数据,第 5 行给了我们一个未使用的标识符(类似于第 2 行的顶点数组对象?),第 6 行创建缓冲区,第 7 行线在 CPU 上分配足够的内存并创建一个指向我们的数据(点)的指针GL_STATIC_DRAW

What does it mean for the object to be active? When would you subsequently use abuffer? What does it mean for a vertex array to bundle associated data, and when was the data associated with this vertex-array object?

对象处于活动状态意味着什么?你以后abuffer什么时候用?顶点数组捆绑关联数据是什么意思,何时与此顶点数组对象关联的数据?

I'm confused about the relationship between abufferand buffer. I'm confused about what the vertex array's relationship with the buffer object is, and at what point that relationship is formed. I'm not sure whether they are, in fact related, but they are presented in the textbook one immediately after the other.

我对abuffer和之间的关系感到困惑buffer。我很困惑顶点数组与缓冲区对象的关系是什么,以及这种关系是在什么时候形成的。我不确定它们是否实际上相关,但它们在教科书中一个接一个地出现。

Any help would be appreciated. Thanks.

任何帮助,将不胜感激。谢谢。

回答by Dietrich Epp

From a low-level perspective, you can think of an array as having two parts to it:

从低级的角度来看,您可以将数组视为由两部分组成:

  • Information about the size, shape, and type of the array (e.g., 32-bit floating point numbers, containing rows of vectors with four elements each).

  • The array data, which is little more than a big blob of bytes.

  • 有关数组大小、形状和类型的信息(例如,32 位浮点数,包含每行具有四个元素的向量行)。

  • 数组数据,只不过是一大块字节。

Even though the low-level concept has mostly stayed the same, the way you specify arrays has changed several times over the years.

尽管低级概念大多保持不变,但您指定数组的方式多年来已经发生了多次变化。

OpenGL 3.0 / ARB_vertex_array_object

OpenGL 3.0 / ARB_vertex_array_object

This is the way you probablyshould be doing things today. It is very rare to find people who can't run OpenGL 3.x and yet still have money to spend on your software.

这就是你今天可能应该做的事情。很少有人不能运行 OpenGL 3.x 但仍然有钱花在你的软件上。

A buffer object in OpenGL is a big blob of bits. Think of the "active" buffer as just a global variable, and there are a bunch of functions which use the active buffer instead of using a parameter. These global state variables are the ugly side of OpenGL (prior to direct state access, which is covered below).

OpenGL 中的缓冲区对象是一大堆位。将“活动”缓冲区视为只是一个全局变量,并且有许多函数使用活动缓冲区而不是使用参数。这些全局状态变量是 OpenGL 丑陋的一面(在直接状态访问之前,将在下面介绍)。

GLuint buffer;

// Generate a name for a new buffer.
// e.g. buffer = 2
glGenBuffers(1, &buffer);

// Make the new buffer active, creating it if necessary.
// Kind of like:
// if (opengl->buffers[buffer] == null)
//     opengl->buffers[buffer] = new Buffer()
// opengl->current_array_buffer = opengl->buffers[buffer]
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// Upload a bunch of data into the active array buffer
// Kind of like:
// opengl->current_array_buffer->data = new byte[sizeof(points)]
// memcpy(opengl->current_array_buffer->data, points, sizeof(points))
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

Now, your typical vertex shader takes vertexesas input, not a big blob of bits. So you need to specify how the blob of bits (the buffer) is decoded into vertexes. That is the job of the array. Likewise, there is an "active" array which you can think of as just a global variable:

现在,典型的顶点着色器将顶点作为输入,而不是一大堆位。因此,您需要指定如何将位 blob(缓冲区)解码为顶点。这就是阵列的工作。同样,有一个“活动”数组,您可以将其视为一个全局变量:

GLuint array;
// Generate a name for a new array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Make the buffer the active array buffer.
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Attach the active buffer to the active array,
// as an array of vectors with 4 floats each.
// Kind of like:
// opengl->current_vertex_array->attributes[attr] = {
//     type = GL_FLOAT,
//     size = 4,
//     data = opengl->current_array_buffer
// }
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Enable the vertex attribute
glEnableVertexAttribArray(attr);

OpenGL 2.0 (the old way)

OpenGL 2.0(旧方式)

In OpenGL 2.x, there weren't vertex arrays and the data was just global. You still had to call glVertexAttribPointer()and glEnableVertexAttribArray(), but you had to call them every timethat you used a buffer. In OpenGL 3.x, you just set up the array once.

在 OpenGL 2.x 中,没有顶点数组,数据只是全局的。您仍然必须调用glVertexAttribPointer()and glEnableVertexAttribArray(),但是每次使用缓冲区都必须调用它们。在 OpenGL 3.x 中,您只需设置一次数组。

Going back to OpenGL 1.5, you could actually use buffers, but you used a separate function to bind each kind of data. For example, glVertexPointer()was for vertex data, and glNormalPointer()was for normal data. Prior to OpenGL 1.5, there weren't buffers, but you could use pointers into your application memory.

回到 OpenGL 1.5,您实际上可以使用缓冲区,但是您使用了一个单独的函数来绑定每种数据。例如,glVertexPointer()用于顶点数据,glNormalPointer()用于法线数据。在 OpenGL 1.5 之前,没有缓冲区,但您可以使用指向应用程序内存的指针。

OpenGL 4.3 / ARB_vertex_attrib_binding

OpenGL 4.3 / ARB_vertex_attrib_binding

In 4.3, or if you have the ARB_vertex_attrib_binding extension, you can specify the attribute format and the attribute data separately. This is nice because it lets you easily switch one vertex array between different buffers.

在4.3中,或者如果你有ARB_vertex_attrib_binding扩展,你可以分别指定属性格式和属性数据。这很好,因为它可以让您轻松地在不同缓冲区之间切换一个顶点数组。

GLuint array;
// Generate a name for a new array array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Enable my attributes
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
// Set up the formats for my attributes
glVertexAttribFormat(loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexAttribFormat(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexAttribBinding(loc_attrib,      0);
glVertexAttribBinding(normal_attrib,   0);
glVertexAttribBinding(texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
// This replaces several calls to glVertexAttribPointer()
// Note: you don't need to bind the buffer first!  Nice!
glBindVertexBuffer(0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glBindVertexBuffer(0, buffer2, 0, 32);

OpenGL 4.5 / ARB_direct_state_access

OpenGL 4.5 / ARB_direct_state_access

In OpenGL 4.5, or if you have the ARB_direct_state_access extension, you no longer need to call glBindBuffer()or glBindVertexArray()just to set things up... you specify the arrays and buffers directly. You only need to bind the array at the end to draw it.

在 OpenGL 4.5 中,或者如果您有 ARB_direct_state_access 扩展,您不再需要调用glBindBuffer()glBindVertexArray()只是进行设置……您直接指定数组和缓冲区。你只需要在最后绑定数组来绘制它。

GLuint array;
// Generate a name for the array and create it.
// Note that glGenVertexArrays() won't work here.
glCreateVertexArrays(1, &array);
// Instead of binding it, we pass it to the functions below.

// Enable my attributes
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
// Set up the formats for my attributes
glVertexArrayAttribFormat(array, loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(array, normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexArrayAttribFormat(array, texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexArrayAttribBinding(array, loc_attrib,      0);
glVertexArrayAttribBinding(array, normal_attrib,   0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);

// You still have to bind the array to draw.
glBindVertexArray(array);
glDrawArrays(...);

ARB_direct_state_access is nice for a lot of reasons. You can forget about binding arrays and buffers (except when you draw) so you don't have to think about hidden global variables that OpenGL is tracking for you. You can forget about the difference between "generating a name for an object" and "creating an object" because glCreateBuffer()and glCreateArray()do both at the same time.

ARB_direct_state_access 很好,原因有很多。您可以忘记绑定数组和缓冲区(除非您绘制),因此您不必考虑 OpenGL 正在为您跟踪的隐藏全局变量。您可以忘记“为对象生成名称”和“创建对象”之间的区别,因为glCreateBuffer()glCreateArray()同时进行。

Vulkan

火神

Vulkan goes even farther and has you write code like the pseudocode I wrote above. So you'll see something like:

Vulkan 走得更远,让您编写类似于我上面编写的伪代码的代码。所以你会看到类似的东西:

// This defines part of a "vertex array", sort of
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0; // Feed data into shader input #0
attrib[0].binding = 0;  // Get data from buffer bound to slot #0
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
// repeat for attrib[1], attrib[2]

回答by Andon M. Coleman

Your interpretation of the book is not completely correct. Vertex Array Objects store no data. They are a class of objects known as containers, like Framebuffer Objects. You may attach/associate other objects with them, but they never store data themselves. As such they are not a context shareable resource.

你对这本书的解释并不完全正确。顶点数组对象不存储数据。它们是一类称为容器的对象,如帧缓冲区对象。您可以将其他对象与它们附加/关联,但它们本身从不存储数据。因此,它们不是上下文可共享资源。

Basically Vertex Array Objects encapsulate vertex array state in OpenGL 3.0. Beginning with OpenGL 3.1 (in lieu of GL_ARB_compatibility) and OpenGL 3.2+ Core profiles, you must have a non-zero VAO bound at all times for commands like glVertexAttribPointer (...)or glDrawArrays (...)to function. The bound VAO forms the necessary context for these commands, and stores the state persistently.

基本上,顶点数组对象在 OpenGL 3.0 中封装了顶点数组状态。从 OpenGL 3.1(代替GL_ARB_compatibility)和 OpenGL 3.2+ 核心配置文件开始,您必须始终有一个非零的 VAO 边界,才能让诸如glVertexAttribPointer (...)或 之类的命令glDrawArrays (...)发挥作用。绑定的 VAO 为这些命令形成必要的上下文,并持久存储状态。

In older versions of GL (and compatibility), the state stored by VAOs was a part of the global state machine.

在旧版本的 GL(和兼容性)中,VAO 存储的状态是全局状态机的一部分。

It is also worth mentioning that the "current" binding for GL_ARRAY_BUFFERis notone of the states that VAOs track. While this binding is used by commands such as glVertexAttribPointer (...), VAOs do not store the binding they only store pointers (the GL_ARB_vertex_attrib_bindingextension introduced alongside GL 4.3 complicates this a bit, so let us ignore it for simplicity).

另外,值得一提的是,“当前”的结合GL_ARRAY_BUFFER不是该规定,VAOs赛道之一。虽然此绑定由诸如 之类的命令使用glVertexAttribPointer (...),但 VAO 不存储绑定,它们只存储指针(GL_ARB_vertex_attrib_binding与 GL 4.3 一起引入的扩展使这有点复杂,因此为了简单起见,让我们忽略它)。

VAOs doremember what is bound to GL_ELEMENT_ARRAY_BUFFER, however, so that indexed drawing commands such as glDrawElements (...)function as you would expect (e.g.VAOs re-use the last element array buffer bound).

然而,VAO确实会记住绑定到的内容GL_ELEMENT_ARRAY_BUFFER,因此索引绘图命令如glDrawElements (...)您所期望的函数(例如,VAO 重新使用最后一个元素数组缓冲区绑定)。

回答by Jossi

The relationship is created when calling glVertexAttribPointer.

该关系是在调用glVertexAttribPointer时创建的。

Overview of VertexArrays

VertexArray 概述

GL_VERTEX_ARRAY_BINDINGand GL_ARRAY_BUFFER_BINDINGare constants but they can point to the global state of the binding. I'm referring to the state not the constant(orange) in the image. Use glGetto find about different global states.

GL_VERTEX_ARRAY_BINDINGGL_ARRAY_BUFFER_BINDING是常量,但它们可以指向绑定的全局状态。我指的是状态而不是图像中的常量(橙色)。使用glGet查找不同的全局状态。

VertexArray is grouping information(including array buffer) about a vertex or many parallel vertices.

VertexArray 是关于一个顶点或许多平行顶点的分组信息(包括数组缓冲区)。

Use GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDINGwith glGetVertexAttribto find which attribute array buffer is set.

GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDINGglGetVertexAttrib一起使用以查找设置了哪个属性数组缓冲区。

glBindBuffer(GL_ARRAY_BUFFERsets the global state GL_ARRAY_BUFFER_BINDING

glBindBuffer(GL_ARRAY_BUFFER设置全局状态GL_ARRAY_BUFFER_BINDING

glBindVertexArraysets the global state GL_VERTEX_ARRAY_BINDING

glBindVertexArray设置全局状态GL_VERTEX_ARRAY_BINDING

回答by ratchet freak

OpenGL is a stateful interface. It's bad, antiquated and ugly but that is legacy for ya.

OpenGL 是一个有状态的接口。它很糟糕,过时和丑陋,但那是你的遗产。

A vertex array object is a collection of buffer bindings that the driver can use to get the data for the draw calls, most tutorials only use the one and never explain how to use multiple VAOs.

顶点数组对象是一组缓冲区绑定,驱动程序可以使用它来获取绘制调用的数据,大多数教程只使用一个,而从不解释如何使用多个 VAO。

A buffer binding tells opengl to use that buffer for related methods in particular for the glVertexAttribPointermethods.

缓冲区绑定告诉 opengl 将该缓冲区用于相关方法,特别是glVertexAttribPointer方法。

回答by Gasim

There is no relationship between VertexArray and VBO.

VertexArray 和 VBO 之间没有关系。

A vertex array allocates the memory in RAM and sends pointer to the API. VBO allocates the memory in the graphics card - system memory has no address for it. If you need to access the vbo data from system you need to copy it from vbo to the system first.

顶点数组在 RAM 中分配内存并将指针发送到 API。VBO 分配显卡中的内存 - 系统内存没有地址。如果您需要从系统访问 vbo 数据,则需要先将其从 vbo 复制到系统。

Also, in newer versions of OpenGL, vertex arrays are completely removed (depcrecated in 3.0, removed in 3.1)

此外,在较新版本的 OpenGL 中,顶点数组被完全删除(在 3.0 中弃用,在 3.1 中删除)