What you described here is called Resource manager or at least a part of resource manager. Describing resources in an external file is a good practice, so you need a resource file where all your meshes are described in some way (consider using XML or JSON).
Class hierarchy
Here is a possible approach to class hierarchy:
Each VAO represents a mesh, defining it's vertex coordinates, texture coordinates, normals, vertex colors and so on. I think there is no reason to use same VBO in several VAOs until you have a very special case of visualization. So lets assume you use each set of data only once, i.e. classes which use VAOs should not know anything about underlying VBOs and it's not necessary to write a class wrapper for VBO.
A set of meshes (maybe containing only one mesh) represents a model. Minimal model class should include handle(s) to VAO(s) and geometry transformations information (rotate, translate, whatever you want). Why not strictly one mesh per model? Sometimes you may need to apply one transformation to a group of meshes, which of them in it's turn has it's own model-local transformation. For example such composition may be used for a kind of skeletal animation or just for rendering a character with arbitrary weapon taken from library of possible weapons. Moreover, you may group such models together getting more complex models with the same interface, so you will get a resemblance of scene graph. Anyway it's a good idea to use composite pattern for model class.
Scene should include collections of models, light sources, force fields and so on.
Resource manager
But where from will the scene (or similar game object) get it's models? Resource manager should answer this question.
Make each model defined by some kind of unique identifier. In the simplest case a path in real or virtual filesystem may be considered as identifier, but it's not very flexible. To my mind, it's better to define all meshes in your resource file using expressive human-readable names and bind each name to set of data (all types of coords, colors, etc) and attributes.
All your code shouldn't use models directly, but it should use handles given to you by resource manager. Obviously resource manager must keep state during program execution and between calls from different places. It's intended to track which meshes are already stored in memory and keeps VAO identifiers of all stored meshes. Consider using singleton pattern for the resource manager.
Example:
ModelHandle footman = resMan->getModel("footman.model");
//.....
footman->setLocation(x,y,z);
footman->draw();
Here the call to getModel("footman.model") begins construction of the model causing calls like
MeshHandle resMan->getMesh("footman1.mesh");
to get all meshes. And getMesh
does the job caused all this explanation. It checks if such mesh was loaded before and if yes, it just returns handle to VAO containing this mesh. Otherwise it creates new VAO object, loads requested data into it and returns handle to newly created object. All subsequent requests of this object will not cause new VAO allocation.
Surely, described scene graph organization is just a rough approximation to what it should look like. For example, it does not make distinction between model and abstract scene graph node, but developing and fine-tuning such hierarchy for your engine is up to you.
Final interface to resource manager class is another topic to discuss and design. Some questions and ideas:
- Will you use singleton or you decide to use global variable for some
reason?
- If you decide to use singleton, maybe you wish to have some other
private non-singleton resource managers for some limited set of
resources? Then consider designing singleton as a wrapping template
class, to make such code possible:
ResourceHandle h1 = Singleton<ResourceMan>::instance->getResource("foo");
ResourceMan myPrivateManager;
ResourceHandle h2 = myPrivateManager.getResource("bar");
- Will you manage all types of resources with one comprehensive manager
or use special manager class for each resource types? Second approach is better. Developing idea of second approach, charge your compiler with writing the code for you! Use template resource manager class with small subset of specialized method. Just specialize one resource creation method per resource type and get all other resource management code untouched!
- Think over resource lifetime. When a particualr VAO should be destroyed? Consider implementing reference counter and\or borrowed reference.
- Caching? Delete data from host memory immediately after loading it to device (video card) or keep it for some time? For how long?
- What about streaming? It shouldn't be resource manager's domain, but streaming support can affect it.
- glIsVertexArray function and it's analogs may be useful.
Sorting
VAOs are not the only resource you need to change while rendering a scene. You also need to change textures, shaders and even framebuffers
The common way to reduce number of state changes is to sort displayable objects by some property.
For example, it's very likely that you will render a given mesh with only one shader. That's why first you may sort all meshes by shader, so you minimize number of shader changes.Then for each shader (i.e. in the list of meshes for the given shader) you may sort meshes by VAO to reduce number of VAO changes to the feasible minimum. Sort by texture? It depends on your application if you need to sort object by texture and where to do that.
Conclusion
To sum up, if you are writing a game engine, you will need a resource manager anyway. If you write a quick-and-dirty partial solution for VAOs, then you will face exactly the same questions and problems handling textures, additional framebuffers and many other objects, so it's better to implement a good resource manager once.
Useful articles to start with:
http://www.gamedev.net/page/resources/_/technical/game-programming/a-resource-manager-for-game-assets-r3807
http://www.gamedev.net/page/resources/_/technical/game-programming/a-simple-fast-resource-manager-using-c-and-stl-r2503
Very useful book:
http://www.gameenginebook.com/