|
@@ -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.
|