什么时候是什么绑定到VAO? [英] When is What bound to a VAO?

查看:260
本文介绍了什么时候是什么绑定到VAO?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在学习OpenGL三天,我可以得到东西做,但我觉得复制粘贴,而不知道我在做什么。我认为我缺乏基本的理解,什么时候是什么(VBO,属性,...)绑定到顶点数组对象(VAO),并没有找到任何资源,澄清这些方面



特别是这些是我的一些问题。如果我创建VAO:

  GLuint vao; 
glGenVertexArrays(1,& vao);

在绑定VAO之前,可以绑定任何东西吗? (如果我现在创建一个VBO,是否绑定到VAO?)

  glBindVertexArray 

绑定VAO后,如果我创建了一个VBO:

  GLuint vbo; 
glGenBuffers(1,& vbo);

是否绑定到VAO?

  glBindVertexArray(vbo); 

或者当我复制一些东西吗?



如果我得到一个属性位置:

  att = glGetAttribLocation(program_id,name); 

是否绑定到VAO?或者在启用它后发生:

  glEnableVertexAttribArray 

...或设置完成后:

  glVertexAttribPointer(att,...); 



像VBOs,所以我希望相同的规则适用。



制服应该像全局变量,所以不应该受到VAO的影响。



关于解除绑定:



如果我将VBO绑定到VAO,然后解除绑定VBO,它是否从VAO分离?



如果我有一个绑定到多个VAO的VBO,当我解开VBO时会发生什么?



关于释放资源:



当我删除VBO时会发生什么?它是否从所有VAO中删除?



IIUC我可以重用程序之间的VBO。但是,如果VAO绑定属性和VBO,并且属性接受程序参数,我可以在程序之间重用VAO吗?为什么属性取一个程序参数?



关于调试:



有没有办法漂亮地打印OpenGL状态机?我想知道已经链接的程序,哪些着色器,哪些VAO存在,哪些VBO绑定到哪些VAO哪些属性绑定到哪些VAO和VBO,他们已经设置?是否启用?



假设有人给我一个VAO,并且我得画。有没有办法知道我是否应该调用glDrawArrays或glDrawElements?我可以从VAO查询这些信息吗?也许还有我的VBO的大小存储在那里?

解决方案

这是很多子问题。但是,由于这个领域经常混淆新的OpenGL爱好者,让我尝试并提供一些内容,希望可以帮助更多的人。我会故意省略一些细节,例如不是源自缓冲区的顶点属性,以避免在这里写一本书。



关键的是要理解VAO是状态的集合。它没有任何数据。它是拥有顶点数据的VBOs。另一方面,VAO包含用于描述绘制调用获取其顶点属性的所有状态。这包括对于每个属性:




  • 如果已启用


  • 在缓冲区中的偏移量开始。

  • 后续属性之间的间距(也称为跨度)。

  • 数据类型。

  • 组件数。



只有一次:





b

将此映射到API调用,以下调用更改当前绑定的VAO跟踪的状态:




  • glEnableVertexAttribArray(...)

  • glDisableVertexAttribArray(...)

  • glVertexAttribPointer(...)

  • glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 。)



请注意,这 code> GL_ARRAY_BUFFER 。用于每个属性的缓冲区是间接跟踪的,基于在为特定属性调用 glVertexAttribPointer()时绑定的缓冲区。



这应该设置特定子问题的基础:


如果我创建一个VAO,它在我绑定VAO之前?


否。 VAO需要绑定才能修改其中存储的任何状态。


(如果我现在创建一个VBO, VAO?)


否。您可以在绑定VAO之前绑定VBO,并使用 glBufferData()填充数据。 VBO本质上只是一个愚蠢的数据容器。但是在VAO中跟踪的任何类型的顶点属性设置只能在VAO绑定之后完成。


如果我得到一个属性位置,是否绑定到VAO?


否, glGetAttribLocation()什么名字建议,这是一个属性位置。它不改变任何状态。您将使用 glEnableVertexAttribArray() glVertexAttribPointer()等调用的属性位置。


或者在启用它之后或者在设置之后发生


当给定的VBO被绑定时,当调用 glVertexAttribPointer()时,属性与给定VBO的关联被建立。


$ b $




p>大多数,但不完全。 GL_ELEMENT_ARRAY_BUFFER 绑定存储在VAO中的状态的一部分。这是有意义的,因为只有一个元素数组缓冲区用于绘制调用(而顶点属性可能来自多个不同的数组缓冲区),没有单独的调用指定使用来自当前绑定的元素数组缓冲区的索引数据,像 glVertexAttribPointer()指定使用来自当前绑定的数组缓冲区的顶点数据。当你调用 glDrawElements()时隐式发生。因此,元素数组缓冲区需要在绘制调用时绑定,这个绑定是VAO状态的一部分。


