如何在 OpenGL 4.5 中使用 vao 和缓冲区
How to use vao and buffers in OpenGL 4.5
我想使用 OpenGL 4.5 渲染三角形。我在网上找到了很多使用旧版本 OpenGL 的示例,但 none 使用 OpenGL 4.5 函数。因此,我尝试 "upgrade" 自己编写一些代码。这是旧的工作代码:
// Triangles to render
vec3 vertices[2][3] = { { vec3(-0.90f, -0.90f, 1.0f), vec3(0.85f, -0.90f, 1.0f), vec3(-0.90f, 0.85f, 1.0f) },
{ vec3(0.90f, -0.85f, 1.0f), vec3(0.90f, 0.90f, 1.0f), vec3(-0.85f, 0.90f, 1.0f) } };
//Initialize
glGenVertexArrays(1, &vaos);
glBindVertexArray(vaos);
glGenBuffers(1, &buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangles), triangles, GL_STATIC_DRAW);
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "triangles.vert" },
{ GL_FRAGMENT_SHADER, "triangles.frag" },
{ GL_NONE, NULL }
};
program = LoadShaders(shaders);
glUseProgram(program);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(0);
//Render
GLint index;
index = glGetUniformLocation(program, "projectionMatrix");
glUniformMatrix3fv(index, 1, true, value_ptr(projectionMatrix));
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vaos);
glDrawArrays(GL_TRIANGLES, 0, nvertices);
然后我 "updated" 将其用于此代码,它似乎没有在屏幕上绘制任何内容:
// Same triangles
// Initialize
glCreateVertexArrays(1, &vaos);
glEnableVertexArrayAttrib(vaos, 0);
glVertexArrayAttribFormat(vaos, 0, 3, GL_FLOAT, GL_FALSE, 0);
glCreateBuffers(1, &buffers);
glNamedBufferData(buffers, sizeof(triangles), triangles, GL_STATIC_DRAW);
glVertexArrayAttribBinding(vaos, 0, 0);
glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 0);
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "triangles.vert" },
{ GL_FRAGMENT_SHADER, "triangles.frag" },
{ GL_NONE, NULL }
};
program = LoadShaders(shaders);
glUseProgram(program);
// Same render
谁能告诉我我做错了什么?
编辑:
triangle.frag
#version 450
in vec4 gl_FragCoord;
out vec4 fColor;
void main ()
{
fColor = vec4 (0.0, 0.0, 1.0, 1.0);
}
triangle.vert
#version 450
layout (location = 0) in vec3 vPosition;
uniform mat3 projectionMatrix;
void main ()
{
vec3 tmp = projectionMatrix*vPosition;
gl_Position = vec4 (tmp, 1.0f);
}
罪魁祸首很可能是这一行:
glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 0);
最后一个参数是stride
,表示两个连续数组元素之间的距离。在传统的glVertexAttribPointer
调用中,也有一个stride
参数,但在语义上有细微差别:
如果您在 glVertexAttribPointer
中使用 0
的 stride
,这是编写 count * sizeof(type)
的便捷快捷方式,并且将假定一个紧密排列的属性数组。
对于 glVertexArrayVertexBuffer
,0
的步幅就意味着 0
,因此它将为该绘制调用的每个顶点提供完全相同的元素。 glVertexArrayVertexBuffer
不能提供相同的快捷方式,因为它不直接绑定到任何顶点属性,并且多个属性可以(并且通常这样做)引用相同的缓冲区索引。 (而且界面也会很奇怪,因为你可以在设置绑定之前或之后设置顶点格式,所以它必须在以后进行评估。)
所以从概念上讲,跨度是属性格式的 而不是 的一部分。该格式仅描述了 单个 顶点所需的所有内容。请注意,此更改与直接状态访问无关。它实际上是在 ARB_vertex_attrib_binding
(自 GL 4.3 以来的核心)中引入的,它确实将缓冲区绑定与属性格式描述分开。该文档中的问题(2)和(3)与这个问题非常相关:
(2) How is a stride of zero interpreted in BindVertexBuffer
?
RESOLVED: No error is generated, all array elements for a given
attribute will be sourced from the same location in the buffer.
(3) How is a stride of zero handled in VertexAttribPointer
?
RESOLVED: BindVertexBuffer
has no knowledge of the attrib format,
so VertexAttribPointer
needs to compute the stride itself. However,
if an application specifies a stride of zero and then queries
VERTEX_ATTRIB_ARRAY_STRIDE
, it returns zero. So the derived stride
that's passed to BindVertexBuffer
must be tracked separately from the
stride originally passed to VertexAttribPointer
, so this spec introduces
a separate piece of state (VERTEX_BINDING_STRIDE
). Rendering always uses
VERTEX_BINDING_STRIDE
.
This can potentially lead to misleading state queries if the API is
abused. For example:
VertexAttribPointer(0, 3, FLOAT, FALSE, 12, 0);
// VERTEX_ATTRIB_ARRAY_STRIDE = 12
// VERTEX_BINDING_STRIDE = 12
BindVertexBuffer(0, buffer, 0, 16)
// now VERTEX_ATTRIB_ARRAY_STRIDE is still 12, but
// VERTEX_BINDING_STRIDE = 16.
长话短说:对于您的用例,您需要
glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 3*sizeof(GLfloat));
我想使用 OpenGL 4.5 渲染三角形。我在网上找到了很多使用旧版本 OpenGL 的示例,但 none 使用 OpenGL 4.5 函数。因此,我尝试 "upgrade" 自己编写一些代码。这是旧的工作代码:
// Triangles to render
vec3 vertices[2][3] = { { vec3(-0.90f, -0.90f, 1.0f), vec3(0.85f, -0.90f, 1.0f), vec3(-0.90f, 0.85f, 1.0f) },
{ vec3(0.90f, -0.85f, 1.0f), vec3(0.90f, 0.90f, 1.0f), vec3(-0.85f, 0.90f, 1.0f) } };
//Initialize
glGenVertexArrays(1, &vaos);
glBindVertexArray(vaos);
glGenBuffers(1, &buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangles), triangles, GL_STATIC_DRAW);
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "triangles.vert" },
{ GL_FRAGMENT_SHADER, "triangles.frag" },
{ GL_NONE, NULL }
};
program = LoadShaders(shaders);
glUseProgram(program);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(0);
//Render
GLint index;
index = glGetUniformLocation(program, "projectionMatrix");
glUniformMatrix3fv(index, 1, true, value_ptr(projectionMatrix));
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vaos);
glDrawArrays(GL_TRIANGLES, 0, nvertices);
然后我 "updated" 将其用于此代码,它似乎没有在屏幕上绘制任何内容:
// Same triangles
// Initialize
glCreateVertexArrays(1, &vaos);
glEnableVertexArrayAttrib(vaos, 0);
glVertexArrayAttribFormat(vaos, 0, 3, GL_FLOAT, GL_FALSE, 0);
glCreateBuffers(1, &buffers);
glNamedBufferData(buffers, sizeof(triangles), triangles, GL_STATIC_DRAW);
glVertexArrayAttribBinding(vaos, 0, 0);
glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 0);
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "triangles.vert" },
{ GL_FRAGMENT_SHADER, "triangles.frag" },
{ GL_NONE, NULL }
};
program = LoadShaders(shaders);
glUseProgram(program);
// Same render
谁能告诉我我做错了什么?
编辑: triangle.frag
#version 450
in vec4 gl_FragCoord;
out vec4 fColor;
void main ()
{
fColor = vec4 (0.0, 0.0, 1.0, 1.0);
}
triangle.vert
#version 450
layout (location = 0) in vec3 vPosition;
uniform mat3 projectionMatrix;
void main ()
{
vec3 tmp = projectionMatrix*vPosition;
gl_Position = vec4 (tmp, 1.0f);
}
罪魁祸首很可能是这一行:
glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 0);
最后一个参数是stride
,表示两个连续数组元素之间的距离。在传统的glVertexAttribPointer
调用中,也有一个stride
参数,但在语义上有细微差别:
如果您在 glVertexAttribPointer
中使用 0
的 stride
,这是编写 count * sizeof(type)
的便捷快捷方式,并且将假定一个紧密排列的属性数组。
对于 glVertexArrayVertexBuffer
,0
的步幅就意味着 0
,因此它将为该绘制调用的每个顶点提供完全相同的元素。 glVertexArrayVertexBuffer
不能提供相同的快捷方式,因为它不直接绑定到任何顶点属性,并且多个属性可以(并且通常这样做)引用相同的缓冲区索引。 (而且界面也会很奇怪,因为你可以在设置绑定之前或之后设置顶点格式,所以它必须在以后进行评估。)
所以从概念上讲,跨度是属性格式的 而不是 的一部分。该格式仅描述了 单个 顶点所需的所有内容。请注意,此更改与直接状态访问无关。它实际上是在 ARB_vertex_attrib_binding
(自 GL 4.3 以来的核心)中引入的,它确实将缓冲区绑定与属性格式描述分开。该文档中的问题(2)和(3)与这个问题非常相关:
(2) How is a stride of zero interpreted in
BindVertexBuffer
?RESOLVED: No error is generated, all array elements for a given attribute will be sourced from the same location in the buffer.
(3) How is a stride of zero handled in
VertexAttribPointer
?RESOLVED:
BindVertexBuffer
has no knowledge of the attrib format, soVertexAttribPointer
needs to compute the stride itself. However, if an application specifies a stride of zero and then queriesVERTEX_ATTRIB_ARRAY_STRIDE
, it returns zero. So the derived stride that's passed toBindVertexBuffer
must be tracked separately from the stride originally passed toVertexAttribPointer
, so this spec introduces a separate piece of state (VERTEX_BINDING_STRIDE
). Rendering always usesVERTEX_BINDING_STRIDE
.This can potentially lead to misleading state queries if the API is abused. For example:
VertexAttribPointer(0, 3, FLOAT, FALSE, 12, 0); // VERTEX_ATTRIB_ARRAY_STRIDE = 12 // VERTEX_BINDING_STRIDE = 12 BindVertexBuffer(0, buffer, 0, 16) // now VERTEX_ATTRIB_ARRAY_STRIDE is still 12, but // VERTEX_BINDING_STRIDE = 16.
长话短说:对于您的用例,您需要
glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 3*sizeof(GLfloat));