VertexBufferObjects problem.

Cd577ee1cb56aa2ad5645b7daa0a2830
0
eddie 101 Jul 25, 2006 at 15:02

Hey.

So, I’m relatively new to graphics programming, as I’m mostly a tools guy by trade. I’m trying to play around with VertexBufferObjects/DrawArrays (are they synonyms? Seems like it, or at least they go hand in hand), but I’m not having any luck.

I’ve basically used Luke Philpot’s code from the DevMaster wiki, with some modification in parts (it’s not really correct and doesn’t compile straight-away), but for some odd reason nothing shows up. My coordinates seem to be OK (if I use a standard glBegin()/glEnd(), I get a nice shiny triangle), but nothing shows up!

I’ve tried making a colour buffer, tried putting glEnable/DisableClientState() calls at the beginning/end of every frame, and various other things, but to no avail.

Can anyone see what I don’t? All the tutorials I’m finding are so mixed up with other things I don’t want to confuse myself with, I can’t find a simple VBO-only tutorial.

Cheers.

// Framework
// (c) 2003 Luke Philpot.

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

#define win32 // comment out for non win32

#ifdef win32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "glext.h"

// VBO Extension Definitions, From glext.h
#define GL_ARRAY_BUFFER_ARB 0x8892
#define GL_STATIC_DRAW_ARB 0x88E4
typedef void (APIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage);

// VBO Extension Function Pointers
PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;                  // VBO Name Generation Procedure
PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;                  // VBO Bind Procedure
PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;                  // VBO Data Loading Procedure
PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;                // VBO Deletion Procedure

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nshow)
{
    SDL_Event e; // for input

    // init window

    SDL_Init(SDL_INIT_VIDEO);
    SDL_SetVideoMode(640, 480, 32, 2);

    // set up OpenGL
    glMatrixMode(GL_PROJECTION);                    
    glLoadIdentity();

    gluPerspective(45, (float) 640 / (float) 480, 1, 512);

    glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
    glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
    glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");

    // enable depth testing
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    GLfloat vertexData[] =  {  0.f,  1.f, 0.f
                            , -1.f, -1.f, 0.f
                            ,  1.f, -1.f, 0.f
                            };

    GLuint vertexBuffer = 0;

    glGenBuffersARB(1, &vertexBuffer);
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertexData), vertexData, GL_STATIC_DRAW_ARB);

    glEnableClientState(GL_VERTEX_ARRAY);

    while (!SDL_PollEvent(&e) || e.key.keysym.sym != SDLK_ESCAPE) // check whether esc has been pressed
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();

            glTranslatef(0, 0, -5);

            glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);

            glVertexPointer(3, GL_FLOAT, 0, 0);

            glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);

        SDL_GL_SwapBuffers();
    }
    
    glDisableClientState( GL_VERTEX_ARRAY );

    return 0;
}

9 Replies

Please log in or register to post a reply.

46407cc1bdfbd2db4f6e8876d74f990a
0
Kenneth_Gorking 101 Jul 25, 2006 at 16:03

After your ‘glGenBuffersARB(1, &vertexBuffer);’, change the line to ‘glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);’. The zero you provide means that no buffer is bound, hence no data is uploaded.

Cd577ee1cb56aa2ad5645b7daa0a2830
0
eddie 101 Jul 25, 2006 at 17:05

Wow, that’s embarrasing.

Luckily for me, that code is part of the original demo, found here:.

Can anyone update it? I don’t seem to have access.

Code that seems to work for me:

// Framework
// (c) 2003 Luke Philpot.

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

#define win32 // comment out for non win32

#ifdef win32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>

// VBO Extension Definitions, From glext.h
#define GL_ARRAY_BUFFER_ARB 0x8892
#define GL_STATIC_DRAW_ARB 0x88E4
typedef void (APIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage);

// VBO Extension Function Pointers
PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;                  // VBO Name Generation Procedure
PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;                  // VBO Bind Procedure
PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;                  // VBO Data Loading Procedure
PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;                // VBO Deletion Procedure

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nshow)
{
    SDL_Event e; // for input

    // init window

    SDL_Init(SDL_INIT_VIDEO);
    SDL_SetVideoMode(640, 480, 32, 2);

    // set up OpenGL
    glMatrixMode(GL_PROJECTION);                    
    glLoadIdentity();

    gluPerspective(45, (float) 640 / (float) 480, 1, 512);

    glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
    glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
    glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");

    // enable depth testing
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    GLfloat vertexData[] =  {  0.f,  1.f, 0.f
                            , -1.f, -1.f, 0.f
                            ,  1.f, -1.f, 0.f
                            };

    GLuint vertexBuffer = 0;

    glGenBuffersARB(1, &vertexBuffer);
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertexData), vertexData, GL_STATIC_DRAW_ARB);

    glEnableClientState(GL_VERTEX_ARRAY);

    while (!SDL_PollEvent(&e) || e.key.keysym.sym != SDLK_ESCAPE) // check whether esc has been pressed
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();

            glTranslatef(0, 0, -5);

            glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);

            glVertexPointer(3, GL_FLOAT, 0, 0);

            glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);

        SDL_GL_SwapBuffers();
    }
    
    glDisableClientState( GL_VERTEX_ARRAY );

    return 0;
}
Cd577ee1cb56aa2ad5645b7daa0a2830
0
eddie 101 Jul 25, 2006 at 19:31

