VAO,VBO,EBO三者的关系
始终要牢记一点,OpenGL是一个巨大的状态机,当我们绑定VAO,VBO或者EBO时,实际上是在告诉OpenGL当前哪个对象处于活动状态,然后进行的操作都是和这个对象相关联的。
先看一张图有个大致理解:
VAO和VBO相对独立,他们的绑定互不影响,EBO与VAO强相关,它的绑定必须在绑定了一个VAO之后,VAO之中要记录EBO的状态信息,意思就是,EBO要在设置哪个VAO时激活(绑定)。
之所以这样设计,是因为索引信息和我们的顶点对象强相关,也就是说,顶点对象是个什么玩意儿某种意义上就是看EBO的,VBO是可以复用的,他就是一堆不同坐标顶点而已。
同理,EBO解绑也必须要在他相关的VAO解绑之后进行,因为如果先解绑EBO,VAO中索引信息就不是激活状态了,失效了,这时候渲染找不到索引信息会出现问题,程序甚至卡死。
当然,解绑VBO,EBO的操作不是必须的,后面会说明。
总体的关系说完了,接下来讲讲细节。
生成VAO,VBO和EBO,就是生成不同对象的句柄,这些对象逻辑都在状态机中,绑定不同句柄就能切换不同对象(数据)。
绑定VAO,就是告诉状态机,我们接下来要设置或应用这个顶点对象了,设置中肯定会有的操作是,设置顶点属性指针,即glVertexAttribPointer,它的四个参数是描述读取顶点的方式:读多少,数据类型,步长(读取完一块每隔多少再读),起始位置;所以这个操作一定在绑定VBO之后(必须得有一个激活的VBO),这些与VBO中的数据息息相关但是对它本身毫无影响,说白了就像是设置一个指向数据的指针,按照设置的方式去读取数据,我们绑定不同的VBO可以应用不同的数据,只是不切换绑定VAO的话读取方式是固定的;
绑定VBO,EBO,顾名思义,Buffer Object,我们所使用的数据真正存在于此,肯定会有的操作是,从CPU上传顶点数据到GPU,即glBufferData,不同的是EBO必须在绑定VAO之后绑定,解绑同样如此。如果说VAO是通过指针应用VBO的数据,那么对EBO数据的使用,就如同直接使用,不需要任何媒介,所以并不需要设置一系列信息告诉状态机怎么用EBO中的数据,它们俩是强相关的,原因前面解释过了不再赘述。
然后是解绑操作,所有的显式解绑都不是必须的,因为绑定到另一个VAO,VBO或者EBO,旧的绑定会自动解绑,但我们仍然推崇显式解绑,因为这样代码的边界更清晰。
下面是设置两个VAO一般的步骤,可以尝试自行调换函数执行顺序看看自己是否理解到位,至少,在程序执行上不会有逻辑错误,也许细节方面理解会不到位。
1 | glGenVertexArrays(1, &VAO_); |
代码中30和35行可以同时去除,因为VAO和VBO绑定独立,只要不解绑VBO,后面用的数据还是原先VBO的,但是,31和36行同时去除将会执行失败,因为VAO中要存储EBO的绑定状态,所以36行不能去除,每设置一个VAO就要绑定一个EBO。