How to "upgrade" to OpenGL 3.3 on Ubuntu 18.04.3 - c++

I've been reading a lot about this but haven't been able to resolve anything yet. I am trying to draw a colored triangle with OpenGL3 but I get the following error:
terminate called after throwing an instance of 'std::runtime_error' what(): Compilation error for vertex shader (from file ./TP1/shaders/triangle.vs.glsl): 0:1(10): error: GLSL 3.30 is not supported. Supported versions are: 1.10, 1.20, 1.30, 1.00 ES, 3.00 ES, 3.10 ES, and 3.20 ES
When I run glxinfo | grep -i opengl I get:
OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) HD Graphics 6000 (Broadwell GT3)
OpenGL core profile version string: 3.3 (Core Profile) Mesa 19.0.8
OpenGL core profile shading language version string: 4.50
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL version string: 3.0 Mesa 19.0.8
OpenGL shading language version string: 4.50
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile
OpenGL extensions:
OpenGL ES profile version string:
OpenGL ES 3.1 Mesa 19.0.8
OpenGL ES profile shading language version string:
OpenGL ES GLSL ES 3.10
OpenGL ES profile extensions:
I tried export MESA_GL_VERSION_OVERRIDE=3.3 which enables me to execute the code but I just get a weird triangle, not a nice equilateral multicolored one.
Here's my full code:
#include <glimac/SDLWindowManager.hpp>
#include <GL/glew.h>
#include <iostream>
#include <glimac/Program.hpp>
#include <glimac/FilePath.hpp>
using namespace glimac;
int main(int argc, char** argv) {
// Initialize SDL and open a window
SDLWindowManager windowManager(800, 600, "GLImac");
// Initialize glew for OpenGL3+ support
GLenum glewInitError = glewInit();
if(GLEW_OK != glewInitError) {
std::cerr << glewGetErrorString(glewInitError) << std::endl;
return EXIT_FAILURE;
}
std::cout << "OpenGL Version : " << glGetString(GL_VERSION) << std::endl;
std::cout << "GLEW Version : " << glewGetString(GLEW_VERSION) << std::endl;
//load shaders and tell OpenGL to use them
FilePath applicationPath(argv[0]);
Program program = loadProgram(applicationPath.dirPath() + "shaders/triangle.vs.glsl",
applicationPath.dirPath() + "shaders/triangle.fs.glsl");
program.use();
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//triangle data
GLfloat vertices[] = { -0.5f, -0.5f, 1.f, 0.f, 0.f, //2 coordinates + 1 0 0 color
0.5f, -0.5f, 0.f, 1.f, 0.f,
0.0f, 0.5f, 0.f, 0.f, 1.f };
glBufferData(GL_ARRAY_BUFFER, (15*(sizeof(float))), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
const GLuint VERTEX_ATTR_POSITION = 3;
const GLuint VERTEX_ATTR_COLOR = 8;
glEnableVertexAttribArray(VERTEX_ATTR_POSITION);
glEnableVertexAttribArray(VERTEX_ATTR_COLOR);
const GLvoid* bouche;
glVertexAttribPointer(VERTEX_ATTR_POSITION, 2, GL_FLOAT, GL_FALSE, (0*sizeof(GL_FLOAT)), bouche);
glVertexAttribPointer(VERTEX_ATTR_COLOR, 3, GL_FLOAT, GL_FALSE, (2*sizeof(GL_FLOAT)), bouche);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(VERTEX_ATTR_POSITION, 2, GL_FLOAT, GL_FALSE, (2*sizeof(GL_FLOAT)), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Application loop:
bool done = false;
while(!done) {
// Event loop:
SDL_Event e;
while(windowManager.pollEvent(e)) {
if(e.type == SDL_QUIT) {
done = true; // Leave the loop after this iteration
}
}
//clean window
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
// Update the display
windowManager.swapBuffers();
}
//liberate allocated memory on GPU (the vbo and vao)
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
return EXIT_SUCCESS;
}

When you use glew, then enable additional extensions by glewExperimental = GL_TRUE;. See the GLEW documentation which says:
GLEW obtains information on the supported extensions from the graphics driver. Experimental or pre-release drivers, however, might not report every available extension through the standard mechanism, in which case GLEW will report it unsupported. To circumvent this situation, the glewExperimental global switch can be turned on by setting it to GL_TRUE before calling glewInit(), which ensures that all extensions with valid entry points will be exposed.
glewExperimental = GL_TRUE;
GLenum glewInitError = glewInit();
if(GLEW_OK != glewInitError) {
std::cerr << glewGetErrorString(glewInitError) << std::endl;
return EXIT_FAILURE;
}
When an named buffer object is bound to the target GL_ARRAY_BUFFER, then the last parameter of glVertexAttribPointer is treated as a byte offset into that buffer.
When glVertexAttribPointer is called, then the vertex array specification is stored in the state vector of the currently bound vertex array object. The buffer which is currently bound to the target GL_ARRAY_BUFFER is associated to the attribute and the name (value) of the object is stored in the state vector of the VAO.
Further note, that the 5th parameter (stride) of glVertexAttribPointer, specifies the byte offset between consecutive generic vertex attribute.
This means before the call of glVertexAttribPointer the Vertex Array Object and the Vertex Buffer Object have to be bound.
The stride parameter has to be 5*sizeof(Glfloat), because the vertex attributes consist of the 5 GLfloat values (x, y, r, g, b).
The offset for VERTEX_ATTR_POSITION is 0 and for VERTEX_ATTR_COLOR it is 2*sizeof(GLfloat), because (r, g b) is after (x, y). Note, that GL_FLOAT is an enumerator constant and not data type, so 2*sizeof(GL_FLOAT) doesn't do what you expect it to do.
//triangle data
GLfloat vertices[] = { -0.5f, -0.5f, 1.f, 0.f, 0.f, //2 coordinates + 1 0 0 color
0.5f, -0.5f, 0.f, 1.f, 0.f,
0.0f, 0.5f, 0.f, 0.f, 1.f };
// create vertex buffer object
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// vertex array object
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// specify the array of generic vertex attribute data
glBindBuffer(GL_ARRAY_BUFFER, vbo); // if "vbo" is still bound then that would not be necessary
glVertexAttribPointer(VERTEX_ATTR_POSITION, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), nullptr);
glVertexAttribPointer(VERTEX_ATTR_COLOR, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), 2*sizeof(GLfloat));
glEnableVertexAttribArray(VERTEX_ATTR_POSITION);
glEnableVertexAttribArray(VERTEX_ATTR_COLOR);
// the following is not necessary, you can let them bound
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
Make sure that the vertex attribute indices are correct:
const GLuint VERTEX_ATTR_POSITION = 3;
const GLuint VERTEX_ATTR_COLOR = 8;
3 and 8 are possible but seem strange. Not this should be the resource indices of the attributes which may be set by Layout qualifier or can be get by glGetAttribLocation after the program is linked.
By the way the coordinates for an equilateral triangle are for example:
GLfloat vertices[] = {
x y r g b
-0.866f, -0.5f, 1.f, 0.f, 0.f,
0.866f, -0.5f, 0.f, 1.f, 0.f,
0.0f, 1.0f, 0.f, 0.f, 1.f };

