views:

143

answers:

5

I'm a little confused as to the proper usage of VBOs in an OpenGL program.

I want to create a terrain paging algorithm, using a map called from a 4096x4096 greyscale heightmap as the "whole" map.

From what I've read, each vertex stored in the VBO will take up 64 bytes.

The problem I have is that most sources state that a single VBO should be between 1-4mb in size, and less VBOs is better. Yet according to my calculations, storing each vertex would take a total of about a gigabyte of data! (4096x4096x64) That's not including that each vertice may need to be stored multiple times for each triangle.

Nor does this accommodate the different vehicles and people that would be on this map once I get the terrain portion of the code worked out.

the other solution I looked at was to page the data from the hard drive while the program is running, but another source says it's a bad idea to create and destroy while the program's running, and that it's also best practice to have as few VBOs as possible.

What I really want to know is, what am I missing? I'm sure I'm making some kind of massive oversight here, because a maximum VBO size of 4mb just seems extremely low, even if I was loading the texture in 64x64 blocks, and the different interactive objects that would populate the map too.

Or are my expectations of what I can achieve just unrealistic? Is there a better method available to me that I'm unaware of? I'm looking at games like Oblivion or Fallout 3, and to some extend Boundless Planet, and seeing massive terrains, and wondering how on earth that can be possible.

I understand how to code, this isn't my first delve into OpenGL, but is my first time attempting to understand and utilize VBOs.

If anyone can shed some light into where my understanding of VBOs is going wrong, it would be much appreciated. Thanks!

A: 

The size of the vertex determines how much space it will take in the vertex buffer. If your vertex consists of only a 3D position you will have 12 bytes per vertex.

That's not including that each vertice may need to be stored multiple times for each triangle.

You can index your data using an index buffer to remove the need for duplicate vertices.

the other solution I looked at was to page the data from the hard drive while the program is running, but another source says it's a bad idea to create and destroy while the program's running, and that it's also best practice to have as few VBOs as possible.

Yes, creating and destroying will have a negative impact on performance but no where near the impact of having a huge vertex buffer. If you want to have a huge terrain; loading/releasing smaller parts of terrain data during is the way to go.

I'm sure I'm making some kind of massive oversight here, because a maximum VBO size of 4mb just seems extremely low, even if I was loading the texture in 64x64 blocks, and the different interactive objects that would populate the map too.

If you're using a vertex that has 64 bytes; 4MB buys you 65536 vertices. (256x256) Which should be enough for just about anything, and if you need more vertices you split them between several vertex buffers.

Disclaimer: Personally I only recently started using OpenGL and won't be much help answering OpenGL specific questions.

Daniel Dimovski
thanks for the reply! So in my situation creating and dropping would be a positive course of action?The reason I mentioned 64 bytes is that most online resources use a very similar data structure for a vertex.Comments appear to format badly with code snippets, but the particular struct can be found in the first code block at:http://sdickinson.com/wordpress/?p=122Due to the univeral approval of this structure I was under the impression that VBOs required vertex data in this format.
Brian
Brian: "univeral approval of this structure"? if you're talking about the comments in the blog I don't see anyone talking about the vertex format. There is no fixed vertex format, VBO is a just a chunk of memory (VRAM) interpreted as place where vertices are stored with no particular vertex format, it's specified by the client.
snk_kid
sorry for the typo :p What I mean is that I was under the assumption it was the "right" way to do things as other sources also used padding to make the data 64 bytes for what they claim is optimal performance. I'm not arguing with you by any means, infact I've taken note of the information here. I'm merely providing my reasons as to why I initially said 64 bytes.
Brian
Brian: Yes, switching in/out areas is in my opinion the way to go when dealing with large enough terrains.
Daniel Dimovski
A: 

As already mentioned the size of a vertex in a VBO depends on your vertex format so there is no fixed format and thus the size is not fixed. Stats on optimal VBO sizes tend to get out of date, don't expect to get this right the first time just play around with the size and profile it's not going to take you that long to do.

About how many VBOs you can have, yes to many VBOs means lots of draw calls. Also nobody said you have destroy them completely, you can reuse them as many times as you want.

What you was thinking about having some kind of paging algorithm isn't bad at all, there is one well known terrain rendering algorithm that uses this approach called Chunked LOD. This algorithm uses a separate paging thread for out-of-core rendering of static terrain.

Don't try to find the ultimate perfect solution, learn to accept imperfection. Don't depend on everyone to give you the answer or all the details just do it yourself and see. You can always refactor and/or optimize later when it actually becomes an issue otherwise you'll never finish.