I took a little bit of time and polished up my demo a bit, and I’ve posted it on my site as a demo. I’d be willing to submit it to DevMaster if people want it.

6837d514b487de395be51432d9cdd078
0
TheNut 179 Jul 26, 2006 at 22:40

What?! No fancy 10 million polygonal heightmap? No super high-resolution models? Pffft…

Tease =)

Here are some performance tips about your code. You won’t see anything significant with a simple triangle, but with complex scenes it can make a difference.

1) 156. glMatrixMode(GL_MODELVIEW);
You need only call this once as OpenGL will save the last state. Move it outside the loop

2) 160. glTranslatef(0, 0, -5);
You can just set the Z-coordinate of the triangle in the vertexData[] array if this is supposed to be static geometry.

3) 173. glColorPointer (3, GL_FLOAT, 0, 0);
It’s slightly faster to represent colours as GL_BYTE (ie: 0 – 255) and there’s virtually no quality difference.

It’s always best to illustrate VBOs with high polygonal geometry. You can create a random heightmap very simply in software with just two loops. BTW, VBOs use to be called “Vertex Array Range” and was an nVidia specific implementation back in the old days.

Cd577ee1cb56aa2ad5645b7daa0a2830
0
eddie 101 Jul 27, 2006 at 00:04

Hey TheNut!

Thanks for the pointers. Yeah, it’s pretty basic so far, but that’s the idea. I’m going to use it to build off of it and see what I can come up with. :)

My next big ‘task’ is to see if I can interleave it (as I understand that can give you a performance gain due to reduced cache misses) and wrap it all in a loving C++ wrapper to make it easy to use.

The only thing I’m having issues with right now is trying to undertand if I should be ‘interleaving’ it by putting coordinates in as { [X], [R], [Y], [G], [Z], , [W], [A] }, and setting the stride to 1, or if I’m to do things as { [X], [Y], [Z], [W], [R], [G], , [A]} and adjusting the third parameter to gl*Pointer accordingly.

Except I can’t seem to get gl*Pointer to take a third parameter (for some reason only 0 works)! Sigh. One day I’ll understand all this.

Thanks for clearing up the VBO vs. VAR thing, by the way.

Cd577ee1cb56aa2ad5645b7daa0a2830
0
eddie 101 Jul 27, 2006 at 00:46

Ah, OK, so I got it. I was confused because I thought I needed the third parameter to be a void* pointer to memory to start off of. From what I understand, the VBO extension overrides that and makes the last parameter actually a float that it uses to calculate the starting offset…. Not that I could find any documentation that told me this.

Anyhow, that appears to work! And I hear that’s the “optimal” way of doing it, so huzzah!

Thanks. ;) Maybe I’ll mark that up in a second tutorial, after I take TheNut’s points and merge them into my first. Yay, basic VBO’s will work now.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Jul 27, 2006 at 00:55

@eddie

The only thing I’m having issues with right now is trying to undertand if I should be ‘interleaving’ it by putting coordinates in as { [X], [R], [Y], [G], [Z], , [W], [A] }, and setting the stride to 1, or if I’m to do things as { [X], [Y], [Z], [W], [R], [G], **, [A]} and adjusting the third parameter to gl*Pointer accordingly.**

Do the second. Keep the position parts together and the color parts together. That’s how the gl*Pointer functions will expect the data, you can’t have separate streams for X, Y, Z, and W components - only a stream for vertex positions. Accordingly keep all the data for a single vertex together. If you use one of the ‘standard’ formats, you can use glInterleavedArrays to set up all the applicable pointers at once, but this is just a shortcut and doesn’t let you do anything you couldn’t do with the gl*Pointer functions.

Except I can’t seem to get gl*Pointer to take a third parameter (for some reason only 0 works)!

That’s odd. You should set the third parameter to the size of your vertex struct.

Edit: You meant the 4th parameter, I guess, which is the pointer parameter.

Not that I could find any documentation that told me this.

http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt explains it in all the gory detail. ;)

Cd577ee1cb56aa2ad5645b7daa0a2830
0
eddie 101 Jul 27, 2006 at 14:14

Right, sorry I meant the 4th. My bad.

Wow, thanks for that link Reedbeta. I didn’t find that in any of my searches. Very tasty.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Jul 27, 2006 at 23:34

http://oss.sgi.com/projects/ogl-sample/registry/ has the official ARB/vendor specs on all the published extensions. There’s noplace else I go for extension documentation. ;)