glVertexAttribPointer澄清 [英] glVertexAttribPointer clarification

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

问题描述

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

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

我们有一个顶点阵列,通过绑定它可以使它成为当前"
然后我们有一个Buffer,我们将其绑定到Target
然后我们通过glBufferData填充该目标 本质上会填充绑定到该目标的任何内容,即我们的Buffer
然后我们调用glVertexAttribPointer,它描述了数据的布局方式-数据就是绑定到GL_ARRAY_BUFFER的任何内容 并将此描述符保存到我们的原始顶点数组

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时,顶点属性是否绑定到顶点数组,然后我们可以随时通过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时将顶点属性绑定到顶点数组吗,因此我们可以通过在不同的时间(不同的顶点)调用glEnableVertexAttribArray来将相同的顶点属性添加到多个顶点数组中数组绑定了吗?

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?

推荐答案

某些术语有些偏离:

  • Vertex Array只是一个包含顶点数据的数组(通常为float[]).它不需要绑定任何东西.不要与Vertex Array Object或VAO混淆,我将在以后进行讨论
  • 存储顶点时通常称为Vertex Buffer ObjectBuffer Object,简称VBO,就是您所说的Buffer.
  • 什么都没有保存回到顶点数组,glVertexAttribPointer的工作方式与glVertexPointerglTexCoordPointer的工作方式完全一样,只是提供了一个数字来指定您自己的属性,而不是命名属性.您将此值作为index传递.下次调用glDrawArraysglDrawElements时,所有glVertexAttribPointer呼叫都会排队.如果您绑定了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表示不对每个顶点进行规范化,后两个零表示没有跨度或偏移在顶点上.
  4. 用它来绘画-glDrawArrays(GL_TRIANGLES, 0, 6);
  5. 接下来绘制的内容可能不会使用属性0(实际上会使用属性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中并使用offsets/stride),然后需要进行5个不同的glVertexAttribPointer调用,从glVertexAttribPointer(0,...);分别将顶点设置为光照贴图坐标.

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拦截并存储.您可以将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调用,只需将VAO与glBindVertexArray绑定,然后调用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时实际上不需要进行FULL绘制调用,只需绑定所有东西即可.不知道为什么我以前认为有必要,但现在已解决.

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天全站免登陆