I want to draw 2 Vertex Buffers but it only draws the second one. I am using OpenGL 4.6 and the COMPAT profile. The code:
float buffer[] =
{
0.0f,0.0f,
1.0f,0.0f,
1.0f,1.0f
};
float buffera[] =
{
0.0f,0.0f,
1.0f,0.0f,
1.0f,-1.0f
};
unsigned int id;
glGenBuffers(1, &id);
glBindBuffer(GL_ARRAY_BUFFER, id);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), buffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unsigned int ida;
glGenBuffers(1, &ida);
glBindBuffer(GL_ARRAY_BUFFER, ida);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), buffera, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unsigned int indices[]
{
0,1,2
};
And then the draw calls:
glBindBuffer(GL_ARRAY_BUFFER, id);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
glBindBuffer(GL_ARRAY_BUFFER, ida);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
When glVertexAttribPointer is called, the the buffer which is currently bound to the target ARRAY_BUFFER is associated to the attribute. It is not sufficient to bind the buffer object. You have to do the vertex specification before drawing the object:
glBindBuffer(GL_ARRAY_BUFFER, id);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
glBindBuffer(GL_ARRAY_BUFFER, ida);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
I recommend to use a Vertex Array Object. The VAO is used to store the vertex specification.
unsigned int vao1;
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
unsigned int id;
glGenBuffers(1, &id);
glBindBuffer(GL_ARRAY_BUFFER, id);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), buffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
unsigned int vao2;
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
unsigned int ida;
glGenBuffers(1, &ida);
glBindBuffer(GL_ARRAY_BUFFER, ida);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), buffera, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
glBindVertexArray(vao1);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
glBindVertexArray(vao2);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
Since you are not using a VAO, only binding the buffer is not enough. The command which establishes from which buffer a draw command reads is glVertexAttribPointer. You have to move this command into to the draw commands (and since they aren't doing anthing, remove them from the initialization.
The code should be something like:
Init:
unsigned int id;
glGenBuffers(1, &id);
glBindBuffer(GL_ARRAY_BUFFER, id);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), buffer, GL_STATIC_DRAW);
unsigned int ida;
glGenBuffers(1, &ida);
glBindBuffer(GL_ARRAY_BUFFER, ida);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), buffera, GL_STATIC_DRAW);
Drawing:
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, id);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
glBindBuffer(GL_ARRAY_BUFFER, ida);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)8);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
Related
This code works fine.
glGenVertexArrays(1, &m_VAO);
glGenBuffers(1, &m_VBO);
glGenBuffers(1, &m_EBO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(VertexFormat), &data[0] , GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GL_UNSIGNED_INT), &indices[0], GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(6 * sizeof(float)));
glBindVertexArray(0);
But when i try to change it to DSA nothing gets drawn on the screen.
glCreateBuffers(1, &m_VBO);
glNamedBufferStorage(m_VBO, data.size() * sizeof(VertexFormat), &data[0], GL_DYNAMIC_STORAGE_BIT);
glCreateBuffers(1, &m_EBO);
glNamedBufferStorage(m_EBO, indices.size() * sizeof(unsigned int), &indices[0], GL_DYNAMIC_STORAGE_BIT);
glCreateVertexArrays(1, &m_VAO);
glVertexArrayVertexBuffer(m_VAO, 0, m_VBO, 0, data.size() * sizeof(VertexFormat));
glVertexArrayElementBuffer(m_VAO, m_EBO);
glEnableVertexArrayAttrib(m_VAO, 0);
glEnableVertexArrayAttrib(m_VAO, 1);
glEnableVertexArrayAttrib(m_VAO, 2);
glVertexArrayAttribFormat(m_VAO, 0, 3 , GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(m_VAO, 1, 3 , GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(m_VAO, 2, 2 , GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(m_VAO, 0, 0);
glVertexArrayAttribBinding(m_VAO, 1, 0);
glVertexArrayAttribBinding(m_VAO, 2, 0);
What is the issue in the DSA section of code?
You did not transfer over two pieces of information.
You didn't specify the stride in glVertexArrayVertexBuffer correctly. When using separate attribute format, a stride of 0 doesn't mean "tightly packed"; it means exactly what it says: zero bytes will be added to get the next array element.
You also didn't specify the offsets for each attribute in glVertexArrayAttribFormat the way you did with glVertexAttribPointer.
Im having problems to add a struct to a OpenGL VBO
This is my struct
struct Vertex {
//vertices
std::vector<glm::vec3> vertices;
//texture coordinates
std::vector<glm::vec3> texCord;
}
This is how im assigning and initializing the VBO
glGenVertexArrays(1, &buffer.VAO);
glGenBuffers(1, &buffer.VBO);
glGenBuffers(1, &buffer.EBO);
glBindBuffer(GL_ARRAY_BUFFER, buffer.VAO);
//Initialize buffer data
glBindBuffer(GL_ARRAY_BUFFER, buffer.VBO);
glBufferData(GL_ARRAY_BUFFER,
vertex.vertices.size() * sizeof(glm::vec3) +
vertex.texCord.size() * sizeof(glm::vec3)
&vertex,
GL_STATIC_DRAW);
//indices attribute
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertex.indices.size() * sizeof(glm::vec2), &vertex.indices[0], GL_STATIC_DRAW);
//vertices coordinates attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, vertices));
//texture coordinates attribute
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCord));
And my draw command looks like this
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(buffer.VAO);
glDrawElements(GL_TRIANGLES, vertex.indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
Is it possible to initialize buffer data with a raw struct and if yes how?
std::vector stores a pointer to dynamically allocated memory. However, you must pass a consecutive buffer to glBufferData.
Create the object's data store with glBufferData, but use glBufferSubData to initialize the buffer:
size_t vertexSize = vertex.vertices.size() * sizeof(glm::vec3);
size_t texCordSize = vertex.texCord.size() * sizeof(glm::vec3);
glBufferData(GL_ARRAY_BUFFER, vertexSize + texCordSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexSize, vertex.vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertexSize, texCordSize, vertex.texCord.data());
Thanks to #Rabbid76 I now solved my problem. Code is down below.
Note: I need to create the buffer before filling data with glBufferSubData
glGenVertexArrays(1, &buffer.VAO);
glGenBuffers(1, &buffer.VBO);
glGenBuffers(1, &buffer.EBO);
glBindBuffer(GL_ARRAY_BUFFER, buffer.VAO);
int vertexSize = sizeof(glm::vec3) * vertex.vertices.size();
int texCordSize = sizeof(glm::vec2) * vertex.texCord.size();
int totalSize = vertexSize + texCordSize;
int indicesSize = sizeof(unsigned int) * vertex.indices.size();
//Create Buffer dynamically
glBufferData(GL_ARRAY_BUFFER, totalSize, NULL, GL_DYNAMIC_DRAW);
//Fill the buffer with data
glBindBuffer(GL_ARRAY_BUFFER, buffer.VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexSize, vertex.vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertexSize, texCordSize, vertex.texCord.data());
//indices attribute
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesSize, vertex.indices.data(), GL_STATIC_DRAW);
//position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3) + sizeof(glm::vec2), (void*)0);
//texture attribute
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec3) + sizeof(glm::vec2), (void*)sizeof(glm::vec3));
glBindVertexArray(0);
I am trying to construct a bar.
First i declare a structure
struct VertexFormat
{
glm::vec3 positions;
glm::vec3 normal;
glm::vec2 texCoord;
VertexFormat(glm::vec3 pos, glm::vec3 norm, glm::vec2 coord) : positions(pos), normal(norm), texCoord(coord)
{ }
};
and than i configure the VAO and the VBO
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(VertexFormat), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size(), &indices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, data.size() * sizeof(VertexFormat), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, data.size() * sizeof(VertexFormat), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, data.size() * sizeof(VertexFormat), (void*)(6 * sizeof(float)));
glBindVertexArray(0);
Nothing gets drawn when i issue the drawing commands
glBindVertexArray(m_VAO);
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
My question is that am i defining the offsets for the data in the buffer correctly ?
There are several problems with this code:
First, the amount of data uploaded to the EBO is wrong. The size of the data has to be given in byte. Assuming that indices contains unsigned integers, the code should be:
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
Then, stride describes the offset between two consecutive vertices in the buffer, not the total size of your data. In your case, every vertex starts sizeof(VertexFormat) after the previous one.
The correct code should be:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(6 * sizeof(float)));
I am working on a simple 3D Engine. I currently have a working setup with multiple VAO's which I can switch between during the render loop, but they all are not using index buffers.
I'm now trying to add a new VAO composed of 4 VBO's: vert position, color, normal and indices.
Everything compiles and runs but the drawing calls to the second VAO (with indexed vertices) do not render. I'm sure there is a problem with my setup somewhere, so I've added this code which includes all the VAO and VBO generations, calls, and uses. Does anything in this code seem wrong, and is this the correct way to set it all up?
VAO1 has 3 buffers: position, color, normals
VAO2 has 3 buffers: position, color, normals and vertex indices
//Initalize vaos and vbos
GLuint vao1, vbo1[3];
GLuint vao2, vbo2[4];
//Generate Vertex arrays:
glGenVertexArrays(1, &vao1);
glGenVertexArrays(1, &vao2);
//Generate Buffers:
glGenBuffers(3, vbo1);
glGenBuffers(4, vbo2);
//Initalize Bufferdata vectors:
vector<GLfloat> VertPosBuffer1Vector;
vector<GLfloat> VertNormalBuffer1Vector;
vector<GLfloat> VertColorBuffer1Vector;
vector<GLfloat> VertPosBuffer2Vector;
vector<GLfloat> VertNormalBuffer2Vector;
vector<GLfloat> VertColorBuffer2Vector;
vector<GLuint> VertIndexBuffer2Vector;
//Fill Buffers:
//(not included but all vectors are filled with data)
//VAO 1
glBindVertexArray(vao1);
//Vertex position buffer:
glBindBuffer(GL_ARRAY_BUFFER, vbo1[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VertPosBuffer1Vector.size(), &VertPosBuffer1Vector[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
//Vertex color buffer:
glBindBuffer(GL_ARRAY_BUFFER, vbo1[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VertColorBuffer1Vector.size(), &VertColorBuffer1Vector[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
//Vertex normal buffer:
glBindBuffer(GL_ARRAY_BUFFER, vbo1[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VertNormalBuffer1Vector.size(), &VertNormalBuffer1Vector[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(2);
//VAO 2
glBindVertexArray(vao2);
//Vertex position buffer:
glBindBuffer(GL_ARRAY_BUFFER, vbo2[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VertPosBuffer2Vector.size(), &VertPosBuffer2Vector[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
//Vertex color buffer:
glBindBuffer(GL_ARRAY_BUFFER, vbo2[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VertColorBuffer2Vector.size(), &VertColorBuffer2Vector[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
//Vertex normal buffer:
glBindBuffer(GL_ARRAY_BUFFER, vbo2[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VertNormalBuffer2Vector.size(), &VertNormalBuffer2Vector[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(2);
//Vertex index buffer:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*VertIndexBuffer2Vector.size(), &VertIndexBuffer2Vector[0], GL_STATIC_DRAW);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(3);
//unbind vao
glBindVertexArray(0);
//bind first vao
glBindVertexArray(vao1);
and
//RENDERLOOP
//render objects from vao1 using:
glDrawArrays(GL_TRIANGLES, start, size);
//switch vao
glBindVertexArray(0);
glBindVertexArray(vao2);
//render objects from vao2 using:
glDrawElements(
GL_TRIANGLES,
start,
GL_UNSIGNED_INT,
(void*)0
);
I have checked that the data in my buffers are correct.
Is it correct that the shader doesn't take in any information of indices? The shader will be the same as if I didn't use an index buffer?
Thank you
The indices are not a vertex attribute. So what you need to do is remove these two lines:
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(3);
I also noticed that you are using the variable "start" as the count argument for glDrawElements. I don't know the values of start and size, but I assume you should use "size" as the second argument in glDrawElements.
In my project I'd like to edit given vertex position which is already in GPU.
Do I need to reload whole model or there is an function to change needed vertex.
This is how I pass mesh to GPU
void Mesh3v3n2t::PassToGPU()
{
glGenVertexArrays(1, &VaoId);
glBindVertexArray(VaoId);
glGenBuffers(1, &VboId);
glBindBuffer(GL_ARRAY_BUFFER, VboId);
glBufferData(GL_ARRAY_BUFFER, 32*vertices.size(),vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 32, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 32, (void*)12);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 32, (void*)24);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glGenBuffers(1, &IndexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*4, indices.data(), GL_STATIC_DRAW);
}
You can use glBufferSubData. You may want to rethink the GL_STATIC_DRAW usage hint if you're going to be doing this frequently, but it's not necessary.