gpt4 book ai didi

c++ - glBindVertexArrays 与 glBindBuffer 的作用是什么,它们的关系是什么?

转载 作者:IT老高 更新时间:2023-10-28 12:12:11 25 4
gpt4 key购买 nike

我是 OpenGL 和图形编程的新手。到目前为止,我一直在阅读一本非常透彻且写得很好的教科书。但是,我在代码中遇到了一个我不太理解的点,我想在我理解这些行之前继续前进。

GLuint abuffer;

glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

本书解释了前三行是创建一个顶点数组对象,它用于将关联数据与顶点数组捆绑在一起。第二行找到一个未使用的名称(我猜是存储在 abuffer 中的无符号整数标识符),第三行创建对象/使其处于事件状态。

这本书解释了第 4-7 行创建了一个 缓冲区对象 来存储我们的数据,第 5 行给了我们一个未使用的标识符(类似于第 2 行的顶点数组对象?),第 6 行创建缓冲区,第 7 行在 CPU 上分配足够的内存并为 GL_STATIC_DRAW 创建指向我们的数据(点)的指针。

对象处于事件状态是什么意思?您随后会在什么时候使用 abuffer?顶点数组捆绑关联数据是什么意思,数据是什么时候与这个顶点数组对象关联的?

我对abufferbuffer 之间的关系感到困惑。我对顶点数组与缓冲区对象的关系是什么以及在什么时候形成这种关系感到困惑。我不确定它们实际上是否相关,但它们在教科书中一个接一个地出现。

任何帮助将不胜感激。谢谢。

最佳答案

从低层次的角度来看,您可以将数组视为由两部分组成:

  • 有关数组的大小、形状和类型的信息(例如,32 位 float ,包含每行四个元素的 vector )。

  • 数组数据,只不过是一大块字节。

尽管低级概念基本保持不变,但多年来指定数组的方式已经发生了数次变化。

OpenGL 3.0/ARB_vertex_array_object

这就是你可能今天应该做的事情。很少有人无法运行 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);

现在,您的典型顶点着色器将 vertexes 作为输入,而不是一大块位。因此,您需要指定如何将位 block (缓冲区)解码为顶点。这就是数组的工作。同样,有一个“事件”数组,您可以将其视为一个全局变量:

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);

OpenGL 2.0(旧方式)

在 OpenGL 2.x 中,没有顶点数组,数据只是全局的。您仍然必须调用 glVertexAttribPointer()glEnableVertexAttribArray(),但您必须在每次使用缓冲区时调用它们。在 OpenGL 3.x 中,您只需设置一次数组。

回到 OpenGL 1.5,您实际上可以使用缓冲区,但您使用单独的函数来绑定(bind)每种数据。例如,glVertexPointer() 用于顶点数据,glNormalPointer() 用于普通数据。在 OpenGL 1.5 之前,没有缓冲区,但您可以使用指向应用程序内存的指针。

OpenGL 4.3/ARB_vertex_attrib_binding

在 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);

OpenGL 4.5/ARB_direct_state_access

在 OpenGL 4.5 中,或者如果您有 ARB_direct_state_access 扩展,则不再需要调用 glBindBuffer()glBindVertexArray() 来进行设置...您直接指定数组和缓冲区。只需要在最后绑定(bind)数组即可绘制。

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(...);

ARB_direct_state_access 很不错,原因有很多。您可以忘记绑定(bind)数组和缓冲区(绘制时除外),因此您不必考虑 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]

关于c++ - glBindVertexArrays 与 glBindBuffer 的作用是什么,它们的关系是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21652546/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com