Sign in to follow this  
Empty_Null

How to generate data efficiently for a VBO.

Recommended Posts

I've set up a VBO in my program that displays an ammount of triangles. But the class system that I use to transform my objects into a vertices, colors and normals vectors is way too inefficient. I only get 9 fps while I generate the positions for 300 cubes containing 36 vertices, colors and normals each. I've set my classes up in such a way. A figure class has multiple vertices/colors/normals and a matrix. An object class has multiple figure classes and another matrix. each 1/50th of a second I update each cube's matrix and recalculate the vertices for it. Now my question is if someone might point out to me what might be more efficient for my code. I would also be interested in how other people have set up their data line to their vbo's.

Share this post


Link to post
Share on other sites
Why would you need to generate 300 cubes? 1 cube is enough.
Then use glScale to give it the size you want and render 300 times.

Share this post


Link to post
Share on other sites
300 cubes are just for the stress test.
It comes around to 10800 triangles.
And scale/movement and rotation are already done trough the matrixes.

Edit:
The point is that I can dynamicly make graphics with this engine.

[Edited by - Empty_Null on May 2, 2009 6:34:21 PM]

Share this post


Link to post
Share on other sites
This is how I set up the vbo

glGenBuffersARB(1, &vboId1);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId1);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, ((testVertices.size() + testNormals.size())*sizeof(float) + testColors.size()*sizeof(GLubyte)), NULL, GL_DYNAMIC_DRAW_ARB);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, testVertices.size()*sizeof(float), &testVertices[0]); // copy vertices starting from 0 offest
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, testVertices.size()*sizeof(float), testNormals.size()*sizeof(float), &testNormals[0]); // copy normals after vertices
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, (testVertices.size() + testNormals.size())*sizeof(float), testColors.size()*sizeof(unsigned char), &testColors[0]); // copy colours after normals

glGenBuffersARB(1, &vboId2);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId2);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, ((testVertices.size() + testNormals.size())*sizeof(float) + testColors.size()*sizeof(unsigned char)), NULL, GL_DYNAMIC_DRAW_ARB);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, testVertices.size()*sizeof(float), &testVertices[0]); // copy vertices starting from 0 offest
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, testVertices.size()*sizeof(float), testNormals.size()*sizeof(float), &testNormals[0]); // copy normals after vertices
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, (testVertices.size() + testNormals.size())*sizeof(float), testColors.size()*sizeof(unsigned char), &testColors[0]); // copy colours after normals


This is what I call every frame to either display vbo1 or vbo2 depending on which one is being updated

if(vboId){glBindBufferARB(GL_ARRAY_BUFFER, vboId1);}
else{glBindBufferARB(GL_ARRAY_BUFFER, vboId2);}

glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);

glNormalPointer(GL_FLOAT, 0, (GLvoid*)(testVertices.size()*sizeof(float)));
glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*)((testVertices.size() + testNormals.size())*sizeof(float)));
glVertexPointer(3, GL_FLOAT, 0, 0);
//glDrawElements(GL_TRIANGLES, vertAmmount, GL_UNSIGNED_BYTE, 0);
glDrawArrays(GL_TRIANGLES, 0, vertAmmount);

glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);

glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);


This is what I use to update the vbo.

if(vboId){glBindBufferARB(GL_ARRAY_BUFFER, vboId1);vboId = false;}
else{glBindBufferARB(GL_ARRAY_BUFFER, vboId2);vboId = true;}
glBufferDataARB(GL_ARRAY_BUFFER_ARB, ((testVertices.size() + testNormals.size())*sizeof(float) + testColors.size()*sizeof(unsigned char)), NULL, GL_DYNAMIC_DRAW_ARB);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, testVertices.size()*sizeof(float), &testVertices[0]); // copy vertices starting from 0 offest
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, testVertices.size()*sizeof(float), testNormals.size()*sizeof(float), &testNormals[0]); // copy normals after vertices
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, (testVertices.size() + testNormals.size())*sizeof(float), testColors.size()*sizeof(unsigned char), &testColors[0]); // copy colours after normals


[Edited by - Empty_Null on May 3, 2009 9:06:15 AM]

Share this post


Link to post
Share on other sites
Try to not use color to see if it improves the speed.
Try another format, like 4 component RGBA GL_FLOAT color.
Try 4 component RGBA UNSIGNED_BYTE color.

Share this post


Link to post
Share on other sites
I've now implemented an unsigned char rgba color scheme.


struct vertex{
float x, y, z;
float normx, normy, normz;
unsigned char red, green, blue, alpha;
unsigned char buffer1;
};


I've also updated my code in my previous post to reflect that.

I've tested my program a bit longer then usual and have noticed that it always starts out at 10fps.
But that it shoots to between 30 and 50fps after around 20 seconds.

Perhaps I've made an error in my fps control code.
I'll post it as well.


loops = 0;

