bevy
bevy copied to clipboard
Replace the font renderer with one without the issues of anti-aliasing/hinting/subpixel/baseline
Bevy version
Bevy 0.5.0.
What you did
Comparison between the font rendered by Bevy (ab_glyph) and Firefox (with subpixel disabled and subpixel enabled).
What you expected to happen
The font rendered with anti-aliasing in Bevy should be as rendered as close as possible as in Firefox (readable in small sizes, sharp, and correct positioning of glyphs).
What actually happened
Issue 1: aliasing
Font in Bevy is "bulkier". It is possible to notice that the anti-aliasing in Bevy generates a pixel with higher lightness than in the other implementations, that it is possible to notice single pixels without zooming-in (look at the letter e
, for example).
The line on the top is Bevy, the line in the middle is Firefox with subpixel disabled, and the line bellow is Firefox with subpixel enabled:
The values indicated are the values of LCh lightness (using the color picker from GIMP). The lightness of the anti-alias in the Bevy implementation is 3-5 times than in the other implementations.
Issue 2: vertical positioning
Another issue is the positioning of the glyphs on the baseline. In Bevy, with certain fonts at certain font sizes, the glyphs will be rendered on the incorrect vertical position:
It only happens with certain sizes, but not others. The examples above (showing the aliasing issues) are rendered in the correct vertical position, but not at size 15.
Possible issue 3: sizing
The size defined in TextStyle
does not match the size in other implementations. On the first image (showing the aliasing issues), for example, I had to use the size 14.5
to match the font size 12
in Firefox.
Additional information
I did this experiment using the font "Fredoka One" on Google Fonts for comparison.
Proposal
Replace the Bevy implementation with one of two existing solutions: fontdue
or swash
. It seems that these two libraries are the best options for font rendering in pure Rust. We should evaluate which features that both have or don't have that are important for Bevy.
Could you also test Bevy with its subpixel_glyph_atlas
Feature enabled?
Issue 2: vertical positioning
Good ol' wavy text... https://github.com/bevyengine/bevy/issues/283, https://github.com/bevyengine/bevy/pull/725, https://github.com/bevyengine/bevy/pull/765
I noticed 1 and 2 while working on my Sudoku game, and strongly support this proposal. Clean text rendering is important and basically impossible to fix as an end user.
Could you also test Bevy with its subpixel_glyph_atlas Feature enabled?
I will give a try.
Akoriam (on Discord showed that the first issue might be solved by applying (2.2) gamma correction in the font renderer and the aliasing of Bevy will look like the anti-aliasing of non-subpixel anti-aliasing of Firefox. What remains to determine if it is worth switching to fontdue
or swash
to 1) solve the bug with vertical positioning or to 2) have the features of those libraries (fontdue
/swash
) in Bevy.
Swash would also allow shaping.
Has there been any further discussion on this? I'm struggling with some fuzzy font rendering which appears to be caused by aliasing as well. Certainly prepared to attempt to contribute a fix, but wondering if anyone else has better ideas.
Has there been any further discussion on this?
Not a great deal, but it seems clear that our current font rendering solution is inadequate. IMO, opening up a draft PR with a backend swap and showing the before / after results would help us come to a concrete decision sooner.
I think the vertical positioning is a Bevy bug, not an ab_glyph
one.
I've tried replicating the built-in text rendering of Bevy using a different TextPipeline<T>
, and after several hours of debugging I found that it returns the glyph position PositionedGlyph
relative to the bounding box of the text section, and not relative to the baseline. Moreover the position is the one of the center of the glyph quad. This is 1) very surprising, and cost me hours because it's not documented, 2) arguable, because the text origin should be on the baseline, so the returned position is not the text origin (in typography terminology) and I suspect prevent doing more complex text positioning like baseline alignement, 3) increase the chance we get sub-pixel positioning wrong by messing with the position ab_glyph
calculated for us.
I strongly suspect the bug is in that transformation code Bevy operates to convert the glyph position. The screenshot really looks like some bug I had while trying to figure out positioning and simplified some code temporarily to make it easier to debug.
A few weeks ago https://github.com/pop-os/cosmic-text was released.
Yep I'm in favor of exploring a migration to this.
I'm interested in playing around with it, though it probably wouldn't it be good enough for a PR. Would a migration be too difficult for someone unfamiliar with the codebase?