I'm asking this question because I haven't found a definitive answer to it.
Let me first of all state a few things about the game and what I have already done. The game is a going to be a RTS set in a procedurally generated world using Simplex noise. The world consists of chunks which are 16 x 16 in size made of sprites that are 64 x 64. I've managed to load and unload chunks dynamically, which works just fine. The world is going to look a bit like Rimworld, so top-down with different layers of sprites (terrain first, transition sprites, trees, decals etc). Newly generated worlds may contain entities that may affect the environment (eg. a village that has become a town) and thereby the chunk. I'm sure this can be calculated using some sort of function, but it's something to take note of.
The main issue I have is when I zoom out, more and more tiles are drawn which severely affects the performance. At about 30000 sprites, the draw section takes 8 ms which is half of what is required to run at 60 FPS. And that's just the terrain. I am using texture atlases to limit draw counts (30000 sprites drawn in 6 counts).
The goal is to be able to zoom out from town/village/city level all the way to being able to see an entire country. This has to be done dynamically (eg. not by clicking on a minimap icon, but just scroll back just like in Supreme Commander).
I've read many articles about this issue, but I haven't found or seen a clear example of where it would work. Here's a list of techniques I have found that are supposed to work:
- Dirty rectangles, as described here, where you only draw new stuff and keep the rest in the backbuffer. This makes a lot of sense, but I am clueless as to how to implement this in Monogame.
- My preffered choice: make extensive use of RenderTargets, as described here, where you draw to a RenderTarget and then save it as a texture. In my case a 16 x 16 chunk consisting of 64 x 64 would create a 1024 x 1024 texture. I really doubt this will work in terms of performance, but the result would consist of highly detailed textures and is also great to use considering the fact that most of it is static (terrain/trees etc), and doesn't change as much. But this also means that everytime a change is made to a chunk, that Texture2D has to be changed using SetData, which from what I've experienced is quite CPU intensive. However if the textures were 16 x 16 it may actually work, and it would also cut down own memory and disk usage.
- Til textures by specifying the SourceRectangle in SpriteBatch. For huge grasslands/oceans this is a plus, since only one sprite is drawn. However for detailed terrain with different colours and different sprites mixed together (biomes and biome transitions) I'm afraid it won't make a huge difference.
- My own solution, which compromises detail, was to use a standard white 64 x 64 tile, give it the colour of the surrounding 4 tiles and then scale it so it covers the 4 previous tiles. The difference here (besides the tile having a plain colour) is that the landscape visibly changed. I should also mention that forests still have to be drawn individually since they aren't perfectly square.
If anyone has any idea on how to tackle this problem, even if it means compromising certain things (such as detail, or using 16 x 16 sprites), I would love to hear it.