Crisp Text and linkWithMesh() Results in Incorrect GUI Position

According to the docs, in order to get crisp Text, set this:

advancedTexture.rootContainer.scaleX = window.devicePixelRatio;
advancedTexture.rootContainer.scaleY = window.devicePixelRatio;

But then GUI controls that linkWithMesh have incorrect position:
https://playground.babylonjs.com/#2ARI2W#138
which should be positioned like this:
https://playground.babylonjs.com/#2ARI2W#139

Is this a bug, or does it require adjusting something else?

Hi!
Try to use advancedTexture.renderScale.

1 Like

Adding @msDestiny14 and @PirateJC for the doc

Oh this might be a bug. Looks if you if your device ratio is not 1. Adding render scale back will make it blurry. Let me log it and take a further look.

Side note about render scale: There was a bug in 4.2 with link meshes and render scale but has since been fixed with this PR currently in the latest build. Fix for link with mesh and render scale by msDestiny14 · Pull Request #11218 · BabylonJS/Babylon.js · GitHub

We can update the docs for sure to add renderscale as an option. :slight_smile:

It would be great to look into it soon if it is a bug and link the github issue here for follow up

2 Likes

After further investigation this is not a bug. Instead this is functionality correct.

The solution of using render scale is correct provided you do set the correct hardware scaling to match. (I hard code 0.5 as the scale in this example to be consistent for everyone looking)
https://playground.babylonjs.com/#2ARI2W#140

1 Like

Actually @ecoin is setting both scales to the same value and that’s not right.

Further explanation of what’s happening when you set the root container’s scale.x and scale.y. Best way to show this is debug drawing in the inspector.

When we set the root containers scale. We are basically taking all the correct calculations we had and saying “shrink that” by the center. So now the entire boundary of the adt has been changed. If you were that determine to go the scale route, you would have to manually offset the position of the adt to match.

I will definitely update the documentation to reflect this!

Hope that gives a little more insight and let us know if you have any questions about this.

2 Likes

Hi @msDestiny14 ,

Your playground example rendered blurry text on my comp (it is more blurry than normal), even though my device pixel ratio is 2, so renderScale 0.5 should work.

Please clarify how to use renderScale correctly if I misunderstood.

The goal is to get both crisp Text and linkWithMesh working, not either or.

Your set device ratio and render scale should be the same value. So if your device ratio is 2 I believe you should also set your render scale to 2.

I arbitrarily hard coded 0.5 in my example since my actual device ration is 1.

That doesn’t work, I tried, the 20px fontSize becomes 5px (i.e. it got smaller by x4 times), so did the Multiline, which was supposed to have 1px lineWidth, became almost invisible.

Which means the renderScale here must be 1/window.devicePixelRatio - which results in correct fontSize, but blurry text like above screenshot.

Ah, yes! I see what you mean. You are correct the engine.setHardwareScalingLevel should be 1/window.devicePixelRatio. Right right.

I’m not entirely sure why it is blurry on your screen but not mine then…even with the same values. hmm :thinking:

If changing the rootContainer.scale.X worked for you. How about just changing the scale.x of the button container itself? Your text is inside the button container.

1 Like

I had the same issue with blurry text using the renderScale solution but scaling the button as recommended looks nice and crispy (I had to scale both x and y otherwise the button was half as tall as it should be). I’m on a new MacBook with devicePixelRatio 2, so maybe a 2X device is needed to see the blurry text issue I guess. :beers:

https://playground.babylonjs.com/#2ARI2W#143

2 Likes

Looks like a bug, Blake’s solution worked for Text, but then Images and all other GUI controls that do not have scaleX, scaleY set got smaller x2 times.

The blurry issue happens to all GUI elements, including SVG image, MultiLine, Rectangle, etc.

1 Like

@sebavan, is there another alternative solution to get crisp GUI, without setting engine hardware scaling level?

I see similar issue three years ago, still not resolved.

Correcting: this example had reversed label, setting engine.setHardwareScalingLevel < 1 did result in crispier 3D content. But current work around requires setHardwareScalingLevel < 1, and manually setting all GUI controls with scaleX = window.devicePixelRatio.

Right now, it’s impossible to achieve crisp GUI on retina screens without suffering performance for 3D content.

This is not an issue we can resolve easily or within the framework. Basically it all boils down to how high dpi is handled.

By default we use css size meaning the back buffer of the canvas is inversely proportional to the zoom level (devicePixelRatio) so every canvas pixel are laid out on several native pixels → text looks blurry.

By changing the hardwareScalingLevel you now have on the canvas back buffer the same res as native which is a lot of pixels to display and rendered think about rendering games at native 8k for instance which obviously is a lot but the text would not be blurry.

The only workaround bringing the best of both worlds could be in your application to setHardwareScalingLevel to native res, then render all of your scene but gui into a renderTargetTexture of your css or desired resolution (smaller than native)

Finally, blit the RTT on the canvas (linear interpolation to magnify) and render the GUI on top.

This would only work for full screen GUI and not for texture created for 3d content.

3 Likes

Using RTT could end up being slower because I have hundreds of Meshes, Materials and Textures on the scene.

Would be more useful to have a 3D position → 2D screen coordinates link observable that I can use to render Text and all other GUI elements using React/ReactNative components with CSS transform: translateX..., instead of Babylon’s GUI.

Does Babylon have something like that?

It opens a lot more possibility than what Babylon GUI currently offers. It means you have the entire frontend UI ecosystem at your disposal, and less components to maintain for Babylon.

RTT would only be slower due to the extra copy involved to the main canvas. Not related to the number of meshes and such.

But saying this linking a mesh to html position can be found here: World To Screen Point - #4 by MackeyK24

1 Like

@msDestiny14 you can look into this PG for the blurry text repro with renderScale: https://playground.babylonjs.com/#2ARI2W#146

1 Like

@msDestiny14, do you have any update on this one ?