diff --git a/tutorials/2d/2d_transforms.rst b/tutorials/2d/2d_transforms.rst index 0184781c62ed..d343f13f39db 100644 --- a/tutorials/2d/2d_transforms.rst +++ b/tutorials/2d/2d_transforms.rst @@ -1,72 +1,167 @@ -.. _doc_viewport_and_canvas_transforms: +.. _doc_2d_transforms: -Viewport and canvas transforms -============================== +2D transforms +============= Introduction ------------ This is an overview of the 2D transforms going on for nodes from the moment they draw their content locally to the time they are drawn onto -the screen. This overview discusses very low level details of the engine. +the screen. This overview discusses very low level details of the engine +and also describes how to use them. -Canvas transform ----------------- +:ref:`Transform2D ` are matrices that convert +coordinates from one coordinate system to an other. In order to use them, +it is beneficial to know which coordinate systems are available in Godot. -As mentioned in the previous tutorial, :ref:`doc_canvas_layers`, every -CanvasItem node (remember that Node2D and Control based nodes use -CanvasItem as their common root) will reside in a *Canvas Layer*. Every -canvas layer has a transform (translation, rotation, scale, etc.) that -can be accessed as a :ref:`Transform2D `. +Godot 2D coordinate systems +--------------------------- -Also covered in the previous tutorial, nodes are drawn by default in Layer 0, -in the built-in canvas. To put nodes in a different layer, a :ref:`CanvasLayer -` node can be used. +The following graphic gives an overview of Godot 2D coordinate systems and the available +node-transforms, transform-functions and coordinate-system related functions. At the left +is the Window Manager screen, at the right are the :ref:`CanvasItems `. For +simplicity reasons this graphic doesn't include :ref:`SubViewport `, +:ref:`SubViewportContainer `, +:ref:`ParallaxLayer` and :ref:`ParallaxBackground` +all of which also influence transforms. -Global canvas transform ------------------------ +The graphic is based on a node tree of the following form: ``root Window (embed Windows)`` ⇒ +``Window`` ⇒ ``CanvasLayer`` ⇒ ``CanvasItem`` ⇒ ``CanvasItem`` ⇒ ``CanvasItem``. +There are more complex combinations possible, like deeply nested Window and SubViewports, +however this example intends to provide an overview of the methodology in general. -Viewports also have a Global Canvas transform (also a -:ref:`Transform2D `). This is the master transform and -affects all individual *Canvas Layer* transforms. Generally, this -transform is not of much use, but is used in the CanvasItem Editor -in Godot's editor. +.. image:: img/transforms_overview.png + :target: ../../_images/transforms_overview.png -Stretch transform ------------------ +Click graphic to enlarge. -Finally, viewports have a *Stretch Transform*, which is used when -resizing or stretching the screen. This transform is used internally (as -described in :ref:`doc_multiple_resolutions`), but can also be manually set -on each viewport. +- **Item Coordinates** + This is the local coordinate system of a :ref:`CanvasItem `. -Input events are multiplied by this transform but lack the ones above. To -convert InputEvent coordinates to local CanvasItem coordinates, the -:ref:`CanvasItem.make_input_local() ` -function was added for convenience. +- **Parent Item Coordinates** + This is the local coordinate system of the parent's *CanvasItem*. + When positioning *CanvasItems* in the *Canvas*, they usually inherit the + transformations of their parent *CanvasItems*. An exceptions is + :ref:`CanvasItems.top_level `. -Transform order ---------------- +- **Canvas Coordinates** + As mentioned in the previous tutorial :ref:`doc_canvas_layers`, there are two + types of canvases and both have a canvas coordinate system. These are also + called world coordinates. A *Viewport* can contain multiple *Canvases* with different + coordinate systems. + +- **Viewport Coordinates** + This is the coordinate system of the :ref:`Viewport `. + +- **Camera Coordinates** + This is only used internally for functionality like 3D-camera ray projections. -For a coordinate in CanvasItem local properties to become an actual -screen coordinate, the following chain of transforms must be applied: +- **Embedder Coordinates / Screen Coordinates** + Every *Viewport* (*Window* or *SubViewport*) in the scene tree is embedded either in a + different node or in the Window Manager. This coordinate system's origin is identical to the + top-left corner of the *Window* or *SubViewport* and its scale is the one of the embedder + or the Window Manager. -.. image:: img/viewport_transforms2.png + If the embedder is the OS Window Manager, then they are also called Screen Coordinates. + +- **Absolute Embedder Coordinates / Absolute Screen Coordinates** + The origin of this coordinate system is the top-left corner of the embedding node or the Window + Manager screen. Its scale is the one of the embedder or the Window Manager. + + If the embedder is the OS Window Manager, then they are also called Absolute Screen + Coordinates. + +Node transforms +--------------- + +Each of the mentioned nodes have one or more transforms associated with them and the +combination of these nodes infer the transforms between the different coordinate systems. +With a few exceptions, the transforms are :ref:`Transform2D ` and the +following list shows details and effects of each of them. + +- **CanvasItem transform** + *CanvasItems* are either *Control*-nodes or *Node2D*-nodes. + + For *Control* nodes this transform consists of a + :ref:`position ` relative to the parent's origin and a + :ref:`scale ` and :ref:`rotation ` + around a :ref:`pivot point `. + + For *Node2D* nodes :ref:`transform ` is a + :ref:`Transform2D `. + + The transform affects the item itself and usually also child-*CanvasItems* and in the case of a + *SubViewportContainer* it affects the contained *SubViewport*. + +- **CanvasLayer transform** + The *CanvasLayer's* :ref:`transform ` affects all + *CanvasItems* within the *CanvasLayer*. It doesn't affect other *CanvasLayers* or *Windows*. + +- **CanvasLayer follow viewport transform** + The *follow viewport transform* is an automatically calculated transform, that is based + on the *Viewport's* :ref:`canvas transform ` and + the *CanvasLayer's* :ref:`follow viewport scale ` + and can be used, if :ref:`enabled `, + to achieve a pseudo 3D effect. It affects the same child nodes as the *CanvasLayer transform*. + +- **Viewport canvas transform** + The :ref:`canvas transform ` affects all + *CanvasItems* in the *Viewport's* default canvas. It also affects *CanvasLayers*, that have + follow viewport transform enabled. The *Viewport's* active :ref:`Camera2D ` + works by changing this transform. It doesn't affect this *Viewport's* embedded *Windows*. + +- **Viewport global canvas transform** + *Viewports* also have a :ref:`global canvas transform `. + This is the master transform and affects all individual *Canvas Layer* and embedded *Window* transforms. + This is primarily used in the CanvasItem Editor in Godot's editor. + +- **Viewport stretch transform** + Finally, *Viewports* have a *stretch transform*, which is used when resizing or stretching the + screen. This transform is used for :ref:`Windows ` as described in + :ref:`doc_multiple_resolutions`, but can also be manually set on *SubViewports* by means of + :ref:`size ` and + :ref:`size_2d_override `. It's + :ref:`translation `, + :ref:`rotation ` and + :ref:`skew ` are the default values and it can only have non-default + :ref:`scale `. + +- **Window transform** + In order to scale and position the *Window's* content as described in + :ref:`doc_multiple_resolutions`, each :ref:`Window ` contains a *window transform*. + It is for example responsible for the black bars at the *Window's* sides so that the `Viewport` + is displayed with a fixed aspect ratio. + +- **Window position** + Every *Window* also has a :ref:`position ` to describe its + position within its embedder. + +- **SubViewportContainer shrink transform** + :ref:`stretch ` together with + :ref:`stretch_shrink ` declare for a + *SubViewportContaner* if and by what integer factor the contained *SubViewport* should be + scaled in comparison to the container's size. Transform functions ------------------- -Obtaining each transform can be achieved with the following functions: +The above graphic shows all available transform functions (exposed to GDScript and also +internal). All transforms are directed from right to left, this means multiplying a transform with +a coordinate results in a coordinate system further to the left, multiplying the +:ref:`affine inverse ` of a transform results in a +coordinate system further to the right: + +.. tabs:: + .. code-tab:: gdscript GDScript + + canvas_pos = get_global_transform() * local_pos + local_pos = get_global_transform().affine_inverse() * canvas_pos + + .. code-tab:: csharp -+----------------------------------+---------------------------------------------------------------------------------------------+ -| Type | Transform | -+==================================+=============================================================================================+ -| CanvasItem | :ref:`CanvasItem.get_global_transform() ` | -+----------------------------------+---------------------------------------------------------------------------------------------+ -| CanvasLayer | :ref:`CanvasItem.get_canvas_transform() ` | -+----------------------------------+---------------------------------------------------------------------------------------------+ -| CanvasLayer+GlobalCanvas+Stretch | :ref:`CanvasItem.get_viewport_transform() ` | -+----------------------------------+---------------------------------------------------------------------------------------------+ + canvasPos = GetGlobalTransform().Xform(localPos) + localPos = GetGlobalTransform().AffineInverse().Xform(canvasPos) Finally, then, to convert a CanvasItem local coordinates to screen coordinates, just multiply in the following order: @@ -74,11 +169,11 @@ coordinates, just multiply in the following order: .. tabs:: .. code-tab:: gdscript GDScript - var screen_coord = get_viewport_transform() * (get_global_transform() * local_pos) + var screen_coord = get_viewport().get_screen_transform() * get_global_transform_with_canvas() * local_pos .. code-tab:: csharp - var screenCord = (GetViewportTransform() * GetGlobalTransform()).Xform(localPos); + var screenCord = (GetViewport().GetScreenTransform() * GetGlobalTransformWithCanvas()).Xform(localPos); Keep in mind, however, that it is generally not desired to work with screen coordinates. The recommended approach is to simply work in Canvas @@ -88,23 +183,22 @@ screen resolution resizing to work properly. Feeding custom input events --------------------------- -It is often desired to feed custom input events to the scene tree. With -the above knowledge, to correctly do this, it must be done the following -way: +It is often desired to feed custom input events to the game. With the +above knowledge, to correctly do this, it must be done the following way: .. tabs:: .. code-tab:: gdscript GDScript var local_pos = Vector2(10, 20) # local to Control/Node2D var ie = InputEventMouseButton.new() - ie.button_index = BUTTON_LEFT - ie.position = get_viewport_transform() * (get_global_transform() * local_pos) - get_tree().input_event(ie) + ie.button_index = MOUSE_BUTTON_LEFT + ie.position = get_viewport().get_screen_transform() * get_global_transform_with_canvas() * local_pos + Input.parse_input_event(ie) .. code-tab:: csharp var localPos = new Vector2(10,20); // local to Control/Node2D var ie = new InputEventMouseButton(); ie.ButtonIndex = (int)ButtonList.Left; - ie.Position = (GetViewportTransform() * GetGlobalTransform()).Xform(localPos); - GetTree().InputEvent(ie); + ie.Position = (GetViewport().GetScreenTransform() * GetGlobalTransformWithCanvas()).Xform(localPos); + Input.ParseInputEvent(ie); diff --git a/tutorials/2d/img/transforms_overview.png b/tutorials/2d/img/transforms_overview.png new file mode 100644 index 000000000000..4b0b3b27f94f Binary files /dev/null and b/tutorials/2d/img/transforms_overview.png differ diff --git a/tutorials/2d/img/viewport_transforms2.png b/tutorials/2d/img/viewport_transforms2.png deleted file mode 100644 index 06e19e72bdf4..000000000000 Binary files a/tutorials/2d/img/viewport_transforms2.png and /dev/null differ