提问者:小点点

什么是什么时候绑定一个VAO?


我已经学习OpenGL三天了,我可以完成一些事情,但我感觉像复制粘贴,而不知道我在做什么。我真的认为我对什么时候是什么(VBO,attributes,。。。)绑定到顶点数组对象(VAO)缺乏基本的了解,也没有找到任何详细阐明这些方面的资源。

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

GLuint vao;
glGenVertexArrays(1, &vao);

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

glBindVertexArray(vao);

绑定VAO后,如果创建VBO:

GLuint vbo;
glGenBuffers(1, &vbo);

它和VAO绑定了吗?还是在我绑定它的时候发生的?

glBindVertexArray(vbo);

或者当我复制一些东西到它上的时候?

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

att = glGetAttribLocation(program_id, "name");

它和VAO绑定了吗?还是在启用后发生:

glEnableVertexAttribArray(att);

。。。或设置后:

glVertexAttribPointer(att, ...);

我猜EBO的行为就像VBO一样,所以我希望同样的“规则”也适用。

制服应该表现得像全球一样,所以它们根本不应该受到VAO的影响。

现在,关于解除绑定:

如果我将VBO“绑定”到VAO,然后将VBO解除绑定,VBO是否与VAO分离?

如果我有一个VBO绑定到多个VAO,当我取消绑定该VBO时会发生什么?

以及释放资源:

当我删除VBO时会发生什么?会从所有VAO中删除吗?或者他们仍然有关于VBO的“悬而未决的参考”?

和关于程序:

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

和关于调试:

有没有办法漂亮地打印OpenGL状态机?我想要一种方法来了解已经链接的程序,与哪些着色器,哪些VAO在那里,哪些VBO绑定到哪些VAO,哪些属性绑定到哪些VAO和VBO,它们已经设置好了吗?它们是否已启用?有哪些制服。。。

和绘制呼叫:

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


共2个答案

匿名用户

这是一大堆分问题。但由于这是一个经常混淆新的OpenGL爱好者的领域,让我尝试并提供一些内容,希望能帮助更多的人。我会有意略过一些细节,比如不是来源于缓冲区的顶点属性,以避免在这里写成一本书。

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

  • 如果已启用。
  • 存储属性的缓冲区。
  • 数据从缓冲区中的偏移量开始。
  • 后续属性之间的间距(也称为步幅)。
  • 数据的类型。
  • 组件的数量。

另外,只有一次:

  • 绑定了哪个元素数组缓冲区。

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

  • GlenableVertexAttriBarray(。。。)
  • GLDisableVertexAttriBarray(。。。)
  • GLVertexAttribPointer(。。。)
  • GLBindBuffer(GL_ELEMENT_ARRAY_BUFFER,。。。)

注意,这不包括GL_ARRAY_BUFFER的当前绑定。每个属性使用的缓冲区都是间接跟踪的,根据为特定属性调用GLVertexAttribPointer()时绑定的缓冲区。

这应为具体的子问题奠定基础:

如果我创建了一个VAO,在绑定VAO之前,任何东西都可以绑定到它吗?

不可以。在您可以修改存储在其中的任何状态之前,需要绑定VAO。

(如果我现在创建一个VBO,它是否绑定到VAO?)

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

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

不,glgetAttribLocation()只执行名称所暗示的功能,即获取属性位置。它不会改变任何状态。您将对诸如GlenableVertexAttribArray()GlVertexAttribPointer()之类的调用使用属性位置。

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

属性与给定VBO的关联是在绑定给定VBO时调用GLVertexAttribPointer()时建立的。

我猜EBO的行为就像VBO一样,所以我希望同样的“规则”也适用。

大部分,但不是全部。GL_ELEMENT_ARRAY_BUFFER绑定是存储在VAO中的状态的一部分。这是有意义的,因为只有一个元素数组缓冲区用于绘制调用(而顶点属性可能来自多个不同的数组缓冲区),并且没有单独的调用指定“使用当前绑定的元素数组缓冲区中的索引数据”,如GLVertexAttribPointer()指定“使用当前绑定的数组缓冲区中的顶点数据”。相反,当您调用GLDraWelements()时,就会隐式地发生这种情况。因此,需要在draw调用时绑定元素数组缓冲区,这种绑定是VAO状态的一部分。

制服应该表现得像全球一样,所以它们根本不应该受到VAO的影响。

正确。制服与着色程序相关联,而不是与VAO相关联。

如果我将VBO“绑定”到VAO,然后将VBO解除绑定,VBO是否与VAO分离?

不是。我相信以上的解释已经涵盖了这一点。

如果我有一个VBO绑定到多个VAO,当我取消绑定该VBO时会发生什么?

因为一个VAO不会发生任何事情,所以多个VAO也不会发生任何事情。

当我删除VBO时会发生什么?会从所有VAO中删除吗?或者他们仍然有关于VBO的“悬而未决的参考”?

这是OpenGL比较黑暗的角落之一。如果你能背诵所有对象类型的确切删除规则(它们并不都一样),你就达到了高级……在这种情况下,VBO会自动与当前绑定的VAO解除绑定,但不会与当前未绑定的其他VAO解除绑定。如果其他VAO有对VBO的引用,则VBO将保持活动状态,直到所有这些绑定被破坏或VAO被删除。

但是,如果VAO绑定属性和VBO,并且属性取一个程序参数,我可以在程序之间重用VAO吗?

是的,您可以将一个VAO用于多个程序。程序状态和VAO状态是独立的。程序中的顶点属性位置指定顶点着色器中每个attribute/in变量的值的来源是哪个顶点属性。

只要多个程序对相同的属性使用相同的位置,您就可以使用相同的VAO。为此,您可能需要在链接程序之前使用布局(location=...)指令(顶点着色器)指定每个程序的属性位置,或者调用GLBindatTribLocation()

有没有办法漂亮地打印OpenGL状态机?

有一些glget*()调用可以让您检索几乎所有的当前OpenGL状态。不方便,但都有。许多平台/供应商还提供开发工具,允许您查看OpenGL在程序执行中的给定点的状态。

假设有人给我一个VAO,我得画出来。有没有办法知道我应该调用glDrawArrays还是GLDraWelements?

这是一个不寻常的场景。大多数时候,您创建了VAO,因此您知道如何绘制它。或者如果是别人创造的,你会让他们画出来。但是如果确实需要,可以使用GLGetIntegerV(GL_ELEMENT_ARRAY_BUFFER_BINDING,...)获取当前绑定的元素数组缓冲区。

匿名用户

VAO表可在规范的State Tables部分找到

在psuedo代码中,它看起来像:

struct VAO{
    GL_INT element_array_binding; //IBO used for glDrawElements and friends
    char* label;//for debugging

    struct{//per attribute values
        bool enabled; //whether to use a VBO for it

        //corresponding to the values passed into glVertexAttribPointer call
        int size;
        unsigned int stride; 
        GL_ENUM type; 
        bool normalized;
        bool integer; //unconverted integers
        bool long; //double precision
        void* offset;
        int bufferBinding;//GL_ARRAY_BUFFER bound at time of glVertexAttribPointer call

        int attributeDiviser; //as used for instancing 

    } attributes[MAX_VERTEX_ATTRIBS];
};

值得注意的是缺少程序状态(哪一个是绑定的,统一值等等)

相关问题