Closed Silver-Streak closed 3 years ago
Thanks for the very detailed explanations :) 👍 I don't have any bandwidth to take a look at this but this is a very interesting project for anyone wanting to contribute to GD.
If anyone can/wants to take a look at this:
I've started looking at the code snippet here: https://codepen.io/Tazy/pen/wJVExB?editors=0010
While I haven't used Javascript in years, I think the main gdjs function around "onGameResolutionResized" (I believe in GDJS.js?) would need to ensure it doesn't scale TextObject using it's normal method, and would instead use the listed function in the snippet around resizing the font. If not GDJS, it might need to be in RuntimeScene.js (specifically gdjs.RuntimeScene.prototype.onGameResolutionResized) and have it exclude TextObjects (or Treat objects differently).
I also believe you might need to disable all of the scaling functionality on the text object itself in the TextObject runtime (likely textruntimeobject.js, textruntimeobject-pixi-renderer.js), to ensure it's scale is always set to 1. This may not be necessary if the above is completed (and incase the user specifically uses scaling events on the object)
I think it would be pretty safe to say font 4px would be the smallest, and then the "BaseFontSize" would always be whatever the player selects as the font size in the editor. I wanted to test this method without any concern of editor functionality to see how it works...but I'm no where near good enough to know how to manipulate any of the functions listed above, or even know if I'm on to something, sadly.
Hopefully if someone does look into this, the above can help. If I'm understanding properly, solution 1 could potentially be applied to regular text objects AND bb text objects, and would (in theory) solve all font scaling...as they're no longer being scaled at all. Any other "blurriness" would be an issue with the font, and not GD5 or Pixi, since they're just rendering the font at the same size Windows would be.
Hello , I am an open source aspirer, trying to learn open source style of programming. Is this the right place I am looking at : https://github.com/4ian/GDevelop/blob/master/GDJS/Runtime/runtimescene.js in this file the "onGameResolutionResized" fuunction. If yes, please help me in understanding what is _layers here.
I think _layers is the call for returning the layer name. I'm not a dev though and could be 100% incorrect, so I'd wait for 4ian, Bouh, or another Contributor to confirm.
I'm not sure we have a precise solution here @deadpool1999. As the label "🙇♀️Careful thinking/design or refactoring needed" indicates, there is probably some more complex underderstanding of how text work. I'm not actually sure there are even changes to do in onGameResolutionResized
. For _layers
, the name is pretty much saying it all, it's a variable containing layers. What's layers? You can find this in the documentation or searching a bit in the code :)
@4ian So I don't think this is one of the items being covered by GSOC, correct? If not, is this something that you would feel eligible for me to throw another bounty on? If we'd rather wait until GSOC is over to see if any pulls it, I'm happy to wait on that too. 😄
I can delete this comment to avoid influencing people's decisions, as well.
This is not in the original project idea list, but could be a project if someone want to make a solid proposal for this. I think though it would be worth a bounty as it's more an in depth investigation that is needed :)
Thanks 4ian.
I have posted a bounty on this issue here: https://www.bountysource.com/issues/89023609-changing-resolution-makes-text-objects-blurry-or-distorted
My overall preference/requirements on this (although obviously I'm not the final say): Preferred:
Medium preference:
Less preference:
@4ian , not sure if you want to throw the Bounty tag on this issue, or if that tag is used on this repository or not. Thanks for your and @Bouh 's time on this over the past few weeks.
$70 USD on bounty source for this issue, @4ian bounty source tag can be added. https://www.bountysource.com/issues/89023609-changing-resolution-makes-text-objects-blurry-or-distorted
I got a e-mail about a mention that isn't here, so I'm assuming it was deleted, however it appears someone was asking about where the text runtime objects I mentioned are located.
They can be found here: https://github.com/4ian/GDevelop/tree/master/Extensions/TextObject
Hope this helps anyone looking into this.
Okay, @Silver-Streak I didn't look into Extensions (and checked only GDJS/Runtime), so I thought TextObjects are treated as normal RuntimeObjects, sorry about that, my bad :) Anyway, I want to ask why do we scale TextObjects? I mean we could've changed their font size instead of scaling? Is there any special purpose for scaling the fonts?
Maybe we could have a function like these which sets the font size instead of setting scale? We are already passing the runtimeScene, which means we could get the resolution, and set the font size accordingly.
@HarsimranVirk I'm not a contributor, and I think 4ian and Bouh/all of the contributors goal is for a careful solution to be put in place for this.
However, if you look at "Potential Solution 1" in the second or third post above, it provides a method to do exactly what you're mentioning. It looks at the "default" resolution for the game, your selected font size, then scales the font size up and down rather than the font itself. It's my personal preferred solution for this since it should avoid all scaling issues altogether for text.
Quoted for posterity:
Potential Solution 1: Do not scale Text objects, keep them at their native size but scale the font size based off the scaling size:
Thread that discusses it - https://www.html5gamedevs.com/topic/36463-pixijs-v4-does-not-remain-sprite-pixelated-as-it-original-is Code example - https://codepen.io/Tazy/pen/wJVExB Note: This seems like it might be the "prettiest" option, in that it should accommodate almost every font/text combination, I do not understand how difficult it would be to implement, however.
@Silver-Streak I've been checking on some functions related to resizing, and I strongly believe that the TextObject, or really any other object is not directly scaled at all. I have 2 reasons for that,
I'm not really familiar with the codebase, but if I had to implement the resizing, I wouldn't access each and every object present in the scene (or layer) and scale them up/down individually. This wouldn't be the most efficient way since there could be dozens of objects in a scene. Instead, I'd scale the entire scene or layer, which would result in indirect scaling of all the objects.
I couldn't find any code related to scaling individual objects, (it's possible that there is some code which I really couldn't find) but I found a lot of stuff scaling scenes and layers. I'd need to confirm this with @4ian and @Bouh, however.
I've tried to simplify what I'm trying to say, here, https://codepen.io/harsimran-singh-virk/pen/oNXydEb?editors=0010
I'm not sure if this is the real cause of the problem, but if it is, then a potential solution can be:
@HarsimranVirk I believe you are correct. TextObject inherits the behavior from (I think) GDJS.js around a "onGameResolutionResized" function.
To implement this method I think there would likely need to be a change so it no longer inherits that scaling 1:1 and instead when onGameResolutionResized is called, TextObjects (and BBtextobjects) use this other font size scaling method, instead of just scaling the object itself.
I'll wait for 4ian and Bouh (or another contributor) to chime in, as I only know very basic JS and found the above from poking around, and it may be completely incorrect.
There is no special scaling applied to objects. All game objects are rendered to a canvas, using the game resolution. The canvas is then stretched to fill the window/page, but not object individually.
This does not seem related to GDevelop. It would be interesting to reproduce the issue of a Pixi sample. Basically, render a text with a font, and put a sprite with some text using the same font and same size next to it. Then, enlarge the canvas. Check if the text is blurred and differs from the sprite. If not, then there must be something that we've wrongly done in GDevelop, or we've not properly applied the styles for resizing using nearest neighbours. If there is a difference, then this should be probably a question for Pixi.js
@4ian
Looking at https://codepen.io/Tazy/pen/wJVExB, it seems like they're applying this alternative scaling logic (or lackthereof) to Text objects using Pixi. If I understand correctly, they're basically creating a separate function that handles text scaling for the canvas, basically creating a separate instance of the GDJS "onGameResolutionResize" (or equivalent) that instead of scaling it just changes font size.
So I think you're correct: This is an issue stemming from applying scaling to the whole Pixi canvas (via pixi). However, it makes me think that maybe a general scaling for all items isn't the best way to do scaling? (or at least, breaking text out of that general scaling would solve this issue)
Again, I"m very much a layman, though 😄 So I'm just trying to understand using what little JS I know.
I've bumped up the bounty on this and asked Bountysource to tweet about it in hopes of spurring more interest. https://www.bountysource.com/issues/89023609-changing-resolution-makes-text-objects-blurry-or-distorted 😄
@Quarkstar This issue is still present in your pixi v5 branch ? Be sure to make good comparaisons between the versions v4/v5.
This issue is still present in your pixi v5 branch ? Be sure to make good comparaisons between the versions v4/v5.
Yes, it's still there. I think it looks the same in v4 and v5 branch.
@Silver-Streak @4ian Nice discussion here; The first solution posted here is quite simple and should do the job. Are there any obstacles in implementing that solution?
If you want to scale text via font size (not by Pixi's internal scaling), you can create a PIXI.Container
wrapper around a PIXI.Text
. This wrapper would have a custom _render
method:
You can extract the "world" scale from the world transform - say max(this.transform.worldTransform.a, this.transform.worldTransform.d)
.
You set the font size of the internally wrapped Pixi text to originalFontSize * worldScale
.
You apply a downscale to the text's transform text.scale.set(this / worldScale)
. This will make the "on-screen" size of the text same as before - but using a larger font size.
@SukantPal
Thank you greatly for chiming in.
While I'm definitely not one that would be able to implement it, could you clarify on the last step? I though the goal would be to avoid any scaling on the text at all. Wouldn't text.scale remain the original size but text font size be changed instead? What does downscaling the text's transform gain?
(This is more curiosity than anything else)
@Silver-Streak Option 1 wants to replace the “scaling factor” with a larger font size. To nullify the “scale”, you need to apply the inverse of it. If you don’t, both the transform scaling and larger font size would be at work..
Hmm, now I'm more confused. If we're removing any scaling from occurring on that object (Leaving text object scale at 100%), wouldn't the larger font size appear 'normal'/same size as before since it's only being displayed when the window resolution has increased/scaled up accordingly?
@Silver-Streak
Look at this: https://jsfiddle.net/ShukantPal/nwvmh1L2/. It shows the demo.
To see the text without my "font-size adjustment", change the name of the TextWrapper#render
method to something else (just add a letter to the front drender
). This will make the text blurry again.
As it is another payperiod, I've bumped up the bounty on this again. https://www.bountysource.com/issues/89023609-changing-resolution-makes-text-objects-blurry-or-distorted
Thanks to SukantPal for all of their input. I'm hoping said input makes it easier for someone to implement.
@Silver-Streak I'm actually ready to do this - I don't know how I'll test if it works locally. @4ian Any guidance to how you develop locally?
Start there: https://github.com/4ian/GDevelop/blob/master/newIDE/README.md :) Then I recommend to try the project uploaded by Silver-Streak to reproduce the issue and see what you can do.
The balise canvas is stretch in the html directly, so even if you rescale the container and increase the fontSize the result is still blurry.
Note you need change the style.padding too if you don't do this the text is crop on top.
Text is still blurry, i've rescale by x4 the fontSize and downscale to 0.25 the text container. The font file used: Silver.zip
@Bouh Hmm, I see. I believe your proposed solution is something like this: https://stackoverflow.com/a/15666143/6805653.
Get the device's pixel ratio, and then
new PIXI.Renderer({
width: yourWidth * ratio,
height: yourHeight * ratio,
autoDensity: true
});
Pixel ratio is still 1 for me. then it change nothing on my preview. autoDensity is only on pixi v5 so i use the current branch of @Quarkstar for test. If i understand correctly autoDensity allow to to pixi to resize the canvas size in CSS ? But the canvas is already resize at the dimension of the window.
For me the issue in at the root when the pixiRenderer is define, instead use the size from the setting of the game we should use the value of the window. Values of the game should the used only for set the size of the window. Tell me if i've lost you in my explaination ^^.
So here my new result.
@Bouh You did kind of lose me there. Here is what I think you said :) - you used somebody's branch that had upgraded GDevelop's Pixi dependency to v5. The window size was set to the game's resolution & the canvas size was set to the window's dimensions. You used resolution: 1
?
My pixel ratio is always 1, resolution too 1.
The game can have options for set width and height for configure the window of the game. 800x600 by default. This value is used for configure the window (it's ok) and used at the rescale event of the window and used for redefine the pixiRenderer, but the value stay 800x600.
So the pixiRenderer comptue for a canvas of 800x600, and after the HTML canvas is rescale with CSS rules. If the quality of the renderer is smaller than the HTML canvas, it's logic for me know to have a poor quality result when we rescale the window is apply on the canvas.
(I try draw a cat on a paper A4, i wish my cat on a poster, if my quality is bad on my paper and rescale my image to poster dimension my beautiful draw loose in quality, it's better if a redraw my cat on the poster. I hope the analogy help ^^)
I try to understand how work this part of GD. But it's give me a good result with my technic. I've open a PR here. See the last commit. And you can try my new build of GD
This work on current master branch under pixi v4.8.6, and it can work also for next branch under pixi v5.
It's only on Text object not yet on BBtext.
I posted it in the PR, but to make sure it's not lost:
Bad news: This seems to still have scaling issues rather than changing font size, unless I'm misunderstanding:
Here's text at native resolution 1920x1080, font size: 72
Here's the window resolution changed to 1280x720, font size still 72 according to debugger:
You can see it still becomes very distorted once I change the resolution.
(Also, this doesn't appear to fix blurriness on BBText, but I don't think we're trying for that currently)
Some more tests with this build: Game set to 1920x1080 resolution. Font: Gravity Pixel Font https://jotson.itch.io/gravity-pixel-font Font Size: 30
At 1080p (Native game resolution, click for full size):
Window resized to 720p (click for full size):
You can see in the word "PRESS" there is a lot of distortion on the S characters.
However, if I change the game resolution to native 720p (2/3 of 1080p) and change the font size to 20 (2/3 of size 30) No distortion on any character (click for full size):
Here's the project files: FontResizeDistortion.zip
@Bouh and I have been talking through this on the discord, so I wanted to post these examples incase anyone else needs to see them, as the difference is noticeable but faint.
Here's 1080p native, zoomed in, with a 1x1 pixel grid.
Notice that the center of each S is the exact same size, ~4 pixels
Here's that same window resized to 720p: Notice that the top S and bottom S are not equal, among other differences.
So it seems like the font size scaling down isn't working properly, at minimum.
@SukantPal Also, Bouh's knee deep in bug hunting for the recent releases, so if you do want to take a crack at this, any help is appreciated. (Edit: To be clear, I mean if you want to take a crack at your own implementation, not necessarily what we're seeing with the build Bouh made. Or both. Honestly I'm just happy if we can get this solved. :D )
Something is different between your screen and mine. Maybe the resolution or the pixel ratio like @SukantPal suggest. i guess it's why i can't see the difference with your screen. Because mine are different. I can't reproduce what you see, then i don't know how debug this, i'am very lost.
The electron menu made the mess, but because it's not present in exported game we should not take it in account. This menu reduce the canvas and affect the CSS size, so i've remove this menu in my preview. For remove this damn electron menu you can just export your game or use my new build below.
I use your project with more information for debug.
htmlCanvasSize, cssCanvasSize, pixiRendererSize, pixiRendererResolution, devicePixelRatio, pixelRatioSize, gameSettingsSize, isFullscreen
On my screen 1920x1080, 144hz, with my build with fix and b92, without electron menu in preview:
For the n°4, if i resize to 1279x719, (1px below), the font is prefect!
We can see when the CSS canvas size have decimals, the font is distorted. It's because electron menu is present and the window cannot be resized bigger than the screen resolution. What you think, how it is for you ?
Thanks Bouh. I'll check later today.
Hmm... I still get the electron menu in preview.
Also, after exporting the provided project using your build, this is what is shown after building it with electron-builder using yarn:
Is something going weird with how it's handling game resolution now?
Even hitting T again to set it to 1080p does this:
Is something going weird with how it's handling game resolution now?
The weird resolution with decimals? You are not in fullscreen so the canvas is reduce by your title bar. Press F for set in fullscreen, and G for windowed.
It's a good news to see resolution to 1 everywhere.
The build number is broken, but it's a custom build between b90 and b92 (it's a version similar to b92, but without the lastest commits about the profiler. I've just added the commit to fix electron. This change nothing for us here.)
You are still not in fullscreen and you have the electron menu. Press F, not F11, F will remove the electron menu, F11 don't.
Yep, I totally missed that. My apologies.
I'm now seeing significant improvement, although still some oddities.
Upscaling tests: Game resolution 1280x720, font size 24, 720p:
Zoomed in:
Game resolution 1280x720, font size 24, full screen (1080p):
Zoomed in:
Note, on the zoomed in view, I only marked the pure white pixels. It seems like there's some very bizarre sub pixel rendering/color blending happening still, but it is CONSIDERABLY better than the production build.
Downscaling tests:
Game resolution 1920x1080 (1.5x 1280x720), font size 32 (1.5x 1280x720), full screen:
Zoomed in:
Game resolution 1920x1080, font size 32, window rescaled to 720p:
Zoomed in:
Not sure what would impact the color blending like that. I think the most interesting thing is that the 1080p 32 font size scaled to 720p does NOT have the same color blending/subpixel rendering that the 720p 24 font size does.
Yeah, still something weird. I did some digging, and this font is designed for font sizes that are multiples of 5, not 8.
Downscale test: Game resolution 1080p, font size 30 full screen:
zoomed in:
Game resolution 1080p, font size 30, resized to 720p:
Zoomed in:
Notice that before resize, each S has a width of the line of 6 pixels. Since 720p is 2/3rds of 1080p, that should mean after resize to 720p, each S should be 4 pixels wide (2/3rds of 6). It is instead 3 pixels wide, with 2 pixels on each side of color blending/subpixel rendering.
Upscale test:
Game resolution 720p, font size 20 (2/3rd 30):
Zoomed in:
(Note, 4 pixels wide on the sides, so already different than the scaled down one above)
Game resolution 720p, font size 20, full screened (scaled up to 1080p):
Zoomed in:
Notice that the upscaled one goes from 4 pixels wide to 6 pixels wide. It seems like upscaling is working how I would think it should, but downscaling is being weird?
Just wanted to throw some updates on this as I've been testing with various fonts and seeing some really weird behaviors. We already know Silver.ttf (https://poppyworks.itch.io/silver) runs into issues once scaled, even with these updates.
Even though this font is heavily used in game development, I wanted to test with some other monospaced pixel fonts, so I've tried Monogram here: https://datagoblin.itch.io/monogram and m6x11 (https://managore.itch.io/m6x11).
They also don't do well with downscaling, and the distortion is heavily noticeable. Unfortunately, going to 1279x719 doesn't fix it for any of the above fonts.
Upscaling, again, is fine.
The more I look for solutions, the problem gets worse. Under PixiV5
The black rectangle should be the text, it's black because
WebGL: INVALID_VALUE: texImage2D: width or height out of range
And it's normal because i change the fontSize x4, and the fontSize is 300. (300*4=1200) and i rescale the font to 0.25.
But this is just the size for one letter, so if you make a sentence, the renderer for the texture will be huge! (~letters is your sentence x 1200 ), my renderer is 50k of width. And the WebGL dont want a huge renderer to calculate like that, so upscaling the font isn't a good solution ?
My best result for now, 1920x1080 resize to 1280x720, font:30 Zoomed
To be fair, font size 300 is already ridiculous. 😄
If you can, help me understand why are we rescaling the font size up then down? Wouldn't we just rescale the font size once per resolution?
(Game resolution 1080p, font size 30, game window resized to 720p (2/3rds 1080p), font size would then be scaled to 20 (2/3rds 720p)
Do we want to loop 4ian or SukantPal back in to see if we need to address this differently, or is this something where maybe it'd be beneficial to just have it as a toggle on game settings (Underneath the resolution settings) with a disclaimer "Very large font sizes such as 200+ may not render correctly"?
@SukantPal So @Bouh and I have been hammering away at this on the discord.
Unfortunately we can't seem to crack what the issue may be, the text distortion still happens one way or another. Do you still have time to take a crack at this?
@Silver-Streak
"Since 720p is 2/3rds of 1080p, that should mean after resize to 720p, each S should be 4 pixels wide (2/3rds of 6). It is instead 3 pixels wide, with 2 pixels on each side of color blending/subpixel rendering."
This only applies when the the leftmost pixel is at a multiple of 6px. I think the problem here is that the "S" is not at a multiple of 6px position, so when you scale down, the position of the first pixel is not a whole number. For example, if the position of the first pixel mod 6 is 1px (so 1, 7, 13 is the position of "S"), then the new position after scaling down has a .33 or .66 in it. Since the position of the "S" is not a integer (after scaling down), it the first & last pixels don't entirely overlap with the "S" (hence are blended).
Did you try to moving the position of PRESS by 1, 2, 3, 4, 5 px (so there must be a multiple of 6px position)? I think that might give some insight.
P.S. Are you using a screenshot and zooming in for those pixel-level images?
For your last question: Yes. screenshot, zoomed in, pixel count.
As for your other question around positioning,, we've tried applying a "draggable" behavior to the text object, and you can watch it distort/become normal again as you move it around the canvas, yes.
Although the above screenshots are mostly focused around the subpixel rendering, that is only part of the concern, and less of a concern than the actual distortion we see on fonts.
Here's an example that shows the distortion more clearly:
And it doesn't appear to be subpixel related as full pixels are being removed/added. This occurs more with more defined pixel fonts such as Monogram (https://datagoblin.itch.io/monogram) or Silver (https://poppyworks.itch.io/silver). Silver has been used in a ton of published games from other engines, and scale to different resolutions without issue.
The distortion we're seeing above does not happen in the codepen example from "Solution 1" at the top of this post either, so we're thinking it has to do with something being applied to the scaling methods.
Edit: Also, shouldn't Pixel Rounding stop the partial pixels (.33/.66) from occurring? because it doesn't seem to be applied (or at least not after a downscale)
Edit: Also, shouldn't Pixel Rounding stop the partial pixels (.33/.66) from occurring? because it doesn't seem to be applied (or at least not after a downscale)
I wish add, even if these settings exist.
Describe the bug
When using a text object (or BBText object), if you resize the game, the text will become either blurry or distorted. This seems to have gotten worse since the release of the new resolution options and events related to them.
This occurs if you resize through any method, including by dragging and resizing the window, using fullscreen on a monitor that is a different resolution, or by using any of the resolution/fullscreen events.
Using the solution here does not solve this problem, although it does slightly reduce the effect: https://forum.gdevelop-app.com/t/solved-pixel-art-fonts-are-fuzzy-text-font-blury/14225
To Reproduce
Create a text object.
Set the font size to something large so it is more noticeable (Size 40+).
Set your game resolution to any size smaller than your monitor (e.g. 1280x720 on a 1080p monitor)
Place the text object in the scene.
Launch the preview, or compile the game and run it.
Stretch the window larger, or set the game to fullscreen.
The text will either be blurry, or have distorted pixels. This occurs regardless of whether using linear or nearest scaling.
I've attached the default platformer example project with some text objects with both the default font and a custom font to show this effect. My project4.zip
In my actual game, here's some examples Using the example fix linked above (showing it does not resolve it):
Here's the text before the window has been changed in size (720p)-
Here's the text after the game has been fullscreened on a 1080p monitor-
It is important to note: If you create an image with the text you want in an image editor (such as gimp) and add it as a sprite object, it does not have the blurriness or distortion when resizing. So it is something specific with how GDevelop/Pixi is scaling the Text Objects.
Other details
Bouh took a crack on this over on the forums to apply some potential fixes we found such as enabling the roundPixels function. This had a noticeable improvement, but it is still being distorted. You can still see the distortion in these images, although they are much better:
I've been doing some digging, and it seems like this is due to how the Text Object is being scaled in GD5's implementation of Pixi. Apparently it's not intended to be scaled like other objects are, due to how Pixi uses the OS' native scaler and that's not optimal for text.
Note: this is my very basic understanding from reading multiple threads on how scaling impacts Pixi.Text, I could be interpreting it wrong.
Here are some alternative methods offered that may resolve this:
Potential Solution 1: Do not scale Text objects, keep them at their native size but scale the font size based off the scaling size:
Potential Solution 2: Adjust the Pixi.Text ratio based off the canvas pixel density:
Potential Solution 3: Signed Distance Field (SDF) Text
Potential Solution 4: Bitmap Font object
Please let me know if there's any other info or testing needed.