3
$\begingroup$

I'm working with OpenGL and facing some difficulties because I'm not familiar with OpenGL. I tried to search related example in Google, but I could not find some useful code.

There are five arrays. I bound and changed the data in compute shahder as follows:

computeShader.use();
int bufferSize = sizeof(vertices) * vertices.size();
glGenBuffers(1, &vbo_Previous);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Previous);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, &vertices[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vbo_Previous);


glGenBuffers(1, &vbo_Current);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Current);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, &vertices[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbo_Current);

glGenBuffers(1, &vbo_Next);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Next);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, &vertices[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, vbo_Next);

glGenBuffers(1, &vbo_Normal);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Normal);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, &normals[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, vbo_Normal);

glGenBuffers(1, &vbo_Tangent);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Tangent);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, &tangents[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, vbo_Tangent);

glGenBuffers(1, &vbo_Binormal);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Binormal);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, &binormals[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, vbo_Binormal);
computeShader.unUse();

And I want to use the data in vertex shader. I tried like that, but I doesn't work.

glGenVertexArrays(1, &vao);
glGenBuffers(1, &ebo);
glBindVertexArray(vao);


int bufferOffset = 0;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Next);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (void*)(bufferOffset));

bufferOffset += sizeof(glm::vec4) * vertices.size();
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Normal);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)(bufferOffset));

bufferOffset += sizeof(glm::vec4) * normals.size();
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Tangent);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (void*)(bufferOffset));

bufferOffset += sizeof(glm::vec4) * tangents.size();
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Binormal);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 0, (void*)(bufferOffset));

//Because the texture coordinate are not changed in compute shader I generated the vbo for texture coordinate data
bufferOffset += sizeof(glm::vec4) * binormals.size();
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2)*texCoords.size(), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, 0, (void*)(bufferOffset));

I hope to use the data in vertex shader as follows:

#version 430 core
layout(location = 0) in vec4 aPos;
layout(location = 1) in vec4 aNormal;
layout(location = 2) in vec4 aTangent;
layout(location = 3) in vec4 aBinormal;
layout(location = 4) in vec2 aTexCoord;

How to set vertex object array to use the data?

$\endgroup$
  • $\begingroup$ What do you mean by ComputeShader.use() ? And if you are passing SSBO to vertex shader you will have to define interface blocks, afaik you can't use them like uniform variables. Check here khronos.org/opengl/wiki/Shader_Storage_Buffer_Object $\endgroup$ – gallickgunner Dec 26 '17 at 12:01
  • $\begingroup$ @wandering-warrior Oh, sorry to confuse you. ComputeShader.use() is just glUseProgram(compute.glsl), so we can ingnore it. And I wonder your meaning 'you can't use them like uniform variables'. I don't want to use the data like uniform variables, instead, I just want to pass the whole arrays to vertex shader, probably it means that when I call glDrawElements or glDrawArrays(triangle), the vertex shader would get the array stream. $\endgroup$ – shashack Dec 26 '17 at 13:21
2
$\begingroup$

I can see a few things wrong here.

First, you're setting your GL buffer size to sizeof(vertices) * vertices.size() This looks wrong. What is vertices? A std::array of vec4? Then you want vertices.size() * sizeof(glm::vec4), or just sizeof(vertices)

Second, as wandering-warrior said, you want to be binding to GL_ARRAY_BUFFER before calling glVertexAttribPointer

Third, I don't know what you're doing with bufferOffset in the second part of the code. This is a valid approach if the data is laid out sequentially in one large buffer (vertices then normals then tangents etc. etc.). But in your case you're using a separate buffer for each data set - so each attribute should start reading from the beginning of its own buffer, i.e. bufferOffset should always be 0.

Fourth, you don't seem to be actually using your compute shader anywhere. It's not enough to just call glUseProgram, you need to call glDispatchCompute after you bind your buffers to actually run it.

