从低层次的角度来看,您可以认为数组有两个部分:
尽管底层概念基本保持不变,但多年来指定数组的方式已经发生了数次更改。
OpenGL 3.0 / ARB_vertex_array_object
这是你的方式也许今天应该做的事情。很少有人无法运行OpenGL 3.x,但仍然有钱可以花在您的软件上。
OpenGL中的缓冲区对象是一大块位。可以将“活动”缓冲区视为一个全局变量,并且有很多函数使用活动缓冲区而不是参数。这些全局状态变量是OpenGL的丑陋一面(在直接状态访问之前,下面将进行介绍)。
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
现在,典型的顶点着色器将顶点作为输入,而不是很大的位。因此,您需要指定如何将位块(缓冲区)解码为顶点。那就是阵列的工作。同样,有一个“活动”数组,您可以将其视为全局变量:
GLuint array;
glGenVertexArrays(1, &array);
glBindVertexArray(array);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(attr);
OpenGL 2.0(旧方法)
在OpenGL 2.x中,没有顶点数组,数据只是全局的。您仍然必须调用glVertexAttribPointer()
和glEnableVertexAttribArray()
,但是每次使用缓冲区时都必须调用它们。在OpenGL 3.x中,只需设置一次阵列。
回到OpenGL 1.5,您实际上可以使用缓冲区,但是您使用了单独的函数来绑定每种数据。例如,glVertexPointer()
用于顶点数据,glNormalPointer()
用于正常数据。在OpenGL 1.5之前,没有缓冲区,但是您可以在应用程序内存中使用指针。
OpenGL 4.3 / ARB_vertex_attrib_binding
在4.3中,或者如果您具有ARB_vertex_attrib_binding扩展名,则可以分别指定属性格式和属性数据。这很好,因为它使您可以轻松地在不同缓冲区之间切换一个顶点数组。
GLuint array;
glGenVertexArrays(1, &array);
glBindVertexArray(array);
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
glVertexAttribFormat(loc_attrib, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(normal_attrib, 3, GL_FLOAT, GL_FALSE, 12);
glVertexAttribFormat(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
glVertexAttribBinding(loc_attrib, 0);
glVertexAttribBinding(normal_attrib, 0);
glVertexAttribBinding(texcoord_attrib, 0);
glBindVertexBuffer(0, buffer, 0, 32);
glBindVertexBuffer(0, buffer2, 0, 32);
OpenGL 4.5 / ARB_direct_state_access
在OpenGL 4.5中,或者如果您具有ARB_direct_state_access扩展名,则不再需要调用glBindBuffer()
或glBindVertexArray()
仅进行设置...直接指定数组和缓冲区。您只需要在最后绑定绑定数组即可绘制它。
GLuint array;
glCreateVertexArrays(1, &array);
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
glVertexArrayAttribFormat(array, loc_attrib, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(array, normal_attrib, 3, GL_FLOAT, GL_FALSE, 12);
glVertexArrayAttribFormat(array, texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
glVertexArrayAttribBinding(array, loc_attrib, 0);
glVertexArrayAttribBinding(array, normal_attrib, 0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);
glBindVertexArray(array);
glDrawArrays(...);
由于许多原因,ARB_direct_state_access很好。您可以忘记绑定数组和缓冲区(绘制时除外),因此不必考虑OpenGL正在为您跟踪的隐藏全局变量。你可以约“为对象,生成名称”和“创建一个对象”,因为之间的差异忘记glCreateBuffer()
,并glCreateArray()
在同一时间两者都做。
武尔坎
Vulkan走得更远,您是否可以像我上面编写的伪代码一样编写代码。因此,您将看到类似以下内容:
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0;
attrib[0].binding = 0;
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
GL_EXT_direct_state_access
,但是不幸的是,这确实排除了在Mesa,Intel或Apple驱动程序上运行代码的可能:-\但是,我认为必须指出,自GL 1.1起就存在了顶点阵列。GL 2.0中唯一发生变化的是引入了通用顶点属性槽。