简体   繁体   中英

How to use vao and buffers in OpenGL 4.5

I'd like to render a triangle using OpenGL 4.5. I have found lot's of examples online using older versions of OpenGL but none using OpenGL 4.5 functions. Therefore I tried to "upgrade" some code myself. This is the old working code:

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

And I "updated" it to this code, which doesn't appear to draw anything on screen:

// 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

Could someone tell me what I did wrong?

Edit: 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);
}

The culprit is most likely this line:

glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 0);

The last parameter is the stride , which means the distance between two consecutive array elements. In the traditional glVertexAttribPointer call, there is also a stride parameter, but there is a slight semantic difference:

If you use a stride of 0 in glVertexAttribPointer , this is a convenient shortcut for writing count * sizeof(type) , and will assume a tightly packed attribute array.

With glVertexArrayVertexBuffer a stride of 0 just means 0 , so it will feed you the very same element for every vertex of that draw call. glVertexArrayVertexBuffer cannot provide the same shourtcut, because it is not directly tied to any vertex attribute, and several attributes can (and usually do) refer to the same buffer index. (And the interface would also be very weird, because you could set the vertex format before or after you set the binding, so it would have to be evaluated later.)

So conceptually, the stride is not part of the attribue format. The format just describes all what is necessary for a single vertex. Note that this change has nothing to do with the direct state access. It was actually introduced with ARB_vertex_attrib_binding (core since GL 4.3), which did separate the buffer binding from the attribute format description. The issues (2) and (3) in that document are very relevant to this question:

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

To make a long story short: For your use case, you will need

glVertexArrayVertexBuffer(vaos, 0, buffers, 0, 3*sizeof(GLfloat));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM