Advertisement

Performance hit when zooming out in 2D-game

Started by March 14, 2018 08:03 AM
6 comments, last by suliman 6 years, 5 months ago

Hi

Im doing a topdown, 2D realtime city builder in c++. Maps are tile-based. In full zoomed in view (scaleFactor 1.0) i can see 100x70 tiles (7k tiles). But if i zoom out to scalefactor 0.5 i can see 28k tiles. This is where I see a massive drop in fps/performance. No big surprise really.

I know the same is true for some games like they are billion, but any good way around this? I guess I can use some level of detail (LOD) and lower it when zooming out, but i still have to go through all the visible tiles on screen, draw all visible units/buildings/resources/trees etc. It's hard to see where to really cut corners! :) I can disable shadows for example at some scaleFactor. Any good guide or tips when it comes to this?

The tiles themselves require 3 passes as they are drawn in layers (shoreline, tint, top terrain) so this is nearly 100k small images drawn to the screen buffer!

First, you should profile your code to know exactly where the bottlenecks are. But from the looks of it, it sounds like there are just too many image draw calls.

Is there a way that you can consolidate your draws so that you only have to draw one image per tile? Possibly something like:

  1. Merge tile layers to one texture
  2. Draw tile texture

Then you'd have 1 texture draw per tile. 28k texture draws instead of 28*3=84k. And you'll only need to update that merged texture if the layers change. So basically you'd just be drawing 1 texture per tile. This will eliminate probably 3 texture draw calls per tile, so it should probably improve your performance by about 3x.

To take it a step further, would it make sense to merge all of your tiles to 1 screen sized texture?

  1. Go through all the tiles on screen, merge each tile and layer for that tile on to a bigger texture
  2. Draw bigger texture

If you did this in a smart way, you'd have 1 screen sized texture created dynamically that you could draw. That would turn 28k * 3 = 84k texture draws into 1 image draw.

Greg FieldsSyntasoft Gameswww.syntasoft.comPost-Time Horse Racing (Available Now)
Advertisement

Batch rendering of all similar tiles might be a major win too, even when zoomed in.

But most definitely profile the code to see where the bottle necks are, guessing is rarely a viable or useful solution :)

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

A trick I employed once was to merge tiles. Instead of drawing 2x2 small tiles (at sub-pixel level so really not an option), I painted just the most visual one. I picked that tile that was most significant in recognizing the big picture.

For land + water, I picked water

For land + city, I picked city

etc

A screenshot would really help here. From your description so far, the usual trick with a fixed viewpoint is to not draw everything every frame, and only draw the sides of the screen as you move around the map. Then you only need to draw the dynamic stuff on top.

I'm doing this on my current game, I maintain a scrolling texture for the background and render slices of this as you move around. Then I draw it as 4 quads onto the frame buffer, and put dynamic stuff on top. Here is a real early video which might illustrate:

 

On 3/14/2018 at 3:03 AM, suliman said:

I know the same is true for some games like they are billion, but any good way around this?

There are a lot of ways around it, the smart part is to figure out which way would help you, hence, every way starts by profiling and figuring out, what the issue is you want to solve. e.g. reducing LODs while you might be spilling memory, will be just some work, with barely benefits for your goal.

 

I guess I can use some level of detail (LOD) and lower it when zooming out,

You could, you could bake textures, stream lower resolutions, batch draw calls, simplify shaders, vectorize culling, add adaptive resolution, thread commandbuffer generation, use asynchronous shaders, render impostors,.. and everyone will "guess" something else what "could" help you. Now you can either implement random things until something helps eventually, or you have to profile first ;). Once you tell us what the source of the perf drop is, you will also get much better suggestions on optimization. (Not random stuff)

 

 

 

 

Advertisement

I profiled a bit. It's definitely the high number of drawing calls (to draw the terrain-tiles) to the screen. I reduce the 4 (I said 3 in the original post) drawing passes to 2 and I leviate most of my problems. 

The problem is I need to draw the tiles in order so the shorelines look nice (see pic below) so i dont think pre-drawing them works. Maybe I should keep track on which tiles are "close to shore" and only draw shorelines for those: tiles in "inland" or in "open sea" can just draw the top terrain ("grass" or similar) as you dont see the shoreline there anyway.

The loop itself is fine; it's the sprite-draws themselves that drain my fps.

screen.jpg.64931b8367eeae4faf9acb1432aa903d.jpg

This topic is closed to new replies.

Advertisement