2

I'm trying to bring my OpenGL code up to speed with Direct State access and have been closely following the code from Guide to Modern OpenGL Functions. I have a little test project with some vertices and colors in the form of:

std::vector<float> vertices;
for (float y = -1.0f; y < 1.1f; y += 1.0f) {
    for (float x = -1.0f; x < 1.1f; x += 1.0f) {
        vertices.emplace_back(x);
        vertices.emplace_back(y);
        vertices.emplace_back(0.5f);
        vertices.emplace_back(0.5f);
        vertices.emplace_back(0.5f);
    }
}

A visual representation of those vertices and their indices:

enter image description here

My main draw code is something like this:

unsigned int vbo = 0;
glCreateBuffers(1, &vbo);
glNamedBufferStorage(vbo, sizeof(float) * vertices.size(), vertices.data(), GL_DYNAMIC_STORAGE_BIT);

// Indices
unsigned int indices[]{ 0,1,3,5,8,7 };
unsigned int ibo = 0;
glCreateBuffers(1, &ibo);
glNamedBufferStorage(ibo, sizeof(unsigned int) * 6, indices, GL_DYNAMIC_STORAGE_BIT);

int bindingindex_a = 1;
int bindingindex_b = 2;
int pos_location = 3;
int color_location = 4;

unsigned int vao = 0;
glCreateVertexArrays(1, &vao);
glVertexArrayVertexBuffer(vao, bindingindex_a, vbo, 0, 5 * sizeof(float));
glVertexArrayVertexBuffer(vao, bindingindex_b, vbo, 0, 5 * sizeof(float));
glVertexArrayElementBuffer(vao, ibo);

glEnableVertexArrayAttrib(vao, pos_location);
glEnableVertexArrayAttrib(vao, color_location);

glVertexArrayAttribFormat(vao, pos_location, 2, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(vao, color_location, 3, GL_FLOAT, GL_FALSE, 2*sizeof(float));

glVertexArrayAttribBinding(vao, pos_location, bindingindex_a);
glVertexArrayAttribBinding(vao, color_location, bindingindex_b);

So I'm drawing two gray triangles with the indices 0,1,3 and 5,8,7. Attribute locations in my shader are specified as in the cpp code:

layout (location = 3) in vec2 pos;
layout (location = 4) in vec3 col;

And this works!:

enter image description here

Even when I increase the difficulty and add a single float value in front, I can adjust the offset in the glVertexArrayVertexBuffer() function by 4 bytes.

The problem is when I want to go from buffer layout A to B:

enter image description here

I adjust my data filling loop to first write the positions, then the colors:

for (float y = -1.0f; y < 1.1f; y += 1.0f) {
    for (float x = -1.0f; x < 1.1f; x += 1.0f) {
        vertices.emplace_back(x);
        vertices.emplace_back(y);
    }
}
for (float y = -1.0f; y < 1.1f; y += 1.0f) {
    for (float x = -1.0f; x < 1.1f; x += 1.0f) {
        vertices.emplace_back(0.5f);
        vertices.emplace_back(0.5f);
        vertices.emplace_back(0.5f);
    }
}

and adjust the calls to glVertexArrayVertexBuffer() and glVertexArrayAttribFormat():

glVertexArrayVertexBuffer(vao, bindingindex_a, vbo, 0, 2 * sizeof(float));
glVertexArrayVertexBuffer(vao, bindingindex_b, vbo, 18*sizeof(float), 3 * sizeof(float));

glVertexArrayAttribFormat(vao, pos_location, 2, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(vao, color_location, 3, GL_FLOAT, GL_FALSE, 0);

So now my global color offset is at 18 floats (9 positions times two components) and my relativeoffset (that's how khronos.org calls it) is at 0 for both. This displays grey things, but not the way they did before. My mental model of how these things work is obviously wrong - where?

Basti
  • 2,228
  • 1
  • 19
  • 25
  • 1
    "*The problem is when I want to go from buffer layout A to B:*" You should not want to do that. If you care about performance, don't change vertex formats. – Nicol Bolas May 25 '20 at 16:33
  • Is abcabc faster than aaabbbccc? – Basti May 25 '20 at 17:35
  • 1
    Generally yes, but my point was more about switching between them with any frequency. And you *certainly* shouldn't be switching between them by modifing the VAO; you should have one interleaved VAO and one non-interleaved VAO. – Nicol Bolas May 25 '20 at 17:48
  • Oh sure, I know that. I merely included example A to show that my code has no fundamental other problem and that I have a rough understanding. I have no intention of changing anything during runtime. But thanks! I didn't know about the perf difference though. – Basti May 25 '20 at 17:49

1 Answers1

3

The offset parameter of glVertexArrayVertexBuffer is the offset of the first element of the buffer in bytes, form the begin of the buffer and stride is distance between consecutive attributes within the buffer.


The vertex specification for case A is wrong:

glVertexArrayVertexBuffer(vao, bindingindex_a, vbo, 0, 5 * sizeof(float));
glVertexArrayVertexBuffer(vao, bindingindex_b, vbo, 0, 5 * sizeof(float));

Each vertex attribute tuple consists of 5 components (x, y, r, g, b).

(x1, y1, r1, g1, b1,   x2, y2, r2, g2, b2,   x3, y3, r3, g3, b3, ...)

Hence the offset for the color attribute is 2*sizeof(float):

glVertexArrayVertexBuffer(vao, bindingindex_a, vbo, 0, 5 * sizeof(float));
glVertexArrayVertexBuffer(vao, bindingindex_b, vbo, 2 * sizeof(float), 5 * sizeof(float));

The byte offset of x1 is 0.
The byte offset of r1 is 2 * sizeof(float).
The distance in bytes from x1 to x2 is 5 * sizeof(float).
The distance in bytes form r1 to r2 is 5 * sizeof(float).


The offset for case B is correct:

glVertexArrayVertexBuffer(vao, bindingindex_a, vbo, 0, 2 * sizeof(float));
glVertexArrayVertexBuffer(vao, bindingindex_b, vbo, 18*sizeof(float), 3 * sizeof(float));

In case B there are 9 vertex coordinates, followed by 3 color attributes. A vertex tuple has w components and a color tuple has 3 components:

(x1, y1, x2, y2, ... x9, y9,  r1, g1, b1, r2, g2, b2, ..., r9, g9, b9)

Hence the offset of the start of the color attribute is 9*sizeof(float) (3 * (x, y)):

glVertexArrayVertexBuffer(vao, bindingindex_a, vbo, 0, 2 * sizeof(float));
glVertexArrayVertexBuffer(vao, bindingindex_b, vbo, 18 * sizeof(float), 3 * sizeof(float));

The byte offset of x1 is 0.
The byte offset of r1 is 18 * sizeof(float).
The distance in bytes form x1 to x2 is 2 * sizeof(float).
The distance in bytes from r1 to r2 is 3 * sizeof(float).

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Huh.. the first I can get to work, but only with 0 for the relativeoffset parameter of glVertexArrayAttribFormat(). The second has wrong colors with the 0 for relativeoffset. Or what would those values be? – Basti May 25 '20 at 16:13
  • "but only with 0 for the relativeoffset parameter" - but that is completely wrong. Case B is correct. _offset_ is the offset of the first element of the buffer and stride is _distance_ between consecutive attributes within the buffer. I've extended the answer. – Rabbid76 May 25 '20 at 16:30