Help - Should I move to VBOs?
Hi
I've written a hobby game. It's a 8 way top down 2d scroller. It uses 32x32 tiles to draw the screen and a single texture made up of 32x32 decals to put onto those tiles.
The screen is smooth scrolled pixel by pixel, and when it scrolls further than a tile distance, a new 32x32 tile is drawn to the screen. This works just fine.
Each frame I go through the array of tiles and pull out the ones that are visible on the screen for that frame - work out their texture coordinates from the single large texture and then draw textured GL_QUADS. At 640x480 resolution this is about 300 tiles.
Finally to my question ! Is this something that would see an improvement in performance by using VBO's? The entire level is about 100x100 tiles in size.
As the screen is always moving, the visible tiles are drawn at different locations each frame - would that mean uploading new vertex positions each frame to the VBO? I'm still trying to get my head around how VBO's and how to structure my data if they are suitable.
Thanks
Using VBO's is always faster, and 10000 quads will see a lot of performance.
Seems that you don't know enough about openGL. Have you ever used glTranslatef, glRotatef, etc? Every vertex is transformed regardless on the gpu. Vertex data is not going to change, but the transformation will. You will just translate by different amounts based on where you want to be in the world.
Quote:As the screen is always moving, the visible tiles are drawn at different locations each frame - would that mean uploading new vertex positions each frame to the VBO?
Seems that you don't know enough about openGL. Have you ever used glTranslatef, glRotatef, etc? Every vertex is transformed regardless on the gpu. Vertex data is not going to change, but the transformation will. You will just translate by different amounts based on where you want to be in the world.
I assume you're using immediate mode right now, so yes VBO could help performance (if you're not limited by something else).
With VBOs you'd transfer the whole grid to video memory once (provided it is static) and then just need to calculate the index buffer each frame in order to render your level. So you would generate ALL tiles (including the correct texture coordinates) when you load the level and build the VBO. Then each frame you calculate the indices for the visible tiles, fill the index buffer (which might be an array in main memory in your case) and issue a single draw call.
And since you have 100x100 = 10.000 tiles, you'd have 40.000 vertices (provided you can't share them between tiles) and thus you should use 16-bit indices (i.e. GL_SHORT) in your index buffer, increasing its performance as well.
You also don't have to recalculate the vertex positions each frame. Just set the appropriate modelview matrix, i.e. use glTranslatef(...) etc. for a start.
With VBOs you'd transfer the whole grid to video memory once (provided it is static) and then just need to calculate the index buffer each frame in order to render your level. So you would generate ALL tiles (including the correct texture coordinates) when you load the level and build the VBO. Then each frame you calculate the indices for the visible tiles, fill the index buffer (which might be an array in main memory in your case) and issue a single draw call.
And since you have 100x100 = 10.000 tiles, you'd have 40.000 vertices (provided you can't share them between tiles) and thus you should use 16-bit indices (i.e. GL_SHORT) in your index buffer, increasing its performance as well.
You also don't have to recalculate the vertex positions each frame. Just set the appropriate modelview matrix, i.e. use glTranslatef(...) etc. for a start.
Understood.
How high will glTranslate() go up to?
If my playfield is 10,000 pixels long - can I translate between 0 and 10,000?
Given my screen resolution is just a sliding window over the entire playfield.
glTranslate(...) can take any arbitrary floating point number. You might, however, run into precision issues if the values get too high. But since you're using 1 unit per pixel I doubt that would be the case here.
Instead of translating 100 units per tile you might consider making each tile 1 unit wide instead and adjusting your projection matrix accordingly.
Instead of translating 100 units per tile you might consider making each tile 1 unit wide instead and adjusting your projection matrix accordingly.
Quote:Each frame I go through the array of tiles and pull out the ones that are visible on the screen for that frame - work out their texture coordinates from the single large texture and then draw textured GL_QUADS. At 640x480 resolution this is about 300 tiles.
Finally to my question ! Is this something that would see an improvement in performance by using VBO's? The entire level is about 100x100 tiles in size.
no using VBOs in your case wont improve matters much (+ most likely wont at all)
whats important is how many tiles youre rendering at a time (not how many are in the whole scene)
300quads == 1200 vertices, which is a tiny amount, IIRC immediate mode on a decent PC can handle manitudes of vertices more than that @ 60fps.
I was assuming 100x100 tiles, x 4 verts = 40,000 vertices.
300quads == 1200 vertices = I think 300 quads on screen he means, which is why he mentioned the resolution.
Gibbon_99: If the first statement I made was the case, the easiest way is to put them all into a VBO and just draw the whole thing. You wont need to calculate what tiles are on screen or anything, it will still run really fast.
To understand the glTranslatef(), draw your current scene, you should have glLoadIdenity()
Draw()
do
glLoadIdentity()
glTranslatef()
Draw()
and you can see how it will work out.
300quads == 1200 vertices = I think 300 quads on screen he means, which is why he mentioned the resolution.
Gibbon_99: If the first statement I made was the case, the easiest way is to put them all into a VBO and just draw the whole thing. You wont need to calculate what tiles are on screen or anything, it will still run really fast.
To understand the glTranslatef(), draw your current scene, you should have glLoadIdenity()
Draw()
do
glLoadIdentity()
glTranslatef()
Draw()
and you can see how it will work out.
I've been trying to get a basic VBO to work - but I'm not having much luck.
I can't see what is wrong with the code below. It draws a full screen textured quad on my laptop ( Intel chipset ) but on the PC ( NVidia GTX 295 ) it doesn't show anything.
On the laptop the texture shows, but it's below everything else that it should be drawn on top of.
All drawing is done in 2D mode and the quad works fine in immediate mode.
Another question - is glBegin() / glEnd() still required when using VBO's?
Thanks
// Draw a test VBOvoid sysTestVBO()//-----------------------------------------------------------------------------{ static bool initDone = false; static GLuint splashVBOID; static GLuint sizeVBO;#define NUM_VERTS_SPLASH 4struct myVertex{ GLfloat x, y; // position GLfloat s, t; // texture coordindate};myVertex myQuad[NUM_VERTS_SPLASH];myQuad[0].x = 0.0f; myQuad[0].y = 0.0f; myQuad[0].s = 0.0f; myQuad[0].t = 0.0f;myQuad[1].x = (GLfloat)winWidth; myQuad[1].y = 0.0f; myQuad[1].s = 1.0f; myQuad[1].t = 0.0f;myQuad[2].x = (GLfloat)winWidth; myQuad[2].y = (GLfloat)winHeight; myQuad[2].s = 1.0f; myQuad[2].t = 1.0f;myQuad[3].x = 0.0f; myQuad[3].y = (GLfloat)winHeight; myQuad[3].s = 0.0f; myQuad[3].t = 1.0f; if (false == initDone) { sizeVBO = sizeof(myVertex) * NUM_VERTS_SPLASH; //(NUM_VERTS_SPLASH * NUM_COORDS_PER_VERT_SPLASH) * sizeof(GLfloat); // // Get the VBO buffer ID glGenBuffers(1, &splashVBOID); glBindBuffer(GL_ARRAY_BUFFER, splashVBOID); glBufferData(GL_ARRAY_BUFFER, sizeVBO, (const GLvoid *)&myQuad, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST); initDone = true; } glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[SPLASH].textureID); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, sizeof(myVertex), (const GLvoid *)&myQuad[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(myVertex), (const GLvoid *)&myQuad[0].s); glBindBuffer(GL_ARRAY_BUFFER, splashVBOID); glDrawArrays(GL_QUADS, 0, NUM_VERTS_SPLASH); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); gl_getAllGLErrors((char *)"After VBO");}
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement