Using glBindVertexArray in update loop in DSA code or not - opengl

I'm the process of converting some opengl code to DSA and everywhere its written not to bind the vertex array, because its inherit in DSA. So I use
GLuint VBO, VAO, indexBuffer;
glCreateVertexArrays(1, &VAO);
glCreateBuffers(1, &indexBuffer);
glCreateBuffers(1, &VBO);
...
instead of the glGen... counterparts.
But now I just wonder whether there is a DSA version of binding the vertex arrays in the update loop. Now I have
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Draw the triangle
ourShader.Use();
const auto Textureloc = glGetUniformLocation(ourShader.Program, "ourTexture");
glBindTextureUnit(Textureloc, texture);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 9, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindTextureUnit(0, 0);
glfwSwapBuffers(window);
}
which works all right. But will I run into some interesting problems later in my coding if I don't replace the glBindVertexArray to something else. Just as I replaced glBindTexture with glBindTextureUnit

To wrap things up, it is perfectly correct to write the update loop as in the example shown in the question. The VAO should be bound when it is used in the update loop. But when you use DSA you don't need to bind the VAO (nor the VBO nor the index buffer) when you modify them.
Therefore there is no alternative glDrawElements that takes VAO id as a parameter like e.g. glVertexArrayElementBuffer does.

Related

What does each function for vertex array buffer drawing in OpenGL do?

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.

glDrawArray not drawing the second time

Hi so i have been basically pulling my hair out trying to understand this OpenGL confusion
i have tried to find answers in books, in tutorials , and even experimenting around with it
SO basically i have a opengl program that draws the first time my two triangles, however when i try to redraw the first triangle again it doesnt seem to be working
i dont know what information i am missing , but its no t making any sense
as far as i understand once the VAO and VBO have been created and bounded and buffered to memory, and vertex attrib pointers set and enabled that once i bind the vao object that i want to draw as many times as i like, i just have to do that
after initialization which works for me, the problem is that once i rebind another vao object it doesnt seem to draw it
my code is quiet long , i can paste it here if you like, but i think that the drawing part of the code would be sufficient
here it is
GLfloat vec[] = {0.0f, 0.0f,
1.0f, -1.0f,
-1.0f, -1.0f};
GLfloat vec2[] = {0.0f, 1.0f,
1.0f, 0.0f,
-1.0f, 0.0f};
//next step is to upload data to graphics memory
//generating a buffer from openGL
GLuint vbo;
GLuint vbo2 ;
GLuint vao;
GLuint vao2;
glGenBuffers(1, &vbo);
glGenBuffers(1, &vbo2);
glGenVertexArrays(1, &vao);
glGenVertexArrays(1, &vao2);
//to upload the actual data must make the object active by binding it to a target
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//upload the data of active object to memory
glBufferData(GL_ARRAY_BUFFER, sizeof(vec), vec, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec2), vec2, GL_STATIC_DRAW);
//bind and draw
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,2,GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays (GL_TRIANGLES, 0, 3);
glXSwapBuffers ( dpy, glxWin );
sleep(3);
glClear(GL_COLOR_BUFFER_BIT);
//rendering second triangle
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBindVertexArray(vao2);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,2,GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays (GL_TRIANGLES, 0, 3);
glXSwapBuffers ( dpy, glxWin );
sleep(3);
//rendering the first triangle again------where the problem lies!!!
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,2,GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays (GL_TRIANGLES, 0, 3);
glXSwapBuffers ( dpy, glxWin );
sleep(3);
You'll also need to clear the depth buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
If you follow a tutorial then you will probably have enabled depth testing in the openGL setup boilerplate it provided. This is because more people will want to use the depth buffer than not.
you can also not call glEnable(GL_DEPTH_TEST); during setup.

Opengl VAO gets overwritten

