godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.14k stars 21.19k forks source link

Scaling a 2D game when exporting to OSX retina is broken #19912

Closed mjtorn closed 6 years ago

mjtorn commented 6 years ago

Godot version: 3.0.3 (Custom built with RichTextLabel font shadows and Spine support)

OS/device including version: macOS Sierra 10.12.6

Retina, Late 2013, Intel Iris Pro 1536MB.

Issue description:

Exporting a 2D game (made with Escoria, to be precise) results in a broken resolution with retina.

The game is made in 1920x1080.

Stretch: Viewport probably shouldn't work, but Stretch: disabled and Stretch: 2d both look very small in the upper-left corner.

(With Viewport, the game overflows off the screen and has a gray area at the top)

I tried different Aspect settings, but Aspect: keep should work as desired according to the multiple resolutions tutorial.

The expected result is that the game would fill the screen as nicely as possible in the 1.77(7):1 aspect ratio defined by the original 1920x1080 resolution.

Steps to reproduce: This problem is visible in an intro video played with VideoPlayer so pretty much anything should reproduce this.

Minimal reproduction project:

On request, I have seven (7) builds of our game that I can share, with notes on how they were exported. Just tell me where to upload!

mjtorn commented 6 years ago

It should also be noted that I heard a description of similar symptoms on Windows 10 HiDPI (installed on a MacBook), but that build was with Stretch: Viewport. Unfortunately I don't have the means to test that myself now, as I do everything in Linux, but worst-case I'll have to figure out a dual boot.

Hoping it helps with development to know that it might be related to scaling strange resolutions in general and not only OSX.

mjtorn commented 6 years ago

I was thinking Stretch: 2d and Aspect: keep would work in Linux as well, with this 4k resolution, ~but it got scaled down.~ Edit: Attaching screenshots of it, a picture's worth a thousand words.

linux-2d-keep 2018-07-03

Looks somewhat similar to Stretch: 2d and Aspect: keep on OSX:

osx-2d-keep

Edit2: The Linux screenshot is still 1920x1080 though it's small in the corner of 3840x2160, the OSX one has a visible area of 1920x972 in a resolution of 2880x1800.

I'm totally lost as to what to do. Should there be one perfect set of settings that makes everything work as expected? Could the common denominator be that Stretch: 2d simply does not "be stretched to cover the whole screen" despite what the documentation says?

Edit3: It could also be that Stretch: viewport should be used, at least in our instance, because it's worked so far with everything except OSX. Then "Finally, this viewport is copied and scaled to fit the screen." might be the culprit and should be made Retina-aware.

Sorry about the edit spam, but this matters a lot to us :/

mjtorn commented 6 years ago

Here's a screenshot of the game with Stretch: Viewport and Aspect: Keep. It looks good, apart from the problems. So maybe the viewport-stretching should be retina/hidpi-aware, asking the OS what the screen should "look like" and scale accordingly. What do you think?

2880x1800 again.

osx-viewport-keep
mjtorn commented 6 years ago

I tried to dig around, or cluelessly stumble around, and found commit a7f18798aab00eecd64af7b824551444cb95f1b5 which says it fixes things.

I'm not saying that's the commit that caused it, @poke1024 , just that it inspired me to dig further. So far I tested what would happen with Godot 2.1.4, so I took the 1920x1080 screenshot of the menu and made a scene of it.

I hope I got the configs right, because I never used 2.1: 1920x1080, allow hidpi, fullscreen, stretch viewport, aspect keep.

godot2_1-fakemenu-viewport-keep

2880x1800 but it works! Doesn't look as good as expected, but it's not horribly broken!

The commit doesn't revert cleanly, so maybe I'll have to try some kind bisect operation.

mjtorn commented 6 years ago

Before starting git bisect, I went through the release versions to be sure where to go with this, and seems I was barking up a slightly wrong tree in my previous comment. Surprisingly, resizable is a relevant option even for fullscreen! It was on by default in all the previous tests, not for me.

This is what it looks like when I enable resizable:

osx-viewport-keep-resizable

It looks good, but observe how the cursor is on the letterbox area, and the strange gray area still persists and the bottom is cut off.

