How to generate data efficiently for a VBO.

Started by
12 comments, last by Empty_Null 14 years, 11 months ago
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.
Advertisement
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.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
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]
I see.
Well, you have to pay attention to the format. I don't know what you are doing. You don't show any code but here are examples.
http://www.opengl.org/wiki/VBO#Sample_Code

and also
http://www.opengl.org/wiki/VBO_-_more#Dynamic_VBO
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
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]
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.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
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.
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]
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.
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 ] );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();}

This topic is closed to new replies.

Advertisement