Vertex buffer object, first attempt. Blank screen!

Hi.

I’ve not used vertex buffer objects before but am trying to get up-to-date with current OpenGL practices.

The following results in a blank green screen where I’d expect to see a green screen and a small triangle. Is there anything obviously wrong with the code? The implementations I’ve used definitely support GL_ARB_vertex_buffer_object.


#define GL_GLEXT_PROTOTYPES 1

#include <assert.h>
#include <GL/glut.h>
#include <GL/glext.h>

#define CHECK_GL_ERROR (assert (glGetError() == GL_NO_ERROR))

typedef float vector3 [3];

static const vector3 triangle [] = {
  {0.0,  0.0,  0.0}, {1.0, 0.0, 0.0},  /* v0, c0 */
  {10.0, 10.0, 0.0}, {0.0, 1.0, 0.0},  /* v1, c1 */
  {0.0,  10.0, 0.0}, {0.0, 0.0, 1.0},  /* v2, c2 */
};
static const int indices [] = {0, 1, 2};
static GLuint buffer_data_id;
static GLuint buffer_index_id;

static void
reshape (int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho (0, w, 0, h, -1, 100);
}

static void
init (void)
{
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();

  /* Create buffer for vertex and color data. */
  glGenBuffers (1, &buffer_data_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);
  CHECK_GL_ERROR;

  /* Allocate and load data. */
  glBufferData (GL_ARRAY_BUFFER, sizeof (triangle), triangle, GL_STATIC_DRAW);
  CHECK_GL_ERROR;

  /* Notify GL that first vertex is at offset 0. */
  glVertexPointer (3, GL_FLOAT, sizeof (vector3), NULL);
  CHECK_GL_ERROR;

  /* Notify GL that first color is at (sizeof (vector3)). */
  glColorPointer (3, GL_FLOAT, sizeof (vector3), (void *) (sizeof (vector3)));
  CHECK_GL_ERROR;

  /* Create index buffer. */
  glGenBuffers (1, &buffer_index_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer_index_id);
  CHECK_GL_ERROR;

  /* Allocate and load data. */
  glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices, GL_STATIC_DRAW);
  CHECK_GL_ERROR;
}

static void
display (void)
{
  glClearColor (0.3f, 0.6f, 0.3f, 1.0f);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  /* Bind vertex and element buffers. */
  glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer_index_id);
  CHECK_GL_ERROR;

  /* Enable vertex and color arrays. */
  glEnableClientState (GL_VERTEX_ARRAY);
  CHECK_GL_ERROR;
  glEnableClientState (GL_COLOR_ARRAY);
  CHECK_GL_ERROR;

  /* Draw data. */
  glDrawElements (GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, NULL);
  CHECK_GL_ERROR;

  glFlush();
  CHECK_GL_ERROR;
}

int
main (int argc, char **argv)
{
  glutInit (&argc, argv);
  glutCreateWindow ("single triangle");
  glutDisplayFunc (display);
  glutReshapeFunc (reshape);
  init ();

  glutMainLoop ();
  return 0;
}


static const int indices [] = {0, 1, 2};

Should read:


static const unsigned char indices [] = {0, 1, 2};

Doesn’t entirely fix the problem but I do at least “something” onscreen.

I made many changes to your code and I got your desired effect. I use this manner always



// test.cpp : main project file.

#include "stdafx.h"
#include <iostream>
#include <vector>

#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/glext.h>
#pragma comment( lib, "glew32.lib" )
#pragma comment ( lib, "glut32.lib" )
typedef float vector3 [3];

static const vector3 triangle [] = {
  {0.0,  0.0,  0.0}, //v0
  {10.0, 10.0, 0.0}, //v1
  {0.0,  10.0, 0.0}, //v2
  {1.0, 0.0, 0.0},   //c0
  {0.0, 1.0, 0.0},   //c1
  {0.0, 0.0, 1.0}};  //c2

static GLuint buffer_data_id;

static void
reshape (int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho (0, 20, 0, 20, 0, 100); // I have used these values instead of w and h
}

static void
init (void)
{
  glewInit();
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();

  /* Create buffer for vertex and color data. */
  glGenBuffers (1, &buffer_data_id);
  glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);

  /* Allocate and load data. */
  glBufferData (GL_ARRAY_BUFFER, sizeof (triangle), triangle, GL_STATIC_DRAW);

  /* Notify GL that first vertex is at offset 0. */
  glVertexPointer (3, GL_FLOAT, 0, NULL); //offset is now 0

  /* Notify GL that first color is at (sizeof (vector3)). */
glColorPointer (3, GL_FLOAT, 0, (void *) (sizeof (vector3) * 3 )); //osffset is now 0
  /* Enable vertex and color arrays. */
  glEnableClientState (GL_VERTEX_ARRAY);
  glEnableClientState (GL_COLOR_ARRAY);

}