Edit: It should be noted that this is the actual game and it behaves the same when exported.

Calinou commented 6 years ago

2880×1800 is a 16:10 resolution (whereas 1920×1080 is 16:9), which is why you're seeing stretching in that resolution. As of Godot 3.0, the engine offers the expand stretch mode which is what you want to use to support multiple aspect ratios without stretching. It's intended to be used with the 2d scaling mode, so make sure to use that instead of viewport.

Note that Godot executables are currently not marked as hiDPI-aware on Windows, so you'll need to do it manually for now. Right-click the Godot editor (or an exported executable), choose Properties and go to the Compatibility tab, force the display scaling mode to Application then restart Godot.

mjtorn commented 6 years ago

@Calinou I tried that now, thanks! Here are some results:

There's this one big letterbox with 2d, expand and allow_hidpi:

osx-2d-expand-hidpi-menu osx-2d-expand-hidpi-dialog

By not allowing hidpi, the letterboxing looks more correct, but that's not viable as the dialog text looks horrible:

osx-2d-expand-nohidpi-dialog

Compared to the viewport approach:

osx-viewport-keep-hidpi-dialog

As much as I appreciate this step forward, is there any way to get the viewport thing to start at the proper place? Or to make the 2d approach be more in the center?

mjtorn commented 6 years ago

PS. I couldn't find a setting to change that gray color. The closest I could find was the boot splash setting which has a background color, but it didn't affect anything.

akien-mga commented 6 years ago

I couldn't find a setting to change that gray color. The closest I could find was the boot splash setting which has a background color, but it didn't affect anything.

Looks like the default clear color (rendering/environment/default_clear_color).

mjtorn commented 6 years ago

Looks like the default clear color (rendering/environment/default_clear_color).

Nice thanks! I'll give that a shot when I'm at the office again tomorrow :)

(Will also have to test the other platforms to be sure all's ok with them...)


I'm very relieved that the worst-case scenario is just a black bar at the top of the screen, in case there's no solution to center it.

I'll also have to try 3.0.4 to see if it's different there.

Really sweet if we can put this issue to bed and I can just keep track of how to configure these in the future, by changing Escoria's defaults ;)

Calinou commented 6 years ago

When using the expand scaling mode, you need to set anchors in controls so that Godot knows how to resize them as the window resolution changes. The root Control node should generally use a "Full Rect" anchor and span over the whole viewport.

mjtorn commented 6 years ago

@Calinou unfortunately I don't understand the "span over the whole viewport" part. We can take this up on IRC - I actually kinda did already, but everyone's idling ;) - but I'm wondering if I should use a CenterContainer or somesuch? I did try and fail, the default-color bar is always there on the top, even if I make it "Full Rect" :(

And for the VideoPlayer I see nothing.

mjtorn commented 6 years ago

godot-control-sprite-broken.tar.gz

This is probably the simplest example I could make. Unlike the scene with the VideoPlayer, this has its clear-color area at the bottom, but the problem is essentially the same.

What am I missing here?

Calinou commented 6 years ago

You could use a black ColorRect node as a child of the root Control node with the anchor set to Full Rect, so that it will always cover the whole viewport. However, since anchoring is relative to the parent, it will only do so if the root Control node also uses Full Rect anchoring.

mjtorn commented 6 years ago

@Calinou I tried to do that finally, but it doesn't change anything. Here's the tarball: godot-control-sprite-broken.colorrect.tar.gz

Did I understand correctly that this is the Full Rect setting from the Layout dropdown, not the one under Layout and Anchors Only?

I made it red instead of black, to see if the letterboxing would be on the top and bottom, but something's still wrong with this.

mjtorn commented 6 years ago

I don't know how to take an appropriate screenshot of the glitching itself, like during a fade animation, but here's a little something on how this fails when the background sprite is 1920x2700.

Here you can see the lack of letterboxing

screen shot 2018-07-04 at 13 55 35

And here the menu isn't laid out correctly

screen shot 2018-07-04 at 13 55 43

I'm really trying my best here, but it seems I've been unable to learn from anything so far.

Is there any chance of this being bad behavior on Godot's part, if 2d+expand should behave as expected?

Calinou commented 6 years ago

