Slow GUI rendering

Yes, that’s right.

No, I haven’t tried that. Does that make sense? There could be dozens or hundreds of hotstops

They have to redraw themselves every time the camera moves

I create them once, if it is a hotspot with a timer it updates its time text every second

const hotspot = new Container();
ADT.addControl(hotspot);
hotspot.linkWithMesh(attachmentNode);

I believe not. Not in this case and not until we get this cloning of ADT feature I’m still waiting on :grin:

For the rest, I will leave @carolhmj (my GUI mentor :woman_teacher:) reply :grin: I don’t feel like taking a chance giving the wrong answer here :grinning: I guess you provided enough information for that to happen. Shouldn’t be all too long… :hourglass_flowing_sand:

2 Likes

Hello! Wasn’t able to check this earlier, sorry! First thing, I’ll add to Seb and say that the game is looking very very nice already!

I’ve started investigating your example and will report back!

1 Like

I’ve tried doing some captures in your scene using CPU slowdown so the problem gets more visible. What looks like to be using the most time is drawImage, like in these two frame examples:


I imagine you’re using some high resolution images for your game, and certain graphic processors (maybe machines with integrated graphics?) struggle to draw them. Keep in mind that when using a GUI image, it is drawn on a 2D canvas context first and then passed as a texture to the 3D main context. And the 3D frame has to wait for the 2D GUI layer to be drawn, which slows everything down. You can see on the captures that _renderForCamera has to wait for _checkUpdate to finish everything before it can end.

One possible solution would be to lower this resolution. It could be something adaptive, where you detect the agent and adjust the images resolution accordingly. Another option would be to move those elements that rerender many times to use billboarded meshes instead of linked GUI. I put together an example here, the two methods aren’t looking exactly the same, but it can be further refined and adjusted: Simple GUI in fullscreen mode | Babylon.js Playground (babylonjs.com). The idea here is, well, since the CPU is struggling to draw these high res images in a 2D canvas context, bypass it entirely and render on 3D context as a texture.

There are other further explorations that could be ventured, like maybe rendering the GUI only every X frames, but I think these first two solutions are simpler.

In addition to pictures, hotspots also show timers (text), so I need DynamicTexture as a minimum. Would it be beneficial if I have to create 100 hotspots (100 dynamic textures)?

Nope, since if those 100 hotspots each have an image, that will still be the same number of drawImage calls which look like the main blocker.

As for the text, there is a way of showing it without having to rely on canvas, which is using an texture atlas. For that, you use an texture that has all the glyphs:
image
and sample uvs from the texture based on the text you want to write. It’s more work than using 2D context, but it can be faster.

EDIT: Also found this GPU text rendering with vector textures · Will Dobbie (wdobbie.com) which is an alternative technique for rendering text fast on the GPU. But I don’t think text is our main problem here, it’s images.

Something that can be done at the framework level itself later on would be to use Web Workers to handle the 2D context, thereby freeing the main thread for rendering 3D only. But since we’re close to 6.0 release, this wouldn’t be started until after the release.

1 Like

Expanding on my question about an texture atlas, an example of how it could be applied is here:
Counters with GUI and billboard instances | Babylon.js Playground (babylonjs.com). It uses instanced planes in billboard mode and a node material shader to show the numbers. If you compare it with the GUI approach, which is also on the example (controlled by the variable useGUI in code), the shader version runs some 10 FPS faster than the GUI one, at least here on my machine.

Sorry, I must be stupid but there is this one thing I do not understand. Will you really have 100 bumbles showing on top of the map at the same time? It would create a mess, wouldn’t it? From the example I saw in the original post only a few of these bubbles/clouds show up at the same time and when you move the scene or interact with another, the previous one(s) disappear. Something I can take in a game. I likely won’t play a game where I have 100+ bubbles/clouds showing-up at the same time. I’m afraid I do not have the brain (nor the eyes) to cope with that much information on display at a same time. Of course, my opinion only.


Hi, I may have exaggerated the maximum number of bumbles a little, but I think 50 could still be:)

Yeah, more like it. I can count 27 in this screenshot. I don’t think more than 50 would be a good thing.
Solves half of the problem (but then only half :sweat_smile:)

Gives me an opportunity to ask you: Where do we stand with this cloning of ADT? At some point during the ‘Gui Adventure’ event, deltakosh and patrickryan seemed to wanting to challenge each other to whom would bring it first… Never heard of it again since then :grin: Faced any issues? Didn’t bring the expected results? :thinking:

Would it maybe be more efficient to use like a Solid Particle System or a Thin Instances that is just using quads and transparency textures?

1 Like

We have a clone method on the ADT already, is that what you’re asking for? I also ended up implementing clone for individual controls when I reworked the PG-GE connection.

Really. I must have missed it. Is it referenced in the doc? I must return there and check this out.
Thx for the info. I was eager to try that.

It is on the docs we auto generate from the classes: Control | Babylon.js Documentation (babylonjs.com), but I don’t think we have it on the documentation page itself :thinking: I need to make an example PG and add it there too :sweat_smile:

EDIT: Ok, added :slight_smile: Update gui.md by carolhmj · Pull Request #804 · BabylonJS/Documentation (github.com)

For the images, using sprites would probably be simple and would be just a single draw call.

For text, the approach above could work (Slow GUI rendering - #21 by carolhmj), or perhaps sdf (simple example here, or counting here) or msdf. This again would be just a single draw call.

I would just use Dynamic Textures and draw the base image sprites first then draw the text.

2 Likes

Definetely is. I’m gonna try this out pretty soon now. Thank you :smiley: