I have a struct to store vertex data for 2 distinct models one is a cube the other a pyramid.
struct Model{
GLuint vboID;
GLfloat* vbo;
GLuint vaoID;
GLfloat* vao;
GLuint vertexStart;
GLuint vertexCount;
};
I create the vbos and generate their buffers like this:
Model cubeModel;
Model pyramidModel;
cubeModel.vbo = cubeVerts; //A GLfloat array I created earlier in code earlier.
cubeModel.vertexCount= sizeof(cubeVerts);//size of the GLfloat array in bytes
pyramidModel.vbo = pyVerts;
pyramidModel.vertexCount= sizeof(pyVerts);
glGenBuffers(1, &cubeModel.vboID); //Generate a buffer for the vertices
glBindBuffer(GL_ARRAY_BUFFER, cubeModel.vboID); //Bind the vertex buffer
glBufferData(GL_ARRAY_BUFFER, cubeModel.vertexCount, cubeModel.vbo, GL_STATIC_DRAW);
And then to draw I use:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, cubeModel.vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
Which works, and I successfully draw the cube, But i've been trying multiple ways to draw the pyramid as well.
What do I need to do to render both on screen at the same time?
EDIT: Here's what i've tried specifically, duplicating the glBufferData() call and passing in the pyramid data then making glDrawArays(GL_TRIANGLES,0,cubeModel.drawcount+pyramidModel.drawCount) figuring the vertex data would stack and glDrawArrays would go through all the geometry passed in one go.
I've also tried making 2 sets of instructions from glGenBuffers() to glDisableClientState() but instead using all of pyramid model's data. This was interesting because my glDrawArrays was:
glDrawArrays(GL_TRIANGLES, 0, cubeModel.drawCount);
glTranslatef(4.0f,0.0f,0.0f);
glDrawArrays(GL_TRIANGLES, 0, pyramidModel.drawCount);
and it ended up drawing a really messed up pyramid 2 times, leading me to believe that when I cal glBufferData() twice the second time Overwrites the data previously passed.
EDIT 2:After Reading Andon's comment I edited some of my code to clarify things, drawCount is now vertexCount, and m_vertexBuffer is now correctly referencing the handle I stored in cubeModel, cubeModel.vboID, instead of using an old class variable I was using to store the handle.
I do not want to muddy up the comments section, because there are a lot of things wrong with your code. But I also do not have time to go through all of them right now, so this is a sort of temporary answer.
glBufferData (...) does not technically overwrite previously passed data, it does something far worse. Every time you call glBufferData (...) it creates a new data store of the size you pass and (optionally) fills it with the data you supply (if you pass something non-NULL). Think of it more like calling free (...) and then malloc (...) or delete [] ... and new Type [...].
glBufferSubData (...) is the preferred technique for appending vertices to a vertex buffer. Unfortunately it does not resize the data store. Sometimes it is handy to over-allocate your VBO and defer supplying it data until later on (using glBufferSubData).
If you use one VBO to store both of your models, you need to know the starting vertex and the vertex count for each model as it relates to your VBO's data. Right now all you know is the number of vertices (and you have it named strangely drawCount instead of vertexCount). To most people, drawCount indicates the number of times you want to draw something, rather than the number of vertices or elements it contains.
The size field of a call to glBufferData (...) is supposed to be the size in bytes of your vertex data. Right now you're passing the number of vertices. More than likely you meant to use sizeof (YourVertexDataStructure) for the size of an individual vertex (sizeof (float [3]) in this case), and something like sizeof (cubeVerts) / sizeof (YourVertexDataStructure) to calculate the number of vertices actually stored in this array. Then the size you pass to glBufferData (...) would be: _size * count_
Related
I'm now maintaining an lagacy code and found "strange" usage in OpenGL.
First, the OpenGL version is 3.2 compability profile.
Then, there is nothing refering to VAO in the code, however, in Dont need to have a VAO? what #Dietrich Epp said is below :
If you use a compatibility OpenGL context, you don't need a VAO. In a sense, there is a "default" VAO which is always bound.
And what confused me is how the data are fed to OpenGL . The pseudocode may explain clear:
// foo.cpp
void PrimitiveLoading()
{
// load vertex position data
glBindBuffer(GL_ARRAY_BUFFER, postionVBO);
glBufferData(GL_ARRAY_BUFFER, /* postion data */);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// load vertex position index data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, /* postion index data */);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// load UV data
glBindBuffer(GL_ARRAY_BUFFER, uvVBO, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, /* UV data */);
glBindBuffer(GL_ARRAY_BUFFER, 0);
/*
The postion data are loaded before ELEMENT, while the UV data are behind.
This means ELEMENT is associated with the postion but not the UV, right?
*/
}
void PrimitiveRendering()
{
// define the vertex postion format
glBindBuffer(GL_ARRAY_BUFFER, postionVBO);
glVertexAttribPointer(/*position attribute setting*/);
// define the uv format
glBindBuffer(GL_ARRAY_BUFFER, uvVBO);
glVertexAttribPointer(/*UV attribute setting*/);
glBindBuffer(GL_ARRAY_BUFFER, 0); // GL_ARRAY_BUFFER bind to 0
// draw
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionEBO);
glDrawElements(GL_TRIANGLES, positionEBO, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
/*
before drawing, GL_ARRAY_BUFFER bind to 0(not bind to both postionVBO and uvVBO), but it works.
And the data are fed to respectively postionVert and uvVert in foo.vert below as expected. how and why ?
Moreover, it seems the ELEMENT affects not not only postionVAO but also uvVAO.
*/
}
// foo.vert
version 150
in vec3 postionVert;
in vec2 uvVert;
...// other code
the questions are written as comments. Could anyone explain how this usage works?
The postion data are loaded before ELEMENT, while the UV data are behind.
This means ELEMENT is associated with the postion but not the UV, right?
No. Index arrays are not "associated" with any attribute. When you do indexed rendering, the index used applies to all attributes. You cannot use different indices to fetch different attributes.
before drawing, GL_ARRAY_BUFFER bind to 0(not bind to both postionVBO and uvVBO), but it works.
Of course it works. What is bound to GL_ARRAY_BUFFER does not matter for rendering purposes. It only matters when you call glVertexAttrib*Pointer, which takes the buffer that is currently bound to that binding point and hooks the given attribute index to that buffer.
Think of GL_ARRAY_BUFFER as just being a weird way of passing an additional parameter to glVertexAttrib*Pointer. Since you didn't call that function, the extra parameter isn't passed to anyone.
When you're "not using a VAO" in compatibility contexts, you're still using a VAO. The VAO-modifying functions all work exactly the same as they do for core contexts. The only difference is that in compatibility, VAO object 0 is a real vertex array object, while in core contexts it is not a valid object. So in compatibility contexts, there's always some VAO that is currently bound.
I thought the VAO (Vertex Array Object) was supposed to store state like the vertex attributes. When I create a VBO I specify my vertex attributes:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)nullptr);
glEnableVertexAttribArray(0);
// And so on
If I bind another VBO I have to call glVertexAttribPointer and glEnableVertexAttribArray three times, that's for every time I switch my VBO. I only have one VAO, I never change it. Is there something wrong? I only use one vertex layout and I'm not understanding what the VAO does if it loses this information each time I switch. Is it only one VBO per VAO?
If you don't want to respecify glVertexAttribPointer before calling a glDraw* function then you need several VAOs not just one. I think you are confusing the what a VBO and a VAO are. A VBO is just an inert piece of memory that contains data. A VAO contains all the information that OpenGL requires to draw a mesh, that includes:
- a reference to the Buffer object containing your vertex data (commonly named VBO)
- a reference to the Buffer object containing your vertex indices (if you are using glDrawElements*)
- the index of the different vertex attributes you are going to use and their layout in the Buffer object containing your vertex data (specified with glEnableVertexAttribArray and glVertexAttribPointer)
So basically for each mesh you are going to draw you need to prepare a corresponding vao:
// at scene preparation time
glBindVertexArray(vaoA); // the following functions will only affect vaoA
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_of_meshA);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_of_meshA);
foreach attrib of meshA
glEnableVertexAttribArray(***);
glVertexAttribPointer(***)
glBindVertexArray(0)
glBindVertexArray(vaoB); // the following functions will only affect vaoB
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_of_meshB);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_of_meshB);
foreach attrib of meshB
glEnableVertexAttribArray(***);
glVertexAttribPointer(***)
glBindVertexArray(0)
//And now at render time:
void render()
{
glBindVertexArray(vaoA);
glDrawElements(***);
glBindVertexArray(vaoB);
glDrawElements(***);
}
for more info check: https://www.opengl.org/wiki/Vertex_Specification
I am currently learning GFLW and OpenGL in C++, and I have come across a very weird error that I really can't figure out why it is occurring. I have two Vertex Buffers, one contains the data for a triangle, and the other contains data for a cube. When I create the Vertex Buffer for the Triangle and draw it without creating the Vertex Buffer for the Cube, it works perfectly and draws to the window the expected triangle. However, if I create the second Vertex Buffer and draw only the triangle again it becomes distorted.
Output when only the triangle Vertex Buffer is created:
Output when both the triangle Vertex Buffer and Cube Vertex Buffer are created (cube vertex buffer is never used)
Vertex Buffer's constructor
VertexBuffer(const GLvoid *data, GLsizeiptr size, GLenum mode, GLsizei count, GLsizei stride, ShaderInterface *shader, GLvoid *positionOffset, GLvoid *normalOffset);
Creating the two vertex buffers:
VertexBuffer *vertexBuffer=new VertexBuffer(vertices,sizeof(vertices),
GL_TRIANGLES,
3,
sizeof(GL_FLOAT)*3,
shaderArray->at(0),
NULL,
NULL);
vertexBufferArray->push_back(vertexBuffer);
VertexBuffer *cubeVertexBuffer=new VertexBuffer(cubeVertices,
sizeof(cubeVertices),
GL_TRIANGLES,
36,sizeof(VertexDataPN),
shaderArray->at(1),
(GLvoid*)(offsetof(VertexDataPN,positionCoordinates)),
(GLvoid*)(offsetof(VertexDataPN,normalCoordinates)));
//vertexBufferArray->push_back(cubeVertexBuffer);
And the contents of the constructor for my Vertex Buffer class:
glGenBuffers(1,&vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER,vertexBufferID);
glBufferData(GL_ARRAY_BUFFER,size,data,GL_STATIC_DRAW);
Also, I have already checked that the vertexBufferID's are different for both of them. The Cube Vertex Buffer is never used or referenced to after it gets created. If anyone knows why this is occurring please let me know.
OpenGL is state-based, which means that objects that change OpenGL's internal state during their initialization can affect its behaviour even if they aren't subsequently used.
You are calling glBindBuffer in your vertex buffer constructor, which means that unless you call glBindBuffer later, the most recently bound buffer (the cube) will remain bound to GL_ARRAY_BUFFER and will be used during rendering.
You need to change your drawing code to call glBindBuffer with the buffer that you intend to use (e.g. the triangle one), before any calls to glVertexAttribPointer.
I have a subfunction that reads a data stream and creates an array of vertex data based on that. The main function calls this subfunction repeatedly and updates the vertex data array, which is then bound to a buffer and drawn. So far, so good. However, I cannot figure out how to add vertices. C++ does not let you reassign or resize entire arrays. I can't use vectors because the OpenGL functions take in arrays, not vectors.
You can use vectors to populate an OpenGL vertex buffer. The values in a vector are guaranteed to be contiguous. See for example these discussions for details on the related language standards:
Are std::vector elements guaranteed to be contiguous?
Is it safe to assume that STL vector storage is always contiguous?
This means that code like the following is safe:
std::vector<GLfloat> vertexPositions;
// Populate vector with vertex positions.
GLuint bufId = 0;
glGenBuffers(1, &bufId);
glBindBuffer(GL_ARRAY_BUFFER, bufId);
glBufferData(GL_ARRAY_BUFFER, vertexPositions.size() * sizeof(GLfloat),
&vertexPositions[0], GL_STATIC_DRAW);
The subtle but critical part is that you pass in the address of the first element of the vector, not the address of the vector object.
I would make a slight edit. While you can use &vertexPositions[0] as the address of the beginning of an STL vector, I prefer to use the function designed to return the address of the beginning of the vector memory, vertexPositions.data().
std::vector<GLfloat> vertexPositions;
// Populate vector with vertex positions.
GLuint bufId = 0;
glGenBuffers(1, &bufId);
glBindBuffer(GL_ARRAY_BUFFER, bufId);
glBufferData(GL_ARRAY_BUFFER, vertexPositions.size() * sizeof(GLfloat), vertexPositions.data(), GL_STATIC_DRAW);
I use STL vectors for OGL data for a number of reasons. It's easy to preallocate if you know the size, and they will grow (and stay contiguous) when you add items. They are easy to iterate through. You can easily create vectors of structures if you want to pass in interleaved data. It all works the same.
I am generating the vertex arrays on the fly on each render and I want to delete the arrays afterwards. Does glDrawArrays immediately copy the vertex arrays to the server? Hence is it safe to delete the vertex arrays after calling glDrawArrays?
float * vp = GetVertices(); // Regenerated on each render
glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), vp);
glDrawArrays(GL_TRIANGLES, 0, nVertices);
delete[] vp; // Can I do this?
Otherwise, how can I determine when it is safe to delete the vertex arrays?
Yes, it is copied immediately, so once you've done the call you can do whatever you like with the array.
Also, as dirkgently pointed out, you need to use delete[] vp to delete an array.
Yes, you can delete the vertex array after calling glDrawArrays. But opengl won't store vertex data in it's memory. It will just use the vertex array and draws on the frame buffer. So next time if you want draw the same vertex, then you have to provide the vertex array again to glDrawArrays.