I want to draw multiple vertex arrays. This is the initialization:
unsigned int va1;
unsigned int vb1;
void init_va1() {
glGenVertexArrays(1, &va1);
glBindVertexArray(va1);
glGenBuffers(1, &vb1);
glBindBuffer(GL_ARRAY_BUFFER, vb1);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(vec2), nullptr, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(vec2), nullptr);
glEnableVertexAttribArray(0);
}
unsigned int va2;
unsigned int vb2;
void init_va2() {
glGenVertexArrays(1, &va2);
glBindVertexArray(va2);
glGenBuffers(1, &vb2);
glBindBuffer(GL_ARRAY_BUFFER, vb2);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(vec2), nullptr, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(vec2), nullptr);
glEnableVertexAttribArray(0);
}
At initialization:
init_va1();
init_va2();
At draw:
glBindVertexArray(va1);
vec2 a1[] = {
vec2(0.0, 0.0),
vec2(0.1, 0.0),
vec2(0.1, 0.1),
vec2(0.0, 0.1),
};
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(a1), a1);
glUniform3f(polygon_color_loc, 0, 1, 0);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glBindVertexArray(va2);
vec2 a2[] = {
vec2(0.0, 0.0),
vec2(-0.1, 0.0),
vec2(-0.1, -0.1),
vec2(0.0, -0.1),
};
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(a2), a2);
glUniform3f(polygon_color_loc, 1, 0, 0);
glDrawArrays(GL_LINE_LOOP, 0, 4);
Whichever vertex array I initialize last will be drawn properly, and the other one will not be drawn. For example, if I call init_va1() and then init_va2(), the drawing using va2 will be shown, and the drawing using va1 will not. If I reorder the calls, then the drawing using va1 will be shown, and the drawing using va2 will not. How do I draw both vertex arrays?
glBufferSubData changes the data of the buffer that is currently bound to the specified target. The current ARRAY_BUFFER is a globale state. you need to bind the proper buffer object when you want to update the data store of the buffer:
glBindBuffer(GL_ARRAY_BUFFER, vb1);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(a1), a1);
glBindVertexArray(va1);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glBindBuffer(GL_ARRAY_BUFFER, vb2);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(a2), a2);
glBindVertexArray(va2);
glDrawArrays(GL_LINE_LOOP, 0, 4);
In contrast to the ARRAY_BUFFER, the Index buffers (ELEMENT_ARRAY_BUFFER) is stated in the Vertex Array Object. If you want to change the contents of an index buffer, it is also possible just to bind the the VAO in which the index buffer is stated.
Related
If I try to read the screen with glreadpixels and then draw the same thing again using gldrawpixels it works, BUT if and only if I use anything else to draw than gldrawarrays and gldrawelements (gluSphere/gluCylinder work just fine). I'm trying to draw an object to the screen and save the pixels in an array.
I tried reading/writing to front/back buffers, reading after I swap buffers, all to no avail.
here is the code that I use to draw the object: (please note that I do not use any kind of buffers outside of this scope).
void CCssample5View::DrawCylinder(Model obj)
{
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
Shader castingShader("casting.vs", "casting.fs");
Shader lightShader("light.vs", "light.fs");
GLuint MatrixID = glGetUniformLocation(castingShader.ID, "MVP");
GLuint ViewMatrixID = glGetUniformLocation(castingShader.ID, "V");
GLuint ModelMatrixID = glGetUniformLocation(castingShader.ID, "M");
GLuint textur = loadBMP_custom("flower.bmp");
GLuint TextureID = glGetUniformLocation(castingShader.ID , "myTextureSampler");
indexVBO(obj.vertices, obj.uvs, obj.normals, obj.indices, obj.indexed_vertices, obj.indexed_uvs, obj.indexed_normals);
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, obj.indexed_vertices.size() * sizeof(glm::vec3), &obj.indexed_vertices[0], GL_STATIC_DRAW);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, obj.indexed_uvs.size() * sizeof(glm::vec2), &obj.indexed_uvs[0], GL_STATIC_DRAW);
GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, obj.indexed_normals.size() * sizeof(glm::vec3), &obj.indexed_normals[0], GL_STATIC_DRAW);
GLuint elementbuffer;
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, obj.indices.size() * sizeof(unsigned short), &obj.indices[0], GL_STATIC_DRAW);
castingShader.use();
GLuint LightID = glGetUniformLocation(castingShader.ID, "LightPosition_worldspace");
computeMatricesFromInputs();
GLfloat gProjectionMatrix[16];
glGetFloatv(GL_PROJECTION_MATRIX, gProjectionMatrix);
glm::mat4 ProjectionMatrix = glm::make_mat4(gProjectionMatrix);// = glm::mat4(gProjectionMatrix);
GLfloat gViewMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, gViewMatrix);
glm::mat4 ViewMatrix = glm::make_mat4(gViewMatrix);// = glm::mat4(gProjectionMatrix);
glm::vec3 lightPos = glm::vec3(4, 4, 4);
glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glm::mat4 ModelMatrix1 = glm::mat4(1.0);
glm::mat4 MVP1 = ProjectionMatrix * ViewMatrix * ModelMatrix1;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textur);
glUniform1i(TextureID, 0);
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP1[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix1[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, // attribute
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 3rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
2, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
// Draw the triangles !
glDrawElements(
GL_TRIANGLES, // mode
obj.indices.size(), // count
GL_UNSIGNED_SHORT, // type
(void*)0 // element array buffer offset
);
//glFlush(); glFinish(); readScreen(screen, GL_RGB, true);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &uvbuffer);
glDeleteBuffers(1, &normalbuffer);
glDeleteBuffers(1, &elementbuffer);
glDeleteProgram(castingShader.ID);
glDeleteTextures(1, &textur);
glDeleteVertexArrays(1, &VertexArrayID);
}
These are my read and draw screen functions:
void CCssample5View::readScreen(GLubyte* screen, GLenum format, bool back)
{
check();
if (format == GL_RGB) {
check();
if (back) {
glReadBuffer(GL_BACK);
check();
}
else {
glReadBuffer(GL_FRONT);
check();
}
}
//glRasterPos2i(00, 00);
//glDisable(GL_DEPTH_TEST);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, w, h, format, GL_UNSIGNED_BYTE, screen);
glFlush();
glFinish();
bool found = false;
for (size_t u = 0; u <= w * h * 4; u++) {
if (screen[u] != 0) {
found = true;
break;
}
}
assert(found);
check();
}
void CCssample5View::drawScreen(GLubyte *screen, GLenum format, bool back)
{
glClear(GL_COLOR_BUFFER_BIT);
//glGetIntegerv(GL_CURRENT_RASTER_POSITION, rasterpos);
if (back) {
glDrawBuffer(GL_BACK);
}
else {
glDrawBuffer(GL_FRONT);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glDrawPixels(w, h, format, GL_UNSIGNED_BYTE, screen);
check();
glFlush();
glFinish();
}
Can not seem to figure out whats wrong when the drawing is perfect except the reading screen part..
I figured it out. All I had to do was add glUseProgram(0) at the very end of the draw cylinder function. After more than 3 weeks of looking into this.
I'm learning openGL programming from tutorials of Chernov # sparky engine on youtube. currently I have a vertex & a fragment shader with required classes for window ,shader etc management. I can use single vertex array object to draw on screen but when the same is done by creating a vertexArray class , it fails.
vertex array class :
#include"vertexArray.h"
namespace graphics{
VertexArray::VertexArray(){
glGenVertexArrays(1,&arrayID);
}
void VertexArray::addBuffer(Buffer* buffer, GLint index){
bind();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrayID);
glEnableVertexAttribArray(index);
glVertexAttribPointer(index, buffer->getComCount(), GL_FLOAT, GL_FALSE, 0, 0);
}
void VertexArray::bind() const{
glBindVertexArray(arrayID);
}
void VertexArray::unbind() const{
glBindVertexArray(0);
}
VertexArray::~VertexArray(){
}
}
my main.cpp file
#include"graphics\window.h"
#include"utils\reader.h"
#include"graphics\shader.h"
#include"math\vec.h"
#include"math\mat4.h"
#include"graphics\buffers\buffer.h"
#include"graphics\buffers\indexbuffer.h"
#include"graphics\buffers\vertexArray.h"
using namespace graphics;
using namespace utils;
using namespace math;
int main(){
Window window;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0, 0, 0, 1);
Reader read1("src/shaders/test.vert");
Reader read2("src/shaders/test.frag");
char * r1 = read1.getData();
char * r2 = read2.getData();
GLfloat vert[] = {
0, 0, 0,
0, 3, 0,
8, 0, 0,
8, 3, 0,
};
Buffer* vbo = new Buffer(vert,4*3,3);
GLushort indices[] = {
0,1,2,
1,3,2
};
indexBuffer ibo(indices,6);
Shader shader(r1, r2);
shader.enable();
#if 0
GLuint sprite1;
glGenVertexArrays(1, &sprite1);
glBindVertexArray(sprite1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sprite1);
vbo->bind();
glVertexAttribPointer(0, vbo->getComCount(), GL_FLOAT, 0, 0, 0);
shader.setUniformMat4("pr_matrix", mat4::orthographic(0.0f, 16.0f, 0.0f, 9.0f, -1.0f, 1.0f));
shader.setUniformMat4("ml_matrix", mat4::translation(vec3(0, 0, 0)));
shader.setUniform2f("light_pos", vec2(8.0f, 4.5f));
shader.setUniform4f("colour", vec4(0.2, 0.0, 0.4, 1));
glEnableVertexAttribArray(0);
glBindVertexArray(0);
GLuint sprite2;
glGenVertexArrays(1, &sprite2);
glBindVertexArray(sprite2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sprite2);
vbo->bind();
glVertexAttribPointer(5, vbo->getComCount(), GL_FLOAT, 0, 0, 0);
shader.setUniformMat4("pr_matrix", mat4::orthographic(0.0f, 16.0f, 0.0f, 9.0f, -1.0f, 1.0f));
shader.setUniformMat4("ml_matrix", mat4::translation(vec3(4, 3, 0)));
shader.setUniform2f("light_pos", vec2(8.0f, 4.5f));
shader.setUniform4f("colour", vec4(0.3, 0.0, 0.2, 1));
glEnableVertexAttribArray(0);
glBindVertexArray(0);
#endif
VertexArray vao;
vao.addBuffer(vbo, 0);
while (!window.closed()){
#if 0
window.clear();
glDrawArrays(GL_TRIANGLES, 0,6);
#endif
double x, y;
x = window.getX();
y = window.getY();
vao.bind();
ibo.bind();
shader.setUniform2f("light_pos", vec2((float) (x*16.0f/960.0f) , (float) (9- 9*y/540.0f)));
glDrawElements(GL_TRIANGLES, ibo.getCount(), GL_UNSIGNED_SHORT, 0);
window.update();
vao.unbind();
ibo.unbind();
}
return 0;
}
Please note that Everything works if I just create a vertex array to an GLuint variable in the main & use it .
I cant seem to find the issue here.
Any help is highly appreciated ..
You have to bind the data to the buffer (See glBufferData).
Vertex attribute buffers can be created like this:
GLfloat vert[] = {
0, 0, 0,
0, 3, 0,
8, 0, 0,
8, 3, 0,
};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*3*4, vert, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Element buffers can be created like this:
GLushort indices[] = {
0,1,2,
1,3,2
};
GLuint ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*3*2, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
A Vertex Array Object and the vertex attribute pointers are specified like this:
GLuint attr_index = 0; // attribute index according to the shader program
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(attr_index , 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(attr_index );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBindVertexArray( 0 );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Note, a Vertex Array Object stores all the information which you specify about the vertex attributes (format, size, attribute index ...) and it refers to the element array buffer.
Finally you can draw the mesh like this:
glBindVertexArray( vao );
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glBindVertexArray( 0 );
actually Im a bit confused about using glBufferSubData and glMapBuffer. In my program I'm loading a mesh of Triangles so i created a Struct of Vertex and initialized my VertexBuffer with the data of whole mesh. I implemented ray-casting and ray-triangle intersection. What im trying to do is, if my cursor intersects with the mesh, the intersected triangle changes his color as long its get intersected. Its working at the moment but when I try to load a bigger mesh with 50.000+ Vertices it doesnt work anymore. I am updating my whole VBO with glBufferData because I dont understand how I can update only Color of Triangles with glBufferSubData. Can someone explain me how I can update only the specific part (e.g. Color) of my VBO ?
struct Vertex
{
glm::vec3 Pos;
glm::vec3 Normal;
glm::vec3 Color;
};
VertexBuffer(void* vertices, size_t size)
{
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_DYNAMIC_DRAW);
glBindVertexArray(0);
}
void Render()
{
glBindVertexArray(vertexBuffer->VAO);
glUseProgram(Fill->program);
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "projection"), 1, GL_FALSE, glm::value_ptr(proj));
for (int j = 0; j < numVertices; j += 3){
if (intersectPlane(this->Vertices[j], this->Vertices[j + 1], this->Vertices[j + 2], ray, orig)){
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
this->Vertices[j].Color = glm::vec3(1.0, 0.0, 0.0);
this->Vertices[j + 1].Color = glm::vec3(1.0, 0.0, 0.0);
this->Vertices[j + 2].Color = glm::vec3(1.0, 0.0, 0.0);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), Vertices, GL_DYNAMIC_DRAW);
}
else{
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
this->Vertices[j].Color = glm::vec3(0.695f, 0.695f, 0.695f);
this->Vertices[j + 1].Color = glm::vec3(0.695f, 0.695f, 0.695f);
this->Vertices[j + 2].Color = glm::vec3(0.695f, 0.695f, 0.695f);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), Vertices, GL_DYNAMIC_DRAW);
}
}
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
GLuint posLoc = glGetAttribLocation(Fill->program, "Position");
GLuint norm = glGetAttribLocation(Fill->program, "Normal");
GLuint colo = glGetAttribLocation(Fill->program, "Color");
glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Pos));
glVertexAttribPointer(norm, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));
glVertexAttribPointer(colo, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Color));
glEnableVertexAttribArray(posLoc);
glEnableVertexAttribArray(norm);
glEnableVertexAttribArray(colo);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
glBufferSubData updates part (or the whole) of the buffer without the need to recreate it.
In your case you can do some calculus to know the position in bytes inside the buffer (so called "offset") of the edge currently selected, and update the buffer just for that pair of vertices.
glMapBuffer gives you a (virtual) pointer to the buffer. You can read or write to that address directly using your C/C++ functions. Be aware to "unmap" when done.
Now, your buffer layout is Pos,Normal,Color and repeat. So: PxPyPzNxNyNzCrCgCbPxPyPzNxNyNzCrCgCbPxPyPzNxNyNzCrCgCb... "interleaved data". You must be carefull with the positions (bytes) you update.
I am trying to draw 2 objects in OpenGL. The window/viewport is (0,0,950,1050). I am not sure this is the right way of doing it, but I thought so. I thought the idea was to create a VBO/VAO per object, bind it, set the data, and repeat that operation for each object.
Then when the objects are to be drawn:
set the shader
bind the data of the first object we want to draw using its vbo (say vbo1)
do the drawing call
bind the data of the next object we want to draw using its vbo (say vbo2)
do the drawing call
...
When I do this, I only get the points of the second object drawn on the screen, but with the color of the first object (it's blue instead of red).
My mistake must be obvious to any expert out there. What do I miss?
// BLUE -----------------------------------
GLuint vbo1, vao1;
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
float arr1[] = { 10, 10, 10, 110, 110, 110, 110, 10 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr1, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
// RED -----------------------------------
GLuint vbo2, vao2;
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
float arr2[] = { 400, 400, 400, 800, 800, 800, 800, 400 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr2, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
while (!glfwWindowShouldClose(window))
{
glClearColor(1, 1, 1, 0.1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(pointShader);
GLint loc;
loc = glGetUniformLocation(pointShader, "pointColor");
// it draws this one but with the color blue!
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
float ptColor2[3] = { 1, 0, 0 };
glUniform3fv(loc, 1, ptColor2);
glDrawArrays(GL_POINTS, 0, 4);
// it doesn't draw this one???
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
float ptColor1[3] = { 0, 0, 1 };
glUniform3fv(loc, 1, ptColor1);
glDrawArrays(GL_POINTS, 0, 4);
glfwSwapBuffers(window);
glfwWaitEvents();
}
EDIT 2 WORKING CODE
Thank you very much to both Reto Koradi and Datenwolf. Combining the answers, helped to come with the right answer. It's sad, these things are not explained properly in books. Hope this post will help other beginners (sorry if the result is a bit misleading, I swapped color between when I asked the question, and when I got the answer).
// RED -----------------------------------
GLuint vbo1, vao1;
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
float arr1[] = { 10, 10, 10, 110, 110, 110, 110, 10 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr1, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
// BLUE -----------------------------------
GLuint vbo2, vao2;
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
float arr2[] = { 400, 400, 400, 800, 800, 800, 800, 400 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr2, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
while (!glfwWindowShouldClose(window))
{
float ratio;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glClearColor(1, 1, 1, 0.1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(pointShader);
GLint loc;
loc = glGetUniformLocation(pointShader, "pointColor");
// red
glBindVertexArray(vao1);
float ptColor1[3] = { 1, 0, 0 };
glUniform3fv(loc, 1, ptColor1);
glDrawArrays(GL_POINTS, 0, 4);
// blue
glBindVertexArray(vao2);
float ptColor2[3] = { 0, 0, 1 };
glUniform3fv(loc, 1, ptColor2);
glDrawArrays(GL_POINTS, 0, 4);
glfwSwapBuffers(window);
glfwWaitEvents();
}
EDIT 3
Note though the order from the first code fragment for the VAO/VBO order declaration would also work. So the above version and the one below are both valid:
// RED -----------------------------------
GLuint vbo1, vao1;
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
float arr1[] = { 10, 10, 10, 110, 110, 110, 110, 10 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr1, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
// BLUE -----------------------------------
GLuint vbo2, vao2;
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
float arr2[] = { 400, 400, 400, 800, 800, 800, 800, 400 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr2, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
The only thing that was really missing in the code was glBindVertexArray.
The problem is in your draw loop, where you call:
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
It does not matter which GL_ARRAY_BUFFER is currently bound when you make the draw call. The correct buffer needs to be bound when you call glVertexAttribPointer(), which you correctly did in your setup code.
The VAOs track all your vertex setup state. So before each draw call, you need to bind the corresponding VAO by calling glBindVertexArray(), instead of the glBindBuffer() calls you have in the posted code:
glBindVertexArray(vao2);
glUniform3fv(...);
glDrawArrays(...);
glBindVertexArray(vao1);
glUniform3fv(...);
glDrawArrays(...);
You must create and bind the Vertex Array Object before specifying the vertex attribute data locations (glVertexAttribPointer). The VAO kind of takes ownership of the data that belongs to the VBO currently bound when making those calls.
(EDIT accidently submitted while still typing)
Assuming you have a core profile context, when you attempt to create that first buffer object, there's no VAO to bind it to yet, so the whole creation of the BO fails. Hence when you try to draw it, nothing gets drawn at all. But what you see drawn is the BO you intended to bind to the second VAO, but because you got the order of operations wrong it ends up in the first VAO.
My Vertex Buffer Object code is supposed to render textures nicely but instead the textures are being rendered oddly with some triangle shapes.
What happens - http://godofgod.co.uk/my_files/wrong.png
What is supposed to happen - http://godofgod.co.uk/my_files/right.png
This function creates the VBO and sets the vertex and texture coordinate data:
extern "C" GLuint create_box_vbo(GLdouble size[2]){
GLuint vbo;
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLsizeiptr data_size = 8*sizeof(GLdouble);
GLdouble vertices[] = {0,0, 0,size[1], size[0],0, size[0],size[1]};
glBufferData(GL_ARRAY_BUFFER, data_size, vertices, GL_STATIC_DRAW);
data_size = 8*sizeof(GLint);
GLint textcoords[] = {0,0, 0,1, 1,0, 1,1};
glBufferData(GL_ARRAY_BUFFER, data_size, textcoords, GL_STATIC_DRAW);
return vbo;
}
Here is some relavant code from another function which is supposed to draw the textures with the VBO.
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor4d(1,1,1,a/255);
glBindTexture(GL_TEXTURE_2D, texture);
glTranslated(offset[0],offset[1],0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_DOUBLE, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer (2, GL_INT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 1, 3);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
I would have hoped for the code to use the first three coordinates (top-left,bottom-left,top-right) and the last three (bottom-left,top-right,bottom-right) to draw the triangles with the texture data correctly in the most efficient way. I don't see why triangles should make it more efficient but apparently that's the way to go. It, of-course, fails for some reason.
I am asking what is broken but also am I going about it in the right way generally?
Thank you.
If you want to use the one VBO for both vertex and texture coordinates you need to group them using a struct.
Define your data:
typedef struct {
GLdouble x, y;
GLint s, t;
} VertexData;
VertexData data[] = {
// x y s t
{0.0, 0.0, 0, 0},
{0.0, size[1], 0, 1},
{size[0], 0.0, 1, 0},
{size[0], size[1], 1, 1}
};
Copy it into VBO:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), (GLvoid*)data, GL_STATIC_DRAW);
Set pointers. Note that stride is your struct's size and pointer itself serves as offset:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_DOUBLE, sizeof(VertexData), (GLvoid*)offsetof(VertexData, x));
glTexCoordPointer(2, GL_INT, sizeof(VertexData), (GLvoid*)offsetof(VertexData, s));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
And draw.
EDIT: Implemented offset with offsetof() as Bahbar suggested.
You're loading data twice to the vbo. The second call to glBufferData is replacing the first one. Then both calls to gl*Pointer actually use the same data when calling draw.