I'm not very experience with the OpenGL library so I'm having trouble understanding why when I move some initialization code to a class or a function, GL stops drawing onto the screen. Some research indicates that the library is "global" or state-based rather than object based?
Anyway, here is some code that works
GLuint vertexArrayBuffer;
glGenVertexArrays(1, &vertexArrayBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBuffer);
// VBO is ready to accept vertex data
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(0);
while(!screen.isClosed()) {
// Give the screen a background color
screen.paint(0.0f, 0.0f, 0.5f, 1.0f);
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
// Switch to display buffer after drawing all of the above
screen.swapBuffers();
This is all enclosed in the main function, with not much programming structure. The output is a nice white triangle onto a blueish background.
This is the issue here, taking the exact code prior to the event loop and wrapping it into a function:
GLuint initVertexArray(vertex vertices[]) {
// Create file descriptor for the VBO for use as reference to gl vertex functions
GLuint vertexArrayBuffer;
glGenVertexArrays(1, &vertexArrayBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBuffer);
// VBO is ready to accept vertex data
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(0);
return vertexArrayBuffer;
}
and calling it GLuint vertexArrayBuffer = initVertexArray(vertices); in the main function, produces no output of any kind, no errors either, just the same blueish background.
Have you checked what sizeof(vertices) is returning. In this case vertices[] will decay into a pointer so I would imagine that sizeof(vertices) is sizeof(vertex*).
Try passing the size of the array alongside it like so:
GLuint initVertexArray(vertex vertices[], const unsigned int size);
Then you would use it like so:
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
instead of:
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
You would then call it in the same scope as you declared your vertices array:
vertex vertices[100];
// sizeof(vertices) here will give the actual size of the vertices array
// eg: sizeof(vertex) * 100 instead of just giving sizeof(vertex*)
GLuint vertexArrayBuffer = initVertexArray(vertices, sizeof(vertices));
Related
I'm learning OpenGL and ran into an "obstacle".
I drew some houses (blocks and pyramids) using an indexbuffer.
This works fine when loading all the vertices (from all houses) into the vertexbuffer and using 1 big indexbuffer. Now I want to animate the objects and load them in the vertexbuffer one by one so I can execute transformation on the objects one by one. The code is not much different from one big buffer, but when I do this I just see some random shapes shooting around on the screen. My code is as follows:
I have a world class which holds the list of 3D objects, has one big list of all vertices (for trial purposes), one big list of indices (also trial) and a method to add an Object3D object to the world.
class World
{
public:
World();
~World();
vector<Object3D> objects;
vector<glm::vec3> Vertices;
vector<GLushort> Indices;
void AddObject(Object3D &object);
};
Object3D class:
class Object3D
{
public:
Object3D();
~Object3D();
glm::vec3 Position;
vector<glm::vec3> Vertices;
vector<unsigned int> Indices;
};
World AddObject method, simply adds the object to the "objects" list and adds the vertices and indices to the "Vertices" and "Indices" lists to create one big buffer:
void World::AddObject(Object3D &object) {
int oldVerticesSize = Vertices.size();
objects.push_back(object);
Vertices.insert(Vertices.end(), object.Vertices.begin(), object.Vertices.end());
for each (GLushort index in object.Indices)
{
Indices.push_back(index + oldVerticesSize);
}
}
When I render the big buffer with all the vertices and indices (as shown below) it works fine.
void WorldRenderer::Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(Vao); //use vao
glDrawElements(GL_TRIANGLES, World.Indices.size(), GL_UNSIGNED_SHORT, 0);
//glDrawArrays(GL_TRIANGLES, 0, World.Vertices.size());
glBindVertexArray(0); //release vao
//Model = glm::rotate(Model, 0.01f, glm::vec3(0.0f, 1.0f, 0.0f));
Mvp = Projection * View * Model;
glUniformMatrix4fv(UniformMvp, 1, GL_FALSE, glm::value_ptr(Mvp));
glutSwapBuffers();
//glutPostRedisplay();
}
When I loop through the objects and load the vertices of the objects in the buffer one-object-at-a-time (as shown below) it shows some random "shapes" which keep "shooting around" or rapidly changing. What am I doing wrong here?
Thanks in advance for any advice.
void WorldRenderer::Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int index = 0;
for each (Object3D mesh in World.objects)
{
Mvp = Projection * View * Model;
UpdateBuffer(mesh.Vertices, mesh.Indices);
glBindVertexArray(Vao); //use vao
glDrawElements(GL_TRIANGLES, mesh.Indices.size() , GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0); //release vao
glUniformMatrix4fv(UniformMvp, 1, GL_FALSE, glm::value_ptr(Mvp));
index++;
}
glutSwapBuffers();
}
UpdateBuffers method:
void WorldRenderer::UpdateBuffer(vector<glm::vec3> vertices, vector<unsigned int> indices) {
//fill Vbo
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size(), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//fill ibo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(Vao);
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
}
For the first Render method (without the loop) the buffers are created once in the init method which looks like this:
void WorldRenderer::Init(int argc, char ** argv) {
InitGlutGlew(argc, argv);
InitMatrices();
glDisable(GL_CULL_FACE);
//-------------- init buffers --------------
// vbo vertices
glGenBuffers(1, &Vbo);
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBufferData(GL_ARRAY_BUFFER, World.Vertices.size() * sizeof(glm::vec3),
&World.Vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//ibo
glGenBuffers(1, &Ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, World.Indices.size() * sizeof(unsigned int),
&World.Indices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// VAO setup
glGenVertexArrays(1, &Vao);
glBindVertexArray(Vao);
// Bind vertices to vao
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
//Bind elements
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
//------ init shaders -----------
InitShader();
}
As soon as I see your UpdateBuffer function, I feel that the glBufferData for vbo is not loaded properly.
The second parameter vertices.size() returns just number of elements in vector but not the actual size of object.
So the second parameter should be vertices.size() * sizeof(glm::vec3)
And the third parameter is ok as it returns pointer to the underlying array. If not working ....directly pass the address of first element as shown below.
Overall it should be something like as shown below.
glBufferData(
GL_ARRAY_BUFFER,
vertices.size() * sizeof(glm::vec3),
&vertices[0],
GL_STATIC_DRAW
);
Check if it works.
Why you are seeing differences?
First render:
Your buffer contain all the world's data for vertices continuosly, when the glDrawElements is called.
So here the mesh1 last vertex is continued with mesh 2 fist vertex.... So you see a kind of closed shape.
Second render:
your buffer contains only one mesh data at a time, when the glDrawElements is called.
so your shape ends for each mesh after calling glDrawElements.
To obtain the same result as first render, you have to first update a single vertex buffer for all meshes ( use glBufferSubData).
Then call glDrawElements once. Then you will see same result.
I want to create multiple vertex buffers in objects (one by object). the constructor is:
VertexBuffer::VertexBuffer(const GLvoid *data,
GLsizeiptr size,
GLenum mode,
GLsizei count,
GLsizei stride,
ShaderInterface *shaderInterface,
GLvoid *positionOffset,
GLvoid *normalOffset)
: _mode(mode),
_count(count),
_stride(stride),
_shaderInterface(shaderInterface),
_positionOffset(positionOffset),
_normalOffset(normalOffset)
{
glGenBuffers(1, &_vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
//
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0); //??????
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
//
}
If I create 1 object VertexBuffer, this works ok. But if I create another object (I won't use it) and I draw the first object again the result is not correct (for example, the object showed is in other place). Why?
You don't seem to store the vao anywhere, but you should. Before drawing each object you shall glBindVertexArray its vao (but not _vertexBufferID) before you call any of glDraw*.
See also this answer to see what state VAOs contain.
I have recently embarked on learning OpenGL for 3d graphics from this website. I understand that there are some very old tutorials out there for this library since it has been around for a long time. Most tutorials use the commands glBegin() and glEnd() to draw shapes. This is very simple and easy to follow in my opinion.
However, it has come to my understanding that this is supposedly outdated and I should be using glDrawArraysinstead. The problem is this, I just don't understand the code/concepts that are needed to draw using this method. The code is as follows:
void draw() {
//i get this bit
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
//I stop getting it here
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
}
Could somebody explain this code line by line and maybe explain the concept behind a buffer. Also, I'm curious, do the old draw commands still work in new versions and if so, is it bad practice to use them?
Please explain everything in as simple language as possible, I'm a complete beginner in this subject. TBH, I dont even know what a buffer is.
I'll explain this on my simple understanding, so some probably going to be wrong.
The old function is deprecated which is like removed/discouraged from using, but it is still there to support backward compatibility. You can read about it here. As far as i know, the old deprecated function is not present in OpenGL ES or WebGL.
You can say buffer object is an OpenGL object that store/allocate memory to store data in the gpu. You can read about it here
glGenBuffers(1, &vertexbuffer);
Generate/create a new buffer. It will assign vertexbuffer with a number which you can use to access the buffer.
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
Start using (bind) the buffer vertexbuffer
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
Allocate memory and set the data for the binded buffer. GL_STATIC_DRAW, GL_DYNAMIC_DRAW, GL_STREAM_DRAW will tell the gpu where to store the memory for the best performance.
glEnableVertexAttribArray(0);
This tell the gpu to start using the attribute located at 0. If you're using a shader you can get it with GLint glGetAttribLocation(GLuint program, const GLchar *name); link
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
Binded it two times, doesn't do anything much. Except you unbind it somewhere else or bind other buffer.
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);
This is to set how the attribute located at 0 is going to be used. This means the attribute is going to be used like: for every vertex, there is 3 floats variable that doesn't need to be normalized which is tightly packed (stride = 0, offset = 0).
P.s: shouldn't the stride be 3 * sizeof(GLfloat)? Edit: nvm, according to this it should be fine.
Edit: According to #Nicol Bolas:
it stores the buffer object that was bound to GL_ARRAY_BUFFER at the time the function was called.
Edit:
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer);. Example:
For the position it would be like glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*) (0 * sizeof(GLfloat)));
For the texture coord it would be like glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*) (3 * sizeof(GLfloat)));
For the color it would be like glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*) (5 * sizeof(GLfloat)));
This is assuming your shader has the location for position at 0, for texture coord at 1, and at 2 for color attribute.
glDrawArrays(GL_TRIANGLES, 0, 3);
Tell the gpu to draw a triangles using 3 vertex with offset 0 from the binded vertex buffer (vertexbuffer).
glDisableVertexAttribArray(0);
Stop using the attribute located at 0.
Vertex Array Object:
GLuint VertexArrayID;
This is the same as vertexbuffer from before, it store the id to access it.
glGenVertexArrays(1, &VertexArrayID);
Same as before too, this generate/create a new vertex array.
glBindVertexArray(VertexArrayID);
Same as before, start using/bind the vertex array.
Now the explanations about vao begin. Basically this object will remember the vbo (can be multiple) and how does it going to be used (from glVertexAttribPointer()), this only needed to be set once. When you're not using vao, each time you unbind and bind the vbo you need to set the attribute again. By using vao you only need to bind the vao as simple as calling glBindVertexArray(GLuint vaoID); and it will do everything for you which help a lot. So, you don't need to bind the vbo, set the attribute, and everything else. Instead just bind the vao, draw, unbind the vao, and done.
Sorry for the long and not perfect explanation.
So I have some code that creates a buffer and puts some vertices in it:
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
I also bind it to a shader attribute:
glBindAttribLocation(programID, 0, "pos");
And, finally, draw it:
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glDrawArrays(GL_TRIANGLES, 0, 3);
Of course, there is other code, but all of this stuff runs fine (displays a red triangle on the screen)
However, the instant I try to factor this stuff out in a struct, nothing will display (here is one of the methods):
void loadVerts(GLfloat verts[], int indices)
{
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glVertexAttribPointer(indice, indices, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(indice);
indice++;
buffers.push_back(vertexbuffer);
}
I've quadruple checked this code, and I've also traced it to make sure it would match the code above whenever its called. My draw call is almost the same as my original:
void draw()
{
glBindBuffer(GL_ARRAY_BUFFER, buffers.at(0));
glDrawArrays(GL_TRIANGLES, 0, 3);
}
I've also tried making this a class, and adding/changing many parts of the code. buffers and indice are just some vars to keep track of buffers and attribute indexes. buffers is an std::vector<GLuint> FWIW.
The main problem is here:
void loadVerts(GLfloat verts[], int indices)
{
...
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
The type of the verts argument is a pointer to GLfloat. Your function signature is equivalent to:
void loadVerts(GLfloat* verts, int indices)
So sizeof(verts), which is used as the second argument to glBufferData(), is 4 on a 32-bit architecture, 8 on a 64-bit architecture.
You will need to pass the size as an additional argument to this function, and use that value as the second argument to glBufferData().
These statements also look somewhat confusing:
glVertexAttribPointer(indice, indices, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(indice);
I can't tell if there's a real problem, but you have two variables with very similar names that are used very differently. indice needs to be the location of the attribute in your vertex shader, while indices needs to be the number of components in the attribute.
So I wanted to implement a simple VBO to see if it was worth switching from display lists for static objects in my scene. So far, I don't think Im doing it anytime soon. So heres my problem: I can render vertices fine, but as soon as I throw in texture coordinates, it crashes. So I do a bit of experimenting and its because I'm binding a texture to the thing. I have NEVER heard of this as being a problem. Literally the exact same code, using display lists works. Here is my code:
//create a vertex buffer object for the particles to use
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//create the data, this is really sloppy
float QuadVertextData[] = {0,0,0,1,0,0,1,1,0,0,1,0};
float QuadTextureData[] = {0,1,1,1,1,0,0,0};
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3, &QuadVertextData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//generate another buffer for the texcoords
glGenBuffers(1, &VBOT);
glBindBuffer(GL_ARRAY_BUFFER, VBOT);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2, &QuadTextureData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
and rendering:
glUseProgram(shader);
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, VBOT);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
I really have no idea why this is happening, Doing a texture without a shader crashes it, binding a shader without a texture crashes it. Any help or advice?
In a core opengl profile, you need to use VAOs in order to work with calls such as glDrawArrays and glDrawElements. A VAO (vertex array object) is a list of binding points for VBOs that encapsulates information such as data format and number of components for each VBO that is bound to it. In code it looks something like this.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3, &QuadVertextData, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glGenBuffers(1, &vbot);
glBindBuffer(GL_ARRAY_BUFFER, vbot);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2, &QuadTextureData, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindVertexArray(0);
The 0 and 1 (the first argument to glVertexAttribPointer) specifies the generic vertex attribute index in your shader. The 2 and 3 (the second argument) specify the number of components. Your input should be defined like this in the shader in order to work with this VAO:
layout(location=0) in vec3 position;
layout(location=1) in vec2 textureCoordinates;
Before drawing anything, you just have to use the shader program, bind your texture and bind the VAO:
glUseProgram(shader);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(vao);
glDrawArrays(GL_QUADS, 0, 4);
Don't forget to set the texture location of the sampler2D uniform in the shader.
If you want to learn more about switching to the OpenGL core profile, I recommand the tutorials from http://www.opengl-tutorial.org/