dontWatchMyProfile
dontWatchMyProfile

Reputation: 46370

Can I create Vertex Buffer Objects without color information?

I want to create a grid of rectangles for a simulation, where we colorize the rectangles based on calculation results.

Initially I would just want to build the VBO to define the grid. And then in every frame simply assign colors to the rectangles.

Is this possible or is a VBO always "hard-wired" with a set of colors? Because all examples I find online do it like this. They initialize the VBO together with colors and not just the vertex position data, like this:

// allocate a new buffer
glGenBuffers(1, &cubeVBO);

// bind the buffer object to use
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);

const GLsizeiptr vertex_size = NUMBER_OF_CUBE_VERTICES*NUMBER_OF_CUBE_COMPONENTS_PER_VERTEX*sizeof(GLfloat);
const GLsizeiptr color_size = NUMBER_OF_CUBE_COLORS*NUMBER_OF_CUBE_COMPONENTS_PER_COLOR*sizeof(GLubyte);

// allocate enough space for the VBO
glBufferData(GL_ARRAY_BUFFER, vertex_size + color_size, 0, GL_STATIC_DRAW);

Upvotes: 1

Views: 461

Answers (2)

led42
led42

Reputation: 781

A VBO is just a piece of memory, you use it to make things run faster by having the data reside in the graphics card. (Some hardware uses system memory for VBO, so not really much to gain in this case) I also find it cleaner to always use VBOs, but that's a bit of a personal preference.

Anyway you can create VBOs, and then change the data inside them, same as piece of RAM, if you need to change everything on VBO every frame again no performance benefit, but if you only need to change stuff from time to time, or some of the data is fixed (say your vertex data), then you start to get some benefits...

for example:

glGenBuffers(1, &vboObjects[vboGroupBeaver]);
glBindBuffer(GL_ARRAY_BUFFER, vboObjects[vboGroupBeaver]);
glBufferData(GL_ARRAY_BUFFER, beaverVerts*8*sizeof(GLfloat), 0, GL_STATIC_DRAW);
GLvoid*  vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
NSString *path;
path = [[NSBundle mainBundle] pathForResource:@"beaver01" ofType:@"bin"];
NSFileHandle *model = [NSFileHandle fileHandleForReadingAtPath:path];
float vertice[8];
int counter = 0;
while (read([model fileDescriptor], &vertice, 8*sizeof(float))) {
    memcpy(vbo_buffer, vertice, 8*sizeof(GLfloat));        // 0
    vbo_buffer += 8*sizeof(GLfloat);
    counter++;
}
NSLog(@"Vertices %1i",counter);
glUnmapBufferOES(GL_ARRAY_BUFFER); 

This bit of code loads a model into a VBO (vboGroupBeaver), in this example it's the first keyframe of a animation. All the data is now in the VBO, if I do this after:

    glVertexPointer(3, GL_FLOAT, 8*sizeof(GLfloat), (GLvoid*)((char*)NULL));
    glNormalPointer(GL_FLOAT, 8*sizeof(GLfloat), (GLvoid*)((char*)NULL+3*sizeof(GLfloat)));
    glTexCoordPointer(2, GL_FLOAT,8*sizeof(GLfloat), (GLvoid*)((char*)NULL+6*sizeof(GLfloat))); 
    glDrawArrays(GL_TRIANGLES, 0, beaverVerts);

I get a beaver drawn... (Notice that I'm using interleaved vertex data, that's why the pointer calls have the extra info). In your case you would have a Color Pointer instead of a Texture pointer.

Now, if you want to change stuff all you have to do is glMapBufferOES to a buffer var, and interate thru it to change only the parts you need. Something like:

vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
for (int i = start; i < end; i++) {
   vbo_buffer += 6*sizeof(GLfloat); // offset to position
   memcpy(vbo_buffer, whatYouWantToChange, 2*sizeof(GLfloat));  // change what you want, watch the size
 }

EDIT give an example with color

First some example data, in this case a triangle with per vertex data interleaved:

static const ColoredTriangle vertexData[] = {
    {
        {0.0, 0.0, 0.0},           // Vertex 0
        {0.0, 0.0, 1.0},           // Normal 
        {1.0, 0.0, 0.0, 1.0}       // Color  
    },
    {
        {0.0, 480.0, 0.0},            // Vertex 1
        {0.0,   0.0, 1.0},            // Normal 
        {1.0, 1.0, 0.0, 1.0}          // Color  
    },
    {
        {320.0, 0.0, 0.0},           // Vertex 2
        {0.0, 0.0, 1.0},             // Normal
        {1.0, 1.0, 1.0, 1.0}         // Color 
    }

Copy the thing to the vbo (after creating/binding/MapBuffer.

memcpy(vbo_buffer, vertexData, 10*3*sizeof(float));

draw the thing

glVertexPointer(3, GL_FLOAT, 10*sizeof(GLfloat), (GLvoid*)((char*)NULL));
glNormalPointer(GL_FLOAT, 10*sizeof(GLfloat), (GLvoid*)((char*)NULL+3*sizeof(GLfloat)));
glColorPointer(4, GL_FLOAT, 10*sizeof(GLfloat), (GLvoid*)((char*)NULL+6*sizeof(GLfloat)))   
glDrawArrays(GL_TRIANGLES, 0, beaverVerts);

So now you have a triangle being draw with interleaved data from the VBO.

Now on each frame you want to do something just change the data.

GLvoid*  vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
vbo_buffer += 6*sizeof(GLfloat); // position the buffer at the first vertex color data
for (int i = 0; i < 3; i++) {
    memcpy(vbo_buffer, newColor, 4*sizeof(GLfloat));
    vbo_buffer += 10*sizeof(GLfloat); // skip the stripe
}
glUnmapBufferOES(GL_ARRAY_BUFFER);

Then draw again, and you just changed the color info. Depending on the number of changes you're going to be making it might be better to change GL_STATIC_DRAW to something else also...

Disclaimer This was made on the fly, so beware of dragons.

Upvotes: 2

tbalazs
tbalazs

Reputation: 599

You can define the vertex coordinates in a VBO and the vertex colors in another, then you can use glVertexAttribPointer (or glVertexPointer, glColorPointer) to set up the vertex attributes for rendering.

Upvotes: 2

Related Questions