简体   繁体   中英

Trouble with glVertexArrayVertexBuffer() / glVertexArrayAttribFormat() in different buffer layouts

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:

在此处输入图像描述

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

在此处输入图像描述

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:

在此处输入图像描述

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?

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

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