Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs

[Quickfixed] Blurry small text

A topic by Rarykos created Sep 13, 2017 Views: 938 Replies: 10
Viewing posts 1 to 10
(1 edit)

Hey!

I have a problem! I'm using UI Super Text Mesh on a canvas with a normal .ttf font, everything's okay for bigger sizes but for small sizes like 18-36 px it gets really blurry sometimes. I've been playing with different settings for 8 hours today and I'm getting a bit desperate. I tried bitmap fonts etc, and the best solution was to use just the .ttf font ,set it to size 500, Hinted Smoothing,  Quality = 21, Size = 0.21, but still there are moments when text changes and it decides to get blurry.

I think it's because characters can move in sub-pixels, so every other line gets blurry and sometimes one line accepts 8 characters and is sharp, but with 9 characters it gets blurry... It's really noticeable when changing alignment, it's always blurry when Centered.

I'm currently making a 2D game where small bubbles appear above characters, so I can't really increase the font size :(

Can you help me somehow?

Developer

Hey!

Here's an experimental pixel snap shader I've been working on, let me know if this changes anything: https://pastebin.com/qjn5grc3

Have you tried a different font and seeing what happens? Or try seeing if the same thing happens with Unity's default UI Text? When messing with this pixel snap shader, I found that some fonts had kerning values that made things line up in really odd ways, and that the exact same problems were happening with the included UI Text, too.

Also, try making the quality value match the size, and see if that helps at all? For UI text, the size /should/ be the actual screen size in pixels, so quality should match up with that. Also see if changing the filter from bilinear to point does anything!

The centred text having this all the time makes me think it has to do with pixel snap, so hopefully the shader is a good starting point? It's not perfect yet, but I want this shader to fix this problem in the next version.

(1 edit)

Thank you for the quick response and possible solutions!

I've tried everything at this point. Battling with this for the second day...
I forgot to mention I'm using a canvas in World Space, so I must scale down either the font or the canvas. Scaling down the canvas works best. I've noticed Dynamic Pixels per Unit don't do anything, so just canvas.scaleX= scaleY=0.01 with huge canvas width and height.

The best setup I've found is:

*size = quality =19 (for my font 1st Sortie)
* .tff font size 500, Hinted Smooth
* filter mode Point
*using that Pixel Snap shader

I've pinpointed the problem. Horizontal alignment. I can't Center or Justify text or it gets blurry. Image below.


I should add that I don't use floating point at any values, line spacing = 1 etc.  Object position, width and all other variables are integers.

I can now use small fonts, so I'm happy for that, Super Text Mesh is a really cool and helpful asset, but it's a shame I can't center the text. :(

Developer

The centred text has gotta be an issue since it's not aligned perfectly, so... the solution would be to get it to line up right. The pixel snap shader /should/ have done this, but I guess I still have more to figure out with that. It might also be possible to align it to the grid inside of STM's code, but that feels like a bit of a clunky solution to me.

I'll give the shader another shot soon! I really hope I can get it working right.

Okay thank you!

Developer

Gave this a huge look-over today, the blurring in your screenshot looks like the type from the font's filter mode, so try changing that from bilinear to point? Other than that, I'm unfortunately not having much luck making this pixel snap shader work much better, yet. I know that friends who have done pixel-perfect games before usually use some combination of render textures to achieve the effect, but I'm not sure if that's compatible with Unity UI.

I also tried comparing Unity's default UI text to STM, and Unity's does seem to do pixel snapping a bit better, but still isn't perfect, either. Since the problem for you seems to be based on when the text is centered, maybe it'd be best to just align it to grid?

I've tried doing this through vertex modification (under the position foldout, check "modify vertices"), and it seems to have pretty good results? It looks about the same as the build-in text stuff, but my setup could be different. Here's the function I'm using:


public void AlignToGrid(Vector3[] verts, Vector3[] middles, Vector3[] positions){
        //figure out offset of first position to grid
        Vector3 firstPosition = positions[0];
        Vector3 roundedPos = new Vector3(Mathf.Round(firstPosition.x), Mathf.Round(firstPosition.y), Mathf.Round(firstPosition.z));
        Vector3 posDifference = firstPosition - roundedPos;
        for(int i=0, iL=verts.Length; i<iL; i++){
            verts[i] += posDifference; //apply this offset to every vertice
        }
    }

make sure the event is set to happen while the editor is running, too! I'll be adding this function to the next update, so you can see it in the sample scene, too.

Oh wow! Yeah that almost solves the problem, it's not perfect because it only works on the first line. Other lines still have positions like 198.5. Tried rounding every vert[i] - that's a mess, but made me think if I could apply different offsets for different lines that would fix everything. But I'm not sure how I'd get the first position of a new line.

Developer (2 edits)

Oh oops, you're right, it's only based upon the very first character right now!

You can see if the row is changed by seeing if position[i]'s y value is different than the previous one! The position[] array is the base position of each letter, so the y value shouldn't change unless the character drops down a row.


Give this a shot, still not sure if it's perfect though:

public void AlignToGrid(Vector3[] verts, Vector3[] middles, Vector3[] positions){
        //figure out offset of first position to grid
        int rowStart = 0;
        Vector3 posDifference = RoundDifference(positions[0]);
        for(int i=0, iL=positions.Length; i<iL; i++){
            if(positions[i].y != positions[rowStart].y){
                rowStart = i; //new row
                posDifference = RoundDifference(positions[rowStart]);
            }
            verts[4*i+0] += posDifference; //apply this offset to every vertice
            verts[4*i+1] += posDifference;
            verts[4*i+2] += posDifference;
            verts[4*i+3] += posDifference;
        }
    }
    private Vector3 RoundDifference(Vector3 original){
        Vector3 roundedPos = new Vector3(Mathf.Round(original.x), Mathf.Round(original.y), Mathf.Round(original.z));
        return original - roundedPos;
    }

(1 edit)

It works, thank you! I was worried if it would still work on wavy text but it's fine.

Edge case : Anchoring it at Middle Center causes a weird thing. Every other line moves up and down trying to adjust offsets on every rebuild.

This is how it looks inside the editor when selected:

Rect transform is anchored at top left, integer positions, width 521, height 73 - constantly changes to 74,73,74,....

Inside the Super Text Mesh component the text is Anchored at Middle Center, and it's Centered. A quick fix I've found is setting the Base Offset y to 0.1, then Rect transform height changes to 72.9999 and the dancing stops.

Or just setting the Rect transform to also be Centered.

Developer

Oh weird... but I guess a quick fix to a quick fix isn't so bad? I'm trying to think of what would even cause this to happen - the same math should be happening every time. I really want to get the shader doing all this automatically in the future, so I really hope this works for now?

Yeah, I'm satisfied! Maybe put it in the FAQ, "if centering and aligning to Middle Center causes the text to dance, add a small 0.01 base offset Y".