Correct way to render thousands of polygons

I understand that VBOs are currently the best way to render polygons.

Here is what I understand VBO’s to be:
(please correct any of the following information if it is wrong)

  • Vertex Buffer Objects take an array of data, package it tightly, and send it to the GPU to be rendered.
  • The memory must already be reserved on the GPU before the data is sent.
  • The goal of using VBOs is to keep the data stored on the GPU for as long as possible (therefore, better for static drawing?)

That being said, I have a couple of questions about them.

1) What parts of the vbo should be done only once, and which need to be called every tick?
2) What parts of the vbo fast and which parts take the most time? (when drawing thousands of polys wrongly, it will slow down to about 1fps)

Now, if somebody really feels like helping me:

3) What is the correct way to render a huge amount of polygons with VBOs in the following example:

I’m rendering a 2d environment made up of probably millions of squares (think terraria).
I have a class for each tile, and a map class that holds 1 list of tiles at the moment.
Should I store the buffer data in the tile class and call it to the map class when needed?
Should I package all of the arrays into one huge array before I send it to a VBO?

Hopefully you’ve got an idea of what I’m trying to do now.

Any information would be helpful as I’m still a newb! xD

Edit: sorry, forgot to mention that I’m using LWJGL to do this.

Hello,

I’m not sure what you mean by 1) but you will have to issue the following OpenGL calls every frame (assuming you interleave the data and have a single vbo):

Bind the VBO (VAO if you use one - what you should do)
Bind the shader program
Call the GL draw methode (There are quite a few depending on how you set up your VBO / VAO) e.g. glDrawElements(…)
Unbind the program
Unbind the VBO (VAO)

Things you don’t have to do and should not do every single frame:

Uploading new/updated data. You should minimize the calls of glBufferData and glBufferSubData

Things you only have to do once:

Compiling/Linking your program
Generating a pointer to your VBO (glGenBuffer)


2)

Expensive GL calls are:

Uploading data. Try to use uniforms (e.g. for (offset)-positions) as much as possible
Switching VBOs (binding / unbinding). Try to use very few VBOs. I think 4 MB / VBO is recommended.

Less expensive:

the drawing itself

3)
If all the quads (2 triangles) require the same vertex attributes (which I think they do) the pack the triangles in VBOs á 4 MB. If you are using more than, say, 20 VBOs you are doing something wrong. So I would suggest that one object holds all the tiles which need the same vertex attributes and one VBO (or more if you have a huge number of triangles) for the geometry data.

One of the more experienced members of this form might give you better advice, but thats what I would suggest you to do.

Thanks for the information :smiley: although I believe it’s what I already had in my mind. (see Map Class below)

In regards to the 3rd question’s answer:

From what I understand, this should draw 1 square (as they’re all on top of each other due to the 0L offset), yet nothing is drawn at all.
I’m certain that openGL is set up correctly because I can draw immediate mode just fine. It’s something to do with how I’m using the VBOs.

Tile Class: http://pastebin.java-gaming.org/30439348749
Map Class: http://pastebin.java-gaming.org/b3043298447

Edit: lol ignore BufferHelper.reserveData(150000) that was just a hotfix so that I could continue testing

I believe one of your problems is that you’re binding your VBOs multiple times in your map class.

public void draw() {
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_COLOR_ARRAY);
      
      for (int i = 0; i < tileList.size(); i++) {
         glBindBuffer(GL_ARRAY_BUFFER, vboIndexHandle);
         glVertexPointer(3, GL_FLOAT, 0, 0L);
         
         glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
         glColorPointer(3, GL_FLOAT, 0, 0L);
         
         glDrawArrays(GL_QUADS, 0, 4);
      }
      glDisableClientState(GL_VERTEX_ARRAY);
      glDisableClientState(GL_COLOR_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
   }

I would re-write it like this:

public void draw() {
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_COLOR_ARRAY);

         glBindBuffer(GL_ARRAY_BUFFER, vboIndexHandle);
         glVertexPointer(3, GL_FLOAT, 0, 0L);
         
         glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
         glColorPointer(3, GL_FLOAT, 0, 0L);
              
        
         glDrawArrays(GL_QUADS, 0, 4);
  
      glDisableClientState(GL_VERTEX_ARRAY);
      glDisableClientState(GL_COLOR_ARRAY);
   }

You may also want to consider making ‘chunks’ of tiles that you create a VBO for. So instead of rendering out all the tiles with one VBO, you will have multiple smaller ones that may take some of the strain off your GPU. Just a thought though.

Yeah I suppose that makes a lot more sense now that I think about it.

However; I may have misled you a little bit in the OP, it’s not this program that I’m having FPS issues with, I’m only having issues with it not drawing at all.

Do you see anything important missing? Or anything that might make the objects not be rendered at all?

Oh god I feel dumb… :-X

whispersforgot to flip the buffers…