我是OpenGL和图形编程的新手.到目前为止,我一直在读一本非常详尽且写得很好的教科书.但是,我在代码中找到了一点,我不太了解,我想在我之前理解这些线条.继续.
GLuint abuffer;
glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);
Run Code Online (Sandbox Code Playgroud)
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
Run Code Online (Sandbox Code Playgroud)
该书解释说,前三行是创建一个顶点数组对象,用于将关联数据与顶点数组捆绑在一起.第二行找到一个未使用的名称(我猜测存储的无符号整数标识符abuffer),第三行创建对象/使其处于活动状态.
这本书解释了第4到第7行创建一个缓冲对象来存储我们的数据,第5行给我们一个未使用的标识符(类似于第2行的顶点数组对象?),第6行创建缓冲区,第7行line在CPU上分配足够的内存并创建指向我们的数据(点)的指针GL_STATIC_DRAW.
对象处于活动状态意味着什么?你abuffer什么时候会用?顶点数组捆绑关联数据是什么意思,以及与此顶点数组对象关联的数据何时?
我对abuffer和之间的关系感到困惑buffer.我对顶点数组与缓冲区对象的关系以及该关系形成的关系感到困惑.我不确定它们是否实际上是相关的,但是它们在教科书中一个接一个地出现.
任何帮助,将不胜感激.谢谢.
Die*_*Epp 136
从低级别的角度来看,您可以将数组视为包含两个部分:
有关数组大小,形状和类型的信息(例如,32位浮点数,包含每行包含四个元素的向量行).
数组数据,只是一大块字节.
尽管低级概念基本保持不变,但多年来指定数组的方式已经发生了多次变化.
这是你的方式也许今天应该做的事情.很难找到那些无法运行OpenGL 3.x且仍然有钱花在你的软件上的人.
OpenGL中的缓冲区对象是一大块位.将"活动"缓冲区视为全局变量,并且有许多函数使用活动缓冲区而不是使用参数.这些全局状态变量是OpenGL的丑陋一面(直接状态访问之前,如下所述).
GLuint buffer;
// Generate a name for a new buffer.
// e.g. buffer = 2
glGenBuffers(1, &buffer);
// Make the new buffer active, creating it if necessary.
// Kind of like:
// if (opengl->buffers[buffer] == null)
// opengl->buffers[buffer] = new Buffer()
// opengl->current_array_buffer = opengl->buffers[buffer]
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Upload a bunch of data into the active array buffer
// Kind of like:
// opengl->current_array_buffer->data = new byte[sizeof(points)]
// memcpy(opengl->current_array_buffer->data, points, sizeof(points))
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
Run Code Online (Sandbox Code Playgroud)
现在,您的典型顶点着色器将顶点作为输入,而不是大块位.因此,您需要指定如何将位blob(缓冲区)解码为顶点.这是阵列的工作.同样,有一个"活动"数组,您可以将其视为一个全局变量:
GLuint array;
// Generate a name for a new array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);
// Make the buffer the active array buffer.
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Attach the active buffer to the active array,
// as an array of vectors with 4 floats each.
// Kind of like:
// opengl->current_vertex_array->attributes[attr] = {
// type = GL_FLOAT,
// size = 4,
// data = opengl->current_array_buffer
// }
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Enable the vertex attribute
glEnableVertexAttribArray(attr);
Run Code Online (Sandbox Code Playgroud)
在OpenGL 2.x中,没有顶点数组,数据只是全局数据.你仍然不得不打电话glVertexAttribPointer()和glEnableVertexAttribArray(),但你必须给他们打电话,每次你使用的缓冲区.在OpenGL 3.x中,您只需设置一次数组.
回到OpenGL 1.5,您实际上可以使用缓冲区,但是您使用单独的函数来绑定每种数据.例如,glVertexPointer()用于顶点数据,glNormalPointer()用于普通数据.在OpenGL 1.5之前,没有缓冲区,但您可以使用指针进入应用程序内存.
在4.3中,或者如果您具有ARB_vertex_attrib_binding扩展名,则可以分别指定属性格式和属性数据.这很好,因为它可以让您轻松地在不同的缓冲区之间切换一个顶点数组.
GLuint array;
// Generate a name for a new array array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);
// Enable my attributes
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
// Set up the formats for my attributes
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);
// Make my attributes all use binding 0
glVertexAttribBinding(loc_attrib, 0);
glVertexAttribBinding(normal_attrib, 0);
glVertexAttribBinding(texcoord_attrib, 0);
// Quickly bind all attributes to use "buffer"
// This replaces several calls to glVertexAttribPointer()
// Note: you don't need to bind the buffer first! Nice!
glBindVertexBuffer(0, buffer, 0, 32);
// Quickly bind all attributes to use "buffer2"
glBindVertexBuffer(0, buffer2, 0, 32);
Run Code Online (Sandbox Code Playgroud)
在OpenGL 4.5中,或者如果你有ARB_direct_state_access扩展,你不再需要调用glBindBuffer()或glBindVertexArray()只是设置...你直接指定数组和缓冲区.您只需要在末尾绑定数组以绘制它.
GLuint array;
// Generate a name for the array and create it.
// Note that glGenVertexArrays() won't work here.
glCreateVertexArrays(1, &array);
// Instead of binding it, we pass it to the functions below.
// Enable my attributes
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
// Set up the formats for my attributes
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);
// Make my attributes all use binding 0
glVertexArrayAttribBinding(array, loc_attrib, 0);
glVertexArrayAttribBinding(array, normal_attrib, 0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);
// Quickly bind all attributes to use "buffer"
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);
// Quickly bind all attributes to use "buffer2"
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);
// You still have to bind the array to draw.
glBindVertexArray(array);
glDrawArrays(...);
Run Code Online (Sandbox Code Playgroud)
ARB_direct_state_access有很多原因.您可以忘记绑定数组和缓冲区(绘制时除外),这样您就不必考虑OpenGL为您跟踪的隐藏全局变量.您可以忘记"为对象生成名称"和"创建对象"之间的区别,因为glCreateBuffer()并且同时glCreateArray()执行这两者.
Vulkan走得更远,你编写的代码就像我上面写的伪代码一样.所以你会看到类似的东西:
// This defines part of a "vertex array", sort of
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0; // Feed data into shader input #0
attrib[0].binding = 0; // Get data from buffer bound to slot #0
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
// repeat for attrib[1], attrib[2]
Run Code Online (Sandbox Code Playgroud)
And*_*man 15
你对这本书的解释并不完全正确.顶点数组对象不存储任何数据.它们是一类称为容器的对象,如Framebuffer Objects.您可以将其他对象附加/关联,但它们从不存储数据.因此,它们不是上下文可共享资源.
基本上,顶点数组对象封装了OpenGL 3.0中的顶点数组状态.从OpenGL 3.1(代替GL_ARB_compatibility)和OpenGL 3.2+ Core配置文件开始,您必须始终为命令设置非零VAO,以便执行glVertexAttribPointer (...)或glDrawArrays (...)运行命令.绑定的VAO形成这些命令的必要上下文,并持久存储状态.
在旧版本的GL(和兼容性)中,VAO存储的状态是全局状态机的一部分.
还值得一提的是,"当前"的结合GL_ARRAY_BUFFER是不是该VAOs跟踪的国家之一.虽然这种绑定被命令使用,例如glVertexAttribPointer (...),VAO不存储绑定,但它们只存储指针(GL_ARB_vertex_attrib_binding与GL 4.3一起引入的扩展使这一点复杂化,所以让我们为了简单起见而忽略它).
然而,VAO 确实记住了绑定的内容GL_ELEMENT_ARRAY_BUFFER,以便索引绘制命令glDrawElements (...)(如您期望的功能)(例如, VAO重新使用最后一个元素数组缓冲区绑定).
调用glVertexAttribPointer时会创建关系.

GL_VERTEX_ARRAY_BINDING并且GL_ARRAY_BUFFER_BINDING是常量,但它们可以指向绑定的全局状态.我指的是图像中的状态而不是常数(橙色).使用glGet查找不同的全局状态.
VertexArray是关于顶点或许多平行顶点的信息(包括数组缓冲区)的分组.
GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING与glGetVertexAttrib一起使用以查找设置的属性数组缓冲区.
glBindBuffer(GL_ARRAY_BUFFER设置全局状态GL_ARRAY_BUFFER_BINDING
glBindVertexArray设置全局状态GL_VERTEX_ARRAY_BINDING
OpenGL是一个有状态的界面。这是不好的,过时的和丑陋的,但这对你们来说是遗产。
顶点数组对象是缓冲区绑定的集合,驱动程序可使用该缓冲区绑定来获取绘制调用的数据,大多数教程仅使用一个,并且从不解释如何使用多个VAO。
缓冲区绑定告诉opengl将缓冲区用于相关方法,尤其是glVertexAttribPointer方法。