I am trying to render two different triangles with IBOs. I stored the six vertices in one VBO and tried to access them through two separate IBOs. The problem is the first IBO renders but the second doesn't. The createVertices and createIndices are called at initialization.
void createVertices()
{
//Vertex Data
GLfloat v[] = { 0.95f, 0.75f, 0.0f, 1.0f,
0.75f, -0.75f, 0.0f, 1.0f,
0.0f, -0.75f, 0.0f, 1.0f, // END OF TRIANGLE 1
-0.75, 0.75f, 0.5f, 1.0f,
-0.75, -0.75f, 0.5f, 1.0f,
0.0f, -0.75f, 0.5f, 1.0f }; // END OF TRIANGLE 2
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//////////
void createIndices()
{
GLushort i[] = { 0,1,2};
glGenBuffers(2, IBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(i), i, GL_STATIC_DRAW);
size = (sizeof(i)/sizeof(GLushort)); // USED IN DRAWELEMENTS
GLushort w[] = { 3,4,5};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(w), w, GL_STATIC_DRAW);
size2 = (sizeof(i)/sizeof(GLushort)); // USED IN DRAWELEMENTS
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
/////////
void Render()
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader.SProgram);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0,4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO[0]);
glDrawElements(GL_TRIANGLES,size,GL_UNSIGNED_SHORT,(GLvoid*)IBO[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO[1]);
glDrawElements(GL_TRIANGLES,size2,GL_UNSIGNED_SHORT,(GLvoid*)IBO[1]);
glUseProgram(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
This doesn't make sense:
glDrawElements(GL_TRIANGLES,size,GL_UNSIGNED_SHORT,(GLvoid*)IBO[0]);
^^^^^^^^^^^^^^
The parameter to glDrawElements with an IBO bound is an offset into the buffer just as it is with gl…Pointer and VBOs. You probably just want this
glDrawElements(GL_TRIANGLES,size,GL_UNSIGNED_SHORT,(GLvoid*)0);
for both your IBOs and just bind the IBO itself with
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO[…]);
Related
I'm trying to draw two triangles using separate VAOs and VBOs but while execution I see only one triangle being rendered. Below is my code snippet. I'm not sure where I'm messing up.
I'm using glfw and glew.
.....
//initialization and creating shader program
.....
GLfloat vertices[] = {
-0.9f, -0.5f, 0.0f, // Left
-0.0f, -0.5f, 0.0f, // Right
-0.45f, 0.5f, 0.0f, // Top
};
GLfloat vertices2[] = {
0.0f, -0.5f, 0.0f, // Left
0.9f, -0.5f, 0.0f, // Right
0.45f, 0.5f, 0.0f // Top
};
GLuint VBO1, VAO1, EBO;
glGenVertexArrays(1, &VAO1);
glGenBuffers(1, &VBO1);
glGenBuffers(1, &EBO);
GLuint VBO2, VAO2;
glGenBuffers(1, &VAO2);
glGenBuffers(1, &VBO2);
glBindVertexArray(VAO1);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)nullptr);
glEnableVertexAttribArray(0);
//glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindVertexArray(VAO1);
glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)nullptr);
glEnableVertexAttribArray(0);
//glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(ShaderProgramID);
glBindVertexArray(VAO1);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glBindVertexArray(0);
glBindVertexArray(VAO2);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glBindVertexArray(0);
glfwSwapBuffers(window);
}
glDeleteVertexArrays(1, &VAO1);
glDeleteVertexArrays(1, &VAO2);
glDeleteBuffers(1, &VBO1);
glDeleteBuffers(1, &VBO2);
glfwTerminate();
...
Although if I create VAOs and VBOs as array like below and change the code above code accordingly I see both the triangles. I'm unable to understand why is it so?
GLuint VAO[2], VBO[2];
GLuint VBO2, VAO2;
glGenBuffers(1, &VAO2);
...
glBindVertexArray(VAO2);
You've initialized VAO2 as a buffer, not a VAO.
This has been bothering me for the last days and I can't figure out why.
I know there are a lot of questions like this one here on stackoverflow but none seem to solve my issue.
So here it is the initialization code:
GLuint EBO[1];
GLuint VAO[1];
GLuint VBO[1];
static vec2 tri_pos[8] = {
{-1.0f, -1.0f},
{-1.0f, -1.0f},
{-1.0f, 1.0f},
{-1.0f, 1.0f},
{ 1.0f, -1.0f},
{ 1.0f, -1.0f},
{ 1.0f, 1.0f},
{ 1.0f, 1.0f} };
static GLuint tri_indices[] = { 0, 1, 2 };
glGenBuffers(1, EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(tri_indices), tri_indices, GL_STATIC_DRAW);
glCreateVertexArrays(1, VAO2);
glBindVertexArray(VAO2[0]);
glCreateBuffers(1, VBO2);
glBindBuffer(GL_VERTEX_ARRAY, VBO2[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(tri_pos), tri_pos, GL_STATIC_DRAW);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(4);
Here I create the buffers and bind them accordingly. I create the VAO, the VBO and the Element Buffer Object.
Then I assign the tri_pos array to a vec4 in the shader and enable it.
After that I call the draw() function to draw the triangles in this case:
//...
glClearBufferfv(GL_COLOR, 0, cColor);
glBindVertexArray(VAO2[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glBindBuffer(GL_VERTEX_ARRAY, VBO2[0]);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
//glDrawArrays(GL_TRIANGLES, 0, 3);
//glDrawArrays(GL_TRIANGLES, 5, 3);
//glDrawArraysInstanced(GL_TRIANGLES, 0, 3, 1);
//glMultiDrawArrays(GL_TRIANGLES, tri_indices, count, 2);
Here I use glDrawElements() with nullptr because Im using a EBO.
Everything compiles just fine. But at runtime it just crashes. I have no clue what I am missing. All the buffers seem me about right.
Anyone got any clue?
This line is wrong:
glCreateBuffers(1, VAO2);
You are creating a buffer but you probably want to create a vertex array:
glCreateVertexArrays(1, VAO2);
Also replace these calls:
glBindBuffer(GL_VERTEX_ARRAY, VBO2[0]);
with:
glBindBuffer(GL_ARRAY_BUFFER, VBO2[0]);
I'm a newbie to OpenGL and I'm trying draw two triangles using two VAOs and only one VBO. Even if after some research, I came to have a better understanding of VAO, VBO and how the needed glew functions work, I have no clue why my program displays only one triangle instead of two. Can somebody help?
...
GLfloat points[] = {
0.5f, 0.5f, 0.0f, //First Triangle
-0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.0f, 0.0f, //Second Triangle
-1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f
};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLuint vao1;
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
GLuint vao2;
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 9);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
...
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shader_program);
glBindVertexArray(vao1);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0);
glfwPollEvents();
glfwSwapBuffers(window);
}
...
The last parameter for this function call is incorrect:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 9);
You're telling it to add 9 bytes, but your points are floats
Try this:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 9 * sizeof(float));
Running a very simple draw a triangle example, I'm trying to find out which lines refer specifically to the VAO definition and which others can run apart.
Currently I'm using this code:
Buffer creation & filling:
TriangleVertices = new float[9]
{
0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
};
TriangleColors = new float[12]
{
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
};
glGenBuffers(1, &VertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), TriangleVertices, GL_STATIC_DRAW);
glGenBuffers(1, &ColorsBuffer);
glBindBuffer(GL_ARRAY_BUFFER, ColorsBuffer);
glBufferData(GL_ARRAY_BUFFER, 12*sizeof(float), TriangleColors, GL_STATIC_DRAW);
glGenVertexArrays(1, &VAOID);
VAO definition:
glBindVertexArray(VAOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, ColorsBuffer);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
Drawing Loop
glBindVertexArray(VAOID);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
The example runs fine if in the drawing loop I include the VAO definition each frame, but it doesn't work if I define the VAO only once before starting to draw so I guess the VAO definition lacks some code.
What am I missing?
EDIT: The code in the question was correct. The problem was coming from collision with other OpenGL calls I thought I wasn't running.
The code described below is just situational. As #derhass commented, there is no need to enable nor disable VertexAttribArray when making the draw call.
...
Old answer:
Unbindinding and disabling each element when not needed anymore fixed the problem, but I don't know if this solution can be widespread or it is specific to my environment only.
Buffer creation & filling:
TriangleVertices = new float[9]
{
0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
};
TriangleColors = new float[12]
{
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
};
glGenBuffers(1, &VertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), TriangleVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &ColorsBuffer);
glBindBuffer(GL_ARRAY_BUFFER, ColorsBuffer);
glBufferData(GL_ARRAY_BUFFER, 12*sizeof(float), TriangleColors, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &VAOID);
VAO definition:
glBindVertexArray(VAOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, ColorsBuffer);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
Drawing Loop
glBindVertexArray(VAOID);
glEnableVertexAttribArray(0);//not needed
glEnableVertexAttribArray(1);//not needed
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);//not needed
glDisableVertexAttribArray(1);//not needed
glBindVertexArray(0);
So i have a couple classes. A renderer and box2drenderer. Now both use their own vertex buffer and their own vertex array object. The Renderer is instantiated first with the following code:
glGenBuffers(1, &ebo);
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLfloat vertices[] = {
// Position(2) Color(3) Texcoords(2)
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // Top-left
1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, // Top-right
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-left
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(5 * sizeof(GLfloat)));
glBindVertexArray(0);
glUseProgram(shaderProgram);
projection = glm::ortho(0.0f, width, height, 0.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUseProgram(0);
Then I call the setup function for the box2d:
void Box2DRenderer::setRenderer(Renderer * r) {
this->renderer = r;
const GLchar * fragSource =
"#version 150 core\n\
precision mediump float;\n\
uniform vec4 u_color;\n\
out vec4 Color;\n\
\n\
void main()\n\
{\n\
Color = u_color;\n\
}";
const GLchar * vertSource =
"#version 150 core\n\
uniform mediump mat4 u_projection;\n\
uniform mediump float u_pointSize;\n\
in vec2 a_position;\n\
\n\
void main()\n\
{\n\
gl_PointSize = u_pointSize;\n\
gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n\
}";
this->renderer->compileProgram(vertSource, fragSource, vertShader, fragShader, shaderProgram);
glUseProgram(shaderProgram);
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_projection"), 1, GL_FALSE, glm::value_ptr(this->renderer->getProjectionMatrix()));
GLuint positionLocation = glGetAttribLocation(shaderProgram, "a_position");
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
glBindVertexArray(0);
colorLocation = glGetUniformLocation(shaderProgram, "u_color");
pointSizeLocation = glGetUniformLocation(shaderProgram, "u_pointSize");
glUseProgram(0);
}
The Renderer for now just draws textures. So i draw the player via the method:
void Renderer::renderTexture(sf::FloatRect &bounds, Texture &texture, Region *region) {
glm::mat4 model;
model = glm::translate(model, glm::vec3(bounds.left, bounds.top, 0.0f));
model = glm::scale(model, glm::vec3(bounds.width, bounds.height, 0.0f));
GLint modelMat = glGetUniformLocation(shaderProgram, "mMatrix");
glUniformMatrix4fv(modelMat, 1, GL_FALSE, glm::value_ptr(model));
float x = region->pos.x / texture.getWidth();
float y = region->pos.y / texture.getHeight();
float rx = (region->width + region->pos.x) / texture.getWidth();
float ry = (region->height + region->pos.y) / texture.getHeight();
GLfloat vertices[] = {
// Position(2) Color(3) Texcoords(2)
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, x, y, // Top-left
1.0f, 0.0f, 1.0f, 1.0f, 1.0f, rx, y, // Top-right
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, rx, ry, // Bottom-right
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, x, ry // Bottom-left
};
glBindTexture(GL_TEXTURE_2D, texture.getTextureId());
glBindVertexArray(vao);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
Now, if i don't initialize the box2d renderer, it works fine. If i have the box2d renderer, the texture coords are getting messed up. The whole texture seems to get drawn across the screen instead of regions at their correct place.
Given i'm turning on and off the BindVertexArray, I feel like I shouldn't have an issue, but for the life of me I can't figure it out. I can post screenshots of the difference if you'd like.
You probably fell victim to a fairly common misconception: Contrary to what you might have expected, the GL_ARRAY_BUFFER binding is not part of the VAO state.
At the tail end of the posted code you have this sequence:
glBindVertexArray(vao);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
The glBufferSubData() call will modify data in the currently bound GL_ARRAY_BUFFER, which is the buffer that you last made a glBindBuffer(GL_ARRAY_BUFFER, ...) call for. This is unrelated to the buffer you had bound when you previously used the VAO.
For additional illustration, here is a typical call sequence:
glBindVertexArray(vaoA);
glBindBuffer(GL_ARRAY_BUFFER, vboA);
glBindVertexArray(vaoB);
glBindBuffer(GL_ARRAY_BUFFER, vboB);
glBindVertexArray(vaoA);
The current GL_ARRAY_BUFFER binding at the end of this sequence is vboB. Since the binding is not part of the VAO state, it is simply based on the most recent glBindBuffer() call.
All you need to do to fix this is to add the glBindBuffer() call before glBufferSubData().
Note that the GL_ELEMENT_ARRAY_BUFFER binding is part of the VAO state. This may seem inconsistent, but it's not. The VAO bundles all the vertex setup state that is used by draw commands. The GL_ELEMENT_ARRAY_BUFFER binding controls which index buffer is used by draw commands, so it is part of this state. On the other hand, the current GL_ARRAY_BUFFER binding has no effect on the draw command, and is therefore not part of the VAO state.