Browse Source

Update the 2D lights and shadows page for Godot 4.0 (#6424)

Hugo Locurcio 2 years ago
parent
commit
4431a725fe

+ 310 - 213
tutorials/2d/2d_lights_and_shadows.rst

@@ -6,238 +6,335 @@
 Introduction
 ------------
 
-This tutorial explains how the 2D lighting works in the
-`lights and shadows <https://github.com/godotengine/godot-demo-projects/tree/master/2d/lights_and_shadows>`_ demo project.
-It begins with a brief description of the resources used in the final demo and then describes how
-to make a scene like the demo step by step.
+By default, 2D scenes in Godot are unshaded, with no lights and shadows visible.
+While this is fast to render, unshaded scenes can look bland. Godot provides the
+ability to use real-time 2D lighting and shadows, which can greatly enhance the
+sense of depth in your project.
 
-.. image:: img/light_shadow_main.png
+.. figure:: img/2d_lights_and_shadows_disabled.webp
+   :align: center
+   :alt: No 2D lights or shadows, scene is unshaded
 
-All the resources for this tutorial can be found in the `official demo repository <https://github.com/godotengine/godot-demo-projects>`_
-on GitHub. I suggest you download it before starting. Alternatively,
-it can be downloaded from the Project Manager. Launch Godot and in the top
-bar select "Templates" and search for "2D Lights and Shadows Demo".
+   No 2D lights or shadows, scene is unshaded
 
-Setup
------
-
-For this demo we use four textures: two for the lights, one for the shadow casters,
-and one for the background. I've included links to them all here if you want to download them
-separately from the demo.
-
-The first is the background image (`background.png <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/background.png>`_)
-used in the demo. You do not necessarily need a background, but we use one for the demo.
-
-The second is a plain black image (`caster.png <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/caster.png>`_)
-to use as our shadow caster object. For a top down game this could be a wall or any
-other object that casts a shadow.
+.. figure:: img/2d_lights_and_shadows_enabled_no_shadows.webp
+   :align: center
+   :alt: 2D lights enabled (without shadows)
 
-Next is the light itself (`light.png <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/light.png>`_).
-If you click the link you will notice how large it is. The image you use
-for a light should cover the area you want your light to cover. This image is
-1024x1024 pixels, so you should use it to cover 1024x1024 pixels in your game.
+   2D lights enabled (without shadows)
 
-Lastly, we have the spotlight image (`spot.png <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/spot.png>`_).
-The demo uses a blob to show where the light is and the larger light
-image to show the effect of the light upon the rest of the scene.
+.. figure:: img/2d_lights_and_shadows_enabled.webp
+   :align: center
+   :alt: 2D lights and shadows enabled
 
+   2D lights and shadows enabled
 
 Nodes
 -----
 
-The demo uses four different nodes:
-  * :ref:`CanvasModulate <class_CanvasModulate>`
-  * :ref:`Sprite2D <class_Sprite2D>`
-  * :ref:`PointLight2D <class_PointLight2D>`
-  * :ref:`LightOccluder2D <class_LightOccluder2D>`
-
-:ref:`CanvasModulate <class_CanvasModulate>` is used to darken the scene.
-
-:ref:`Sprite2Ds <class_Sprite2D>` are used to display the textures for the light blobs, the
-background, and for the shadow casters.
-
-:ref:`PointLight2Ds <class_PointLight2D>` are used to light the scene. The way a light typically works
-is by adding a selected texture over the rest of the scene to simulate lighting. But it can be
-used in other ways, for example masking out parts of the scene.
+There are several nodes involved in a complete 2D lighting setup:
 
-:ref:`LightOccluder2Ds <class_LightOccluder2D>` are used to tell the shader which parts of
-the scene cast shadows. The shadows appear only on areas covered by the :ref:`PointLight2D <class_PointLight2D>` and
-their direction is based on the center of the :ref:`Light <class_PointLight2D>`.
+- :ref:`CanvasModulate <class_CanvasModulate>` (to darken the rest of the scene)
+- :ref:`PointLight2D <class_PointLight2D>` (for omnidirectional or spot lights)
+- :ref:`DirectionalLight2D <class_PointLight2D>` (for sunlight or moonlight)
+- :ref:`LightOccluder2D <class_LightOccluder2D>` (for light shadow casters)
+- Other 2D nodes that receive lighting, such as Sprite2D or TileMap.
 
-Lights
-------
+:ref:`CanvasModulate <class_CanvasModulate>` is used to darken the scene by
+specifying a color that will act as the base "ambient" color. This is the final
+lighting color in areas that are *not* reached by any 2D light. Without a
+CanvasModulate node, the final scene would look too bright as 2D lights would
+only brighten the existing unshaded appearance (which appears fully lit).
 
-:ref:`Lights <class_Light2D>` cover the entire extent of their respective Texture. They use additive
-blending to add the color of their texture to the scene.
+:ref:`Sprite2Ds <class_Sprite2D>` are used to display the textures for the light
+blobs, the background, and for the shadow casters.
 
-.. image:: img/light_shadow_light.png
+:ref:`PointLight2Ds <class_PointLight2D>` are used to light the scene. The way a
+light typically works is by adding a selected texture over the rest of the scene
+to simulate lighting.
 
-:ref:`Lights <class_Light2D>` have four ``Modes``: ``Add``, ``Sub``, ``Mix``, and ``Mask``.
+:ref:`LightOccluder2Ds <class_LightOccluder2D>` are used to tell the shader
+which parts of the scene cast shadows. These occluders can be placed as
+independent nodes or can be part of a TileMap node.
 
-``Add`` adds the color of the light texture to the scene. It brightens the area under the light.
+The shadows appear only on areas covered by the :ref:`PointLight2D
+<class_PointLight2D>` and their direction is based on the center of the
+:ref:`Light <class_PointLight2D>`.
 
-``Sub`` subtracts the color of the light from the scene. It darkens the area under the light.
+.. note::
 
-``Mix`` mixes the color of the light with the underlying scene. The resulting brightness is
-halfway between the color of the light and the color underneath.
+    The background color does **not** receive any lighting. If you want light to
+    be cast on the background, you need to add a visual representation for the
+    background, such as a Sprite2D.
 
-``Mask`` is used to mask out areas that are covered by the light. Masked out areas are hidden or revealed based on
-the color of the light.
+    The Sprite2D's **Region** properties can be helpful to quickly create a
+    repeating background texture, but remember to also set **Texture > Repeat** to
+    **Enabled** in the Sprite2D's properties.
 
-For the demo the lights have two components, the :ref:`Light <class_Light2D>` itself (which
-is the effect of the light), and a :ref:`Sprite2D <class_Sprite2D>` blob which is an image showing the
-location of the light source. A child :ref:`Sprite2D <class_Sprite2D>` is not necessary to make a
-:ref:`Light <class_Light2D>` work.
-
-.. image:: img/light_shadow_light_blob.png
-
-Shadows
--------
-
-Shadows are made by intersecting a :ref:`Light <class_Light2D>` with a :ref:`LightOccluder2D <class_LightOccluder2D>`.
-
-By default shadows are turned off. To turn them on click on the :ref:`Light <class_Light2D>`
-and under the Shadows section check ``Enabled``.
-
-In the demo we are using a :ref:`Sprite2D <class_Sprite2D>` with a Texture on it to make the "Shadow Casters",
-but in reality all you need is a couple of :ref:`LightOccluder2Ds <class_LightOccluder2D>`. By itself
-the :ref:`LightOccluder2D <class_LightOccluder2D>` looks like a dark spot and in this demo the :ref:`Sprite2D <class_Sprite2D>` is
-just a black square.
-
-Step by step
+Point lights
 ------------
 
-Now that we have covered the basics of the nodes being used, we can now walk step by step through
-the process of making a scene like the one found in the demo.
-
-First add a :ref:`Sprite2D <class_Sprite2D>` and set its texture to the `background image <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/background.png>`_. For your game this can be any
-background you choose. For this style of shadow it is most likely to be a floor texture.
-
-.. image:: img/light_shadow_background.png
-
-Next create three :ref:`PointLight2D's <class_PointLight2D>` and set their textures to the `light image <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/light.png>`_. You can alter their
-color in the top section. By default shadows are turned off and the ``mode`` is set to ``add``. This
-means that each light adds its own color to whatever is underneath.
-
-.. image:: img/light_shadow_all_lights_no_blob.png
-
-Next add a child :ref:`Sprite2D <class_Sprite2D>` to each of the :ref:`Light <class_Light2D>` nodes, and set
-the :ref:`Sprite2D's <class_Sprite2D>` texture to the `blob image <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/spot.png>`_. Each of these
-should stay centered on the :ref:`Light <class_Light2D>` node. The blob is the image of the light
-itself while the :ref:`Light <class_Light2D>` shows the effect that the light has on the scene. The
-:ref:`LightOccluder2D's <class_LightOccluder2D>` which we will add later, will treat the position of the light as the center of the :ref:`Light <class_Light2D>`
-node, which is why we want the blob to be centered on its parent :ref:`Light <class_Light2D>`.
-
-.. image:: img/light_shadow_all_lights.png
-
-.. note:: The animations in the demo will not be covered here. See :ref:`doc_introduction_animation`
-          for information on creating animations.
-
-Right now the scene should look too bright. This is because all three lights are adding color to the scene.
-This is why the demo uses a :ref:`CanvasModulate <class_CanvasModulate>` in the scene. The
-:ref:`CanvasModulate <class_CanvasModulate>` multiplies the entire viewport by a specific color.
-
-Add a :ref:`CanvasModulate <class_CanvasModulate>` to the scene and set its color to ``rgb(70, 70, 70)``.
-This will make the scene sufficiently dark to see the effects of the lights distinctly.
-
-.. image:: img/light_shadow_ambient.png
-
-Now we add the shadow casters.
-
-The demo uses a :ref:`Node <class_Node2D>` named "casters" to organize the shadow casters. Add a
-:ref:`Node2D <class_Node2D>` to the scene. It will be used to group all the shadow casters together.
-This way we can show and hide them all at the same time.
-
-Each shadow caster is made of a :ref:`Sprite2D <class_Sprite2D>`, with a :ref:`LightOccluder2D <class_LightOccluder2D>`
-child. For the demo the :ref:`Sprite2D <class_Sprite2D>` has a texture
-set to the `caster image <https://raw.githubusercontent.com/godotengine/godot-demo-projects/master/2d/lights_and_shadows/caster.png>`_ and nothing else. The child :ref:`LightOccluder2D <class_LightOccluder2D>` is where all the magic happens. In a
-game the :ref:`Sprite2D <class_Sprite2D>` could be more than a black box; it could be an image of whatever object is casting
-the shadow: a wall, a magical chest, or anything else.
-
-.. image:: img/light_shadow_sprites.png
-
-:ref:`LightOccluder2Ds <class_LightOccluder2D>` tell the game what shape the occluder has. They hold
-an :ref:`OccluderPolygon2D <class_OccluderPolygon2D>`, which is a container
-for a polygon and some other information. For this demo, since our wall is a square, we
-set ``Polygon`` to a square. The other default settings are fine.
-
-The first setting, ``Closed`` can be either ``on`` or ``off``. A closed polygon occludes light
-coming from all directions. An open polygon only occludes light from one direction.
-
-``Cull Mode`` lets you select which direction gets culled. The default is ``Disabled``, meaning the occluder
-will cast a shadow no matter which side the light is on. The other two settings ``Clockwise`` and
-``Counter-Clockwise`` refer to the winding order of the vertices of the polygon. The winding order
-is used to determine which side of the line is inside the polygon. Only outward facing lines cast shadows.
-
-To illustrate the difference, here is an image of a :ref:`LightOccluder2D <class_LightOccluder2D>` with ``Closed``
-set to ``off`` in the corresponding :ref:`OccluderPolygon2D <class_OccluderPolygon2D>`, so that the
-lines of the polygon can be seen:
-
-.. image:: img/light_shadow_cull_disabled.png
-
-.. note:: ``Cull Mode`` is set to ``Disabled``. All three lines cast shadows.
-
-.. image:: img/light_shadow_cull_clockwise.png
-
-.. note:: ``Cull Mode`` is set to ``Clockwise``. Only the top and right lines cast shadows.
-
-.. image:: img/light_shadow_cull_counter_clockwise.png
-
-.. note:: ``Cull Mode`` is set to ``Counter-Clockwise``. Only the bottom line casts a shadow.
-          If ``Closed`` was set to ``on`` there would be an additional vertical line on the
-          left which would cast a shadow as well.
-
-When you have added the :ref:`LightOccluder2Ds <class_LightOccluder2D>` the shadows still won't
-appear. You need to go back into the :ref:`PointLight2Ds <class_PointLight2D>` and under the Shadow
-section set ``Enable`` to ``on``. This turns on shadows with hard edges like in the image below.
-
-.. image:: img/light_shadow_filter0_pcf0.png
-
-To give the shadows that nice, soft edge look we set the variables ``filter``, ``filter smooth``, and
-``gradient length``. Godot supports `Percentage Closer Filtering <https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch11.html>`_
-(PCF), which takes multiple samples of the shadow map around a pixel and blurs them to create
-a smooth shadow effect. The higher the number of samples the smoother the shadow will
-look, but the slower it will run. That is why Godot provides 3-13 samples by default and allows you to choose.
-The demo uses PCF7.
-
-.. image:: img/light_shadow_normal.png
-
-.. note:: This is a shadow rendered with the demo's settings. ``gradient length`` is set
-          to ``1.3``, ``filter smooth`` is set to ``11.1``, and ``filter`` is set to ``PCF7``.
-
-.. image:: img/light_shadow_pcf13.png
-
-.. note:: ``filter`` is set to ``PCF13``. Notice how the shadow becomes wider, this is because the
-          distance between samples is based on the variable ``filter smooth``.
-
-In order to make use of filtering you need to set the ``filter smooth`` variable.
-This dictates how far apart the samples are. If you want the soft area to extend quite far, you can increase
-the size of ``filter smooth``. However, with few samples and a large filter smooth, you can see lines
-forming between the samples.
-
-.. image:: img/light_shadow_filter30.png
-
-.. note:: ``filter smooth`` is set to ``30``.
-
-The different :ref:`Light <class_Light2D>` nodes in the demo use different values for filter smooth.
-Play around with it and see what you like.
-
-.. image:: img/light_shadow_filter0.png
-
-.. note:: ``filter smooth`` is set to ``0``.
-
-Lastly, there is the variable ``gradient length``. For some smooth shadows it is preferable not to have the
-shadow start immediately on the object, as this produces a hard edge. The gradient length variable creates
-a smooth gradient to begin the shadow to reduce the effect of the hard edge.
-
-.. image:: img/light_shadow_grad0.png
-
-.. note:: ``gradient length`` is set to ``0``.
-
-.. image:: img/light_shadow_grad10.png
-
-.. note:: ``gradient length`` is set to ``10``.
-
-You will need to play around with the options a bit to find settings that suit your project. There is no right solution
-for everyone, which is why Godot provides so much flexibility. Just keep in mind that the higher ``filter``
-set the more expensive the shadows will be.
+Point lights (also called positional lights) are the most common element in 2D
+lighting. Point lights can be used to represent light from torches, fire,
+projectiles, etc.
+
+PointLight2D offers the following properties to tweak in the inspector:
+
+- **Texture:** The texture to use as a light source. The texture's size
+  determines the size of the light. The texture may have an alpha channel, which
+  is useful when using Light2D's **Mix** blend mode, but it is not required if
+  using the **Add** (default) or **Subtract** blend modes.
+- **Offset:** The offset for the light texture. Unlike when you move the light
+  node, changing the offset does *not* cause shadows to move.
+- **Texture Scale:** The multiplier for the light's size. Higher values will
+  make the light extend out further. Larger lights have a higher performance
+  cost as they affect more pixels on screen, so consider this before increasing
+  a light's size.
+- **Height:** The light's virtual height with regards to normal mapping. By
+  default, the light is very close to surfaces receiving lights. This will make
+  lighting hardly visible if normal mapping is used, so consider increasing this
+  value. Adjusting the light's height only makes a visible difference on
+  surfaces that use normal mapping.
+
+If you don't have a pre-made texture to use in a light, you can use this "neutral"
+point light texture (right-click > **Save Image As…**):
+
+.. figure:: img/2d_lights_and_shadows_neutral_point_light.webp
+   :align: center
+   :alt: Neutral point light texture
+
+   Neutral point light texture
+
+If you need different falloff you can procedurally create a texture by assigning
+a **New GradientTexture2D** on the light's **Texture** property. After creating
+the resource, expand its **Fill** section and set the fill mode to **Radial**.
+You will then have to adjust the gradient itself to start from opaque white to
+transparent white, and move its starting location to be in the center.
+
+Directional light
+-----------------
+
+New in Godot 4.0 is the ability to have directional lighting in 2D. Directional
+lighting is used to represent sunlight or moonlight. Light rays are casted
+parallel to each other, as if the sun or moon was infinitely far away from the
+surface that is receiving the light.
+
+DirectionalLight2D offers the following properties:
+
+- **Height:** The light's virtual height with regards to normal mapping (``0.0``
+  = parallel to surfaces, ``1.0`` = perpendicular to surfaces). By default, the
+  light is fully parallel with the surfaces receiving lights. This will make
+  lighting hardly visible if normal mapping is used, so consider increasing this
+  value. Adjusting the light's height only makes a visual difference on surfaces
+  that use normal mapping. **Height** does not affect shadows' appearance.
+- **Max Distance:** The maximum distance from the camera center objects can be
+  before their shadows are culled (in pixels). Decreasing this value can prevent
+  objects located outside the camera from casting shadows (while also improving
+  performance). Camera2D zoom is not taken into account by **Max Distance**,
+  which means that at higher zoom values, shadows will appear to fade out sooner
+  when zooming onto a given point.
+
+.. note::
+
+    Directional shadows will always appear to be infinitely long, regardless
+    of the value of the **Height** property. This is a limitation of the shadow
+    rendering method used for 2D lights in Godot.
+
+    To have directional shadows that are not infinitely long, you should disable
+    shadows in the DirectionalLight2D and use a custom shader that reads from
+    the 2D signed distance field instead. This distance field is automatically
+    generated from LightOccluder2D nodes present in the scene.
+
+Common light properties
+-----------------------
+
+Both PointLight2D and DirectionalLight2D offer common properties, which are part
+of the Light2D base class:
+
+- **Enabled:** Allows toggling the light's visibility. Unlike hiding the light
+  node, disabling this property will not hide the light's children.
+- **Editor Only:** If enabled, the light is only visible within the editor. It
+  will be automatically disabled in the running project.
+- **Color:** The light's color.
+- **Energy:** The light's intensity multiplier. Higher values result in a brighter light.
+- **Blend Mode:** The blending formula used for light computations. The default
+  **Add** is suited for most use cases. **Subtract** can be used for negative
+  lights, which are not physically accurate but can be used for special effects.
+  The **Mix** blend mode mixes the value of pixels corresponding to the light's
+  texture with the values of pixels under it by linear interpolation.
+- **Range > Z Min:** The lowest Z index affected by the light.
+- **Range > Z Max:** The highest Z index affected by the light.
+- **Range > Layer Min:** The lowest visual layer affected by the light.
+- **Range > Layer Max:** The highest visual layer affected by the light.
+- **Range > Item Cull Mask:** Controls which nodes receive light from this node,
+  depending on the other nodes' enabled visual layers **Occluder Light Mask**.
+  This can be used to prevent certain objects from receiving light.
+
+Setting up shadows
+------------------
+
+After enabling the **Shadow > Enabled** property on a PointLight2D or
+DirectionalLight2D node, you will not see any visual difference initially. This
+is because no nodes in your scene have any *occluders* yet, which are used as a
+basis for shadow casting.
+
+For shadows to appear in the scene, LightOccluder2D nodes must be added to the
+scene. These nodes must also have occluder polygons that are designed to match
+the sprite's outline.
+
+Along with their polygon resource (which must be set to have any visual effect),
+LightOccluder2D nodes have 2 properties:
+
+- **SDF Collision:** If enabled, the occluder will be part of a real-time
+  generated *signed distance field* that can be used in custom shaders. When not
+  using custom shaders that read from this SDF, enabling this makes no visual
+  difference and has no performance cost, so this is enabled by default for
+  convenience.
+- **Occluder Light Mask:** This is used in tandem with PointLight2D and
+  DirectionalLight2D's **Shadow > Item Cull Mask** property to control which
+  objects cast shadows for each light. This can be used to prevent specific
+  objects from casting shadows.
+
+There are two ways to create light occluders:
+
+Automatically generating a light occluder
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Occluders can be created automatically from Sprite2D nodes by selecting the
+node, clicking the **Sprite2D** menu at the top of the 2D editor then choosing
+**Create LightOccluder2D Sibling**.
+
+In the dialog that appears, an outline will surround your sprite's edges. If the
+outline matches the sprite's edges closely, you can click **OK**. If the outline
+is too far away from the sprite's edges (or is "eating" into the sprite's
+edges), adjust **Grow (pixels)** and **Shrink (pixels)**, then click **Update
+Preview**. Repeat this operation until you get satisfactory results.
+
+Manually drawing a light occluder
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Create a LightOccluder2D node, then select the node and click the "+" button at
+the top top of the 2D editor. When asked to create a polygon resource, answer
+**Yes**. You can then start drawing an occluder polygon by clicking to create
+new points. You can remove existing points by right-clicking them, and you can
+create new points from the existing line by clicking on the line then dragging.
+
+The following properties can be adjusted on 2D lights that have shadows enabled:
+
+- **Color:** The color of shaded areas. By default, shaded areas are fully
+  black, but this can be changed for artistic purposes. The color's alpha
+  channel controls how much the shadow is tinted by the specified color.
+- **Filter:** The filter mode to use for shadows. The default **None** is the
+  fastest to render, and is well suited for games with a pixel art aesthetic
+  (due to its "blocky" visuals). If you want a soft shadow, use **PCF5**
+  instead. **PCF13** is even softer, but is the most demanding to render. PCF13
+  should only be used for a few lights at once due to its high rendering cost.
+- **Filter Smooth:** Controls how much softening is applied to shadows when
+  **Filter** is set to **PCF5** or **PCF13**. Higher values result in a softer
+  shadow, but may cause banding artifacts to be visible (especially with PCF5).
+- **Item Cull Mask:** Controls which LightOccluder2D nodes cast shadows,
+  depending on their respective **Occluder Light Mask** properties.
+
+.. figure:: img/2d_lights_and_shadows_hard_shadow.webp
+   :align: center
+   :alt: Hard shadows
+
+   Hard shadows
+
+.. figure:: img/2d_lights_and_shadows_soft_shadow.webp
+   :align: center
+   :alt: Soft shadows (PCF13, Filter Smooth 1.5)
+
+   Soft shadows (PCF13, Filter Smooth 1.5)
+
+.. figure:: img/2d_lights_and_shadows_soft_shadow_streaks.webp
+   :align: center
+   :alt: Soft shadows with streaking artifacts due to Filter Smooth being too high (PCF5, Filter Smooth 4)
+
+   Soft shadows with streaking artifacts due to Filter Smooth being too high (PCF5, Filter Smooth 4)
+
+Occluder draw order
+^^^^^^^^^^^^^^^^^^^
+
+**LightOccluder2Ds follows the usual 2D drawing order.** This is important for 2D
+lighting, as this is how you control whether the occluder should occlude the
+sprite itself or not.
+
+If the LightOccluder2D node is a *sibling* of the sprite, the occluder will
+occlude the sprite itself if it's placed *below* the sprite in the scene tree.
+
+If the LightOccluder2D node is a *child* of the sprite, the occluder will
+occlude the sprite itself if **Show Behind Parent** is disabled on the
+LightOccluder2D node (which is the default).
+
+Normal and specular maps
+------------------------
+
+Normal maps and specular maps can greatly enhance the sense of depth of your 2D
+lighting. Similar to how these work in 3D rendering, normal maps can help make
+lighting look less flat by varying its intensity depending on the direction of
+the surface receiving light (on a per-pixel basis). Specular maps further help
+improve visuals by making some of the light reflect back to the viewer.
+
+Both PointLight2D and DirectionalLight2D support normal mapping and specular
+mapping. Since Godot 4.0, normal and specular maps can be assigned to any 2D
+element, including nodes that inherit from Node2D or Control.
+
+A normal map represents the direction in which each pixel is "pointing" towards.
+This information is then used by the engine to correctly apply lighting to 2D
+surfaces in a physically plausible way. Normal maps are typically created from
+hand-painted height maps, but they can also be automatically generated from
+other textures.
+
+A specular map defines how much each pixel should reflect light (and in which
+color, if the specular map contains color). Brighter values will result in a
+brighter reflection at that given spot on the texture. Specular maps are
+typically created with manual editing, using the diffuse texture as a base.
+
+.. tip::
+
+    If you don't have normal or specular maps for your sprites, you can generate
+    them using the free and open source `Laigter <https://azagaya.itch.io/laigter>`__
+    tool.
+
+To set up normal maps and/or specular maps on a 2D node, create a new
+CanvasTexture resource for the property that draws the node's texture. For
+example, on a Sprite2D:
+
+.. figure:: img/2d_lights_and_shadows_create_canvastexture.webp
+   :align: center
+   :alt: Creating a CanvasTexture resource for a Sprite2D node
+
+   Creating a CanvasTexture resource for a Sprite2D node
+
+Expand the newly created resource. You can find several properties you will need
+to adjust:
+
+- **Diffuse > Texture:** The base color texture. In this property, load the
+  texture you're using for the sprite itself.
+- **Normal Map > Texture:** The normal map texture. In this property, load a
+  normal map texture you've generated from a height map (see the tip above).
+- **Specular > Texture:** The specular map texture, which controls the specular
+  intensity of each pixel on the diffuse texture. The specular map is usually
+  grayscale, but it can also contain color to multiply the color of reflections
+  accordingly. In this property, load a specular map texture you've created (see
+  the tip above).
+- **Specular > Color:** The color multiplier for specular reflections.
+- **Specular > Shininess:** The specular exponent to use for reflections. Lower
+  values will increase the brightness of reflections and make them more diffuse,
+  while higher values will make reflections more localized. High values are more
+  suited for wet-looking surfaces.
+- **Texture > Filter:** Can be set to override the texture filtering mode,
+  regardless of what the node's property is set to (or the
+  **Rendering > Textures > Canvas Textures > Default Texture Filter** project
+  setting).
+- **Texture > Repeat:** Can be set to override the texture filtering mode,
+  regardless of what the node's property is set to (or the
+  **Rendering > Textures > Canvas Textures > Default Texture Repeat** project
+  setting).
+
+After enabling normal mapping, you may notice that your lights appear to be
+weaker. To resolve this, increase the **Height** property on your PointLight2D
+and DirectionalLight2D nodes. You may also want to increase the lights's
+**Energy** property slightly to get closer to how your lighting's intensity
+looked prior to enabling normal mapping.

BIN
tutorials/2d/img/2d_lights_and_shadows_create_canvastexture.webp


BIN
tutorials/2d/img/2d_lights_and_shadows_disabled.webp


BIN
tutorials/2d/img/2d_lights_and_shadows_enabled.webp


BIN
tutorials/2d/img/2d_lights_and_shadows_enabled_no_shadows.webp


BIN
tutorials/2d/img/2d_lights_and_shadows_hard_shadow.webp


BIN
tutorials/2d/img/2d_lights_and_shadows_neutral_point_light.webp


BIN
tutorials/2d/img/2d_lights_and_shadows_soft_shadow.webp


BIN
tutorials/2d/img/2d_lights_and_shadows_soft_shadow_streaks.webp


BIN
tutorials/2d/img/lights_and_shadow_pointlight2d_texture_example.webp