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.
Related
This is my code:
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
const int IMAGE_SIZE = 32;
GLFWwindow* window;
GLuint vao;
GLuint vbo;
int initWindow() {
// Initialize GLFW
if (!glfwInit()) {
cerr << "Error: Failed to initialize GLFW." << endl;
return 1;
}
// Set up GLFW window hints for OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Create window
window = glfwCreateWindow(IMAGE_SIZE * 20, IMAGE_SIZE * 20 + 60, "PBM Image", NULL, NULL);
if (!window) {
cerr << "Error: Failed to create GLFW window." << endl;
glfwTerminate();
return 1;
}
// Create context
glfwMakeContextCurrent(window);
// Set color and blendmode
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Create and bind VAO and VBO
glGenVertexArrays(1, &vao);
glBindVertexArray(vao); // Here is the spot where I get the exception
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
return 0;
}
void renderImage(vector<unsigned char> vertices) {
// Update VBO data
glBufferData(GL_ARRAY_BUFFER, vertices.size(), vertices.data(), GL_STATIC_DRAW);
// Set vertex attribute pointers
glVertexAttribPointer(0, 3, GL_UNSIGNED_BYTE, GL_FALSE, 3 * sizeof(unsigned char), (void*)0);
glEnableVertexAttribArray(0);
// Unbind VBO and VAO
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Set up projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, IMAGE_SIZE, 0.0, IMAGE_SIZE, 0.0, 1.0);
// Clear screen
glClear(GL_COLOR_BUFFER_BIT);
// Bind VAO
glBindVertexArray(vao);
// Draw points
glDrawArrays(GL_POINTS, 0, vertices.size() / 3);
// Unbind VAO
glBindVertexArray(0);
// Swap buffers
glfwSwapBuffers(window);
}
int main() {
if (initWindow()) return 1;
// Here comes the code that generates vector<unsigned char> vertices
renderImage(vertices);
getchar();
// Delete VAO and VBO
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
// Terminate GLFW
glfwTerminate();
return 0;
}
It uses glew to setup opengl and glfw for window handling. After initializing the window it generates vector<unsigned char> vertices which renderImage takes in. Afterwards it removes VAO, VBO and terminates GLFW. But it won't even come to that point because it throws the following exception at glBindVertexArray(vao);:
Exception thrown at 0x0000000000000000 in generator.exe: 0xC0000005: Access violation executing location 0x0000000000000000.
Here are my lib and include settings and folders:
VC++ Directories
Input
Lib Folder
Lib x64 Folder
Include GL
Include GLFW
glew needs to be initialized (see Initializing GLEW). If glew is not initialized, the OpenGL API function pointers are not set. Call glewInit() right after glfwMakeContextCurrent(window):
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
return 1;
I've been looking into how to make the bubble texture transparent but haven't found anything that would fit in my code. I have tried with glColor4f() but I might be putting it in the wrong place. I'm a total beginner in openGL and I've been given a basic code to which I need to add other objects in order to make a 2D scene. I also don't exactly know what every single line does.
These are the relevant pieces of code:
// Globals
GLuint locT; // location of "T" uniform variable in myShaderProgram
GLuint locT2;
// Textures
GLuint myBubblesTexture = 0;
// Shader program object for applying textures to our shapes
GLuint myShaderProgram;
// Vertex Buffer Object IDs for the ground texture object
GLuint bubblesPosVBO, bubblesColourVBO, bubblesTexCoordVBO, bubblesIndicesVBO;
// 1) Position Array - Store vertices as (x,y) pairs
static GLfloat bubblesVertices[] = {
-0.2f, -0.2f,
-0.2f, 0.2f,
0.2f, -0.2f,
0.2f, 0.2f
};
// 2) Colour Array - Store RGB values as unsigned bytes
static GLubyte bubblesColors[] = {
255, 0, 0, 255,
255, 255, 0, 255,
0, 255, 0, 255,
0, 255, 255, 255
};
// 3) Texture coordinate array (store uv coordinates as floating point values)
static float bubblesTextureCoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
// 4) Index Array - Store indices to quad vertices - this determines the order the vertices are to be processed
static GLubyte bubblesVertexIndices[] = { 0, 1, 2, 3 };
void init(int argc, char* argv[]);
void setupBubblesTextureVBO(void);
void display(void);
void drawTexturedBubblesVBO(void);
int _tmain(int argc, char* argv[])
{
init(argc, argv);
glutMainLoop();
// Shut down COM
shutdownCOM();
return 0;
}
void init(int argc, char* argv[]) {
// Initialise COM so we can use Windows Imaging Component
initCOM();
// Initialise FreeGLUT
glutInit(&argc, argv);
glutInitContextVersion(3, 3);
glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(1200, 800);
glutInitWindowPosition(64, 64);
glutCreateWindow("Funky Fish");
// Register callback functions
glutDisplayFunc(display);
// Initialise GLEW library
GLenum err = glewInit();
// Setup colour to clear the window
glClearColor(0.2f, 0.2f, 0.8f, 0.0f);
glLineWidth(9.0f);
//Load textures
myBubblesTexture = fiLoadTextureA("bubbles.png");
//Shader setup
myShaderProgram = setupShaders(string("Shaders\\basic_vertex_shader.txt"), string("Shaders\\basic_fragment_shader.txt"));
// Get uniform location of "T" variable in shader program (we'll use this in the play function to give the uniform variable "T" a value)
locT = glGetUniformLocation(myShaderProgram, "T");
//Setup the bubbles using VBO
setupBubblesTextureVBO();
}
// our bubbles
void setupBubblesTextureVBO(void) {
// setup VBO for the quad object position data
glGenBuffers(1, &bubblesPosVBO);
glBindBuffer(GL_ARRAY_BUFFER, bubblesPosVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(bubblesVertices), bubblesVertices, GL_STATIC_DRAW);
// setup VBO for the quad object colour data
glGenBuffers(1, &bubblesColourVBO);
glBindBuffer(GL_ARRAY_BUFFER, bubblesColourVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(bubblesColors), bubblesColors, GL_STATIC_DRAW);
// setup VBO for the quad object texture coord data
glGenBuffers(1, &bubblesTexCoordVBO);
glBindBuffer(GL_ARRAY_BUFFER, bubblesTexCoordVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(bubblesTextureCoords), bubblesTextureCoords, GL_STATIC_DRAW);
// setup quad vertex index array
glGenBuffers(1, &bubblesIndicesVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bubblesIndicesVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(bubblesVertexIndices), bubblesVertexIndices, GL_STATIC_DRAW);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw our bubble
drawTexturedBubblesVBO();
glutSwapBuffers();
}
void drawTexturedBubblesVBO(void) {
glUseProgram(myShaderProgram);
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Move our bubble to the centre of the screen
GUMatrix4 T = GUMatrix4::translationMatrix(0.0f, 0.0f, 0.0f);
glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);
// Bind each vertex buffer and enable
// The data is still stored in the GPU but we need to set it up (which also includes validation of the VBOs behind-the-scenes)
// Bind texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, myBubblesTexture);
glUniform1i(glGetUniformLocation(myShaderProgram, "texture"), 0);
glEnable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, bubblesPosVBO);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, bubblesColourVBO);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bubblesTexCoordVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(2);
// Bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bubblesIndicesVBO);
// Draw the object - same function call as used for vertex arrays but the last parameter is interpreted as an offset into the currently bound index buffer (set to 0 so we start drawing from the beginning of the buffer).
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (GLvoid*)0);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glDisable(GL_TEXTURE_2D);
// use to force disable our shaderprogram
// glUseProgram(0);
}
The code looks OK so:
Does your Texture have an alpha channel?
Does your OpenGL context pixel format has Alpha channel buffer?
What kind of transparency you want (whole texture have the same transparency, or the transparency should be modulated)?
The glColor4f(1.0,1.0,1.0,alpha) will work only if your textures are configured to be modulated by glColor and have nonzero alpha channel set so you need to add:
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
call after binding the texture to make it work.
In case you do not have alpha channel (in texture or in pixelformat) you can use:
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
Also take a look at:
OpenGL - How to create Order Independent transparency?
I am trying to make a triangle and I'm using GLEW, GLFW and GLM as extensions of OpenGL.
Here's the code I have:
#include <stdlib.h>
#include <stdio.h>
#include <gl\glew.h>
#include <GLFW\glfw3.h>
#include <glm\glm.hpp>
using namespace glm;
int main()
{
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want OpenGL 3.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); //We don't want the old OpenGL
// Open a window and create its OpenGL context
GLFWwindow* window; // (In the accompanying source code, this variable is global)
window = glfwCreateWindow(1024, 768, "Tutorial 01", 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");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window); // Initialize GLEW
glewExperimental = true; // Needed in core profile
if (glewInit() != GLEW_OK)
{
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// An array of 3 vectors which represents 3 vertices
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,
};
// This will identify our vertex buffer
GLuint vertexbuffer;
// Generate 1 buffer, put the resulting identifier in vertexbuffer
glGenBuffers(1, &vertexbuffer);
// The following commands will talk about our 'vertexbuffer' buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
// Give our vertices to OpenGL.
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
do {
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. 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
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
glDisableVertexAttribArray(0);
// 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);
}
Edit
The code is not displaying the white triangle its just opens the window and shows empty black.
Also at first I added the code I messed around with, which is missing part of the code. However it still does not produce the white triangle.
Do I need to use a shader for OpenGL 3.3?
You need to use a shader or you won't see anything. If you do see something then that is unspecified behavior. Which highly depend on each individual driver.
You could try fiddling with the clear color and clear the screen:
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
The tutorial was able to get a white triangle on a black background. On my computer the opposite was the case.
The tutorial also points out:
If you’re on lucky, you can see the result (don’t panic if you don’t)
So read the rest of the tutorial, it also includes a shader.
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);
I just get a black screen when I try to use a vbo. I'm using GLFW with GLEW. It does the same with textures but I didn't use textures to see if that'd work, but for some reason it's not. I had it working but I made some changes to the code, so I think I may have done something. PS: If the code has an error in it, let me know, as I removed code that doesn't affect rendering and I may have deleted important code on accident
Here is main.cpp, with some stuff that doesn't affect OpenGL removed:
//Include all OpenGL stuff, such as gl.h, glew.h, and glfw3.h
#include "gl.h"
//Include a header which adds some functions for loading shaders easier, there is nothing wrong with this code though
#include "shader.h"
float data[3][3] = {
{0.0, 1.0, 0.0},
{-1.0, -1.0, 0.0},
{1.0, -1.0, 0.0}
};
int main()
{
if (!glfwInit())
return 1;
GLFWwindow* window;
window = glfwCreateWindow(800, 600, "VBO Test", NULL, NULL);
if (!window)
{
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
if (GLEW_OK != glewInit())
{
return 1;
glfwTerminate();
}
//There are normal error handling stuff I do to ensure everything is loaded properly, so the shaders not loading isn't a concern as it'll clearly tell me :)
GLuint vertexShader = loadShader("shader.vert", GL_VERTEX_SHADER);
GLuint fragmentShader = loadShader("shader.frag", GL_VERTEX_SHADER);
GLuint program = createProgram(vertexShader, fragmentShader);
//Also, the shader files should make everything I draw yellow, and they are not defective
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glColorPointer(3, GL_FLOAT, 0, 0);
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
glUsePorgram(program);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
shader.vert
void main(void)
{
gl_Position = gl_Vertex;
}
shader.frag
void main()
{
//Set fragment
gl_FragColor = vec4( 1.0, 1.0, 0.0, 1.0 );
}
The main thing that jumps to mind is not enabling the client states for vertex and colour pointers.
Since the colour and position data overlaps, the colours will look a little strange. I'd start with just the glVertexPointer and glEnableClientState(GL_VERTEX_ARRAY), using a single glColor3f call. Then add a colour array later.
Also, you're buffering the same data to the same VBO twice. The VBO only needs to be bound before one call to glBufferData and the gl*Pointer functions.
Personally I don't like the 2D array, even though it probably works when declared statically. OpenGL will take data out of memory linearly. Using an array of structs can be quite nice.
See this for an small example:
http://goanna.cs.rmit.edu.au/~pknowles/SimpleVBO.c