Try using TextureRect instead of Sprite (it's good practice for textures used for GUI purposes), and make the TextureRect use Center anchoring (while it's parented to the ColorRect with Full Rect anchoring).

It should then look like this while the window aspect ratio is narrower than 16:9 (here, I made the ColorRect red for visibility):

Narrow

And like this when the aspect ratio is wider than 16:9:

Wide

mjtorn commented 6 years ago

Thanks @Calinou ! That worked for the TextureRect, though I haven't made the buttons actual buttons yet or anything.

For the scene with the VideoPlayer, this does not work. I have the Control node with "Full Rect", a ColorRect with "Full Rect" and the VideoPlayer with "Center".

Is the tree going to be different for every type of node?

And later on, when the root (the visible root of the scene, not the ViewPort) is a Node2D, is that fundamentally wrong? Should it always always always be a Control?

Because that's where I hit a snag, having the tree like

Control
|
+- ColorRect (To hide the clear color)
   +- Sprite (Room background)

as the Sprite can't have that kind of layout, ie. be "Center" from the Layout dropdown.

I tried centering it through Offset, which pushed the Sprite mostly off-screen.

I tried Region Rect, but it did nothing.

Thanks again!

Zireael07 commented 6 years ago

Tip: don't use sprites for UI elements. If you need it to be positioned relatively to the dropdown, use a TextureRect instead.

mjtorn commented 6 years ago

Soon you'll see a grown man cry.

What's considered a UI element? Is the background of a game UI? Because I tried looking this up, whether or not a Control node is always required and couldn't find anything, but there are tutorials out there who do just fine with a Sprite background in their games.

mjtorn commented 6 years ago

Just a quick status report: I noticed that using the Control-based structure in our proper game did not work, so I started hacking stuff away just to see what could be the cause of it.

I will have to investigate further if Escoria is actually to blame here. It's not impossible, as the code base is quite old and it seems very few people on the planet know its history. I sure don't :(

mjtorn commented 6 years ago

Sorry about having left this hanging, but I've had nothing but distractions for a long time :(

Preliminary findings so far indicate it very much is a problem with Escoria, probably fixed by https://github.com/godotengine/escoria/pull/205/commits/518eee57b44800d79c8b77f6d952520f6b492263 but that's not all...

~The exported game behaves differently depending on if I export it under Linux or OSX.~ I have to verify this a million times because any change seems to affect everything and at worst require recompiling and rebuilding the OSX export template etc. ~Still it looks like if I export it under Linux, the Retina alignments are way off. If I export it in OSX, it works as expected.~

If I'm correct, and hopefully I'll have time early next week to get back to this, I may have to make the sacrifice and run my export Python script on OSX. Assuming it creates legit Linux and Windows builds. Exporting on OSX has the added advantage of automatically signing the app and putting in a DMG, which shouldn't be belittled.

EDIT: This is is why a million tests are not enough; I had somehow reverted back to "expand" on Linux, which obviously wouldn't work. Of course the point about DMGs still remain.

jesselawson commented 6 years ago

I develop on both Mac and Windows and am using Godot 3.0.6 with C#. My Windows box has a huge 2880x1800 resolution, and my Mac is a MBP Retina @ 1920x1200.

For this example, I hard-set my target resolution to 1024x640 and achieved the desired results:

private Vector2 WindowSize = new Vector2(1024,640);

public override void _Ready()
{
    OS.SetWindowSize(WindowSize);
    GetViewport().SetSize(WindowSize);
    GetTree().SetScreenStretch(SceneTree.StretchMode.Viewport, SceneTree.StretchAspect.Expand, WindowSize);
    OS.SetWindowFullscreen(true);
}

Again, with Godot 3.0.6 (C#) this is working on Mac and Windows as intended.

So I believe you did find an issue native to the build you're using. It is possible that the fixes in a7f1879 addressed this, which is why I am not seeing it.

18120 is a similar issue that talks about this as well.

mjtorn commented 6 years ago

I managed to run the game on OSX today just fine. It's not the same as thorough testing, but because this has been hanging over all the summer holidays and things don't appear to be horribly broken anymore, I'll close this.

Thanks everyone for your help!