Incorrect data-layout per instance

I’m trying to create a simple object which has two properties.
Vertex positions, which will all be set once, and will be the same for every object.
And Texture coordinates, which will (probably) be different for every object.
I’m also using instanced drawing, to render the objects.

The texture coordinates I’m passing through a VBO which is set up like this.

// Every one of "textureCoordinatesN" is an array of 12 floats describing a "per-vertex" texture coordinate 
std::array<std::array<float, 12>, 3> textureCoordinateBuffer =
{
    textureCoordinates1,
    textureCoordinates2,
    textureCoordinates3,
};

std::uint32_t textureCoordinatesVBO =0;

glGenBuffers(1, &textureCoordinatesVBO);
glBindBuffer(GL_ARRAY_BUFFER, textureCoordinatesVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoordinateBuffer), textureCoordinateBuffer.data(), GL_DYNAMIC_DRAW);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(std::array<float, 12>), 0);
glEnableVertexAttribArray(1);

glVertexAttribDivisor(1, 1);

This is how it’s laid out in my vertex shader

layout(location = 0) in vec2 VertexPosition;
layout(location = 1) in vec2 TextureCoordinate;

Now, the problem is this is how OpenGL interprets my data, according to RenderDoc.

Screenshot 2022-02-15 205409

Which to me is absolutely baffling, because those are the correct texture coordinates, but they only appear on the first row, and are “duplicated(?)” for every subsequent row. What’s more, is that this is also the case for every single drawn instance.
(VertexPosition is in screen space)
I’ve been stuck on this issue for hours, any help is greatly appreciated

Per-instance data is constant for all vertices in an instance. It only changes when moving to a separate instance. That’s what instancing is.

Instancing is not for applying different arrays of data to different instances.

Yeah, I had a feeling it was something like that. Is there any way I can set “per-vertex” per instance data?

Not as attributes. If you have M instances with N vertices, attribute array sizes are either M/k (where k is the attribute divisor) or N (for a zero divisor); you can’t have an M×N attribute array. You can fudge it by using both gl_InstanceID and gl_VertexID to perform lookups in a uniform array (e.g. SSBO), although there’s likely to be some overhead compared to attributes.

Note that if you want to do this, and you want to take advantage of base-instance rendering, you will have to add gl_BaseInstance to the gl_InstanceID value to get the proper instance index.

Thank you all for the suggestions, so far.
I’ve decided I’ll go with the SSBO route, actually that’s what I thought I should be using after posting this question. However I’m struggling against something quite odd.

This is how my vertex shader structured at the moment

layout(location = 0) in vec2 VertexPosition;

layout(std430, binding = 0) readonly buffer TextureCoordinateInput
{
    uint NumberOfVertices;
    vec2 TextureCoordinate[];
};

out vec2 VertexShaderTextureCoordinateOutput;
...

void main()
{
    VertexShaderTextureCoordinateOutput  = TextureCoordinate[gl_VertexID + (gl_InstanceID * NumberOfVertices)];
};

This is how I’m setting my SSBO

constexpr std::uint32_t numberOfVertices = 6;

const std::array<std::array<float, 12>, 3> glyphTextureCoordinateBuffer =
{
    glyphTextureCoordinates1,
    glyphTextureCoordinates2,
    glyphTextureCoordinates3,
};

glGenBuffers(1, &_glyphTextureCoordinatesSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, _glyphTextureCoordinatesSSBO);

glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(glyphTextureCoordinateBuffer) + sizeof(numberOfVertices), nullptr, GL_DYNAMIC_DRAW);

glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(numberOfVertices), &numberOfVertices);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(numberOfVertices), sizeof(glyphTextureCoordinateBuffer), glyphTextureCoordinateBuffer.data());

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, _glyphTextureCoordinatesSSBO);

Now, the odd thing is, is that it seems that the TextureCoordinate array is being read +4 bytes from the data inside glyphTextureCoordinateBuffer .
Screenshot 2022-02-16 190953

This is the correct data that is being copied to TextureCoordinate
Screenshot 2022-02-16 191126

Notice that it’s literally +4 bytes from the start

You forgot to access the array. You computed the array index just fine, but you never used it on the array itself. That’s why the compiler made you put that vec2 cast there; because you computed an integer and was trying to assign it to a vec2.

I’m so sorry. That was a typo I’ve overlook, I updated the code in the shader

Also, maybe I should’ve mentioned it before, but if I remove NumberOfVertices from the SSBO (in GLSL), and initialization (in C++), and instead, I hard-code a number, it works just fine.

That’s a layout problem. vec2 is aligned to 8 bytes. You need 4 bytes of padding between the the vertex count and the array.

1 Like

Once again, you were absolutely correct. Thank you very much for your help

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.