I am currently writing a program that requires updating my VBO data constantly.
However, I found out that if I call glBindBuffer(GL_ARRAY_BUFFER, 0) after I initialize my buffer, the window closed itself somehow.
Below is my code snippet:
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(pts[0]) * pts.size(), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
mvp_location = glGetUniformLocation(program, "MVP");
vpos_location = glGetAttribLocation(program, "vPos");
glEnableVertexAttribArray(vpos_location);
glVertexAttribPointer(vpos_location, 3, GL_FLOAT, GL_FALSE,
sizeof(float) * 3, (void*) 0);
while(!glfwWindowShouldClose(window)) {
glUseProgram(program);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pts[0]) * pts.size(), &pts);
glBindBuffer(GL_ARRAY_BUFFER, 0);
mat4x4_mul(mvp, m, p);
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glDrawArrays(GL_POINTS, 0, pts.size());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
FYI: pts is constantly updated.
IS there a way to tell vertex shader that the VBO data is updated?
Edit: updated the code snippet
Edit: I am supposed to draw pts.size() number of vertices each time but there is only one point appeared on the screen
Right before your draw call there where you have glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); you need to actually set the attrib pointer(glVertexAttribPointer()). A secondary note is that GlVertexAttribPointer() binds GL_ARRAY_BUFFER to the specified attribute pointer. Where you call it at the moment there is nothing bound to GL_ARRAY_BUFFER.
For reference GLEnum error = glGetError() will return an the error state of openGL and is a powerful debugging tool. If you're using glew, glewGetErrorString() will get a string for any non-zero error code which explains the error in more detail.
p.s. sorry for my poor writing skills.
Related
I wanna render a rectangle with GL_ELEMENT_ARRAY_BUFFER but I get only one line render. With GL_ARRAY_BUFFER it works. For example, I've tried to render only one triangle but it also doesn't work.
Screenshot
Init:
Vertex[] vertices = [
Vertex(-0.5, -0.5, 0), Vertex(0.5, -0.5, 0), Vertex(0, 0.5, 0)
];
GLuint[] indices = [0, 1, 2];
GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.length * Vertex.sizeof, vertices.ptr, GL_STATIC_DRAW);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBindBuffer(GL_TRIANGLES, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.sizeof, &indices, GL_STATIC_DRAW);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, null);
glCompileShader(vertexShader);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, null);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
Rendering:
glClearColor(0.2, 0.2, 0.2, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, float.sizeof * 3, cast(void*) 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(shaderProgram);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, &indices);
Full code.
What is wrong?
I've got a solution. There was an issue with:
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, &indices);
&indices is a ptr to an entire array. But seems OpenGL requires ptr to each array element with indices.ptr.
I currently have an OpenGL project in which I am using GLFW for the window and context creation, and GLAD for loading OpenGL functions. The GLAD version I am using is OpenGL 4.6, compatibility profile, with all extensions (including ARB_direct_state_access).
My current graphics card settings are
OpenGL Version: 4.6.0 NVIDIA 457.09
GLSL Version: 4.60 NVIDIA
Renderer: GeForce GTX 970/PCIe/SSE2
Vendor: NVIDIA Corporation
When I run the following non-DSA code, it works fine.
// Create vertex array object and bind it
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create an index buffer object and use the data in the indices vector
GLuint ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size()*sizeof(GLint), indicies.data(), GL_STATIC_DRAW);
// Create a array buffer object and use the positional data which has x,y,z components
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, positions.size()*sizeof(GLfloat), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
However when I try to translate this code to a DSA format and run it, the program opens a window and then terminates without and useful debug information.
GLuint vao;
glGenVertexArrays(1, &vao);
GLuint vbo;
glCreateBuffers(1, &vbo);
glNamedBufferStorage(vbo, positions.size()*sizeof(GLfloat), positions.data(), GL_DYNAMIC_STORAGE_BIT);
glVertexArrayVertexBuffer(vao, 0, vbo, 0, 0);
glEnableVertexArrayAttrib(vao, 0);
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(vao, 0, 0);
GLuint ibo;
glCreateBuffers(1, &ibo);
glNamedBufferStorage(ibo, sizeof(GLint)*indicies.size(), indicies.data(), GL_DYNAMIC_STORAGE_BIT);
glVertexArrayElementBuffer(vao, ibo);
In both cases I bind the Vertex Array Object before drawing like so
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, indicies.size(), GL_UNSIGNED_INT, 0);
Why is my DSA like code not working?
When you use glVertexArrayVertexBuffer you must specify the stride argument. The special case in which the generic vertex attributes are understood as tightly packed when the stride is 0, as when using glVertexAttribPointer, does not apply when using glVertexArrayVertexBuffer.
glVertexArrayVertexBuffer(vao, 0, vbo, 0, 0);
glVertexArrayVertexBuffer(vao, 0, vbo, 0, 3*sizeof(float));
It won't cause an error if stride is 0, but that doesn't mean it makes sense.
I checked this question.
gldrawarrays does not draw anything => not applicable because I am using shaders.
My code goes as follows:
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
This initialises a vao first.
GLuint vertexBuffer;
glGenBuffers(1,&vertexBuffer);
float vertices[]={
-0.5f,-0.5f,
0.0f,0.0f,
0.5f,0.5f
};
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
Binds the buffer and adds the data
const char* vertexSource = reader("./shaders/chapter-one.vert").c_str();
GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vShader, 1, &vertexSource, NULL);
glCompileShader(vShader);
GLint vStatus;
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vStatus);
if(vStatus!=GL_TRUE){
printf("Vertex Shader not Compiled\n");
}
char vBuffer[512];
glGetShaderInfoLog(vShader, 512, NULL, vBuffer);
cout<<vBuffer;
const char* fragmentSource = reader("./shaders/chapter-one.frag").c_str();
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fShader, 1, &fragmentSource, NULL);
glCompileShader(fShader);
GLint fStatus;
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fStatus);
if(fStatus!=GL_TRUE){
printf("Fragment Shader not compiled");
}
char fBuffer[512];
glGetShaderInfoLog(fShader, 512, NULL, fBuffer);
cout << fBuffer;
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vShader);
glAttachShader(shaderProgram, fShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
Adds the shader and creates a program. I also retrieve errors and logs for each step which are empty currently. So no errors compiling or creating shaders and program.
GLuint posLoc = glGetAttribLocation(shaderProgram, "p");
printf("%i\n", posLoc);
glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLoc);
Gets the attribute from shader to feed the data to.
glDrawArrays(GL_LINES, 0, 3); // => This part does not work
Upon calling glGetError() after glDrawArrays I get 1282 error. I know glDrawArrays is causing this error as just before glDrawArrays I tried calling glGetErrors() and there wer no errors.
I think the problem is in setup somewhere
Any Suggestions??
Edit: I tried changing my code according to Rabbid76's suggestion and I am still getting the same error.
I checked the documentation and I think this is the applicable case.
GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to an enabled array and the buffer object's data store is currently mapped.
What does it mean in this situation and what changes should I make?
Full code here
Yes, I got took both my code and example code side by side and changed anything that seemed inconsistent. I changed both glDrawElements and had to adjust my glVertexAttribPointer. Stupid mistake. Thank you.
There is no glDrawArrays in your code. There is just a glDrawElements and that will cause an error, because you have not specified any Index buffer.
Furthermore, the type argument to glDrawElements has to be the type of the indices. The allowed types are GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.
Remove glDrawElements and use glDrawArrays to solve the issue:
glDrawElements(GL_TRIANGLES, 3, GL_FLOAT, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
Furthermore the Vertex Buffer Object and the Vertex Array Object have to be bound, before invoking glVertexAttribPointer. glVertexAttribPointer associates the buffer which is currently bound to the target GL_ARRAY_BUFFER to the specified attribute (index) and states the specification in the state vector of the Vertex Array Object.
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
So I was looking at another SO question regarding the command glVertexAttribPointer and I ran into a slight confusion. The accepted answer to this question explains,
But there's an additional implied piece of state that is also stored away for attribute 0 when you make the call: the data is read from the buffer currently bound to GL_ARRAY_BUFFER
This makes sense to me, but what if I have multiple buffers that are bound as GL_ARRAY_BUFFER? How does the glVertexAttribPointer() method know which one to set the attributes of?
For example, in my code, I'm drawing a gradient triangle. To do this, I've created 2 VBOs, one with color data in an array and another with vertex locations.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
static const GLfloat points[] = {
//data here
};
static const GLfloat colors[] = {
//data here
};
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
vs = glCreateShader(GL_VERTEX_SHADER);
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vs, 1, &vertexShaderData, NULL);
glShaderSource(fs, 1, &fragShaderData, NULL);
glCompileShader(vs);
glCompileShader(fs);
sp=glCreateProgram();
glBindFragDataLocation(sp, 0, "outColor");
glAttachShader(sp, vs);
glAttachShader(sp, fs);
glLinkProgram(sp);
glUseProgram(sp);
glGenBuffers(1, &colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 9);
When I call the command, where do I specify which buffer to use?
This makes sense to me, but what if I have multiple buffers that are bound as GL_ARRAY_BUFFER?
That's not possible. When you bind a buffer (or any OpenGL object) to a target, it automatically unbinds whatever was there before.
OpenGL object targets are like global variables. What happens when you set a global integer to 3? It's old value is gone.
glVertexAttribPointer will always use whatever buffer is currently bound to GL_ARRAY_BUFFER. So in your first call, it will use buffer. In your second call, it will use colorBuffer.
This is why it is important to remember that glVertexAttribPointer operates on what is currently bound. Because even after you bind colorBuffer, and set it to be used by attribute 1, attribute 0 still receives its vertex data from buffer.
So while you cannot have multiple buffers bound to GL_ARRAY_BUFFER, you can use multiple buffers as sources for your vertex data.
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/