制服应该表现得像全局,所以他们不应该受到VAO的影响。


正确。


如果我将VBO绑定到VAO,然后解除绑定VBO,它从VAO分离?


否。我相信这已经被上面的解释覆盖了。


如果我有一个绑定到多个VAO的VBO,当我解除绑定VBO?


由于一个VAO没有任何反应,因此对多个VAO没有作用。


当我删除VBO时会发生什么?它是否从所有VAO中删除?或者它们仍然有对VBO的悬挂引用?


这是OpenGL的一个较暗的角落。如果您可以为所有对象类型(它们不是全部相同)陈述确切的删除规则,则您已达到高级级别...在这种情况下,VBO将从当前绑定的VAO ,但来自当前未绑定的其他VAO。如果其他VAO引用了VBO,则VBO将保持活动,直到所有这些绑定都被断开,或者VAO被删除。


如果VAO绑定属性和VBO,并且属性接受程序参数,我可以在程序之间重用VAO吗?


VAO多个程序。程序状态和VAO状态是独立的。程序中的顶点属性位置指定哪个顶点属性用于为 c>变量中的每个属性 / 顶点着色器。



只要多个程序对相同的属性使用相同的位置,就可以使用相同的VAO。为了实现这一点,你可以使用 layout(location = ...)指令顶点着色器来指定每个程序的属性位置,或者通过调用 glBindAttribLocation()在链接程序之前。


状态机?


glGet *()几乎所有的当前OpenGL状态。不方便,但它都可用。许多平台/供应商还提供开发人员工具,允许您在程序执行的某个时间点查看OpenGL状态。


我是一个VAO,我必须画它。有没有办法知道我是否应该调用glDrawArrays或glDrawElements?


这是一个不常见的情况。大多数时候,你创建VAO,所以你知道如何绘制它。或者如果有人创造它,你会要求他们画它。但是如果你真的需要它,你可以得到当前绑定的元素数组缓冲区 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,...)


I've been learning OpenGL for three days and I can get stuff done but I feel like copy pasting without knowing what I'm doing. I seriously think I lack basic understanding about when is exactly what (VBO, attributes, ...) bound to a Vertex Array Object (VAO), and haven't found any resources that clarify these aspects in detail.

In particular, these are some of my issues. If I create a VAO:

GLuint vao;
glGenVertexArrays(1, &vao);

can anything get bound to it before I bind the VAO? (if I create a VBO now, is it bound to the VAO?)

glBindVertexArray(vao);

After binding the VAO, if I create a VBO:

GLuint vbo;
glGenBuffers(1, &vbo);

is it bound to the VAO? Or does it happen when I bind it?

glBindVertexArray(vbo);

Or maybe when I copy something to it?

If I get an attribute location:

att = glGetAttribLocation(program_id, "name");

is it bound to the VAO? Or does it happen after enabling it:

glEnableVertexAttribArray(att);

... or after setting it:

glVertexAttribPointer(att, ...);

?

I guess EBOs behave just like VBOs, so I hope the same "rules" apply.

Uniforms should behave like globals, so they shouldn't be affected by VAOs at all.

Now, about unbinding:

If I "bind" a VBO to a VAO, and then unbind the VBO, does it get detached from a VAO?

If I have a VBO that is bound to multiple VAOs, what happens when I unbind that VBO?

And about freeing resources:

What happens when I delete an VBO? Does it get deleted from all the VAOs ? Or do they still have "dangling references" to that VBO?

And about programs:

IIUC I can reuse VBOs between programs. However, if VAOs bind attributes and VBOs, and attributes take a program parameter, can I reuse VAOs between programs? Why do attributes take a program parameter at all?

And about debugging:

Is there a way to pretty print the OpenGL state machine? I would like a way to know the programs that have been linked, with which shaders, which VAOs are there, which VBOs are bound to which VAOs, which attributes are bound to which VAOs and VBOs, have they been set? are they enabled? which uniforms are there...

And about drawing calls:

Suppose someone gives me a VAO, and I have to draw it. Is there a way to know if I should be calling glDrawArrays or glDrawElements? Can I query somehow this information from a VAO? Maybe along with the sizes of my VBOs stored in there?

解决方案