Also, it's not common practice to store binormals in an array, since they can be reconstructed in the fragment shader from the tangent and normal using a cross product.

I would do it something like this (using OpenGL 4.5 with the new Direct State Access functions to save all those buffer bindings).

int bufferSize = sizeof(vertices);

glCreateBuffers(1, &vbo_Previous);
glNamedBufferData(vbo_Previous, bufferSize, &vertices[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vbo_Previous);

glCreateBuffers(1, &vbo_Current);
glNamedBufferData(vbo_Current, bufferSize, &vertices[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbo_Current);

glCreateBuffers(1, &vbo_Next);
glNamedBufferData(vbo_Next, bufferSize, &vertices[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, vbo_Next);

glCreateBuffers(1, &vbo_Normal);
glNamedBufferData(vbo_Normal, bufferSize, &normals[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, vbo_Normal);

glCreateBuffers(1, &vbo_Tangent);
glNamedBufferData(vbo_Tangent, bufferSize, &tangents[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, vbo_Tangent);

glCreateBuffers(1, &vbo_Texcoords);
glNamedBufferData(vbo_Texcoords, sizeof(texCoords), &texCoords[0], 
GL_STATIC_DRAW);

glCreateBuffers(1, &ebo);
glNamedBufferData(ebo, sizeof(elements), &elements[0], GL_STATIC_DRAW);
//you have element data in an array, right?

glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);

glBindVertexBuffer(0, vbo_Next, 0, 0);
glVertexAttribBinding(0,0);
glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, 0);
glBindVertexBuffer(1, vbo_Normal, 0, 0);
glVertexAttribBinding(1,1);
glVertexAttribFormat(1, 4, GL_FLOAT, GL_FALSE, 0);
glBindVertexBuffer(2, vbo_Tangent, 0, 0);
glVertexAttribBinding(2,2);
glVertexAttribFormat(2, 4, GL_FLOAT, GL_FALSE, 0);
glBindVertexBuffer(3, vbo_Texcoords, 0, 0);
glVertexAttribBinding(3,3);
glVertexAttribFormat(3, 2, GL_FLOAT, GL_FALSE, 0);
glVertexArrayElementBuffer(vao, ebo);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);

computeShader.use();
glDispatchCompute (/*number of groups*/)
computeShader.unUse();

glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);

renderShader.use();
glDrawElements(GL_TRIANGLES, elements.size(), GL_UNSIGNED_INT, 0);
renderShader.unUse();
$\endgroup$
1
$\begingroup$

I think you are confusing all the binding targets thingy. From what I see your vertex data is coming from compute shader after some processing and now you want to pass it to the vertex shader.

You can create a buffer object once, use it as an SSBO for use in a compute shader then use it as a VBO for use in rendering. i.e

// Setup SSBO for use in Compute shader
glGenBuffers(1, &vbo_Current);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_Current);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, &vertices[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbo_Current);

// Setup the same Buffer object as VBO for use in rendering
glBindBuffer(GL_ARRAY_BUFFER, vbo_Current);   <- Note the change in binding target
GlVertexAttribPointer().......                <- set your vertex data

Hence there is no need to generate 1 more buffer object for the texture, just pass the same buffer but change the binding points to GL_ARRAY_BUFFER

However do note that you need to use appropriate Memory barrier calls as SSBO reads and writes are incoherent memory accesses. Don't know much about these but you can find more information here

$\endgroup$
  • $\begingroup$ I think the source of confusion is target parameter in glBufferData. If buffer object is just data, when why we need to specify this to actually upload raw data? $\endgroup$ – narthex Dec 26 '17 at 15:49
  • $\begingroup$ @narthex: Because that's how OpenGL objects work. Unless you're using DSA, you have to bind them somewhere to the context to be able to edit them. This is one of the most consistent parts of the OpenGL API, and it's basically the first thing anyone should learn about OpenGL. $\endgroup$ – Nicol Bolas Dec 26 '17 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.