I read two demos about 'Getting started with OpenGL'
Google Android hello-gl2
gl_code.cpp
learnopengl.com Hello-Triangle
hello_triangle.cpp
For the last parameter of glVertexAttribPointer :
google android demo : use array name gTriangleVertices
learnOpenGL.com demo : use 0.
google android demo :
glUseProgram(gProgram);
checkGlError("glUseProgram");
glVertexAttribPointer(gvPositionHandle, 2,
GL_FLOAT, GL_FALSE, 0,
gTriangleVertices); // array name
checkGlError("glVertexAttribPointer");
glEnableVertexAttribArray(gvPositionHandle);
learnOpenGL.com code segment :
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3,
GL_FLOAT, GL_FALSE,
3 * sizeof(float),
(void*)0); // my question : `0`
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
click : code comparision screenshot
I tend to think that learnOpenGL's demo is wrong,
but learnOpenGL is a well-known website, it's impossible to make mistakes.
Finally , both demos can display triangle correctly.
I'm confused.
I'm confused about when to pass 0 and when to pass the pointer value ?
The last parameter of glVertexAttribPointer has the type const void * for reasons of compatibility.
If a non-zero named buffer object is bound to the GL_ARRAY_BUFFER target, the last argument (pointer) is treated as a byte offset into the buffer object's data store:
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
In legacy OpenGL (compatibility profile OpenGL Context) it is possible to specify a data pointer directly (in this case it must not be bound a buffer object, because the pointer should not be treated as a byte offset into the buffer):
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), gTriangleVertices);
However, there is more. See glVertexAttribPointer and glVertexAttribFormat: What's the difference?
Related
I'm attempting to move a vertex by modifying it's positional vertex attribute. As a test, I have added the line vertices[0] = 0.4f; both before and after the creation of my VAO procedure, to see whether I am able to modify the vertices array after an initial render. When I add it before the VAO creation, it modifies the location of the vertex, and when it is added afterwards it does not. This leads me to believe my rendering procedure:
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
Somehow isn't actually updating the buffer with the current float[] in memory. However, I can then replace the line glBindVertexArray(VAO); with the whole rendering procedure:
// 2. copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
// 2. copy our vertex indices in a buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
// 3. then set our vertex attributes pointers:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
glEnableVertexAttribArray(1);
And with this as my rendering procedure, I can update the vertices array and this change is carried across to the GPU, updating the position of the vertex on-screen. Here is my VAO creation code:
// Generate a Vertex Array Object to store our rendering procedure.
unsigned int VAO;
glGenVertexArrays(1, &VAO);
// 1. bind Vertex Array Object, Element Buffer Object
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// 2. copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
// 2. copy our vertex indices in a buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
// 3. then set our vertex attributes pointers:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
glEnableVertexAttribArray(1);
So it works when I express the rendering procedure explicitly, but not when I store it in a VAO? From what I understand, a VAO is a construct for storing a rendering procedure, and when we then run glBindVertexArray(VAO);, this rendering procedure is carried out. Am I understanding this wrong? Is there another line I need in either the creation of the VAO or when rendering?
Here is the full source in C++: https://pastebin.com/DgZuZt4K
And the same thing written in OpenTK, C#: https://pastebin.com/DHj9UN16
[...] From what I understand, a VAO is a construct for storing a rendering procedure, [...]
No it is not. A Vertex Array Object stores states.
When glBufferData/glBufferSubData is called, then the buffer object's data store is initialized respectively updated.
When glVertexAttribPointer is called, then states are set in the state vector of the VAO. The buffer object which is currently bound to the target GL_ARRAY_BUFFER is associated to the specified vertex attribute in the currently bound VAO.
The VAO stores the information about how to interpret the vertex information and the id of the VBO for each attribute.
But the VAO does not store a procedure or even a process. When you have changed the vertices, then you have to update the Vertex Buffer Object by either glBufferSubData or buffer mapping.
Related: What is the proper way to modify OpenGL vertex buffer?
If you want to specify and enable a vertex attribute (glVertexAttribPointer / glEnableVertexAttribArray), then you have to bind the VAO and the VBO. The VAO stores the specification and the id of the VBO is stored in the VAO.
If you want to update the vertex coordinates and attributes (e.g. glBufferSubData), then you have to bind the VBO.
If you want to draw the mesh (e.g. glDrawArrays), then it is sufficient to bind the VAO.
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.
I use old way to provide the data to vertex buffer in OpenGL
glGenBuffers(1, buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(pos), pos, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
Since OpenGL 4.3 there a new slightly more clear way to provide data to vertex shader appears
const GLfloat colors[] =
{
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
glBindVertexBuffer(1, buffer, 0, 3 * sizeof(GLfloat));
glVertexAttribFormat(1, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(1, 1);
glEnableVertexAttribArray(1);
but I can't find any resources explaining how to provide data using new way. Of course I can do like this
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); //i can do even so, and later I can use glBindVertexBuffer
but it looks not really elegant. If I will not use glBindBuffer and only use glBindVertexBuffer and then use glBufferData, I'll overwrite data in buffer that was bind using glBindBuffer.
So question is: can I provide data to vertex buffer other way or I should always use glBindBuffer, glBufferData and only after that use glBindVertexBuffer, glVertexBufferFormat, glVertexAttribFormat and glVertexAttribBinding. Thank you!
From what I can tell from the OpenGL 4.3 specification, you will still need to bind the vertex buffer to a "regular" binding point in order to update its data:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
This problem has effectively been solved in the 4.5 specification with the introduction of DSA functions, which allow you to update the buffer data without binding it to a slot first:
glNamedBufferSubData(buffer, offset, size, data);
glVertexAttribFormat and glVertexAttribBinding are telling OpenGL how the data is organized in the buffer; essentially they replace glVertexAttribPointer (and only glVertexAttribPointer). Loading the data still happens with glBuffer[Sub]Data.
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));
I'm trying to draw a quad for a background (2D) using OpenGL 3.x+. Quads are deprecated, so the goal is to use two triangles to make a rectangle that fills the screen. It's working, but I'm not 100% clear on everything here.
Setup
GLuint positionBufferObject;
GLfloat vertexPositions[] =
{
-1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 1.0f,
};
glGenBuffers(1, &positionBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
I understand the vertexPositions, it's an array of vertices.
glGenBuffers() is saying, I want 1 buffer and assign id to &positionBufferObject?
glBufferData() uploads the vertexPositions to the GPU's memory; but how does it know were to upload it since I didn't give it an ID?
Draw
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 5);
glDisableVertexAttribArray(0);
glEnableVertexAttribArray() just says I'm going to be drawing with array 0?
glDrawArrays() - what if I want to draw two vertex arrays? How does it know which ones to render? It knows that from the above command?
Not sure what glVertexAttribPointer() does?
glDrawArrays() is clear.
Clean up, I think this is right?
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &positionBufferObject);
I only do the setup/cleanup once.
Bonus points:
Is this the most effective way to render this? I read that I'm suppose to be submitting and be rendering in "batches" [?] since 3.x+ doesn't do immediate mode any more. There is also only one array, so batches won't help performance in this case, but if I had say "a very large number" of vertxArrays to draw, would it be the same process?
In setup they are storing the array id as positionBufferObject, but have it hardcoded in the rendering loop. Seems like it would get confusing after a dozen or so arrays, why isn't it good practice to use the variable instead of hardcode it?
glGenBuffers(1, &positionBufferObject); says "make a vertex buffer object, and positionBufferObject is its ID."
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject); says "positionBufferObject is now the current GL_ARRAY_BUFFER."
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); says "upload vertexPositions to the ID currently bound to GL_ARRAY_BUFFER (which is positionBufferObject)."
glEnableVertexAttribArray(0); says "vertex attribute array 0 is now available for use."
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); says "vertex attribute array 0 is to be interpreted as consisting of groups of 4 floats."
glDrawArrays(GL_TRIANGLE_STRIP, 0, 5); says "draw a triangle strip with five indices from every enabled array."
glDisableVertexAttribArray(0); says "we're done for the time being with vertex attribute array 0."
In answer to user697111's question about multiple arrays, it's quite simple.
Each vertex attribute needs to be associated with a buffer object. Rather than specifying the buffer object with glVertexAttribPointer, the association is done through GL_ARRAY_BUFFER. When you call glVertexAttribPointer (or any gl*Pointer call), the buffer that is currently bound to GL_ARRAY_BUFFER will be used as the source for that attribute. So, consider the following:
glBindBuffer(GL_ARRAY_BUFFER, myPositionData);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, ..., 0);
glBindBuffer(GL_ARRAY_BUFFER, myColorData);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, ..., 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(...);
Attribute 0 will come from the buffer object myPositionData, and attribute 1 will come from the buffer object myColorData. The fact that I undid the binding to GL_ARRAY_BUFFER before calling glDrawArrays does not change where the data for those attributes comes from.