Help optimizing my Mapbox-like map implementation

Hi guys,

I am working on pretty-much replicating this example of Mapbox with threejs: https://docs.mapbox.com/mapbox-gl-js/example/satellite-map/. My current result looks pretty much alike but I am noticing slowness in rendering on my Desktop (dropping to 45 FPS when panning or zooming a lot). Ideally I would like it to be smooth on a weaker graphics card (13" inches MacBook Pro from 2 years ago), which in its current state is unlikely since according to the profiler, latency is spent in WebGLRenderer#render.

Now regarding the implementation, the gist of it is that whenever the camera moves:

  • I add the tiles that need to be rendered
  • I clean-up tiles that aren’t required anymore

I represent a Tile as a Group containing a Mesh, made of a PlaneGeometry and a MeshBasicMaterial. Tiles are often added and removed from the scene (I use a pool to recycle tiles so the geometry and material aren’t recreated, only the texture changes).

While I am currently fighting with Z-fighting because tiles of different LODs overlap, I am also wondering if there isn’t a radically different approach that would yield better results. Something like maintaining a large plane/texture, “blit’ing” tiles onto it and playing with shaders for instance? Before moving forward with such a big change, I was hoping to get some feedback first in order to not waste my time going in the wrong direction.

Thanks in advance for your advice!

A few of things.

First, I think having plane geometry in there and grouping that mesh is an overkill - it’s just not necessary, drop at least the group.

Second, make sure your materials are similar enough that they don’t re-compile.

Third, make sure you don’t have too many tiles in view at the same time. If you have, say, more than 100 tiles in view at the same time - you are probably at the wrong LOD.

Fourth, Overdraw. If you are displaying several overlapping tiles - you are overdrawing, this wastes GPU bandwidth.

Fifth, make sure you purge old tiles from the Cache (three.js records and stores all textures in a thing called Cache). Otherwise you will be leaking memory.

Sixth, Use BMP format for textures, this will avoid decoding, decoding can be expensive.

Thanks for the tips!

I will remove that. I originally had the group to add an optional wireframe for debugging.

They are all the same size but have different polygonOffsetFactor to attempt to solve the Z-fighting. As you suggested I will stop overdrawing all together, which will remove the need for that difference. Anything else to keep in mind to avoid them to recompile?

Yes, 100 is definitely the upper bound. Since I am doing 3D I am mixing LODs to limit the amount of tiles being rendered.

As mentioned above I am now working on this following your advice.

Do I need to do anything more than calling Texture#dispose()?

Unfortunately constrained by the tile provider I am using. At the moment it is JPEG.

Thanks a bunch for the pieces of advice, I will report back once I implemented them! :slight_smile: