Engine V2 migration causing issues with text/ui

Hi all

I’ve started migrating our project to engine v2 and the text in the ui has become blurry?

Left is v2, right is v1.

Can anyone explain what’s happening here?

I’m also noticing a big difference in the colours generally speaking, but I assume that is somewhat to be expected…

There should be no color change. If you see one, it is probably the color space difference. Make sure in v2 your texture has sRGB checkbox ticked. As for blurry text, not sure. If you could create a blank project with only a text element that shows it is blurry, we could take a look.

Could be related to this PR? fix(element): render MSDF text at the true glyph edge by willeastcott · Pull Request #8935 · playcanvas/engine · GitHub

I recommend checking out this PR @lemonmad

Fonts are now rendered at the exact same weight as your source TTF font asset. At the same time, font artifacts should be pretty much eliminated.

Previously, developers would get around this by selecting the font asset in the Inspector and tweaking the Intensity property. If your project has that, you can now set that back to zero.

I’m happy to help investigate further if what I write above didn’t help.

Just checked intensity and all fonts the project are set to 0.

So just to confirm I loaded the same fonts into an empty project and switched engine version, there is definitely a difference. Most notable on the poplar font but they all get a little tighter in the sharp corners and inside spaces. (The last image is just from open office, a sanity check haha)

Can you provide me with the URL of that new project please?

It looks like this is just a limitation of the 64px per character font atlas. If we bump the character cell size to 128px, you get this in comparison

Here is Claude’s explanation of why wasn’t this a problem with engine v1:

Because v1 never actually rendered the glyph at the edge the atlas encodes — it had a built-in erosion bias that happened to be bigger than Poplar’s encoding error.

The mechanism. The v1 shader remapped the sampled field before thresholding: sigDistInner = (sigDist − 0.05) / 0.95, then applied smoothstep around 0.5. Solve that for the raw field value and v1’s effective edge sits at 0.525, not 0.5. Every glyph rendered ~0.2 texels thinner than the true outline (0.025 × pxrange 8).

Poplar’s counter valley is encoded at 0.498 — the data says the hole barely exists:

  • v1, edge 0.525: the valley clears the threshold by 0.027 → renders as an open hole (my sim of the actual v1 math gives ~0.33 alpha at the valley center — dark, clearly a counter).

  • v2, edge 0.5 (true edge, per the msdf contract): the valley misses by 0.002 — one byte — → ~0.48 alpha, a half-gray smudge.

So the atlas data was marginal all along; v1’s bias silently absorbed a ~1-byte encoding deficit, and #8935 removed the bias because faithful weight was the goal (“fonts now render at the exact same weight as your source TTF”).

Two supporting effects:

  1. v1’s erosion wasn’t free — it had the mirror-image bug. Values just above 0.5 (hairline strokes) got eroded to nothing: thin crossbars and strokes dropped out of magnified text, and all fonts rendered lighter than designed. That’s #2948, the very bug #8935 fixed. Poplar’s hairline counter lives in exactly the zone the old bias protected; hairline strokes live in the zone it destroyed. You can’t set one global threshold that saves both when the feature is ~1 texel wide — only more atlas resolution genuinely fixes it.

  2. v1’s minification blur hid the rest. v1’s smoothing term saturated at 0.5, so small text went uniformly soft, and its mipmapped atlases corrupted the median the same way v2.20’s did — but with the eroded threshold, corrupted values regressing toward 0.5 classified as outside, so the failure read as “text fades/thins at distance” (a familiar v1 trait) instead of “counters fill in against crisp strokes,” which is much more noticeable.

So: same marginal data in both engines. v1 = biased renderer + soft AA that masked the data’s flaws (while causing its own); v2 = faithful renderer that exposed them. The 128-cell atlas fixes the data itself, which is why it holds up without needing either bias.

So the real solution here is to expose a Character Cell Size option in the Editor’s Asset Import settings. 64px/128px being the options.

Thanks for looking into this!

Is this something that is likely to be implemented soon, or should I find an alternative font?

I think me and @KPal can get something implemented into the Editor to allow you to pick a font atlas resolution in the next few days.

Amazing! Thank you :smiley:

Would this solution also fix the issue where text becomes very distorted the further it is from the camera?

Screenshot Capture - 2026-07-09 - 15-31-35

Screenshot Capture - 2026-07-09 - 15-31-14

This only seems to have happened some time in the last 2 weeks and we’ve been on Engine v2 that whole time.

I’m not quite sure. Can you please share a reproducible test case, @Devortel?

It only seems to happen when the text has an outline, here is an example:

Interesting, thanks for sharing. I see this on my Win11 laptop:

Interesting, this is a build we have deployed to production: https://poki.com/en/preview/a601b558-b49f-46c8-a13e-78b975209c89/d7247fae-8f73-499a-8bd7-5d3a9bb596f3

On your Win11 laptop, do the timers underneath the scoreboards look blurry at a distance?

I see:

Damn, sorry that example wasn’t very helpful then. Your browser isn’t connecting to our multiplayer servers or leaderboards endpoint.

Edit: I think those endpoints are blocked in the UK, that’s why it didn’t work.

I’m going to give up on this bug for now, it’s not game-breaking

Oh, are you sure? I’m happy to debug. Which OS/browser are you seeing this in?