diff --git a/tutorials/2d/2d_lights_and_shadows.rst b/tutorials/2d/2d_lights_and_shadows.rst index 654f4b59c..13866f336 100644 --- a/tutorials/2d/2d_lights_and_shadows.rst +++ b/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 `_ 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 `_ -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 ------ +.. figure:: img/2d_lights_and_shadows_enabled_no_shadows.webp + :align: center + :alt: 2D lights enabled (without shadows) -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. + 2D lights enabled (without shadows) -The first is the background image (`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 `_) -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. - -Next is the light itself (`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. - -Lastly, we have the spotlight image (`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 ` - * :ref:`Sprite2D ` - * :ref:`PointLight2D ` - * :ref:`LightOccluder2D ` +There are several nodes involved in a complete 2D lighting setup: -:ref:`CanvasModulate ` is used to darken the scene. +- :ref:`CanvasModulate ` (to darken the rest of the scene) +- :ref:`PointLight2D ` (for omnidirectional or spot lights) +- :ref:`DirectionalLight2D ` (for sunlight or moonlight) +- :ref:`LightOccluder2D ` (for light shadow casters) +- Other 2D nodes that receive lighting, such as Sprite2D or TileMap. -:ref:`Sprite2Ds ` are used to display the textures for the light blobs, the -background, and for the shadow casters. +:ref:`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:`PointLight2Ds ` 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. +:ref:`Sprite2Ds ` are used to display the textures for the light +blobs, the background, and for the shadow casters. -:ref:`LightOccluder2Ds ` are used to tell the shader which parts of -the scene cast shadows. The shadows appear only on areas covered by the :ref:`PointLight2D ` and -their direction is based on the center of the :ref:`Light `. +:ref:`PointLight2Ds ` 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. -Lights ------- +:ref:`LightOccluder2Ds ` 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. -:ref:`Lights ` cover the entire extent of their respective Texture. They use additive -blending to add the color of their texture to the scene. +The shadows appear only on areas covered by the :ref:`PointLight2D +` and their direction is based on the center of the +:ref:`Light `. -.. image:: img/light_shadow_light.png +.. note:: -:ref:`Lights ` have four ``Modes``: ``Add``, ``Sub``, ``Mix``, and ``Mask``. + 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. -``Add`` adds the color of the light texture to the scene. It brightens the area under 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. -``Sub`` subtracts the color of the light from the scene. It darkens the area under the light. - -``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. - -``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. - -For the demo the lights have two components, the :ref:`Light ` itself (which -is the effect of the light), and a :ref:`Sprite2D ` blob which is an image showing the -location of the light source. A child :ref:`Sprite2D ` is not necessary to make a -:ref:`Light ` work. - -.. image:: img/light_shadow_light_blob.png - -Shadows -------- - -Shadows are made by intersecting a :ref:`Light ` with a :ref:`LightOccluder2D `. - -By default shadows are turned off. To turn them on click on the :ref:`Light ` -and under the Shadows section check ``Enabled``. - -In the demo we are using a :ref:`Sprite2D ` with a Texture on it to make the "Shadow Casters", -but in reality all you need is a couple of :ref:`LightOccluder2Ds `. By itself -the :ref:`LightOccluder2D ` looks like a dark spot and in this demo the :ref:`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. +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. -First add a :ref:`Sprite2D ` and set its texture to the `background image `_. For your game this can be any -background you choose. For this style of shadow it is most likely to be a floor texture. +PointLight2D offers the following properties to tweak in the inspector: -.. image:: img/light_shadow_background.png +- **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. -Next create three :ref:`PointLight2D's ` and set their textures to the `light image `_. 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. +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…**): -.. image:: img/light_shadow_all_lights_no_blob.png +.. figure:: img/2d_lights_and_shadows_neutral_point_light.webp + :align: center + :alt: Neutral point light texture -Next add a child :ref:`Sprite2D ` to each of the :ref:`Light ` nodes, and set -the :ref:`Sprite2D's ` texture to the `blob image `_. Each of these -should stay centered on the :ref:`Light ` node. The blob is the image of the light -itself while the :ref:`Light ` shows the effect that the light has on the scene. The -:ref:`LightOccluder2D's ` which we will add later, will treat the position of the light as the center of the :ref:`Light ` -node, which is why we want the blob to be centered on its parent :ref:`Light `. + Neutral point light texture -.. image:: img/light_shadow_all_lights.png +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. -.. note:: The animations in the demo will not be covered here. See :ref:`doc_introduction_animation` - for information on creating animations. +Directional light +----------------- -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 ` in the scene. The -:ref:`CanvasModulate ` multiplies the entire viewport by a specific color. +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. -Add a :ref:`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. +DirectionalLight2D offers the following properties: -.. image:: img/light_shadow_ambient.png +- **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. -Now we add the shadow casters. +.. note:: -The demo uses a :ref:`Node ` named "casters" to organize the shadow casters. Add a -:ref:`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. + 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. -Each shadow caster is made of a :ref:`Sprite2D `, with a :ref:`LightOccluder2D ` -child. For the demo the :ref:`Sprite2D ` has a texture -set to the `caster image `_ and nothing else. The child :ref:`LightOccluder2D ` is where all the magic happens. In a -game the :ref:`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. + 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. -.. image:: img/light_shadow_sprites.png +Common light properties +----------------------- -:ref:`LightOccluder2Ds ` tell the game what shape the occluder has. They hold -an :ref:`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. +Both PointLight2D and DirectionalLight2D offer common properties, which are part +of the Light2D base class: -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. +- **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. -``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. +Setting up shadows +------------------ -To illustrate the difference, here is an image of a :ref:`LightOccluder2D ` with ``Closed`` -set to ``off`` in the corresponding :ref:`OccluderPolygon2D `, so that the -lines of the polygon can be seen: +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. -.. image:: img/light_shadow_cull_disabled.png +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. -.. note:: ``Cull Mode`` is set to ``Disabled``. All three lines cast shadows. +Along with their polygon resource (which must be set to have any visual effect), +LightOccluder2D nodes have 2 properties: -.. image:: img/light_shadow_cull_clockwise.png +- **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. -.. note:: ``Cull Mode`` is set to ``Clockwise``. Only the top and right lines cast shadows. +There are two ways to create light occluders: -.. image:: img/light_shadow_cull_counter_clockwise.png +Automatically generating a light occluder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. 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. +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**. -When you have added the :ref:`LightOccluder2Ds ` the shadows still won't -appear. You need to go back into the :ref:`PointLight2Ds ` and under the Shadow -section set ``Enable`` to ``on``. This turns on shadows with hard edges like in the image below. +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. -.. image:: img/light_shadow_filter0_pcf0.png +Manually drawing a light occluder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To give the shadows that nice, soft edge look we set the variables ``filter``, ``filter smooth``, and -``gradient length``. Godot supports `Percentage Closer Filtering `_ -(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. +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. -.. image:: img/light_shadow_normal.png +The following properties can be adjusted on 2D lights that have shadows enabled: -.. 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``. +- **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. -.. image:: img/light_shadow_pcf13.png +.. figure:: img/2d_lights_and_shadows_hard_shadow.webp + :align: center + :alt: Hard shadows -.. 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``. + Hard shadows -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. +.. figure:: img/2d_lights_and_shadows_soft_shadow.webp + :align: center + :alt: Soft shadows (PCF13, Filter Smooth 1.5) -.. image:: img/light_shadow_filter30.png + Soft shadows (PCF13, Filter Smooth 1.5) -.. note:: ``filter smooth`` is set to ``30``. +.. 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) -The different :ref:`Light ` nodes in the demo use different values for filter smooth. -Play around with it and see what you like. + Soft shadows with streaking artifacts due to Filter Smooth being too high (PCF5, Filter Smooth 4) -.. image:: img/light_shadow_filter0.png +Occluder draw order +^^^^^^^^^^^^^^^^^^^ -.. note:: ``filter smooth`` is set to ``0``. +**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. -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. +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. -.. image:: img/light_shadow_grad0.png +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). -.. note:: ``gradient length`` is set to ``0``. +Normal and specular maps +------------------------ -.. image:: img/light_shadow_grad10.png +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. -.. note:: ``gradient length`` is set to ``10``. +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. -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. +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 `__ + 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. diff --git a/tutorials/2d/img/2d_lights_and_shadows_create_canvastexture.webp b/tutorials/2d/img/2d_lights_and_shadows_create_canvastexture.webp new file mode 100644 index 000000000..fc0f94992 Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_create_canvastexture.webp differ diff --git a/tutorials/2d/img/2d_lights_and_shadows_disabled.webp b/tutorials/2d/img/2d_lights_and_shadows_disabled.webp new file mode 100644 index 000000000..7be2891c8 Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_disabled.webp differ diff --git a/tutorials/2d/img/2d_lights_and_shadows_enabled.webp b/tutorials/2d/img/2d_lights_and_shadows_enabled.webp new file mode 100644 index 000000000..e357cc592 Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_enabled.webp differ diff --git a/tutorials/2d/img/2d_lights_and_shadows_enabled_no_shadows.webp b/tutorials/2d/img/2d_lights_and_shadows_enabled_no_shadows.webp new file mode 100644 index 000000000..a8feaa4f6 Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_enabled_no_shadows.webp differ diff --git a/tutorials/2d/img/2d_lights_and_shadows_hard_shadow.webp b/tutorials/2d/img/2d_lights_and_shadows_hard_shadow.webp new file mode 100644 index 000000000..790baa935 Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_hard_shadow.webp differ diff --git a/tutorials/2d/img/2d_lights_and_shadows_neutral_point_light.webp b/tutorials/2d/img/2d_lights_and_shadows_neutral_point_light.webp new file mode 100644 index 000000000..e71af9f13 Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_neutral_point_light.webp differ diff --git a/tutorials/2d/img/2d_lights_and_shadows_soft_shadow.webp b/tutorials/2d/img/2d_lights_and_shadows_soft_shadow.webp new file mode 100644 index 000000000..4441023ef Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_soft_shadow.webp differ diff --git a/tutorials/2d/img/2d_lights_and_shadows_soft_shadow_streaks.webp b/tutorials/2d/img/2d_lights_and_shadows_soft_shadow_streaks.webp new file mode 100644 index 000000000..acee9687b Binary files /dev/null and b/tutorials/2d/img/2d_lights_and_shadows_soft_shadow_streaks.webp differ diff --git a/tutorials/2d/img/lights_and_shadow_pointlight2d_texture_example.webp b/tutorials/2d/img/lights_and_shadow_pointlight2d_texture_example.webp new file mode 100644 index 000000000..9eff601ba Binary files /dev/null and b/tutorials/2d/img/lights_and_shadow_pointlight2d_texture_example.webp differ