glVertexAttribPointer 澄清 [英] glVertexAttribPointer clarification

查看:24
本文介绍了glVertexAttribPointer 澄清的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

只是想确保我正确理解这一点(我会在 SO Chat 上问,但它已经死在那里了!):

Just want to make sure I understand this correctly (I'd ask on SO Chat, but it's dead in there!):

我们有一个顶点数组,我们通过绑定它使其成为当前"
然后我们有一个缓冲区,我们将其绑定到目标
然后我们通过 glBufferData 填充那个 Target它基本上填充了绑定到该目标的任何内容,即我们的 Buffer
然后我们调用 glVertexAttribPointer,它描述了数据的布局方式——数据是绑定到 GL_ARRAY_BUFFER 的任何东西并且这个描述符被保存到我们原来的 Vertex Array

We've got a Vertex Array, which we make "current" by binding it
then we've got a Buffer, which we bind to a Target
then we fill that Target via glBufferData which essentially populates whatever was bound to that target, i.e. our Buffer
and then we call glVertexAttribPointer which describes how the data is laid out -- the data being whatever is bound to GL_ARRAY_BUFFER and this descriptor is saved to our original Vertex Array

(1) 我的理解正确吗?
文档 对所有内容之间的相关性有点稀疏.

(1) Is my understanding correct?
The documentation is a little sparse about how everything correlates.

(2) 是否有某种默认的顶点数组?因为我忘记/省略了 glGenVertexArraysglBindVertexArray 并且我的程序在没有它的情况下运行良好.

(2) Is there some kind of default Vertex Array? Because I forgot/omitted glGenVertexArrays and glBindVertexArray and my program worked fine without it.

我错过了一个步骤...glEnableVertexAttribArray.

I missed a step... glEnableVertexAttribArray.

(3) 调用glVertexAttribPointer时是否与Vertex Array绑定了Vertex Attrib,然后我们可以随时通过glEnableVertexAttribArray启用/禁用那个attrib,不管当前绑定的是哪个顶点数组?

(3) Is the Vertex Attrib tied to the Vertex Array at the time glVertexAttribPointer is called, and then we can enable/disable that attrib via glEnableVertexAttribArray at any time, regardless of which Vertex Array is currently bound?

或(3b) 调用glEnableVertexAttribArray时是否与Vertex Array绑定的Vertex Attrib,因此我们可以通过调用glEnableVertexAttribArray<将同一个Vertex Attrib添加到多个Vertex Array中/code> 在不同的时间,当不同的顶点数组被绑定时?

Or (3b) Is the Vertex Attrib tied to the Vertex Array at the time glEnableVertexAttribArray is called, and thus we can add the same Vertex Attrib to multiple Vertex Arrays by calling glEnableVertexAttribArray at different times, when different Vertex Arrays are bound?

推荐答案

有些术语有点不对:

  • A Vertex Array 只是一个包含顶点数据的数组(通常是一个 float[]).它不需要绑定到任何东西.不要与 Vertex Array Object 或 VAO 混淆,我稍后会讲到
  • 一个Buffer Object,在存储顶点时通常被称为Vertex Buffer Object,或者简称VBO,就是你所谓的Buffer.
  • 没有任何东西被保存回顶点数组,glVertexAttribPointer 的工作方式与 glVertexPointerglTexCoordPointer 的工作方式完全一样,只是你得到的不是命名属性提供一个数字来指定您自己的属性.您将此值作为 index 传递.您所有的 glVertexAttribPointer 调用都会排队等待您下次调用 glDrawArraysglDrawElements.如果您绑定了 VAO,VAO 将存储您所有属性的设置.
  • A Vertex Array is just an array (typically a float[]) that contains vertex data. It doesn't need to be bound to anything. Not to be confused with a Vertex Array Object or VAO, which I will go over later
  • A Buffer Object, commonly referred to as a Vertex Buffer Object when storing vertices, or VBO for short, is what you're calling just a Buffer.
  • Nothing gets saved back to the vertex array, glVertexAttribPointer works exactly like glVertexPointer or glTexCoordPointer work, just instead of named attributes, you get to provide a number that specifies your own attribute. You pass this value as index. All your glVertexAttribPointer calls get queued up for the next time you call glDrawArrays or glDrawElements. If you have a VAO bound, the VAO will store the settings for all your attributes.

这里的主要问题是您将顶点属性与 VAO 混淆了.顶点属性只是为绘图定义顶点、texcoords、法线等的新方法.VAO 存储状态.我将首先解释如何使用顶点属性进行绘图,然后解释如何使用 VAO 减少方法调用的数量:

