Proposal: Improving text rendering #7535
Replies: 29 comments 5 replies
-
It is should not be in core. Pixi SDF is right example. Plz, don't try make Phaser from PIXI |
Beta Was this translation helpful? Give feedback.
-
I'd like to give some more context. I have asked @SukantPal to research alternative Text/BitmapText approaches that have different trade-offs. Particularly, if we can find something that performs better than Text and looks great. I think there are a number of approaches here. Some might be appropriate as 3rd part plugins, some might be in the repo but not bundled, and some might replace/augment the current API. Let's figure out what the most fruitful Text rendering approach is that optimizes for performance but with fewer trade-off to BitmapText. |
Beta Was this translation helpful? Give feedback.
-
There are a few pieces of criteria that I'd use judge a good Text display object:
|
Beta Was this translation helpful? Give feedback.
-
Ok.
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
U very naive:
We can't use external dependences, because will be same problem as |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Ok. U win. Do it. But outside core, then we will looks it and decide what we should do then. |
Beta Was this translation helpful? Give feedback.
-
@eXponenta please stop being so hostile. We are exploring approaches nothing is solid yet. Please be constructive and do not use insults. |
Beta Was this translation helpful? Give feedback.
-
@eXponenta Are you sure we support right-to-left text as of now? Another approach we are thinking is to render each glyph using canvas 2D (same as of now) separately and cache them into an atlas. The atlas can be reused globally for all What do you think about accepting that into core? |
Beta Was this translation helpful? Give feedback.
-
Hey peeps, this is really exciting to hear these new approaches on the table. @eXponenta, echoing @bigtimebuddy, let's keep it constructive please. You clearly have some good insight into the new proposed approach, but lets aim to see if we can mitigate the issues raised and keep it friendly :) On text, heres my 2 cents (pence?).. Personally I think the most valuable approach is to gain the speed and performance of bitmap text but without the need to actually create a bitmap font beforehand. Dynamic bitmap texture building if you will! Dynamic bitmap fonts pros
cons
ideas
SDF Most people have no idea what that is so it should ideally be hidden. If we need to externally generate the SDF fields or code required to generate is too large or complex then this would be better at home as a plugin for sure:
Exact bezier curve renderingThis is an interesting approach for sure! I had looked into this in the past and decided that the shader switches introduced into the rendering loop and the extra tessellation required would have a large overhead. @SukantPal , you are closer to this idea than I am right now so would like to get your take on my concerns! Having said that, maybe it might be worth building a prototype that we can test and bash about a bit to validate our thinking? Exciting times for text :D |
Beta Was this translation helpful? Give feedback.
-
SDF generation is costly , and there are a packing time (when we nded pack different fonts in atlass), but it can be cached on client (as all other variant). |
Beta Was this translation helpful? Give feedback.
-
oh wow, thats a tiny bit of code! Looks ripe for a shader to be doing too! |
Beta Was this translation helpful? Give feedback.
-
@GoodBoyDigital The tiny-sdf package generates a single channel distance field. It doesn’t produce sharp corners when you cache the text at smaller font sizes. That can be mitigated by caching at the same font size being rendered. Single channel SDF generation shouldn’t be too bad. The multi channel SDF is superior except that it is way too complicated. I couldn’t understand how Chumskly was encoding corners. Now, everything we are considering won’t support rtl and Ltr layout mixed (as @eXponenta pointed out correctly). But I don’t think we are officially supporting it right now either. The exact approach has two benefits - small cache size (you are caching vertices not all the pixels), antialiasing even when the setting “antialiasing” is turned off (text is expected to be antialiased always I think. Current implementation does that by using canvas 2D). As for the demo, did you look at my quadratic Bézier curve demo? https://codepen.io/sukantpal/pen/GRJawBg?editors=0010 —— |
Beta Was this translation helpful? Give feedback.
-
Nice, Yes, no worries about rtl or ltr that will always be available through current method and is a problem all custom text rendering techniques will need solving at a later date. The Bezier demo is cool, but I do not feel it is enough for understand the true complexities that may be hiding if we render a full sentence. The stuff I wrote about dynamic bitmapfonts above is pretty much exactly what you mentioned about glyph caching. I think that is definitely a useful route to go down! In summary: The Bezier curve solutions: This could be good route, but I feel this requires further R&D to figure how it fits into a real production use cases. Dynamic Bitmapfonts from normal fonts: This we should definitely explore as we know this will give good perf whilst also keeping API simple. My Favourite :D Single channel SDF Appreciate its not going to be as good multichannel SDF, but the demo looked pretty good to me! If text can scale nicely with and we can have one texture per font, then I think this route could worth investigating too! |
Beta Was this translation helpful? Give feedback.
-
@GoodBoyDigital I think the demo does have pretty good text. But there are visible differences if you try to look for details: The text on the top is not sharp - the edges have wiggles. Each font+(~12-15px differences in font-size) combinations might need to be cached separately. I totally fine with going for SDF if the those wiggles are unimportant or if we can go with caching at multiple font sizes. The simplest solution is also fine for me 💯tbh! |
Beta Was this translation helpful? Give feedback.
-
Hey all. I'm a super laymen on all things Pixi, but am a user of GDevelop which uses Pixi as its backend, and I've been digging into this for a while for GDevelop's implementation of PixiJS and text rendering. It's actually impactful for a game I'm working on that has a lot of text. (You can see my research/examples in the issue I've posted in GDevelop: 4ian/GDevelop#1449 ) One of the options I found was focused around outright ignoring the scaling issues with text and eliminating them altogether by always leaving text scale at 100%, but scaling the text font size instead? This is font agnostic, and seems to work at all sizes. Here's a code example where that's being done using Pixi: https://codepen.io/Tazy/pen/wJVExB I actually have a bounty on this issue as I was hoping someone could just modify the Pixi Text extension for GDevelop, but (being the layman that I am) I didn't realize that this was a much larger issue with Pixi itself. No idea if there are potential issues with this method, but it would seem to avoid all of the performance issues of sdf/msdf/etc. |
Beta Was this translation helpful? Give feedback.
-
@Silver-Streak If you mean increasing the font-size by the scale applied on the text display-object, then how would that be better in terms of performance? SDF stuff helps performance because you don't re-render at larger font-sizes. |
Beta Was this translation helpful? Give feedback.
-
@Silver-Streak Of course, your proposal will improve quality but I don't see how it will improve performance. |
Beta Was this translation helpful? Give feedback.
-
Unless I'm misunderstanding, wouldn't changing the font size use less resources than scaling the entire object, or loading in another renderer? Again, I'm super layman when it comes to how Pixi's scaling actually works, it just made sense to me that leaving the font at native resolution but just changing the text size would be faster than scaling it. If that's incorrect, apologies for the distraction. |
Beta Was this translation helpful? Give feedback.
-
@Silver-Streak Scaling is implemented as a transform. You have a transformation matrix - and changing the scale in that matrix is a trivial operation. As of now, the text is rendered using Canvas 2D API into a canvas. Then it is copied onto the screen. Changing the scale will just change the screen coordinates to which the text in the canvas is mapped to. |
Beta Was this translation helpful? Give feedback.
-
Ahh, that makes sense. That's unfortunate, although to be fair my issue is more with the graphical rendering of fonts becoming blurry after being scaled, but I thought it'd be better performance too. While I'd be excited for someone to implement it to fix the general text quality issues, I can totally understand wanting to improve performance as well. Thanks for talking through it with me. |
Beta Was this translation helpful? Give feedback.
-
@Silver-Streak No problem. Implementing a quality-first text should not be hard in WebGL either, however. Some applications are implementing text by creating a mesh on their own. You can parse the font file, make a list of vertices, and tessellate it. Those vertices can be rendered through a mesh. At high scales, this can cause slight "edges" - because ultimately, you are rendering the text as triangles. For even higher quality, you can use the "exact bezier curve" shader I was talking about in this thread - it will render the curves as curves and not triangles. If you need help with text quality, I can help you guys out :) |
Beta Was this translation helpful? Give feedback.
-
@SukantPal I'm definitely not a contributor to GDevelop, (nor would you want me to be. I'm predominantly a Business Systems Analyst/DevOps in life, not a developer 😄 ) although I love that project and am active in the community. I also know there are other members of the community would love to see a solution for scaled text quality. However, if you want to take a look at the issue in the post, I also have a bounty for it over on Bountysource as well open to all. I don't want to take up any more headspace here, though, as it's obvious there's a much deeper conversation going on around Pixi in general, and my suggestion wasn't as spot on as I thought it was. |
Beta Was this translation helpful? Give feedback.
-
@Silver-Streak I might take a look, since I've nothing better to do in corona-season |
Beta Was this translation helpful? Give feedback.
-
I know this is a closed thread, but I'm sure everyone is still looking for the best way to improve text rendering. I did noticed that someone had a msdf implementation that worked with Pixi v5. https://github.com/cjsjy123/pixi-msdf-text-v5 Figured I would mention it to those interested. |
Beta Was this translation helpful? Give feedback.
-
This thread should definitely be re-opened and kept alive - or at least have some sort of update every so often, as this is one of the most looked for issues. |
Beta Was this translation helpful? Give feedback.
-
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Beta Was this translation helpful? Give feedback.
-
Any updates on how we can make the text performance crisper without consuming too much memory? restarting the thread |
Beta Was this translation helpful? Give feedback.
-
The community has said it - Pixi's text rendering performance needs to improve. This issue is devoted to how we can improve and what I think will be the best way to deliver:
Signed-distance fields: This technique renders the text into a texture (using Canvas 2D API) and applies a distance transform. In simple terms, the distance transform will set the value of each pixel in the output texture to the distance of that pixel to the nearest outline of the text in the input texture. pixi-sdf-text is an example: https://github.com/PixelsCommander/pixi-sdf-text
VTMs: Vector texture maps encode curve discontinuities at pixel level in textures.
Exact bezier curve rendering: This renders the font "as is" by tessellating everything except the curves. The curves are rendered using a special fragment shader (no sampling of the curve is done, it is rendered exactly on the GPU with antialiasing): https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf. I created a demo for quadratic bezier curve: https://codepen.io/sukantpal/pen/GRJawBg?editors=0010
@bigtimebuddy and I discussed these methods and we thought the third approach is the best because:
SDFs require pre-generated atlases. Generating multi-channel SDFs is very complicated (if we want to do it at runtime).
VTMs are way too complicated for just fonts.
Exact bezier curves just requires you to render the font as a path like everything else in Graphics.
Beta Was this translation helpful? Give feedback.
All reactions