I'm learning opengl and currently I'm struggeling with VAOs.
I would like to draw a cube and a triangle using VAOs but unfortunately, only the object that I create later is drawn. This is what I do in the main loop:
void main()
{
//loading shader, generate window, etc ...
//generate a cube:
GLuint cube_vao = generateCube();
//next, generate a triangle:
GLuint triangle_vao = generateTriangle();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
do
{
//draw:
glBindVertexArray(triangle_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(cube_vao);
glDrawArrays(GL_TRIANGLES, 0, 12*3);
glfwPollEvents();
glfwSwapBuffers(window);
} while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
}
Both, generateCube() and generateTriangle() do basically the same thing: create the vertices, create vbo, create vao and set the attributes. Then they return the vao id.
This is generateTriangle() for example:
generateTriangle()
{
//generate the vertex positions:
GLfloat triangle_pos[] = //not part of the snippet -> too long
//generate vbo for the positions:
GLuint pos_vbo;
glGenBuffers(1, &pos_vbo);
glBindBuffer(GL_ARRAY_BUFFER, pos_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_pos), triangle_pos, GL_STATIC_DRAW);
//next, generate the vertex colors:
GLfloat triangle_color[] = //not part of the snippet -> too long
//generate vbo for the colors:
GLuint col_vbo;
glGenBuffers(1, &col_vbo);
glBindBuffer(GL_ARRAY_BUFFER, col_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_color), triangle_color, GL_STATIC_DRAW);
//generate VAO:
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLint pos_attrib_id = glGetAttribLocation(programID, "line_pos");
glEnableVertexAttribArray(pos_attrib_id);
glBindBuffer(GL_ARRAY_BUFFER, pos_vbo);
glVertexAttribPointer(pos_attrib_id, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
GLint col_attrib_id = glGetAttribLocation(programID, "color");
glEnableVertexAttribArray(col_attrib_id);
glBindBuffer(GL_ARRAY_BUFFER, col_vbo);
glVertexAttribPointer(col_attrib_id, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);
//function to set the perspective (argument is the model matrix)
setPerspective(glm::mat4(1.0f));
return vao;
}
With this code, only the cube gets drawn.
Furthermore, if I comment out the lines:
glBindVertexArray(cube_vao); and glDrawArrays(GL_TRIANGLES, 0, 12*3); in the main, the triangle gets drawn but has the color and position of the cube, this is driving me crazy.
I'm using OSX with the shader versions 120 if that helps.
VAOs were introduced as standard functionality in OpenGL 3.0. On Mac OS, the default context version is 2.1. So you will need to specifically request a 3.x context during setup.
The exact mechanics of getting a 3.x context will depend on the window system interface/toolkit you are using. For example in GLUT, you include the GLUT_3_2_CORE_PROFILE flag in the argument to glInitDisplayMode(). With Cocoa, you include NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core in the pixel format attributes.
Note that Mac OS only supports the Core Profile for 3.x and later contexts. So you will not be able to use deprecated functionality anymore.

texture buffer object without shader

all tutorials online are written in opengl 3+ with intesive use of shader.
I was wondering, can I create a texture buffer object and show the texture without using shader? In very old opengl uber deprecate api calls you can write gltexcoord, I just tried this way only to see if my loader was OK, and it's alright.
Using TBO I'm encountering some problems..
Let's suppose I'm creating a quad, then after loading the image (named txtr), I will store coordinates in a vector
terrainTBO.push_back(1);
terrainTBO.push_back(1);
terrainTBO.push_back(0);
terrainTBO.push_back(1);
terrainTBO.push_back(1);
terrainTBO.push_back(0);
terrainTBO.push_back(0);
terrainTBO.push_back(0);
then, in initializing process of terrain I'm doing
(obviously I'm not writing here about vertices and indices)
glBindBuffer(GL_ARRAY_BUFFER, *texture_buffer);
glBufferData(GL_ARRAY_BUFFER, vectorSizeOf(*texture_indices), &(*texture_indices)[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
In drawing part:
glEnable(GL_TEXTURE_2D);
glhBindTexture(txtr);
glBindBuffer(GL_ARRAY_BUFFER, *vboId);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, *tboId);
glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *iboId);
glDrawElements(GL_TRIANGLES, (*indices).size(), GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisable(GL_TEXTURE_2D);
The quad is created correctly, but no texture is shown into.. How can I achieve my texture? Is shader mandatory in these cases?

Binding a Non-Zero Texture Crashes Program With VBO's

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/