0

Using OpenGL 4.1, I am trying to figure out if it is possible to bind a set of vertices as a vertex array and then use that same vertex data as a uniform buffer object for a shader program (or visa versa) without sending the data to the GPU again.

EDIT: I need to add that I'm on macOS 10.15 which means I have access to openGL 4.1 core only.

My plan is that I'd like to update some point vertex data with one shader program (using GL_POINTS vertex type and no frag shader output), and then draw on a quad "canvas" using the updated vertex data as uniform data, as the quad's fragment colour calculations will rely on distances from every point that exists. I don't want to have to pull the data back and forth between the GPU and CPU, and this is one of the nicest solutions I could think of so far (if it is indeed possible and not inherently against the openGL way).

So I've bound the vertex data to a vertex array like so:

auto vertexArray = std::make_unique<VertexArray>();
vertexArray->vertexType = VertexType::Points;

std::vector<float> positions = {
        -0.5f, -0.5f,
        0.0f, 0.5f,
        0.5f, -0.5f
};

std::vector<uint32_t> indices = {
        0, 1, 2
};

vertexArray->numVertices = positions.size() / 2;
vertexArray->numIndices = indices.size();

glGenVertexArrays(1, &vertexArray->vertexArrayId);
glBindVertexArray(vertexArray->vertexArrayId);

glGenBuffers(1, &vertexArray->vertexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, vertexArray->vertexBufferId);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(float), positions.data(), GL_STATIC_DRAW);

glGenBuffers(1, &vertexArray->indexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexArray->indexBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint32_t), indices.data(), GL_STATIC_DRAW);

// Call per vertex attribute (vec2 position is 1 attribute)
glVertexAttribPointer(/*index*/ 0,
        /*numValues*/ 2,
        /*type*/ GL_FLOAT,
        /*normalised*/ GL_FALSE,
        /*bytesToNextInstanceOfAttribute*/ sizeof(float) * 2,
        /*offsetToNextAttribute*/ (const void*) 0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);

I would like then to be able to use this data that's already been sent to the GPU as a uniform buffer object in a shader program (though not the one that is being used to "render" this vertex array). Maybe something a bit like the following pseudo code that in an ideal world would give me access to the previously bound vertex buffer data in the canvas frag shader using a uniform buffer object called "u_pointVertexList":

glBindBuffer(GL_UNIFORM_BUFFER, vertexArray->vertexBufferId);
int location = glGetUniformLocation(canvasShaderProgramID, "u_pointVertexList");
debug::assertTrue(location != -1, "");
glProgramUniformFooBah(canvasShaderProgramID, location, vertexArray->vertexBufferId);

For some background, my first attempted solution was to just render the points to the window with a large point size each and a frag shader written per point object... But as far as I can tell, you can't render points with anything other than a single block colour. If that's incorrect, please let me know as that would be by far the easiest solution. Any other ideas on how to achieve this would also be appreciated if this is not a viable solution.

Iron Attorney
  • 1,003
  • 1
  • 9
  • 22
  • 7
    "*I'd like to update some point vertex data with one shader program*" This seems confused. A VS cannot modify the vertex data it is given. You can use transform feedback or image load/store or SSBOs as ways to write to buffer objects, but you can't do any of these to the vertex data that you're *currently reading from*. So are you talking about manipulating the actual bytes that are being consumed as inputs to the VS or not? – Nicol Bolas Dec 19 '20 at 18:10
  • Ah, that's a good observation. If that's not the correct process then I guess not. My ultimate goal is to be able to use moving point vertex data in a quad-canvas' frag shader, so every frame the point vertices will be updated, and every frame the quad-canvas will be redrawn based on this new vertex data. As the quad's vertex shader will be processing the vertices that form the quad itself, I don't imagine the quad's vertex shader is going to help with this, thus why I'm thinking I need to do this in separate programs... Unless this is the kind of thing a geom shaders can help me with? – Iron Attorney Dec 19 '20 at 18:45
  • @NicolBolas sorry I just re-read your answer... I don't yet know about transform feedback but the name alone sounds promising so I'll read up on that... Otherwise, would a possible solution be to use the point vertex shader to write to a UBO or SSBO output, bind that UBO or SSBO as a uniform input of the quad shader so that is able to work with the updated vertex data, and then can I somehow copy that UBO or SSBO data back into the point vertex buffer once that frame is rendered without pulling the data back to the CPU? – Iron Attorney Dec 19 '20 at 19:54
  • My plan is that I'd like to update some point vertex data with one shader program (using GL_POINTS vertex type and no frag shader output) - do not do such a thing. Your GL_UNIFORM_BUFFER can be updated with compute shader. – Hihikomori Dec 19 '20 at 21:40
  • Vulkan would be the better choice in this case. – Hihikomori Dec 19 '20 at 22:49
  • While it's not a direct solution to the problem, I have started learning Vulkan to have access to more features on macOS, and I'm not disappointed I've done so... it's early days, but I'm pretty confident I'm not going to look back once I've got to grips with it, it feels much cleaner than openGL (which I'm aware is kind of the point of it...) – Iron Attorney Dec 21 '20 at 20:02

0 Answers0