snk_kid
+4  A: 

From what I've read, each vertex stored in the VBO will take up 64 bytes.

It can take as many bytes as you want, depending on vertex format.
position + normal + texcoords = 4*(3+3+2) = 32 bytes per vertex
position + normal + texcoords + tangent vector (for bump) = 4*(3+3+2+3) = 44 bytes

That's not including that each vertice may need to be stored multiple times for each triangle.

Identical vertices should not be stored multiple times. Use indexed primitives (triangle lists or triangle strips). Bind buffer for indicies, then use glDrawElements and glDrawRangeElements . Keep in mind that you can use quads in OpenGL - you don't have to use only triangles.

(4096x4096x64)

You don't need to create quad for every pixel on the map. Some areas are completely flat (i.e. height doesn't change), so adding extra triangles there will be a waste of resources. If you add some kind of mesh simplification algorithm to finished landscape, you should be able to drop quite a lot of triangles. Also, too many polygons will lead to problems - A triangle or quad should take several pixels. If there are multiple primitives that should occupy same pixel, the rendered result will be a bit "noisy". So you'll have to take desired level of detail into account.

The problem I have is that most sources state that a single VBO should be between 1-4mb in size, and less VBOs is better.

I wouldn't trust every source, especially on the internet. A lot of people writing tutorials are far from being "experts". Another thing is that in DirectX (not OpenGL), it is recommended to put everything(i.e. all objects with compatible vertex format) into one large static vertex buffer (VBO analog), when possible, and avoid switching buffers to reduce CPU overhead for rendering calls. So advice that "VBO shouldn't be larger than 4 MB" looks extremely suspicious to me.

Information may be trustworthy only if it comes from API developer or from a driver developer (ATI or NVidia). Or when it is absolutely certain that author (of tutorial or article) has a lot of experience in the field and not another clueless wannabe game developer. Documents that come from GDC, Siggraph, ATI, NVidia may be trusted. Some tutorial written by anonymouse "someone" should be checked for being actually correct.

Anyway, regarding performance, microsoft had two documents: "Top Issues for Windows Titles" "Performance Optimizations (Direct3D 9)" (DirectX stuff, but some advices can be applicable to OpenGL).

Also, NVidia has a collection of OpenGL resources, that include performance-related utilities (GLexpert may be useful for you, and there is NVIdia OpenGL SDK, etc.). In general, when you're trying to improve performance, try different techniques, and measure results instead of blindly following someone's advice. See how many extra frames per second you get from using one technique or another.

Yet according to my calculations, storing each vertex would take a total of about a gigabyte of data! (4096x4096x64)

This is correct if you'll build entire map this way. But there is no reason to load entire map at once, so you'll just need immediately visible chunk of map.

I'm looking at games like Oblivion or Fallout 3, and to some extend Boundless Planet, and seeing massive terrains, and wondering how on earth that can be possible.

They DON'T load everything at once. Only objects that are visible, current "chunk" of terrain and low-polygonal version of few nearby terrain chunks are loaded at any single moment. Game stores only object that are currently used, or that will be used soon. It constantly gets data from HDD.

SigTerm
Alright thanks :) I'll keep that in mind when looking through examples, perhaps the 4mb rule was just outdated, and thanks for the link to the resources, GLexpert would come in really handy when experimenting with this!
Brian
The 4mb recommendation is likely the optimal vbo size for rendering as defined for certain nvidia cards. This optimal size is different for every card, so the general rule is to not use vbo that are too small or too big.
5ound
+1  A: 

I suspect you're not using height maps as intended. You have a 4096x4096 image, which is an array of pixels, not intended to be used as vertices. The whole point of storing heights in a texture (a.k.a. height map) is to avoid such a level of detail in the geometry (i.e., in vertex buffers).

The exact usage technique depends on your context. If the terrain is for visualization only, I'd recommend presenting it on a single quad (4 vertices), and using shaders like light maps, displacement mapping or parallax mapping. If it is intended for some interaction with other objects (e.g., characters walking on it), then some geometry is in order - but certainly not 4096x4096. Here's one way to sample the height map adaptively, by it's local detail level.

Ofek Shilon
A: 

If you page data in/out, you'll need at least 4 VBOs in case you're rendering near a "four corners" boundary. But as you move around, you can replace the data within these four VBOs instead of creating/releasing them all the time. For this method you should use one of the "dynamic" usage flags, to let OpenGL know that the data may change, but it will be used more than once each time.

Ben Voigt