One of the biggest challenges of graphics programming is handling the CPU overhead of the API calls that move memory around and that update buffers and resources. For open-world games, one of the most expensive operations is copying the vertex and index buffers over to the GPU.
The first thing I did for my renderer was the naive approach. I made a model struct and each model had it's own index and vertex buffer so that when rendering I would just copy over the vertex and index buffers for each model and then render accordingly. This worked during the initial stage, but once I started adding in more assets and ran the profiler I saw how inefficient it was so I decided to do some simple optimizations.
The biggest optimization in the renderer API calls was combining compatible buffers into one big buffer and reducing the number of API calls for updating the index and vertex buffer. This allows us to now have a few large copy operations in the render loop and then use draw calls that index into the unified buffers using offsets stored in each game object as opposed to allowing each game object to store it's own model data and significantly sped up the rendering code.
Further optimizations would be multithreaded rendering calls and using texture atlases to reduce the number of textures that need to be copied. However, given the limits placed on this project that isn't a priority right now.
By Joseph Whittington