static void
display (void)
{
  glClearColor (0.3f, 0.6f, 0.3f, 1.0f);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


 glDrawArrays( GL_TRIANGLES, 0, 3 ); //I used this function instead of glDrawElements 

  glFlush();
}

int main(int argc, _TCHAR * argv )
{
  glutInit (&argc, (char**)argv);
  glutInitDisplayMode( GLUT_RGB );
  glutCreateWindow ("single triangle");
  glutDisplayFunc (display);
  glutReshapeFunc (reshape);
  init();

  glutMainLoop ();
   return 1;
}


Hi.

Thanks for the reply. I do have a few questions, however.


static const vector3 triangle [] = {
  {0.0,  0.0,  0.0}, //v0
  {10.0, 10.0, 0.0}, //v1
  {0.0,  10.0, 0.0}, //v2
  {1.0, 0.0, 0.0},   //c0
  {0.0, 1.0, 0.0},   //c1
  {0.0, 0.0, 1.0}};  //c2

I’m not actually concerned about performance at the moment (having working code is obviously better) but I’ve been advised against packing data like that due to the fact that modern cards like data interleaved for cache locality. I’m also worried that you changed the data in order to fix the problem… I’d rather find out what I was doing wrong with my original data! :slight_smile:


  glOrtho (0, 20, 0, 20, 0, 100); // I have used these values instead of w and h

Any particular reason?


 glDrawArrays( GL_TRIANGLES, 0, 3 ); //I used this function instead of glDrawElements 


Why did you use glDrawArrays? I’ve been following various examples around the web and they all use glDrawElements.

My current code looks like this:


#define GL_GLEXT_PROTOTYPES 1

#include <assert.h>
#include <GL/glut.h>
#include <GL/glext.h>

#define CHECK_GL_ERROR (assert (glGetError() == GL_NO_ERROR))

typedef float vector3 [3];

static const vector3 triangle [] = {
  {10.0,  200.0, 0.0}, {1.0, 1.0, 1.0},  /* v0, c0 */
  {600.0, 10.0,  0.0}, {0.0, 0.0, 1.0},  /* v1, c1 */
  {0.0,   0.0,   0.0}, {0.0, 0.0, 0.0},  /* v2, c2 */
};
static const unsigned char indices [] = {0, 1, 2};
static GLuint buffer_data_id;
static GLuint buffer_index_id;

static void
reshape (int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho (0, w, 0, h, -1, 100);
}

static void
init (void)
{
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();

  /* Create buffer for vertex and color data. */
  glGenBuffers (1, &buffer_data_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);
  CHECK_GL_ERROR;

  /* Allocate and load data. */
  glBufferData (GL_ARRAY_BUFFER, sizeof (triangle), triangle, GL_STATIC_DRAW);
  CHECK_GL_ERROR;

  /* Notify GL that first vertex is at offset 0. */
  glVertexPointer (3, GL_FLOAT, sizeof (vector3), NULL);
  CHECK_GL_ERROR;

  /* Notify GL that first color is at (sizeof (vector3)). */
  glColorPointer (3, GL_FLOAT, sizeof (vector3), (void *) (sizeof (vector3)));
  CHECK_GL_ERROR;

  /* Create index buffer. */
  glGenBuffers (1, &buffer_index_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer_index_id);
  CHECK_GL_ERROR;

  /* Allocate and load data. */
  glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices, GL_STATIC_DRAW);
  CHECK_GL_ERROR;
}

static void
display (void)
{
  glClearColor (0.3f, 0.6f, 0.3f, 1.0f);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  /* Bind vertex and element buffers. */
  glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer_index_id);
  CHECK_GL_ERROR;

  /* Enable vertex and color arrays. */
  glEnableClientState (GL_VERTEX_ARRAY);
  CHECK_GL_ERROR;
  glEnableClientState (GL_COLOR_ARRAY);
  CHECK_GL_ERROR;

  /* Draw data. */
  glDrawElements (GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, NULL);
  CHECK_GL_ERROR;

  glFlush();
  CHECK_GL_ERROR;
}

int
main (int argc, char **argv)
{
  glutInit (&argc, argv);
  glutCreateWindow ("single triangle");
  glutDisplayFunc (display);
  glutReshapeFunc (reshape);
  init ();

  glutMainLoop ();
  return 0;
}

And gives almost the correct results except that it seems to be pulling data for the third vertex out of nowhere (it should be a black vertex at 0,0 but is yellow instead).

/* Bind vertex and element buffers. */
glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);

You should read this wiki page, particularly the section in question.

The glPointer calls are what makes an association between a vertex attribute and a buffer object. They say, “Take the buffer object in the GL_ARRAY_BUFFER slot and have this vertex attribute come from there.” Changing GL_ARRAY_BUFFER after this association is made means nothing. So if you want to set a vertex attribute to pull from a particular buffer object, you must bind the buffer to GL_ARRAY_BUFFER followed by calling glPointer for that attribute.