The main issue here is that you're confusing vertex attributes with VAOs. Vertex attributes are just the new way of defining vertices, texcoords, normals, etc. for drawing. VAOs store state. I'm first going to explain how drawing works with vertex attributes, then explain how you can cut down the number of method calls with VAOs:

  1. 您必须先启用一个属性,然后才能在着色器中使用它.例如,如果您想将顶点发送到着色器,您很可能会将其作为第一个属性 0 发送.因此,在渲染之前,您需要使用 glEnableVertexAttribArray(0);.
  2. 既然启用了一个属性,您需要定义它要使用的数据.为此,您需要绑定您的 VBO - glBindBuffer(GL_ARRAY_BUFFER, myBuffer);.
  3. 现在我们可以定义属性 - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);.参数顺序:0是你定义的属性,3是每个顶点的大小,GL_FLOAT是类型,GL_FALSE表示不对每个顶点进行归一化,最后 2 个零表示顶点上没有步幅或偏移.
  4. 用它画一些东西 - glDrawArrays(GL_TRIANGLES, 0, 6);
  5. 接下来你绘制的东西可能不会使用属性 0(实际上它会,但这是一个例子),所以我们可以禁用它 - glDisableVertexAttribArray(0);
  1. You must enable an attribute before you can use it in a shader. For example, if you want to send vertices over to a shader, you're most likely going to send it as the first attribute, 0. So before you render, you need to enable it with glEnableVertexAttribArray(0);.
  2. Now that an attribute is enabled, you need to define the data it's going to use. In order to do so you need to bind your VBO - glBindBuffer(GL_ARRAY_BUFFER, myBuffer);.
  3. And now we can define the attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);. In order of parameter: 0 is the attribute you're defining, 3 is the size of each vertex, GL_FLOAT is the type, GL_FALSE means to not normalize each vertex, the last 2 zeros mean that there's no stride or offset on the vertices.
  4. Draw something with it - glDrawArrays(GL_TRIANGLES, 0, 6);
  5. The next thing you draw may not use attribute 0 (realistically it will, but this is an example), so we can disable it - glDisableVertexAttribArray(0);

将其包裹在 glUseProgram() 调用中,您就拥有了一个可以正确使用着色器的渲染系统.但是假设您有 5 个不同的属性,顶点、texcoords、法线、颜色和光照贴图坐标.首先,您将对这些属性中的每一个进行单个 glVertexAttribPointer 调用,并且您必须事先启用所有属性.假设您按照我列出的方式定义属性 0-4.您可以像这样启用所有这些:

Wrap that in glUseProgram() calls and you have a rendering system that works with shaders properly. But let's say you have 5 different attributes, vertices, texcoords, normals, color, and lightmap coordinates. First of all, you would be making a single glVertexAttribPointer call for each of these attributes, and you'd have to enable all the attributes beforehand. Let's say you define the attributes 0-4 as I have them listed. You would enable all of them like so:

for (int i = 0; i < 5; i++)
    glEnableVertexAttribArray(i);

然后您必须为每个属性绑定不同的 VBO(除非您将它们全部存储在一个 VBO 中并使用偏移量/步幅),然后您需要进行 5 个不同的 glVertexAttribPointer 调用,来自 glVertexAttribPointer(0,...); to glVertexAttribPointer(4,...); 分别用于顶点到光照贴图坐标.

And then you would have to bind different VBOs for each attribute (unless you store them all in one VBO and use offsets/stride), then you need to make 5 different glVertexAttribPointer calls, from glVertexAttribPointer(0,...); to glVertexAttribPointer(4,...); for vertices to lightmap coordinates respectively.

希望这个系统本身就有意义.现在我将转到 VAO 来解释如何使用它们来减少执行此类渲染时的方法调用次数.请注意,没有必要使用 VAO.

Hopefully that system alone makes sense. Now I'm going to move on to VAOs to explain how to use them to cut down on the number of method calls when doing this type of rendering. Note that using a VAO is not necessary.

Vertex Array Object 或 VAO 用于存储所有 glVertexAttribPointer 调用的状态和每个 glVertexAttribPointer 的目标 VBO代码>进行了调用.

A Vertex Array Object or VAO is used to store the state of all the glVertexAttribPointer calls and the VBOs that were targeted when each of the glVertexAttribPointer calls were made.

您通过调用glGenVertexArrays 生成一个.要将您需要的所有内容存储在 VAO 中,请使用 glBindVertexArray 将其绑定,然后执行完整的绘制调用.所有 draw 绑定调用都会被 VAO 拦截并存储.您可以使用 glBindVertexArray(0);

You generate one with a call to glGenVertexArrays. To store everything you need in a VAO, bind it with glBindVertexArray, then do a full draw call. All the draw bind calls get intercepted and stored by the VAO. You can unbind the VAO with glBindVertexArray(0);

现在当你想绘制对象时,你不需要重新调用所有的 VBO 绑定或 glVertexAttribPointer 调用,你只需要用 glBindVertexArray<绑定 VAO/code> 然后调用 glDrawArraysglDrawElements 并且您将绘制完全相同的东西,就像您进行所有这些方法调用一样.之后您可能也想解除绑定 VAO.

Now when you want to draw the object, you don't need to re-call all the VBO binds or the glVertexAttribPointer calls, you just need to bind the VAO with glBindVertexArray then call glDrawArrays or glDrawElements and you'll be drawing the exact same thing as though you were making all those method calls. You probably want to unbind the VAO afterwards too.

解除绑定 VAO 后,所有状态都会恢复到绑定 VAO 之前的状态.我不确定您在绑定 VAO 时所做的任何更改是否保留,但这可以通过测试程序轻松解决.我想您可以将 glBindVertexArray(0); 视为绑定到默认"VAO...

Once you unbind the VAO, all the state returns to how it was before you bound the VAO. I'm not sure if any changes you make while the VAO is bound is kept, but that can easily be figured out with a test program. I guess you can think of glBindVertexArray(0); as binding to the "default" VAO...

更新:有人让我注意到实际绘制调用的必要性.事实证明,在设置 VAO 时,您实际上并不需要进行完整的绘制调用,只需进行所有绑定即可.不知道为什么我之前认为有必要,但现在已经修复了.

Update: Someone brought to my attention the need for the actual draw call. As it turns out, you don't actually need to do a FULL draw call when setting up the VAO, just all the binding stuff. Don't know why I thought it was necessary earlier, but it's fixed now.

这篇关于glVertexAttribPointer 澄清的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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