That's a lot of sub-questions. But since this an area that is often confusing newer OpenGL enthusiasts, let me try and provide some content that will hopefully help more people. I will intentionally skim over some details, like vertex attributes that are not sourced from a buffer, to avoid writing a book here.

The key thing to understand is that a VAO is a collection of state. It does not own any data. It's VBOs that own vertex data. A VAO, on the other hand, contains all the state used to describe where a draw call gets its vertex attributes from. This includes, for each attribute:

  • If it's enabled.
  • Which buffer the attribute is stored in.
  • At which offset in the buffer the data starts.
  • The spacing between subsequent attributes (aka the stride).
  • The type of the data.
  • The number of components.

Plus, once only:

  • Which element array buffer is bound.

Mapping this to API calls, the following calls change state tracked by the currently bound VAO:

  • glEnableVertexAttribArray(...)
  • glDisableVertexAttribArray(...)
  • glVertexAttribPointer(...)
  • glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)

Note that this does not include the current binding of GL_ARRAY_BUFFER. The buffer used for each attribute is tracked indirectly, based on which buffer was bound when glVertexAttribPointer() is called for the specific attribute.

This should set the basis for the specific sub-questions:

If I create a VAO, can anything get bound to it before I bind the VAO?

No. The VAO needs to be bound before you can modify any state stored in it.

(if I create a VBO now, is it bound to the VAO?)

No. You can bind a VBO before you bind a VAO, and fill the VBO with data using glBufferData(). A VBO is essentially just a dumb data container. But any kind of vertex attribute setup tracked in the VAO can only be done after the VAO is bound.

If I get an attribute location, is it bound to the VAO?

No, glGetAttribLocation() only does what the name suggests, which is get an attribute location. It does not change any state. You will use the attribute locations for calls like glEnableVertexAttribArray() and glVertexAttribPointer().

Or does it happen after enabling it ... or after setting it

The association of an attribute with a given VBO is established when you call glVertexAttribPointer() while the given VBO is bound.

I guess EBOs behave just like VBOs, so I hope the same "rules" apply.

Mostly, but not entirely. The GL_ELEMENT_ARRAY_BUFFER binding is part of the state stored in the VAO. This makes sense because there is only one element array buffer used for a draw call (while the vertex attributes could come from multiple different array buffers), and there is no separate call that specifies "use the index data from the currently bound element array buffer", like glVertexAttribPointer() specifies "use the vertex data from the currently bound array buffer". Instead that happens implicitly when you call glDrawElements(). Therefore, the element array buffer needs to be bound at the time of the draw call, and this binding is part of the VAO state.

Uniforms should behave like globals, so they shouldn't be affected by VAOs at all.

Correct. Uniforms are associated with shader programs, not VAOs.

If I "bind" a VBO to a VAO, and then unbind the VBO, does it get detached from a VAO?

No. I believe this is already covered by the explanations above.

If I have a VBO that is bound to multiple VAOs, what happens when I unbind that VBO?

Since nothing happens with one VAO, still nothing with multiple VAOs.

What happens when I delete an VBO? Does it get deleted from all the VAOs ? Or do they still have "dangling references" to that VBO?

This is one of the darker corners of OpenGL. If you can recite the exact deletion rules for all object types (they are not all the same), you have reached the advanced level... In this case, the VBO is automatically unbound from the currently bound VAO, but not from other VAOs that are not currently bound. If other VAOs have references to the VBO, the VBO will stay alive until all those bindings are broken, or the VAOs deleted.

However, if VAOs bind attributes and VBOs, and attributes take a program parameter, can I reuse VAOs between programs?

Yes, you can use a VAO for multiple programs. Program state and VAO state are independent. The vertex attribute location in the program specifies which vertex attribute is used to source the values for each attribute/in variable in the vertex shader.

As long as multiple programs use the same locations for the same attributes, you can use the same VAO. To make this possible, you may want to specify the attribute location for each program by using the layout (location=...) directive the vertex shader, or by calling glBindAttribLocation() before linking the program.

Is there a way to pretty print the OpenGL state machine?

There are glGet*() calls that let you retrieve pretty much all of the current OpenGL state. Not convenient, but it's all available. Many platforms/vendors also provide developer tools that allow you to look at OpenGL state at a given point in your program execution.

Suppose someone gives me a VAO, and I have to draw it. Is there a way to know if I should be calling glDrawArrays or glDrawElements?

This is an unusual scenario. Most of the time, you create the VAO, so you know how to draw it. Or if somebody else created it, you would ask them to draw it. But if you really need it, you can get the currently bound element array buffer with glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ...).

这篇关于什么时候是什么绑定到VAO?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