0
votes

I figured that OpenGL (I'm using OpenGL 4.0) supports Vertex Buffer Objects which is (correct me if I'm wrong) a dynamic way to draw vertexes, binding them similar to texture binding when you can free a dynamic array of pixels after binding it to a texture and you will still be able to draw it even if the pixel data in the array is lost. I tried to make a mini-minecraft game, but after drawing 256x256x60 world (256 width and height and 60 blocks depth) the game TOTALLY got stuck. I tried just drawing 256x256x6 but it still wasn't as fast as, for example, Minecraft runs. I drew the a block the following way:

void DrawBlock(double x, double y, double z, float xx, float yy, float zz)
{
   // Render a color-cube consisting of 6 quads with different colors
    xx = xx / 2;
    yy = yy / 2;
    zz = zz / 2;
    x -= xx;
    y -= yy;
    z -= zz;

    glBegin(GL_QUADS);                // Begin drawing the color cube with 6 quads
      // Top face (y = z + zz)
      // Define vertices in counter-clockwise (CCW) order with normal pointing out
      glColor3f(0.0f, 1.0f, 0.0f);     // Green
      glVertex3f(x + xx, y + yy, z - zz);
      glVertex3f(x - xx, y + yy, z - zz);
      glVertex3f(x - xx, y + yy,  z + zz);
      glVertex3f(x + xx, y + yy,  z + zz);

      // Bottom face (y = z - zz)
      glColor3f(1.0f, 0.5f, 0.0f);    // Orange
      glVertex3f(x + xx, y - yy,  z + zz);
      glVertex3f(x - xx, y - yy,  z + zz);
      glVertex3f(x - xx, y - yy, z - zz);
      glVertex3f(x + xx, y - yy, z - zz);

      // Front face  (z = z + zz)
      glColor3f(1.0f, 0.0f, 0.0f);    // Red
      glVertex3f(x + xx, y + yy, z + zz);
      glVertex3f(x - xx, y + yy, z + zz);
      glVertex3f(x - xx, y - yy, z + zz);
      glVertex3f(x + xx, y - yy, z + zz);

      // Back face (z = z - zz)
     glColor3f(1.0f, 1.0f, 0.0f);    // Yellow
      glVertex3f(x + xx, y - yy, z - zz);
      glVertex3f(x - xx, y - yy, z - zz);
      glVertex3f(x - xx, y + yy, z - zz);
      glVertex3f(x + xx, y + yy, z - zz);

      // Left face (x = z - zz)
      glColor3f(0.0f, 0.0f, 1.0f);    // Blue
      glVertex3f(x - xx, y + yy,  z + zz);
      glVertex3f(x - xx, y + yy, z - zz);
      glVertex3f(x - xx, y - yy, z - zz);
      glVertex3f(x - xx, y - yy,  z + zz);

      // Right face (x = z + zz)
       glColor3f(1.0f, 0.0f, 1.0f);     // Magenta
      glVertex3f(x + xx, y + yy, z - zz);
      glVertex3f(x + xx, y + yy,  z + zz);
      glVertex3f(x + xx, y - yy,  z + zz);
      glVertex3f(x + xx, y - yy, z - zz);
   glEnd();  // End of drawing color-cube
}

when the x, y and z data is in an array of structures called "Block". I still didn't do anything but the drawing, only because the drawing keeps getting stuck, the display function always call the DrawBlock() 256x256x6 or 256x256x60 times in EVERY run of it. How do I do it dynamically using VBO ? I looked at the internet but some undefined functions appeared like glGenBuffersARB() and so. Any example code for one simple cube ?

1
Look at this question OpenGL: VBO or glBegin() + glEnd()?. You really should learn the fundamental things of OpenGL before starting a huge project like this. Additionally you should read about Voxel Engines, because even with VBO you will have problems if you try to render all blocks. - t.niese
@t.niese Between now it's just moving between the blocks :P - Zach
I think so, but this (managing and rendering the blocks in a fast way) is one of the complicate parts in a block based game. ;) adding collision detection (walking on blocks will be even more complicate). - t.niese
@t.niese collision detection between blocks - 3 dimensional ? Nope, up to now it all worked on a small amount, EVERYTHING. And I have an idea on how to make the collision with NO loops, just about 2-3 if statements :P Anyway, do you have any example code for using VBO? - Zach
Did you ever bother to follow the link in my first comment reading the question, and the answer to it (or searching for VBO tutorial in the web)? Anyway I tried to give you the good advice to first learn the basics of modern OpenGL (3.2+) not just how to use VBO and to look for voxel engines. - t.niese

1 Answers

0
votes

If you are drawing 256x256x6 blocks without any optimization, you will make 393216 draw calls if you use the way above.

Minecraft is using chunks for loading and rendering. You should load one chunk and render one chunk at one with only one draw call. Means one Vertex Buffer Object holds one chunk. This can be done by a lot of optimization. I have tried something similar and arvhied nearly 600 FPS at one chunk with 64*64*256 Blocks using one render call.

I've loaded the chunk form the hdd and stored one bit per block (0 if not active, 1 if active) Then I processed the chunk and skipped blocks which are not active, as well as all blocks which are not visible (all sides of the block are covered by other blocks). The next optimization was to only render the side which is visible. Lets say that there is one block (2D)

    x
   xB
    x 

B is you block and x are the other blocks around the current one. So instead of creating all 4 (8 Triangles - 24 Verts - 72 Floats) sides you just create the right side (2 Triangles - 6 Verts - 18 Floats). I append the floats to a buffer (vector or other dynamic data structure). The content of this data structure is now uploaded to the VBO and later the whole chunk is rendered at once. And there is a lot of more improvements, But you just have to reduce the number of vertices in you "mesh"/"chunk".

If you are using more chunks, you can also add a lot of other optimization, Do not render invisible or empty chunks.

And after that you can take a look at "Deferred Shading". This can improve you frame rate. Using deferred shading, you only shade what is visible to the player. Blocks not visible (those of the tunnels in Minecraft, or Blocks covered by a mountain) are not shaded.

I recommended reading this: https://sites.google.com/site/letsmakeavoxelengine/ Is is not finished yet but the basics are explained and the authors shows some code, as well as some more details.

I also recommend to take a deeper look at VertexBufferObjects and the modern OpenGL. (if you want to use old OpenGL take a look at "display lists")

Without "Display Lists" or "VBO" the triangles are copied to the GPU again and again each time you call render - This is very slow. Therefore use the VBO to copy them once and just tell OpenGL: here is the list, it is already on the device, just render it!