mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-01-03 05:48:42 +03:00
394 lines
18 KiB
ReStructuredText
394 lines
18 KiB
ReStructuredText
.. _doc_2d_lights_and_shadows:
|
|
|
|
2D lights and shadows
|
|
=====================
|
|
|
|
Introduction
|
|
------------
|
|
|
|
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.
|
|
|
|
.. figure:: img/2d_lights_and_shadows_disabled.webp
|
|
:align: center
|
|
:alt: No 2D lights or shadows, scene is unshaded
|
|
|
|
No 2D lights or shadows, scene is unshaded
|
|
|
|
.. figure:: img/2d_lights_and_shadows_enabled_no_shadows.webp
|
|
:align: center
|
|
:alt: 2D lights enabled (without shadows)
|
|
|
|
2D lights enabled (without shadows)
|
|
|
|
.. figure:: img/2d_lights_and_shadows_enabled.webp
|
|
:align: center
|
|
:alt: 2D lights and shadows enabled
|
|
|
|
2D lights and shadows enabled
|
|
|
|
Nodes
|
|
-----
|
|
|
|
There are several nodes involved in a complete 2D lighting setup:
|
|
|
|
- :ref:`CanvasModulate <class_CanvasModulate>` (to darken the rest of the scene)
|
|
- :ref:`PointLight2D <class_PointLight2D>` (for omnidirectional or spot lights)
|
|
- :ref:`DirectionalLight2D <class_DirectionalLight2D>` (for sunlight or moonlight)
|
|
- :ref:`LightOccluder2D <class_LightOccluder2D>` (for light shadow casters)
|
|
- Other 2D nodes that receive lighting, such as Sprite2D or TileMapLayer.
|
|
|
|
: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:`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.
|
|
|
|
: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 TileMapLayer node.
|
|
|
|
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>`.
|
|
|
|
.. note::
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Point lights
|
|
------------
|
|
|
|
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
|
|
-----------------
|
|
|
|
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.
|
|
|
|
.. _doc_2d_lights_and_shadows_setting_up_shadows:
|
|
|
|
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 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.
|
|
|
|
.. note::
|
|
|
|
**Lighting and shadow resolution in pixel-art games**
|
|
|
|
The engine computes 2D lighting and shadows at the **Viewport's pixel resolution**,
|
|
not at the source texture's texel resolution. The appearance of lights and shadows
|
|
depends on your window or Viewport resolution, not on the resolution of individual
|
|
sprite textures.
|
|
|
|
If you create a pixel-art game and want pixelated or blocky lighting and shadows
|
|
that match your art style, **Nearest** texture filtering will **not** achieve
|
|
this effect. Nearest filtering affects only how the engine samples textures — it
|
|
does not change how the engine renders lighting and shadows.
|
|
|
|
To achieve pixelated lighting and shadows, use a custom shader to modify
|
|
``LIGHT_VERTEX`` and ``SHADOW_VERTEX`` to snap light sampling to a pixel grid.
|
|
The following shader snaps lighting to a grid using the ``floor()`` function:
|
|
|
|
.. code-block:: glsl
|
|
|
|
shader_type canvas_item;
|
|
|
|
uniform float pixel_size = 4.0;
|
|
|
|
void fragment() {
|
|
// Snap lighting and shadows to pixel grid.
|
|
LIGHT_VERTEX.xy = floor(LIGHT_VERTEX.xy / pixel_size) * pixel_size;
|
|
SHADOW_VERTEX = floor(SHADOW_VERTEX / pixel_size) * pixel_size;
|
|
|
|
// Normal rendering.
|
|
COLOR = texture(TEXTURE, UV);
|
|
}
|
|
|
|
This works by dividing the position by ``pixel_size`` to convert to grid space,
|
|
using ``floor()`` to round down to the nearest grid point, then multiplying back
|
|
to convert to screen space. The result forces the engine to sample lighting from
|
|
discrete grid positions, which creates the pixelated effect.
|
|
|
|
For more information on canvas item shaders, see :ref:`CanvasItem shaders <doc_canvas_item_shader>`.
|
|
|
|
.. 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)
|
|
|
|
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. 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.
|
|
|
|
Using additive sprites as a faster alternative to 2D lights
|
|
-----------------------------------------------------------
|
|
|
|
If you run into performance issues when using 2D lights, it may be worth
|
|
replacing some of them with Sprite2D nodes that use additive blending. This is
|
|
particularly suited for short-lived dynamic effects, such as bullets or explosions.
|
|
|
|
Additive sprites are much faster to render, since they don't need to go through
|
|
a separate rendering pipeline. Additionally, it is possible to use this approach
|
|
with AnimatedSprite2D (or Sprite2D + AnimationPlayer), which allows for animated
|
|
2D "lights" to be created.
|
|
|
|
However, additive sprites have a few downsides compared to 2D lights:
|
|
|
|
- The blending formula is inaccurate compared to "actual" 2D lighting. This is
|
|
usually not a problem in sufficiently lit areas, but this prevents additive
|
|
sprites from correctly lighting up areas that are fully dark.
|
|
- Additive sprites cannot cast shadows, since they are not lights.
|
|
- Additive sprites ignore normal and specular maps used on other sprites.
|
|
|
|
To display a sprite with additive blending, create a Sprite2D node and assign a
|
|
texture to it. In the inspector, scroll down to the **CanvasItem > Material**
|
|
section, unfold it and click the dropdown next to the **Material** property.
|
|
Choose **New CanvasItemMaterial**, click the newly created material to edit it,
|
|
then set **Blend Mode** to **Add**.
|