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);
}
Scott Stensland
  • 26,870
  • 12
  • 93
  • 104
  • 2
    You need to have a very modern graphics processor to support OpenGL version 4.x, and even so you might be limited to an earlier implementation if the drivers don't exist yet. What are you running it on ? Shaders are a usual problem. – Jon Goodwin Oct 16 '16 at 01:10
  • I have a GTX 760 and the latest drivers installed. I'm using glew to load the OpenGL extensions and it confirms that ARB_direct_state_access is available. –  Oct 16 '16 at 15:54
  • try #version 430 instead of #version 450 .... this says GTX 760 supports OpenGL 4.3 http://www.geforce.com/hardware/desktop-gpus/geforce-gtx-760/specifications – Scott Stensland Oct 16 '16 at 16:27
  • 2
    @ScottStensland: Those are only the most recent GL versions back when the GPUs were first released. NVidia is supporting OpenGL 4.5 for all cards back to Fermi / Geforce 400. – derhass Oct 16 '16 at 17:05

1 Answers1

1

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));
derhass
  • 43,833
  • 2
  • 57
  • 78