Related

How to draw two or more triangles in OpenGL?

Can someone show show me how I can modify my code so I can draw more than one triangle?
I'm hoping to accomplish something like the picture shown here:
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
// Include GLEW
#include <GL/glew.h>
// Include GLFW
#include <GLFW/glfw3.h>
GLFWwindow* window;
// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;
#include <common/shader.hpp>
int main(void)
{
// Initialise GLFW
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
window = glfwCreateWindow(1024, 768, "Tutorial 04 - Colored Cube", NULL, NULL);
if (window == NULL) {
fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders("TransformVertexShader.vertexshader", "ColorFragmentShader.fragmentshader");
// Get a handle for our "MVP" uniform
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
int verticeCount = 3;
static const GLfloat g_vertex_buffer_data[] = {
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
};
static const GLfloat g_color_buffer_data[] = {
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
};
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);
GLuint colorbuffer;
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
do {
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
glm::mat4 MVP = glm::mat4(1.0);
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, verticeCount * 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
// Cleanup VBO and shader
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &colorbuffer);
glDeleteProgram(programID);
glDeleteVertexArrays(1, &VertexArrayID);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
It's actually right in front of your nose.
Triangles are defined by 3 vertices.
static const GLfloat g_vertex_buffer_data[] = {
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
};
Here, you initialized your vertex data array with 3, 3-dimensional vertices. That's 1 triangle.
Adding more triangles, i.e. 3 sets of 3 vertices, to this array is all you need to do, along with extending the g_color_buffer_data array and changing verticeCount accordingly.
So this:
static const GLfloat g_vertex_buffer_data[] = {
-0.50f, +0.50f, +0.00f,
+0.50f, +0.50f, +0.00f,
+0.50f, -0.50f, +0.00f,
-0.50f, -0.25f, +0.00f,
-0.50f, -0.50f, +0.00f,
-0.25f, -0.50f, +0.00f,
};
static const GLfloat g_color_buffer_data[] = {
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
};
would give you 2 triangles: 1 red, 1 blue.
You could also define verticeCount as:
int verticeCount = sizeof(g_vertex_buffer_data) / (sizeof(g_vertex_buffer_data[0]) * 3);
(Thread on finding the size of a C-style array in C++)
This way you won't manually have to change it.
You can always create a new vertex buffer, but it is usually a good idea to implement vertex and fragment shaders instead. If you choose to use shaders, you can draw the buffer, transform the vertex shader, then draw the buffer again. Fragment shaders also provide a better way of specifying color dynamically. You can read more and see some examples at https://learnopengl.com/Getting-started/Shaders

Creating a second VAO and drawing two shapes in OpenGL 4

I am trying to solve the experiments in the book Anton's OpenGL 4 Tutorials. In the first chapter's experiments it ask to create a second VAO to draw 2 shapes instead of one but I have no clue how to do this, how can a second be displayed simultaneously?
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
int main () {
// start GL context and O/S window using the GLFW helper library
if (!glfwInit ()) {
fprintf (stderr, "ERROR: could not start GLFW3\n");
return 1;
}
GLFWwindow* window = glfwCreateWindow (640, 480, "Hello Triangle", NULL, NULL);
if (!window) {
fprintf (stderr, "ERROR: could not open window with GLFW3\n");
glfwTerminate();
return 1;
}
glfwMakeContextCurrent (window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit ();
// get version info
const GLubyte* renderer = glGetString (GL_RENDERER); // get renderer string
const GLubyte* version = glGetString (GL_VERSION); // version as a string
printf ("Renderer: %s\n", renderer);
printf ("OpenGL version supported %s\n", version);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable (GL_DEPTH_TEST); // enable depth-testing
glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
GLfloat points[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
GLuint vbo = 0;
glGenBuffers (1, &vbo);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, 18 * sizeof (float), points, GL_STATIC_DRAW);
GLuint vao = 0;
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
glEnableVertexAttribArray (0);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
//second vao
GLuint vao_two = 0;
glGenVertexArrays(1, &vao_two);
glBindVertexArray(vao_two);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
const char* vertex_shader =
"#version 400\n"
"in vec3 vp;"
"in vec3 vp2;"
"void main() {"
" gl_Position = vec4(vp.x, vp.y + 0.2, vp.z, 1.0);"
" gl_Position2 = vec4(vp2.x, vp2.y - 0.9, vp2.z, 1.0);"
"}";
const char* fragment_shader =
"#version 400\n"
"out vec4 frag_colour;"
"void main () {"
" frag_colour = vec4 (0.0, 1.0, 0.0, 1.0);"
"}";
GLuint vs = glCreateShader (GL_VERTEX_SHADER);
glShaderSource (vs, 1, &vertex_shader, NULL);
glCompileShader (vs);
GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
glShaderSource (fs, 1, &fragment_shader, NULL);
glCompileShader (fs);
GLuint shader_programme = glCreateProgram();
glAttachShader (shader_programme, fs);
glAttachShader (shader_programme, vs);
glLinkProgram(shader_programme);
glClearColor(0.6f, 0.6f, 0.6f, 0.0f);
while (!glfwWindowShouldClose (window)) {
// wipe the drawing surface clear
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram (shader_programme);
glBindVertexArray (vao);
// draw points 0-3 from the currently bound VAO with current in-use shader
glDrawArrays (GL_TRIANGLES, 0, 6);
glBindVertexArray (vao_two);
glDrawArrays (GL_TRIANGLES, 0, 6);
// update other events like input handling
glfwPollEvents ();
// put the stuff we've been drawing onto the display
glfwSwapBuffers (window);
}
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
Actually, you are drawing two different shapes, however, because you use the same vertex buffer object in both vertex attribute objects (vao and vao_two) they have the same coordinates and they overlap.
Try to make 2 GLfloat arrays of points with different coordinates and attribute each one to a different vertex buffer object and then each vertex buffer object to a different vertex attribute object, then your shapes will be distinct.
First bind the buffers and then draw them all:
glBindVertexArray(vao);
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLES, 0, 6);
Alternatively you can draw first the first shape and then the second:
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLES, 3, 3);

OpenGL - rebinding glBindVertexArray doesn't draw anything to the screen

I'm just starting out trying to learn opengl, and in the process of decoupling various parts of the code into classes I'm running into issues.
This is a pretty simple question. In the following code, it draws the image to the screen if the glBindVertexArray(0) at the bottom of the Mesh constructor is commented out, but the image is not drawn if I put it in.
There is a glBindVertexArray(vao) command RIGHT before the glDrawElements call in the Mesh.draw() function, so it seems like it should work, but it doesn't.
Main code:
int main(int argc, char*argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0)
std::cout << "SDL did not intizlize. SDL Error: " << SDL_GetError() << std::endl;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_Window* window = SDL_CreateWindow("OpenGL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
SDL_GLContext context = SDL_GL_CreateContext(window);
glewExperimental = GL_TRUE;
GLenum glewTest = glewInit();
if (glewTest != GLEW_OK)
std::cout << glewGetErrorString(glewTest) << std::endl;
std::cout << glGetError() << std::endl;
Mesh mesh;
Shaders shaders("basicShader");
Texture texture("kitten.png");
//Loop stuff
bool quit = false;
SDL_Event e;
double frameCounter = 0;
double time = SDL_GetTicks();
while (!quit) {
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
quit = true;
}
if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.sym == SDLK_ESCAPE)
quit = true;
}
}
++frameCounter;
if (SDL_GetTicks() - time >= 500) {
std::cout << "FPS: " << frameCounter / ((SDL_GetTicks() - time) / 1000) << std::endl;
frameCounter = 0;
time = SDL_GetTicks();
}
// Clear the screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
mesh.draw();
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Swap buffers
SDL_GL_SwapWindow(window);
}
mesh.~Mesh();
SDL_GL_DeleteContext(context);
SDL_Quit();
return 0;
}
Mesh class code:
Mesh::Mesh() {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
GLfloat vertices[] = {
-0.5f, 0.5f, 0.0, 0.0,
0.5f, 0.5f, 1.0, 0.0,
0.5f, -0.5f, 1.0, 1.0,
-0.5f, -0.5f, 0.0, 1.0
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &ebo);
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);
//glBindVertexArray(0);
}
void Mesh::draw() {
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glBindVertexArray(0);
}
Mesh::~Mesh() {
glDeleteVertexArrays(1, &vao);
}
I also have shader setup code not posted here, which calls glVertexArrayPointer() and glEnableVertexAttribArray() to set up the vertex attributes.
The problem is with the glVertexAttribPointer() and glEnableVertexAttribArray() calls that you make while setting up your shader. Both of these calls modify state of the current VAO.
If you call:
glBindVertexArray(0);
at the end of setting up your mesh, 0 is now your current VAO (which is a legal VAO in the Compatibility Profile, but not in the Core Profile). So calls to glVertexAttribPointer() and glEnableVertexAttribArray() you make after this will now modify the state in VAO 0.
When you make the call to bind your VAO at the start of your draw() method:
glBindVertexArray(vao);
you're using all the state in your mesh VAO. Which in turn means that the state you set up in VAO 0 is not used. Since you never made glVertexAttribPointer() and glEnableVertexAttribArray() calls while your mesh VAO was bound, the vertex attributes are now not set up at all.
You were really just lucky that it worked when you did not unbind the VAO at the end of the constructor. Since the mesh VAO was still bound while you set up your shader, the glVertexAttribPointer() and glEnableVertexAttribArray() calls modified your mesh VAO state, which produced the desired result. But this would most likely fail miserably if you ever use more than one mesh/shader.
You really need to set up the vertex state while you set up your mesh, while the VAO for the specific mesh is bound. The following calls all modify VAO state, and must be made while the correct VAO is bound:
glEnableVertexAttribArray(...)
glDisableVertexAttribArray(...)
glVertexAttribPointer(...)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)
Modifying vertex setup state while setting up a shader program is also conceptually questionable. The vertex setup state is not part of the shader program state.

