From b1b47eb78cfba719b2fc17ea3151bbe4b78bf05d Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Sat, 31 Aug 2024 22:34:32 -0400 Subject: [PATCH] Reduce imprecision in Multiple Resolutions doc I tried to make this doc page clearer and remove bugs, because I find it hard to understand as is. - The resizing discussion mixed talking about resizing to fit a screen and resizing to fit a window. Because the animated gifs do a great job of demonstrating the Stretch Mode differences using resizing of windows, I changed most "screen" references to "window" references. - Replaced the word "display" with "screen" in most cases, as it's an unneeded synonym that made me wonder if there was a difference. - Corrected several instances of referring to the viewport width and height settings as window width and height, or base window width and base window height. - Standardized referring to "base size" in most places instead of sometimes referring to "viewport size" or to "base window size". - Fleshed out the description of Canvas Item vs Viewport stretch mode. Maybe I made it worse, but I had to go onto reddit to find a clearer description than what existed. What clicked for me was a reddit summary saying "Canvas Items first scales the images, and then renders them. Viewport renders the images, and then scales them." I was then able to (hopefully!) clarify the mode descriptions. - Replaced Keep Height description with basically "like Keep Width but for height", rather than making the user check the copy-and-modified description vs Keep Width's for differences. - Asserted that Stretch Mode=Viewport completely avoids scaling artifacts when Stretch Scale Mode is set to Integer. If I'm wrong, please let me know. It's still not clear to me why the Stretch Mode=Viewport example animated gif never looks fuzzy, assuming the author recorded it using Stretch Scale Mode=Fractional, since the Stretch Scale Mode section seems to imply that random resizing of small resolution sprites should cause artifacts unless Stretch Scale Mode=Integer. - Applied style guide to some long lines. I may have introduced bugs due to not perfectly understanding the subject matter, and am happy to revise further if you explain what I got wrong. --- tutorials/rendering/multiple_resolutions.rst | 202 ++++++++++--------- 1 file changed, 109 insertions(+), 93 deletions(-) diff --git a/tutorials/rendering/multiple_resolutions.rst b/tutorials/rendering/multiple_resolutions.rst index f44db43fa5e..e48b545330e 100644 --- a/tutorials/rendering/multiple_resolutions.rst +++ b/tutorials/rendering/multiple_resolutions.rst @@ -56,8 +56,8 @@ Godot provides several useful tools to do this easily. Base size --------- -A base size for the window can be specified in the Project Settings under -**Display → Window**. +A base size for the game window can be specified in the Project Settings +under **Display → Window**. .. image:: img/screenres.webp @@ -70,17 +70,9 @@ blue rectangle in the 2D editor. There is often a need to support devices with screen and window sizes that are different from this base size. Godot offers many ways to control how the viewport will be resized and stretched to different -screen sizes. +screen and window sizes. -.. note:: - - On this page, *window* refers to the screen area allotted to your game - by the system, while *viewport* refers to the root object (accessible - from ``get_tree().root``) which the game controls to fill this screen area. - This viewport is a :ref:`Window ` instance. Recall from the - :ref:`introduction ` that *all* Window objects are viewports. - -To configure the stretch base size at runtime from a script, use the +To configure the base size stretch at runtime from a script, use the ``get_tree().root.content_scale_size`` property (see :ref:`Window.content_scale_size `). Changing this value can indirectly change the size of 2D elements. However, to @@ -122,6 +114,21 @@ most flexible way to deal with the problem, it can be a lot of work, code and guessing, so Godot provides a set of parameters in the project settings to handle multiple resolutions. +.. note:: + + While games are usually run in fullscreen mode, so that the game window's + resolution is equal to the screen resolution, the same challenges arise + when the game is run in a window resized by the user to an arbitrary + width and height. For the rest of this page, we will discuss resizing + your game to fit a *window*, but the same logic applies when the game is + running in fullscreen mode. + + On this page, *window* refers to the screen area allotted to your game + by the system, while *viewport* refers to the root object (accessible + from ``get_tree().root``) which the game controls to fill this screen area. + This viewport is a :ref:`Window ` instance. Recall from the + :ref:`introduction ` that *all* Window objects are viewports. + Stretch settings ---------------- @@ -132,39 +139,48 @@ Stretch settings are located in the project settings and provide several options Stretch Mode ^^^^^^^^^^^^ -The **Stretch Mode** setting defines how the base size is stretched to fit -the resolution of the window or screen. The animations below use a "base -size" of just 16×9 pixels to demonstrate the effect of different stretch -modes. A single sprite, also 16×9 pixels in size, covers the entire viewport, -and a diagonal :ref:`Line2D ` is added on top of it: +The **Stretch Mode** setting defines how the base size specified in the +Project Settings` **Display** section is stretched to fit the resolution +of the window. The animations below use a base size of just 16×9 pixels to +demonstrate the effect of different stretch modes. A single sprite, also +16×9 pixels in size, covers the entire viewport, and a diagonal +:ref:`Line2D ` is added on top of it: .. image:: img/stretch_demo_scene.png .. Animated GIFs are generated from: .. https://github.com/ttencate/godot_scaling_mode -- **Stretch Mode = Disabled** (default): No stretching happens. One - unit in the scene corresponds to one pixel on the screen. In this - mode, the **Stretch Aspect** setting has no effect. +- **Stretch Mode = Disabled** (default): No stretching happens. The + :ref:`Viewport ` is resized from the base size to the + window's resolution, so that one unit in the scene corresponds to one + pixel in the window. In this mode, the **Stretch Aspect** setting has + no effect. .. image:: img/stretch_disabled_expand.gif -- **Stretch Mode = Canvas Items**: In this mode, the base size specified in - width and height in the project settings is - stretched to cover the whole screen (taking the **Stretch Aspect** - setting into account). This means that everything is rendered - directly at the target resolution. 3D is unaffected, - while in 2D, there is no longer a 1:1 correspondence between sprite - pixels and screen pixels, which may result in scaling artifacts. +- **Stretch Mode = Canvas Items**: The root :ref:`Viewport ` + is resized from the base size to the window's resolution (taking the + **Stretch Aspect** setting into account). Each CanvasItem is then + scaled by the same amount as the base size was scaled. For example, + if the base size is 16x9 and the window is 160x180, each CanvasItem + will be stretched by a factor of 10 horizontally and 20 vertically. + This means that everything is rendered at the window's resolution. + 3D is unaffected, while in 2D, there is no longer a 1:1 correspondence + between sprite pixels and window pixels, which may result in scaling + artifacts. For example, in the animation below, the "16:9" sprite is + being scaled by arbitrary amounts, which rarely aligns the edges of + the sprite image's pixels with the window pixels. .. image:: img/stretch_2d_expand.gif -- **Stretch Mode = Viewport**: Viewport scaling means that the size of - the root :ref:`Viewport ` is set precisely to the - base size specified in the Project Settings' **Display** section. +- **Stretch Mode = Viewport**: The size of the root + :ref:`Viewport ` is set precisely to the base size. The scene is rendered to this viewport first. Finally, this viewport is scaled to fit the screen (taking the **Stretch Aspect** setting into - account). + account). This should avoid the scaling artifacts possible in + **Canvas Items** mode (with the help of the **Stretch Scale Mode** + setting, described below). .. image:: img/stretch_viewport_expand.gif @@ -185,17 +201,17 @@ are part of your scene, and can be drawn to. The gray areas correspond to the region outside the blue frame you see in the 2D editor. - **Stretch Aspect = Ignore**: Ignore the aspect ratio when stretching - the screen. This means that the original resolution will be stretched - to exactly fill the screen, even if it's wider or narrower. This may - result in nonuniform stretching: things looking wider or taller than - designed. + the viewport. This means that the viewport will be stretched + to exactly fill the window, even if the window is wider or narrower. + This may result in nonuniform stretching: things looking wider or + taller than designed. .. image:: img/stretch_viewport_ignore.gif - **Stretch Aspect = Keep**: Keep aspect ratio when stretching the - screen. This means that the viewport retains its original size - regardless of the screen resolution, and black bars will be added to - the top/bottom of the screen ("letterboxing") or the sides + viewport. This means that the viewport retains its original size + regardless of the window resolution, and black bars will be added to + the top/bottom of the window ("letterboxing") or the sides ("pillarboxing"). This is a good option if you know the aspect ratio of your target @@ -205,11 +221,12 @@ to the region outside the blue frame you see in the 2D editor. .. image:: img/stretch_viewport_keep.gif - **Stretch Aspect = Keep Width**: Keep aspect ratio when stretching the - screen. If the screen is wider than the base size, black bars are - added at the left and right (pillarboxing). But if the screen is - taller than the base resolution, the viewport will be grown in the - vertical direction (and more content will be visible to the bottom). - You can also think of this as "Expand Vertically". + viewport. If the window's aspect ratio is wider than the base size, + black bars are added at the left and right (pillarboxing). But if the + window's aspect ratio is taller than the base size, the viewport will + be grown in the vertical direction (and more of your scene will be + visible to the bottom). You can also think of this as "Expand + Vertically". This is usually the best option for creating GUIs or HUDs that scale, so some controls can be anchored to the bottom @@ -217,12 +234,11 @@ to the region outside the blue frame you see in the 2D editor. .. image:: img/stretch_viewport_keep_width.gif -- **Stretch Aspect = Keep Height**: Keep aspect ratio when stretching - the screen. If the screen is taller than the base size, black - bars are added at the top and bottom (letterboxing). But if the - screen is wider than the base resolution, the viewport will be grown - in the horizontal direction (and more content will be visible to the - right). You can also think of this as "Expand Horizontally". +- **Stretch Aspect = Keep Height**: Similar to **Keep Width** above, but + adds black bars on top and bottom (letterboxing) as needed, and allows + the viewport to grow wider as needed, making more of your scene + visible to the right. You can also think of this as "Expand + Horizontally". This is usually the best option for 2D games that scroll horizontally (like runners or platformers). @@ -230,22 +246,22 @@ to the region outside the blue frame you see in the 2D editor. .. image:: img/stretch_viewport_keep_height.gif - **Stretch Aspect = Expand**: Keep aspect ratio when stretching the - screen, but keep neither the base width nor height. Depending on the - screen aspect ratio, the viewport will either be larger in the - horizontal direction (if the screen is wider than the base size) or - in the vertical direction (if the screen is taller than the original - size). + viewport, but keep neither the base width nor height. Depending on the + window's aspect ratio, the viewport will either be larger in the + horizontal direction (if the window's aspect ratio is wider than the + base size) or in the vertical direction (if the window's aspect ratio + is taller than the base size). .. image:: img/stretch_viewport_expand.gif .. tip:: To support both portrait and landscape mode with a similar automatically - determined scale factor, set your project's base resolution to be a *square* + determined scale factor, set your project's base size to be a *square* (1:1 aspect ratio) instead of a rectangle. For instance, if you wish to design - for 1280×720 as the base resolution but wish to support both portrait and - landscape mode, use 720×720 as the project's base window size in the - Project Settings. + for 1280×720 as the target resolution but wish to support both portrait and + landscape mode, set the base size to 720×720 in the Project Settings' + **Display** section. To allow the user to choose their preferred screen orientation at run-time, remember to set **Display > Window > Handheld > Orientation** to ``sensor``. @@ -265,17 +281,17 @@ what the **Stretch** options above already provide. The default value of ``1.0`` means that no additional scaling occurs. For example, if you set **Scale** to ``2.0`` and leave **Stretch Mode** on -**Disabled**, each unit in your scene will correspond to 2×2 pixels on the -screen. This is a good way to provide scaling options for non-game applications. +**Disabled**, each unit in your scene will correspond to 2×2 pixels in the +window. This is a good way to provide scaling options for non-game applications. -If **Stretch Mode** is set to **canvas_items**, 2D elements will be scaled -relative to the base window size, then multiplied by the **Scale** setting. This -can be exposed to players to allow them to adjust the automatically determined -scale to their liking, for better accessibility. +If **Stretch Mode** is set to **Canvas Items**, 2D elements will be scaled +relative to the viewport's base size, then multiplied by the **Scale** setting. +This can be exposed to players to allow them to adjust the automatically +determined scale to their liking, for better accessibility. -If **Stretch Mode** is set to **viewport**, the viewport's resolution is divided +If **Stretch Mode** is set to **Viewport**, the viewport's base size is divided by **Scale**. This makes pixels look larger and reduces rendering resolution -(with a given window size), which can improve performance. +(for a given window size), which can improve performance. To configure the stretch scale at runtime from a script, use the ``get_tree().root.content_scale_factor`` property (see @@ -318,7 +334,7 @@ For example, if your viewport base size is 640×360 and the window size is 1366 - When using ``fractional``, the viewport is displayed at a resolution of 1366×768 (scale factor is roughly 2.133×). The entire window space is used. Each pixel in the viewport corresponds to 2.133×2.133 pixels in the displayed - area. However, since displays can only display "whole" pixels, this will lead + area. However, since screens can only display "whole" pixels, this will lead to uneven pixel scaling which results in incorrect appearance of pixel art. - When using ``integer``, the viewport is displayed at a resolution of 1280×720 (scale factor is 2×). The remaining space is filled with black bars on all @@ -335,7 +351,7 @@ mode with the ``integer`` scale mode). .. tip:: Games should use the **Exclusive Fullscreen** window mode, as opposed to - **Fullscreen** which is designed to prevent Windows from automatically + **Fullscreen** window mode designed to prevent Windows from automatically treating the window as if it was exclusive fullscreen. **Fullscreen** is meant to be used by GUI applications that want to use @@ -359,11 +375,11 @@ Desktop game **Non-pixel art:** -- Set the base window width to ``1920`` and window height to ``1080``. If you have a - display smaller than 1920×1080, set **Window Width Override** and **Window Height Override** to +- Set the viewport width to ``1920`` and viewport height to ``1080``. If you have a + screen smaller than 1920×1080, set **Window Width Override** and **Window Height Override** to lower values to make the window smaller when the project starts. -- Alternatively, if you're targeting high-end devices primarily, set the base - window width to ``3840`` and window height to ``2160``. +- Alternatively, if you're targeting high-end devices primarily, set the + viewport width to ``3840`` and viewport height to ``2160``. This allows you to provide higher resolution 2D assets, resulting in crisper visuals at the cost of higher memory usage and file sizes. Note that this will make non-mipmapped textures grainy on low resolution devices, @@ -371,12 +387,12 @@ Desktop game :ref:`doc_multiple_resolutions_reducing_aliasing_on_downsampling`. - Set the stretch mode to ``canvas_items``. - Set the stretch aspect to ``expand``. This allows for supporting multiple aspect ratios - and makes better use of tall smartphone displays (such as 18:9 or 19:9 aspect ratios). + and makes better use of tall smartphone screens (such as 18:9 or 19:9 aspect ratios). - Configure Control nodes' anchors to snap to the correct corners using the **Layout** menu. **Pixel art:** -- Set the base window size to the viewport size you intend to use. Most pixel +- Set the viewport width and height to the viewport size you intend to use. Most pixel art games use viewport sizes between 256×224 and 640×480. 640×360 is a good baseline, as it scales to 1280×720, 1920×1080, 2560×1440, and 3840×2160 without any black bars when using integer scaling. Higher viewport sizes will require @@ -405,60 +421,60 @@ Mobile game in landscape mode Godot is configured to use landscape mode by default. This means you don't need to change the display orientation project setting. -- Set the base window width to ``1280`` and window height to ``720``. -- Alternatively, if you're targeting high-end devices primarily, set the base - window width to ``1920`` and window height to ``1080``. +- Set the viewport width to ``1280`` and viewport height to ``720``. +- Alternatively, if you're targeting high-end devices primarily, set the + viewport width to ``1920`` and viewport height to ``1080``. This allows you to provide higher resolution 2D assets, resulting in crisper visuals at the cost of higher memory usage and file sizes. Many devices have - even higher resolution displays (1440p), but the difference with 1080p is - barely visible given the small size of smartphone displays. + even higher resolution screens (1440p), but the difference with 1080p is + barely visible given the small size of smartphone screens. Note that this will make non-mipmapped textures grainy on low resolution devices, so make sure to follow the instructions described in :ref:`doc_multiple_resolutions_reducing_aliasing_on_downsampling`. - Set the stretch mode to ``canvas_items``. - Set the stretch aspect to ``expand``. This allows for supporting multiple aspect ratios - and makes better use of tall smartphone displays (such as 18:9 or 19:9 aspect ratios). + and makes better use of tall smartphone screens (such as 18:9 or 19:9 aspect ratios). - Configure Control nodes' anchors to snap to the correct corners using the **Layout** menu. .. tip:: To better support tablets and foldable phones (which frequently feature - displays with aspect ratios close to 4:3), consider using a base resolution + screens with aspect ratios close to 4:3), consider using a viewport resolution that has a 4:3 aspect ratio while following the rest of the instructions - here. For instance, you can set the base window width to ``1280`` and the - base window height to ``960``. + here. For instance, you can set the viewport width to ``1280`` and the + viewport height to ``960``. Mobile game in portrait mode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- Set the base window width to ``720`` and window height to ``1280``. -- Alternatively, if you're targeting high-end devices primarily, set the base - window width to ``1080`` and window height to ``1920``. +- Set the viewport width to ``720`` and viewport height to ``1280``. +- Alternatively, if you're targeting high-end devices primarily, set the + viewport width to ``1080`` and viewport height to ``1920``. This allows you to provide higher resolution 2D assets, resulting in crisper visuals at the cost of higher memory usage and file sizes. Many devices have - even higher resolution displays (1440p), but the difference with 1080p is - barely visible given the small size of smartphone displays. + even higher resolution screens (1440p), but the difference with 1080p is + barely visible given the small size of smartphone screens. Note that this will make non-mipmapped textures grainy on low resolution devices, so make sure to follow the instructions described in :ref:`doc_multiple_resolutions_reducing_aliasing_on_downsampling`. - Set **Display > Window > Handheld > Orientation** to ``portrait``. - Set the stretch mode to ``canvas_items``. - Set the stretch aspect to ``expand``. This allows for supporting multiple aspect ratios - and makes better use of tall smartphone displays (such as 18:9 or 19:9 aspect ratios). + and makes better use of tall smartphone screens (such as 18:9 or 19:9 aspect ratios). - Configure Control nodes' anchors to snap to the correct corners using the **Layout** menu. .. tip:: To better support tablets and foldable phones (which frequently feature - displays with aspect ratios close to 4:3), consider using a base resolution + screens with aspect ratios close to 4:3), consider using a viewport resolution that has a 3:4 aspect ratio while following the rest of the instructions - here. For instance, you can set the base window width to ``960`` and the - base window height to ``1280``. + here. For instance, you can set the viewport width to ``960`` and the + viewport height to ``1280``. Non-game application ^^^^^^^^^^^^^^^^^^^^ -- Set the base window width and height to the smallest window size that you intend to target. +- Set the viewport size to the smallest window size that you intend to target. This is not required, but this ensures that you design your UI with small window sizes in mind. - Keep the stretch mode to its default value, ``disabled``. - Keep the stretch aspect to its default value, ``ignore``