while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {

for ( Iter2 = testParticle.begin( ) ; Iter2 != testParticle.end( ) ; Iter2++ ){
Iter2->update();//these are the boxes and update changes the matrix for them
}

updateVBO();//vbo that isn't drawn is updated

next_game_tick += SKIP_TICKS;
loops++;
}

interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
/ float( SKIP_TICKS );
dwFrames++;
dwCurrentTime = GetTickCount(); // Even better to use timeGetTime()
dwElapsedTime = dwCurrentTime - dwLastUpdateTime;
if(dwElapsedTime >= 1000){ //to update the fps in the program header
wsprintf(szFPS, "FPS = %u", (UINT)(dwFrames * 1000.0 / dwElapsedTime));
SetWindowText(hWnd,szFPS);
dwFrames = 0;
dwLastUpdateTime = dwCurrentTime;
}


This code happens before drawing the vbo.

Share this post


Link to post
Share on other sites
It seems my limiting the boxes to only update each 1/50th of a second was killing my fps.

I removed the while loop in my fps limiting code and update the boxes each frame.

Now I can handle 2200 boxes at a fps of 14.

Which comes down to 79200 vertices/colors/normals or 26400 triangles.

They might be some other things I might improve.

Because when I compare this to some of the games I play on my comp there's a big difference.

[Edited by - Empty_Null on May 3, 2009 3:09:49 PM]

Share this post


Link to post
Share on other sites
Drawing boxes like that and trying to compare it against any real game is meaningless.

1) Your doing alot of really small draw calls(each draw call is relatively expensive).

2) Your updating the buffer each frame, why in the world are you doing that? Just pass the modified matrix into OGL, don't manually modify your vertices each frame.

Share this post


Link to post
Share on other sites
as other say doing what youre doing is pointless (try a real scene)

though in saying that it perhaps still seems slow (though depending on cpu)
just tried a simple slut app
(verts only)
10,000 boxs @ ~70fps a single draw call per box drawelements
drawbox()
{
glVertexPointer( 3, GL_FLOAT, 0, corners );
glEnableClientState( GL_VERTEX_ARRAY );
glDrawElements( GL_QUADS, 24, GL_UNSIGNED_SHORT, indices );
}

btw same speed in immediate


drawbox()
{
glBegin( GL_QUADS );
for ( int i=0; i<24; i++ )
glVertex3fv( corners[ indices[i] ] );
glEnd();
}

srand(1234);

for ( int i=0; i<10000; i++ )
{
glPushMatrix();
glTranslatef( (rand()%100-50)*0.1, (rand()%100-50)*0.1, (rand()%100-50)*0.1 );
drawbox();
glPopMatrix();
}

Share this post


Link to post
Share on other sites
Quote:
Original post by AndyPandyV2
Drawing boxes like that and trying to compare it against any real game is meaningless.

1) Your doing alot of really small draw calls(each draw call is relatively expensive).

2) Your updating the buffer each frame, why in the world are you doing that? Just pass the modified matrix into OGL, don't manually modify your vertices each frame.


I know that comparing it to a game isn't realistic but it's a nice goal t o have.

1) The ammount of triangles doesn't really matter since I upload them all into one buffer anyway. And the vbo buffer lets the graphic card handle the rest.

2) of course I'm updating the buffer every frame. I'm not using GL_DYNAMIC_DRAW_ARB for nothing. And how should one send a matrix thogether with a vbo buffer? I have looked for something like that but haven't been able to find anything that looks like it. Hence why I did it manually.

Share this post


Link to post
Share on other sites
Quote:
Original post by zedz
as other say doing what youre doing is pointless (try a real scene)

though in saying that it perhaps still seems slow (though depending on cpu)
just tried a simple slut app
(verts only)
10,000 boxs @ ~70fps a single draw call per box drawelements
drawbox()
{
glVertexPointer( 3, GL_FLOAT, 0, corners );
glEnableClientState( GL_VERTEX_ARRAY );
glDrawElements( GL_QUADS, 24, GL_UNSIGNED_SHORT, indices );
}

btw same speed in immediate


drawbox()
{
glBegin( GL_QUADS );
for ( int i=0; i<24; i++ )
glVertex3fv( corners[ indices[i] ] );
glEnd();
}

srand(1234);

for ( int i=0; i<10000; i++ )
{
glPushMatrix();
glTranslatef( (rand()%100-50)*0.1, (rand()%100-50)*0.1, (rand()%100-50)*0.1 );
drawbox();
glPopMatrix();
}


Your examples are old news to me. They only deal with static data. While I've made my code so that the data is made dynamically so I can change it at will. You can compare the boxes to graphical objects that change each and every frame.

Share this post


Link to post
Share on other sites
I'd also like to see a good example of how to best use VBOs when dealing with dynamic geometry; one thing I'm not clear on is whether there's even a point, or whether it's better to just use VAs.

Share this post


Link to post
Share on other sites
Good question.

That's what I'm also trying to find out.

But why would vbo have an streaming or dynamic mode if it wouldn't use dynamic geometry?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this