Looking for a good approach to render tiled-based maps efficiently

I am creating a grid- or tiled-based map system in C++. That system uses quadratic meshes as ground planes for each grid cell.
Maybe something like this (just an example, not my game):

First I tried to create a new simple actor, with a static mesh component, for each grid cell / ground plane / tile. But it turned out for large maps (say 100 x 100 = 10.000 map cells or even larger), for example when rotating the camera around the map zoomed out, then FPS would drop drastically. I thought that are just too many actors transformed each tick.

So I changed the system to use instanced static mesh components with one single actor instead. That works fine also for such large maps. However, now I encountered the problem that every time I remove a mesh instance (to replace it with another tile / mesh instance) that removal takes a bit of time, which adds up when I remove many mesh instances at once. From my research this seems to be normal ISM behaviour.

So … what would be a better approach to deal with this requirement of tile- or grid-based maps built UE4 via C++?

Are you using memory pool to keep the reference memory of the tile and just reuse it instead of creating another one ?

When I replace a tile with another one then I remove the mesh instance of ISM component A and add a new mesh instance to ISM component B.

Instances in an ISM are just a linear list of transforms. Removing items from arrays like that is not optimal, since all elements after the removed item must be shifted. You need a different way to manage the instance arrays more effectively. I don’t know how you are keeping track of which index in which ISM component each tile is, so here are some ideas:

  • You can copy the transform of the last instance in the array into the index you removed. This way removal would be super fast, but the order of the items will change so you’d need to keep track of this somehow when you need to change this tile again.
  • You can try to set the scale of the instance you removed to zero and add its index into a list of “free slots”. When adding a new instance, reuse the indices from the “free slot list”. I never tried this, so you’d need to set to see if there’s any overhead to having zero-scaled instances

Also, remember that ISMs don’t do per-instance culling. If any part of the ISM component bounding box is visible, the whole thing is rendered. So if your level is much larger than what the camera can show, it would be wise to break your level in smaller “chunks” of tiles. Changing one 16x16 or 32x32 chunk’s instances would also be much faster than changing the instances of one massive ISM with several thousands instances.

Thanks for your ideas @Manoel.Neto, I will have a look at your ideas!

I am more and more thinking that this whole ISM idea is not the best approach. Wouldn’t it be better to have a “normal” landscape actor (i.e. only one mesh) and only place the tile textures or materials (e.g. for a road) via decals on to the ground? Or is there a better way to “paint” textures/materials in a grid on to the landscape actor?

If you’re not going to be changing heights like the picture you provide, paper2D has a really nice map editor.

Might be worth checking out. Even if you plan to change heights, you may be able to utilize this feature.
Unsure if this can be changed at runtime though or if it’s editor only, if you play to do some sort of dynamic level creation.