glDrawArrays only draws a single point at the origin (OpenGL with glut on ubuntu)

I am trying to display a simple triangle with OpenGL (I am using freeglut3-dev and libglew1.6 on Ubuntu 12.04 and coding in NetBeans 7.2). The code compiles and links with no problems, but displays only a blank screen (with initialized colour) but only a single white point at the origin (instead of 3 points for each of the triangle vertices). My code is below:
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include "math_3d.h"
GLuint VBO;
static void RenderSceneCB()
{
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glutSwapBuffers();
}
static void InitializeGlutCallbacks()
{
glutDisplayFunc(RenderSceneCB);
}
static void CreateVertexBuffer()
{
Vector3f Vertices[3];
Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f);
Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f);
Vertices[2] = Vector3f(0.0f, 1.0f, 0.0f);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowSize(1024, 768);
glutInitWindowPosition(100, 100);
glutCreateWindow("Tutorial 03");
InitializeGlutCallbacks();
// Must be done after glut is initialized!
GLenum res = glewInit();
if (res != GLEW_OK) {
fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
return 1;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
CreateVertexBuffer();
glutMainLoop();
return 0;
}
Here is a screenshot of what I see:
Here is a picture of what it should look like:
I am following this tutorial. Vector3f is just a structure with three data members: x, y, z.
Read the next chapter of the tutorial, it explains it all.
A vertex is simply a set of attributes, which are referenced by their number (0 in your case). This number however doesn't tell the GL what the data are, and thus how to use them. With the old API you had specific vertex specification functions for each attribute; glVertexPointer() was used to provide position attributes, glTexCoordPointer() texture coordinates, etc. Today it is up to you to use the attributes the way you want, through shaders, which are explained in the next chapter of your tutorial.

Vertex Buffer Object not drawing in SDL window

I'm just using the opengl SDL template with Xcode, and everything runs fine. I removed the Atlantis code, and changed the main extension to .mm, then added some testing code to drawGL. Drawing a simple triangle (using immediate mode) at this point inside drawGL gives me a white triangle, but when I add the code to draw using a vertex buffer object, i just get a black window.
Here is my VBO drawing code:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity();
GLuint buffer;
float vertices[] = {
0.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 0.0f,
1.0f,-1.0f, 0.0f
};
// VBO doesn't work :(
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 9, vertices, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableClientState(GL_VERTEX_ARRAY);
Your glVertexPointer() call looks suspect for VBO usage. I think you need a BUFFER_OFFSET construct instead of the vertices pointer.