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.
A vertex buffer object (VBO) is an OpenGL feature that provides methods for uploading vertex data (position, normal vector, color, etc.) to the video device for non-immediate-mode rendering.
VBOs are intended to enhance the capabilities of OpenGL by providing many of the benefits of immediate mode, display lists and vertex arrays, while avoiding some of the limitations. They allow data to be grouped and stored efficiently like vertex arrays to promote efficient data transfer.
A VBO is a buffer of memory which the gpu can access. That's all it is. A VAO is an object that stores vertex bindings. This means that when you call glVertexAttribPointer and friends to describe your vertex format that format information gets stored into the currently bound VAO.
The simplest method of updating VBO is copying again new data into the bound VBO with glBufferData() or glBufferSubData().
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With