I have a map that consists of many HexTiles in 3D. Now I want to overlay information for each tile.

The first method I tried is making a seperate viewport and using a viewport texture to display the information on the tile, but the performance is really bad and it uses too much vram, because I need too many viewports. Even sharing viewports for tiles that display the same information does not work.

The next method I tried is projecting UI elements directly to the tile with unproject_position() and scaling the elements accordingly to the distance to the camera. This method works really well for smaller maps (60x40 tiles), but for larger maps (max 300x200) the performance drops because the position is calculated every frame. Even using multiple threads does not help much.

Is there a solution I am missing or are there any workarounds you can think of that allow me to display information for every tile?

Thank you very much

You could perform unproject_position() less often to avoid performance drops (using a Timer node with random offset on each instance), but this will cause the UI to visibly lag behind when the camera moves.

Alternatively, you can display less UI elements (e.g. only display them if they're close enough to the mouse cursor).

Billboards in 3D space should be pretty fast (since you won't need to project the position, they already exist in 3D). Just a quad mesh with a texture on it. You could easily have thousands of them with no problem updating in real-time 3D. The actual UI would be a texture you'd have to render (using a viewport for each UI element is too much, they are very heavy). So you'd need to take each UI scene and save it to a texture, then update the texture on the billboard. But this can't be every frame, so you could update the UI like once a second (or several seconds) and space them out so the whole UI doesn't refresh every frame (like just update one billboard on one frame, the next frame update the next billboard, etc.). Also, how many tiles do you have on screen, and is it really necessary to have a UI on all of them visible at all times? Maybe only show the UI when you mouse over the tile.

@Kjell291 said: The next method I tried is projecting UI elements directly to the tile with unproject_position() and scaling the elements accordingly to the distance to the camera. This method works really well for smaller maps (60x40 tiles), but for larger maps (max 300x200) the performance drops because the position is calculated every frame. Even using multiple threads does not help much.

Adding to optimizations mentioned by others; unproject and display the UI only for tiles that are inside camera frustum and are close enough to the camera. For very large maps you'll have to employ some type of hierarchical space partitioning scheme (like quad tree) to avoid brute force iteration over tiles.

@Kjell291 I was planning on doing the rest of my UI objects this way. I really like having all the 2D control nodes projected in 3d. Reading @cybereality ’s suggestion though at most I’ll keep the one I’ve done (maybe) and use billboards for the next ones. I guess for displays in 3d the planning should start in the modeling phase. But even something simple like having one part of a 3d object be for displaying a loading bar it seems like quite a lot of work, and not work that’s easy to change or fidget with. Shaders will be involved I’m sure.

Thanks a lot, I will implement your suggestions right away.

Ahhh! I thought I only had one such viewport in my game but it I forgot each one of my grid components also has it's own! If you can, (like I can) just let them share one. In my game I can make it so only one such tile displays info at one time. This way I can just shuffle one of these useful viewports around as different tiles need them. I noticed before after 80 or 100 or so of these scenes loaded in with the viewports my game would break. Now I'm starting to think it was because of all these cool viewports.

a year later