I see. Thanks.

Changing the sequence of calls hasn’t fixed the problem. However, on the vertex buffer object page linked to from the page you mentioned, the author writes:


glVertexPointer(3, GL_FLOAT, 64, BUFFER_OFFSET(0));
glNormalPointer(GL_FLOAT, 64, BUFFER_OFFSET(12));
glClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(2, GL_FLOAT, 64, BUFFER_OFFSET(24));
glClientActiveTexture(GL_TEXTURE1);
glTexCoordPointer(2, GL_FLOAT, 64, BUFFER_OFFSET(32));
glClientActiveTexture(GL_TEXTURE2);
glTexCoordPointer(2, GL_FLOAT, 64, BUFFER_OFFSET(40));

Note the ‘64’ for the third parameter. In other words, he’s passing the accumulated size of a vertex coordinate, normals, texture coordinates, etc. In my code, I used:


  /* Notify GL that first vertex is at offset 0. */
  glVertexPointer (3, GL_FLOAT, sizeof (vector3), NULL);
  CHECK_GL_ERROR;

  /* Notify GL that first color is at (sizeof (vector3)). */
  glColorPointer (3, GL_FLOAT, sizeof (vector3), (void *) (sizeof (vector3)));
  CHECK_GL_ERROR;

I’m passing the size of a vertex coordinate then the size of an RGB triple.

I’m about to try passing in the size of a combined element and see what happens.

… Which works.

Final version, for future reference:


#define GL_GLEXT_PROTOTYPES 1

#include <assert.h>
#include <GL/glut.h>
#include <GL/glext.h>

#define CHECK_GL_ERROR (assert (glGetError() == GL_NO_ERROR))

typedef float vector3 [3];

static const vector3 triangle [] = {
  {10.0,  200.0, 0.0}, {1.0, 1.0, 1.0},  /* v0, c0 */
  {600.0, 10.0,  0.0}, {0.0, 0.0, 1.0},  /* v1, c1 */
  {0.0,   0.0,   0.0}, {0.0, 0.0, 0.0},  /* v2, c2 */
};
static const unsigned char indices [] = {0, 1, 2};
static GLuint buffer_data_id;
static GLuint buffer_index_id;

static void
reshape (int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho (0, w, 0, h, -1, 100);
}

static void
init (void)
{
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();

  /* Create buffer for vertex and color data. */
  glGenBuffers (1, &buffer_data_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);
  CHECK_GL_ERROR;

  /* Allocate and load data. */
  glBufferData (GL_ARRAY_BUFFER, sizeof (triangle), triangle, GL_STATIC_DRAW);
  CHECK_GL_ERROR;

  /* Create index buffer. */
  glGenBuffers (1, &buffer_index_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer_index_id);
  CHECK_GL_ERROR;

  /* Allocate and load data. */
  glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices, GL_STATIC_DRAW);
  CHECK_GL_ERROR;
}

static void
display (void)
{
  glClearColor (0.3f, 0.6f, 0.3f, 1.0f);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  /* Bind vertex and element buffers. */
  glBindBuffer (GL_ARRAY_BUFFER, buffer_data_id);
  CHECK_GL_ERROR;
  glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer_index_id);
  CHECK_GL_ERROR;

  /* Notify GL that first vertex is at offset 0. */
  glVertexPointer (3, GL_FLOAT, sizeof (vector3) * 2, NULL);
  CHECK_GL_ERROR;

  /* Notify GL that first color is at (sizeof (vector3)). */
  glColorPointer (3, GL_FLOAT, sizeof (vector3) * 2, (void *) (sizeof (vector3)));
  CHECK_GL_ERROR;

  /* Enable vertex and color arrays. */
  glEnableClientState (GL_VERTEX_ARRAY);
  CHECK_GL_ERROR;
  glEnableClientState (GL_COLOR_ARRAY);
  CHECK_GL_ERROR;

  /* Draw data. */
  glDrawElements (GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, NULL);
  CHECK_GL_ERROR;

  /* Disable vertex and color arrays. */
  glDisableClientState (GL_VERTEX_ARRAY);
  CHECK_GL_ERROR;
  glDisableClientState (GL_COLOR_ARRAY);
  CHECK_GL_ERROR;

  glFlush();
  CHECK_GL_ERROR;
}

int
main (int argc, char **argv)
{
  glutInit (&argc, argv);
  glutCreateWindow ("single triangle");
  glutDisplayFunc (display);
  glutReshapeFunc (reshape);
  init ();

  glutMainLoop ();
  return 0;
}

well, with your final code, I learned a new manner to work with VBOS :slight_smile:
Note that I changed the values of glOrtho() and vertexes to get the correct size for triangle ( independent of the w and h ). You can use any sizes you like . But with larger values for w and h, you get smaller triangle in your code.