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