草庐IT

c++ - 什么时候绑定(bind)到 VAO?

coder 2023-05-31 原文

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

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

GLuint vao;
glGenVertexArrays(1, &vao);

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

绑定(bind) VAO 后,如果我创建一个 VBO:
GLuint vbo;
glGenBuffers(1, &vbo);

是绑定(bind)到VAO吗?或者当我绑定(bind)它时它会发生吗?
glBindVertexArray(vbo);

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

如果我得到一个属性位置:
att = glGetAttribLocation(program_id, "name");

是绑定(bind)到VAO吗?或者启用它后是否发生:
glEnableVertexAttribArray(att);

...或设置后:
glVertexAttribPointer(att, ...);

?

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

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

现在,关于解除绑定(bind):

如果我将 VBO“绑定(bind)”到 VAO,然后解除绑定(bind) VBO,它会与 VAO 分离吗?

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

关于释放资源:

当我删除 VBO 时会发生什么?它是否会从所有 VAO 中删除?或者他们仍然对那个 VBO 有“悬空引用”吗?

关于程序:

IIUC 我可以在程序之间重用 VBO。但是,如果 VAO 绑定(bind)属性和 VBO,并且属性采用程序参数,我是否可以在程序之间重用 VAO?为什么属性完全采用程序参数?

关于调试:

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

关于绘图调用:

假设有人给了我一个 VAO,我必须绘制它。有没有办法知道我应该调用 glDrawArrays 还是 glDrawElements?我可以从 VAO 以某种方式查询这些信息吗?也许连同我存储在那里的 VBO 的大小?

最佳答案

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

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

  • 如果启用。
  • 属性存储在哪个缓冲区中。
  • 数据在缓冲区中的哪个偏移量开始。
  • 后续属性之间的间距(又名步幅)。
  • 数据的类型。
  • 组件的数量。

  • 另外,只有一次:
  • 绑定(bind)了哪个元素数组缓冲区。

  • 将此映射到 API 调用,以下调用会更改当前绑定(bind)的 VAO 跟踪的状态:
  • glEnableVertexAttribArray(...)
  • glDisableVertexAttribArray(...)
  • glVertexAttribPointer(...)
  • glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)

  • 请注意,这是不是 包括 GL_ARRAY_BUFFER 的当前绑定(bind).根据 glVertexAttribPointer() 时绑定(bind)的缓冲区,间接跟踪用于每个属性的缓冲区。为特定属性调用。

    这应该为特定的子问题奠定基础:

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



    不可以。必须先绑定(bind) VAO,然后才能修改其中存储的任何状态。

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



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

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



    不,glGetAttribLocation()只做顾名思义的事情,即获取属性位置。它不会改变任何状态。您将使用属性 location 来进行类似 glEnableVertexAttribArray() 的调用。和 glVertexAttribPointer() .

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



    当您调用 glVertexAttribPointer() 时,将建立属性与给定 VBO 的关联。而给定的 VBO 是绑定(bind)的。

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



    大多数,但不完全。 GL_ELEMENT_ARRAY_BUFFER装订状态的一部分存储在 VAO 中。这是有道理的,因为只有一个元素数组缓冲区用于绘制调用(而顶点属性可能来自多个不同的数组缓冲区),并且没有单独的调用指定“使用来自当前绑定(bind)元素数组缓冲区的索引数据", 喜欢 glVertexAttribPointer()指定“使用当前绑定(bind)数组缓冲区中的顶点数据”。相反,当您调用 glDrawElements() 时,这种情况会隐式发生。 .所以在draw call的时候需要绑定(bind)元素数组buffer,这个绑定(bind)是VAO状态的一部分。

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



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

    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?



    由于一个 VAO 没有任何 react ,多个 VAO 仍然没有任何 react 。

    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?



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

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



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

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

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



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

    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?



    这是一个不寻常的场景。大多数情况下,您创建 VAO,因此您知道如何绘制它。或者,如果其他人创建了它,您会要求他们绘制它。但是如果你真的需要它,你可以用 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ...) 获取当前绑定(bind)的元素数组缓冲区.

    关于c++ - 什么时候绑定(bind)到 VAO?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26552642/

    有关c++ - 什么时候绑定(bind)到 VAO?的更多相关文章

    1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

      我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

    3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

      我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

    4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

      为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

    6. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    7. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

      它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

    8. ruby - Infinity 和 NaN 的类型是什么? - 2

      我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

    9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

      如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

    10. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

      关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

    随机推荐