Merged Lighting and Shadow Mapping tutorials, re-done them for Godot 3 and moved them to 3D
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
@@ -8,6 +8,6 @@
|
||||
introduction_to_3d
|
||||
3d_performance_and_limitations
|
||||
spatial_material
|
||||
shader_materials
|
||||
lighting
|
||||
high_dynamic_range
|
||||
using_gridmaps
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
.. _doc_lighting:
|
||||
|
||||
Lighting
|
||||
========
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Lights emit light that mix with the materials and produces a visible
|
||||
result. Light can come from several types of sources in a scene:
|
||||
|
||||
- From the Material itself, in the form of the emission color (though
|
||||
it does not affect nearby objects unless baked).
|
||||
- Light Nodes: Directional, Omni and Spot.
|
||||
- Ambient Light in the
|
||||
:ref:`Environment <class_Environment>`.
|
||||
- Baked Light (read :ref:`doc_light_baking`).
|
||||
|
||||
The emission color is a material property. You can read more about it
|
||||
in the :ref:`doc_fixed_materials` tutorial.
|
||||
|
||||
Light nodes
|
||||
-----------
|
||||
|
||||
As mentioned before, there are three types of light nodes: Directional,
|
||||
Omni and Spot. Each has different uses and will be described in
|
||||
detail below, but first let's take a look at the common parameters for
|
||||
lights:
|
||||
|
||||
.. image:: img/light_params.png
|
||||
|
||||
Each one has a specific function:
|
||||
|
||||
- **Color**: Base color for emitted light.
|
||||
- **Energy**: Energy multiplier. This is useful to saturate lights or working with :ref:`doc_high_dynamic_range`.
|
||||
- **Indirect Energy**: Secondary multiplier used with indirect light (light bounces). This works in baked light or GIProbe.
|
||||
- **Negative**: Light becomes substractive instead of additive. It's sometimes useful to manually compensate some dark corners.
|
||||
- **Specular**: Affects the intensity of the specular blob in objects affected by this light. At zero, this light becomes a pure diffuse light.
|
||||
- **Cull Mask**: Objects that are in the selected layers below will be affected by this light.
|
||||
|
||||
Shadow Mapping
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Lights can optionally cast shadows. This gives them greater realism (light does not reach occluded areas), but it can incur a bigger performance cost.
|
||||
There is a list of generic shadow parameters, each also has a specific function:
|
||||
|
||||
- **Enabled**: Check to enable shadow mapping in this light.
|
||||
- **Color**: Areas occluded are multiplied by this color. It is black by default, but it can be changed to tint shadows.
|
||||
- **Bias**: When this parameter is too small, self shadowing occurs. When too large, shadows separate from the casters. Tweak to what works best for you.
|
||||
- **Contact**: Performs a short screen-space raycast to reduce the gap generated by the bias.
|
||||
- **Reverse Cull Faces**: Some scenes work better when shadow mapping is rendered with face-culling inverted.
|
||||
|
||||
Below is an image of how tweaking bias looks like. Default values work for most cases, but in general it depends on the size and complexity of geometry.
|
||||
|
||||
.. image:: img/shadow_bias.png
|
||||
|
||||
Finally, if gaps cant be solved, the Contact option can help:
|
||||
|
||||
.. image:: img/shadow_contact.png
|
||||
|
||||
Any sort of bias issues can always be fixed by increasing the shadow map resolution, although that may run worse in lower end hardware.
|
||||
|
||||
Directional light
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is the most common type of light and represents a light source
|
||||
very far away (such as the sun). It is also the cheapest light to compute and should be used whenever possible
|
||||
(although it's not the cheapest shadow-map to compute, but more on that later).
|
||||
|
||||
Directional light models an infinite number of parallel light rays
|
||||
covering the whole scene. The directional light node is represented by a big arrow, which
|
||||
indicates the direction of the light rays. However, the position of the node
|
||||
does not affect the lighting at all, and can be anywhere.
|
||||
|
||||
.. image:: img/light_directional.png
|
||||
|
||||
Every face whose front-side is hit by the light rays is lit, the others stay dark. Most light types
|
||||
have specific parameters but directional lights are pretty simple in nature so they don't.
|
||||
|
||||
Directional Shadow Mapping
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To compute shadow maps, the scene is rendered (only depth) from an orthogonal point of view that covers
|
||||
the whole scene (or up to the max distance). There is, however, a problem with this approach because objects
|
||||
closer to the camera receive blocky shadows.
|
||||
|
||||
.. image:: img/shadow_blocky.png
|
||||
|
||||
To fix this, a technique named "Parallel Split Shadow Maps" (or PSSM) is used. This splits the view frustum in 2 or 4 areas. Each
|
||||
area gets it's own shadow map. This allows small, close areas to the viewer to have the same shadow resolution as a huge, far-away area.
|
||||
|
||||
.. image:: img/pssm_explained.png
|
||||
|
||||
With this, shadows become more detailed:
|
||||
|
||||
.. image:: img/shadow_pssm.png
|
||||
|
||||
To control PSSM, a number of parameters are exposed:
|
||||
|
||||
.. image:: img/directional_shadow_params.png
|
||||
|
||||
Each split distance is controlled relative to the camera far (or max distance), so 0 is where the eye and 1 is where the shadow ends far away.
|
||||
Default values generally work well, but tweaking the first split a bit is often common to give more detail to close objects.
|
||||
|
||||
Always make sure to set a shadow max distance according to what the scene needs. The closer the max distance, the higher quality they shadows will have.
|
||||
|
||||
Sometimes, the transition between a split and the next can look bad. To fix this, the **"Blend Splits"** option can be turned own, which sacrifices detail for smoother
|
||||
transitions.
|
||||
|
||||
.. image:: img/blend_splits.png
|
||||
|
||||
The **"Normal Bias"** parameter can be used to fix special cases of self shadowing when objects are perpendicular to the light. The only downside is that it makes
|
||||
the shadow a bit thinner.
|
||||
|
||||
.. image:: img/normal_bias.png
|
||||
|
||||
The **"Bias Split Scale"** parameter can control extra bias for the splits that are far away. If self shadowing occurs only on the splits far away, this value can fix them.
|
||||
|
||||
Finally, the **"Depth Range"** setting allows choosing between a stable shadow with motion, or maximizing the depth range. The former ensures that, when the camera moves, the blockyness
|
||||
of the shadow does not appear to wobble, while the later ensures more resolution (which can compensate the wobbliness). Just experiment which setting works better for your scene.
|
||||
|
||||
Shadowmap size for directional lights can be changed in Project Settings -> Rendering -> Quality:
|
||||
|
||||
.. image:: img/project_setting_shadow.png
|
||||
|
||||
Increasing it can solve bias problems, but reduce performance. Shadow mapping is an art of tweaking.
|
||||
|
||||
Omni light
|
||||
~~~~~~~~~~
|
||||
|
||||
Omni light is a point source that emits light spherically in all directions up to a given
|
||||
radius .
|
||||
|
||||
.. image:: img/light_omni.png
|
||||
|
||||
In real life, light attenuation is an inverse function, which means omni lights don't really have a radius.
|
||||
This is a problem, because it means computing several omni lights would become really demanding.
|
||||
|
||||
To solve this, a radius is introduced, together with an attenuation function.
|
||||
|
||||
.. image:: img/light_omni_params.png
|
||||
|
||||
These two parameters allow tweaking how this works visually, in order to find aesthetically pleasing results.
|
||||
|
||||
.. image:: img/light_attenuation.png
|
||||
|
||||
|
||||
Omni Shadow Mapping
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Omni light shadow mapping is relatively straightforward, as it just works. The main issue that needs to be
|
||||
considered is the algorithm used to render it.
|
||||
|
||||
Omni Shadows can be rendered as either "Dual Paraboloid" or "Cube Mapped". The former renders very quickly but can cause deformations,
|
||||
while the later is more correct but more costly.
|
||||
|
||||
.. image:: img/shadow_omni_dp_cm.png
|
||||
|
||||
If the objects being renderer are mostly irregular, Dual Paraboloid is usually enough. In any case, shadows are often cached too, so it may
|
||||
not make much of a difference (more on that later).
|
||||
|
||||
|
||||
Spot light
|
||||
~~~~~~~~~~
|
||||
|
||||
Spot lights are similar to omni lights, except they emit light only into a cone
|
||||
(or "cutoff"). They are useful to simulate flashlights,
|
||||
car lights, refletors, spots, etc. This type of light is also attenuated towards the
|
||||
opposite direction it points to.
|
||||
|
||||
.. image:: img/light_spot.png
|
||||
|
||||
Spot lights share the same **Range** and **Attenuation** as **OmniLight**, and add two extra parameters:
|
||||
|
||||
- **Angle**: The aperture angle of the light
|
||||
- **Angle Attenuation**: The cone attenuation, which helps soften the cone borders.
|
||||
|
||||
|
||||
Spot Shadow Mapping
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Spots dont need any parameters for shadow mapping, they should just work. Keep in mind that, at more than 89 degrees, shadows
|
||||
stop functioning for spots, and you should consider using an Omni light.
|
||||
|
||||
Shadow Atlas
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Unlike Directional lights, which have their own shadow texture, Omni and Spot lights are assigned to slots of a shadow atlas.
|
||||
This atlas can be configured in Project Settings -> Rendering -> Quality -> Shadow Atlas.
|
||||
|
||||
.. image:: img/shadow_atlas.png
|
||||
|
||||
The resolution applies to the whole Shadow Atlas. This atlas is divided in four quadrants:
|
||||
|
||||
.. image:: img/shadow_quadrants.png
|
||||
|
||||
Each quadrant, can be subdivided to allocate any number of shadow maps, following is the default subdivision:
|
||||
|
||||
.. image:: img/shadow_quadrants2.png
|
||||
|
||||
The allocation logic is simple, the biggest shadow map represents a light the size of the screen (or bigger), and
|
||||
as soon as lights get further away from the screen (hence) smaller shadow mapps represent slots for lights that
|
||||
appear smaller on screen.
|
||||
|
||||
Every frame, the following logic is done for all lights:
|
||||
|
||||
1. Check if the light is on a slot of the right size, if not, re-render it and move it to a larger/smaller slot.
|
||||
2. Check if any object affecting the shadow map has changed, if it did, re-render the light.
|
||||
3. If neither of the above has happened, nothing is done and the shadow is left untouched.
|
||||
|
||||
If the slots in a quadrant are full, lights are pushed back to smaller slots depending on size and distance.
|
||||
|
||||
This allocation strategy works for most games, but you may to use a separate one in some cases (as example, a top-down game where
|
||||
all lights are around the same size and quadrands may have all the same subdivision).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
.. _doc_materials:
|
||||
|
||||
Materials
|
||||
=========
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Materials can be applied to most visible 3D objects. Basically they
|
||||
describe how light interacts with that object. There are many
|
||||
types of materials, but the main ones are the
|
||||
:ref:`FixedMaterial <class_FixedMaterial>` and the
|
||||
:ref:`ShaderMaterial <class_ShaderMaterial>`.
|
||||
Tutorials for each of them exist :ref:`doc_fixed_materials` and :ref:`doc_shader_materials`.
|
||||
|
||||
This tutorial is about the basic properties shared between them.
|
||||
|
||||
.. image:: img/material_flags.png
|
||||
|
||||
Flags
|
||||
-----
|
||||
|
||||
Materials, no matter which type they are, have an associated set of flags.
|
||||
Their use will be explained in the following.
|
||||
|
||||
Visible
|
||||
~~~~~~~
|
||||
|
||||
Toggles whether the material is visible. If unchecked, the object will
|
||||
not be shown.
|
||||
|
||||
Double sided & inverted faces
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Godot by default only shows geometry faces (triangles) when their front-side
|
||||
faces the camera. If looking at the front-side of a face, its vertices
|
||||
have to be oriented clockwise by definition. For closed objects, the
|
||||
back-side of faces is never visible because they are hidden by other
|
||||
faces. SO not drawing invisible triangles (whose vertices are oriented
|
||||
counter-clockwise on the view plane) saves a lot of GPU power.
|
||||
|
||||
However, for flat or open objects, the back-side of faces might be visible
|
||||
and needs to be drawn as well. The "double sided" flag makes sure that no matter the facing,
|
||||
the triangle will always be drawn. It is also possible to invert this
|
||||
check and draw only counter-clockwise looking faces, though it's not
|
||||
very useful except for a few cases (like drawing outlines).
|
||||
|
||||
Unshaded
|
||||
~~~~~~~~
|
||||
|
||||
Objects are always black unless light affects them, and their shading
|
||||
changes according to the type and direction of lights. When this flag is
|
||||
turned on, the diffuse color is displayed right the same as it appears
|
||||
in the texture or parameter:
|
||||
|
||||
.. image:: img/material_unshaded.png
|
||||
|
||||
On top
|
||||
~~~~~~
|
||||
|
||||
When this flag is turned on, the object will be drawn after everything
|
||||
else has been drawn and without a depth test. This is generally useful
|
||||
for objects which shall never be hidden by other objects such as HUD effects
|
||||
or gizmos.
|
||||
|
||||
Ligthmap on UV2
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
When using lightmapping (see the :ref:`doc_light_baking` tutorial), this option
|
||||
determines that the lightmap should be accessed on the UV2 array instead
|
||||
of regular UV.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
Some parameters also exist for controlling drawing and blending:
|
||||
|
||||
Blend mode
|
||||
~~~~~~~~~~
|
||||
|
||||
Objects are usually blended in Mix mode. Other blend modes (Add and Sub)
|
||||
exist for special cases (usually particle effects, light rays, etc.) but
|
||||
materials can be set to them:
|
||||
|
||||
.. image:: img/fixed_material_blend.png
|
||||
|
||||
Line width
|
||||
~~~~~~~~~~
|
||||
|
||||
When drawing lines, the size of them can be adjusted here per material.
|
||||
|
||||
Depth draw mode
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
This is a tricky but very useful setting. By default, opaque objects are
|
||||
drawn using the depth buffer and translucent objects are not (but are
|
||||
sorted by depth). This behavior can be changed here. The options are:
|
||||
|
||||
- **Always**: Draw objects with depth always, even those with alpha.
|
||||
This often results in glitches like the one in the first image (which
|
||||
is why it's not the default).
|
||||
- **Opaque Only**: Draw objects with depth only when they are opaque,
|
||||
and do not set depth for alpha. This is the default because it's fast,
|
||||
but it's not the most correct setting. Objects with transparency that
|
||||
self-intersect will always look wrong, especially those that mix
|
||||
opaque and transparent areas, like grass, tree leaves, etc. Objects
|
||||
with transparency also can't cast shadows, this is evident in the
|
||||
second image.
|
||||
- **Alpha Pre-Pass**: The same as above, but a depth pass is performed
|
||||
for the opaque areas of objects with transparency. This makes objects
|
||||
with transparency look much more correct. In the third image it is
|
||||
evident how the leaves cast shadows between them and into the floor.
|
||||
This setting is turned off by default because, while on PC this is
|
||||
not very costly, mobile devices suffer a lot when this setting is
|
||||
turned on, so use it with care.
|
||||
- **Never**: Never use the depth buffer for this material. This is
|
||||
mostly useful in combination with the "On Top" flag explained above.
|
||||
|
||||
.. image:: img/material_depth_draw.png
|
||||
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 115 KiB |
@@ -1,9 +0,0 @@
|
||||
Lighting
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:name: toc-learn-features-lighting
|
||||
|
||||
lighting
|
||||
shadow_mapping
|
||||
@@ -1,122 +0,0 @@
|
||||
.. _doc_lighting:
|
||||
|
||||
Lighting
|
||||
========
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Lights emit light that mix with the materials and produces a visible
|
||||
result. Light can come from several types of sources in a scene:
|
||||
|
||||
- From the Material itself, in the form of the emission color (though
|
||||
it does not affect nearby objects unless baked).
|
||||
- Light Nodes: Directional, Omni and Spot.
|
||||
- Ambient Light in the
|
||||
:ref:`Environment <class_Environment>`.
|
||||
- Baked Light (read :ref:`doc_light_baking`).
|
||||
|
||||
The emission color is a material property. You can read more about it
|
||||
in the :ref:`doc_fixed_materials` tutorial.
|
||||
|
||||
Light nodes
|
||||
-----------
|
||||
|
||||
As mentioned before, there are three types of light nodes: Directional,
|
||||
Omni and Spot. Each has different uses and will be described in
|
||||
detail below, but first let's take a look at the common parameters for
|
||||
lights:
|
||||
|
||||
.. image:: img/light_params.png
|
||||
|
||||
Each one has a specific function:
|
||||
|
||||
- **Enabled**: Light is emitted only if this flag is set.
|
||||
- **Bake Mode**: When using the light baker, the role of this light can
|
||||
be defined in this enumerator. The role will be followed even if the
|
||||
light is disabled, which allows to configure a light and then disable
|
||||
it for baking.
|
||||
- **Energy**: This value is a multiplier for the light, it's especially
|
||||
useful for :ref:`doc_high_dynamic_range` and for Spot and Omni lights, because it can
|
||||
create very bright spots near the emitter.
|
||||
- **Diffuse and Specular**: These light values get multiplied by the
|
||||
material light and diffuse colors. A white value does not mean
|
||||
that light will be white, but that the material color will be kept.
|
||||
- **Operator**: It is possible to make some lights negative for a
|
||||
darkening effect.
|
||||
- **Projector**: Lights can project a texture for the diffuse light
|
||||
(currently only supported in Spot light).
|
||||
|
||||
Directional light
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is the most common type of light and represents a light source
|
||||
very far away (such as the sun). It is also
|
||||
the cheapest light to compute and should be used whenever possible
|
||||
(although it's not the cheapest shadow-map to compute, but more on that
|
||||
later).
|
||||
|
||||
Directional light models an infinite number of parallel light rays
|
||||
covering the whole scene. The directional light node is represented by a big arrow, which
|
||||
indicates the direction of the light rays. However, the position of the node
|
||||
does not affect the lighting at all, and can be anywhere.
|
||||
|
||||
.. image:: img/light_directional.png
|
||||
|
||||
Every face whose front-side is hit by the light rays is lit, the others stay dark.
|
||||
Most light types
|
||||
have specific parameters but directional lights are pretty simple in
|
||||
nature so they don't.
|
||||
|
||||
Omni light
|
||||
~~~~~~~~~~
|
||||
|
||||
Omni light is a point source that emits light spherically in all directions up to a given
|
||||
radius (distance from the node's position). The radius is a parameter of the light and
|
||||
can be controlled by the user. Just as in real life, the intensity of omni light
|
||||
decreases with the distance and vanishes at the defined radius. Omni light sources
|
||||
should be used to represent lamps or bulbs or any other light source that originates
|
||||
approximately in a point.
|
||||
|
||||
.. image:: img/light_omni.png
|
||||
|
||||
In reality, the attenuation of omni light is proportional to the squared distance
|
||||
from the point source. This can be easily understood if you imagine a sphere around
|
||||
the omni light with a certain radius. No matter how large the sphere is, the number
|
||||
of rays passing through it is always the same. If the radius of the sphere is doubled,
|
||||
the area of the sphere increases by four. In other words, the density of rays
|
||||
(the number of rays per square area) decreases quadratically with the distance.
|
||||
|
||||
Inverse-quadratic attenuation curves are inconvenient for artists: they
|
||||
never reach zero and have almost infinitely large values near the emitter.
|
||||
So Godot simulates omni light with an artist-controlled exponential curve
|
||||
instead.
|
||||
|
||||
.. image:: img/light_attenuation.png
|
||||
|
||||
Spot light
|
||||
~~~~~~~~~~
|
||||
|
||||
Spot lights are similar to omni lights, except they emit light only into a cone
|
||||
(or "cutoff"). They are useful to simulate flashlights,
|
||||
car lights, etc. This kind of light is also attenuated towards the
|
||||
opposite direction it points to.
|
||||
|
||||
.. image:: img/light_spot.png
|
||||
|
||||
Ambient light
|
||||
-------------
|
||||
|
||||
Ambient light can be found in the properties of a WorldEnvironment
|
||||
(remember only one of such can be instanced per scene). Ambient light
|
||||
consists of a uniform light and energy. This light is applied the same
|
||||
to every single pixel of the rendered scene, except to objects that used
|
||||
baked light.
|
||||
|
||||
Baked light
|
||||
-----------
|
||||
|
||||
Baked light stands for pre-computed ambient light. It can serve multiple
|
||||
purposes, such as baking light emitters that are not going to be used in
|
||||
real-time, and baking light bounces from real-time lights to add more
|
||||
realism to a scene (see :ref:`doc_light_baking` tutorial for more information).
|
||||
@@ -1,188 +0,0 @@
|
||||
.. _doc_shadow_mapping:
|
||||
|
||||
Shadow mapping
|
||||
==============
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Simply throwing a light is not enough to realistically illuminate a
|
||||
scene. It should be, in theory, but given the way video hardware
|
||||
works, parts of objects that should not be reached by light are lit
|
||||
anyway.
|
||||
|
||||
Most people (including artists), see shadows as something projected by
|
||||
light, as if they were created by the light itself by darkening places
|
||||
that are hidden from the light source.
|
||||
|
||||
This is actually not correct and it's important to understand that
|
||||
shadows are places where light simply does not reach. As a rule (and
|
||||
without counting indirect light) if a light is turned off, the places
|
||||
where shadow appear should remain the same. In other words, shadows
|
||||
should not be seen as something "added" to the scene, but as an area
|
||||
that "remains dark".
|
||||
|
||||
All light types in Godot can use shadow mapping, and all support several
|
||||
different techniques that trade quality by performance. Shadow mapping
|
||||
uses a texture storing the "depth view" of the light and checks against
|
||||
it in real-time for each pixel it renders.
|
||||
|
||||
The bigger the resolution of the shadow map texture, the more detail the
|
||||
shadow has, but more video memory and bandwidth consumed (which means
|
||||
frame-rate goes down).
|
||||
|
||||
Shadows by light type
|
||||
---------------------
|
||||
|
||||
Directional light shadows
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Directional lights can affect a really big area. The bigger the scene,
|
||||
the bigger the affected area. Given the shadow map resolution stays the
|
||||
same, the same amount of shadow pixels cover a bigger area, resulting in
|
||||
blocky shadows. Multiple techniques exist to deal with resolution
|
||||
problems, but the most common one is PSSM (Parallel Split Shadow Maps):
|
||||
|
||||
.. image:: img/shadow_directional.png
|
||||
|
||||
These techniques divide the view in 2 or 4 sections, and a shadow is
|
||||
rendered for each. This way, close objects can use larger shadow while
|
||||
further away objects will use one in less detail, but in proportion this
|
||||
seems to make the shadow map size increase while it's actually kept the
|
||||
same. Of course, this technique is not free, the more splits the more
|
||||
the performance goes down. On mobile, it is generally inconvenient to
|
||||
use more than 2 splits.
|
||||
|
||||
An alternative technique is PSM (Perspective Shadow Mapping). This
|
||||
technique is much cheaper than PSSM (as cheap as orthogonal), but it
|
||||
only really works for a few camera angles respect to the light. In other
|
||||
words, PSM is only useful for games where the camera direction and light
|
||||
direction are both fixed, and the light is not parallel to the camera
|
||||
(which is when PSM completely breaks).
|
||||
|
||||
Omni light shadows
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Omnidirectional lights are also troublesome. How to represent 360 degrees
|
||||
of light with a single texture? There are two alternatives, the first
|
||||
one is to use DPSM (Dual Paraboloid Shadow Mapping). This technique is
|
||||
fast, but it requires DISCARD to be used (which makes it not very usable
|
||||
on mobile). DPSM can also look rather bad if the geometry is not
|
||||
tessellated enough, so more vertices might be necessary if it doesn't
|
||||
look tight. The second option is to simply not use a shadow map, and use
|
||||
a shadow cubemap. This is faster, but requires six passes to render all
|
||||
directions and is not supported on the current (GLES2) renderer.
|
||||
|
||||
.. image:: img/shadow_omni.png
|
||||
|
||||
As few considerations when using DPSM shadow maps:
|
||||
|
||||
- Keep Slope-Scale on 0.
|
||||
- Use a small value for Z-Offset, if this look wrong, make it smaller.
|
||||
- ESM filtering can improve the look.
|
||||
- The seams between the two halves of the shadow are generally
|
||||
noticeable, so rotate the light to make them show less.
|
||||
|
||||
Spot light shadows
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Spot light shadows are generally the simpler, just needing a single
|
||||
texture and no special techniques.
|
||||
|
||||
.. image:: /img/shadow_spot.png
|
||||
|
||||
Shadows parameters
|
||||
------------------
|
||||
|
||||
The fact that shadows are actually a texture can generate several
|
||||
problems. The most common is Z fighting (lines at the edge of the
|
||||
objects that cast the shadows. There are two ways to fix this, the first
|
||||
is to tweak the offset parameters, and the second is to use a filtered
|
||||
shadow algorithm, which generally looks better and has not as many
|
||||
glitches, but consumes more GPU time.
|
||||
|
||||
Adjusting z-offset
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
So, you have decided to go with non-filtered shadows because they are
|
||||
faster, you want a little more detail or maybe you just like the sexy
|
||||
saw-like shadow outlines because they remind you of your favorite
|
||||
previous-gen games. Truth is, this can be kind of be a pain, but most of the
|
||||
time it can be adjusted to have nice results. There is no magic number and
|
||||
whatever result you come up will be different from scene to scene, it
|
||||
just takes a while of tweaking. Let's go step by step.
|
||||
|
||||
First step is to turn on the shadows, let's assume that both Z-Offset
|
||||
and Z-Slope-Scale are at 0. You will be greeted by this:
|
||||
|
||||
.. image:: img/shadow_offset_1.png
|
||||
|
||||
Holy crap, the shadow is all over the place and extremely glitchy! This
|
||||
happens because the shadow is fighting with the same geometry that is
|
||||
casting it. This is called "self-shadowing". To avoid this meaningless
|
||||
fight, you realize you need to make peace between the shadow and the
|
||||
geometry, so you push back the shadow a little by increasing the shadow
|
||||
Z-Offset. This improves things a lot:
|
||||
|
||||
.. image:: img/shadow_offset_2.png
|
||||
|
||||
But it's not quite perfect, self shadowing did not disappear completely.
|
||||
So close to perfection but still not there.. so in a turn of greed you
|
||||
increase the Z-Offset even more!
|
||||
|
||||
.. image:: img/shadow_offset_3.png
|
||||
|
||||
And it gets rid of those self-shadowings! Hooray! Except something is
|
||||
wrong.. oh, right. Being pushed back too much, the shadows start
|
||||
disconnecting from their casters, which looks pretty awful. Ok, you go
|
||||
back to the previous Z-offset.
|
||||
|
||||
This is when Z-Slope-Scale comes to save the day. This setting makes
|
||||
shadow caster objects thinner, so the borders don't self-shadow:
|
||||
|
||||
.. image:: img/shadow_offset_4.png
|
||||
|
||||
Aha! Finally something that looks acceptable. It's perfectly acceptable
|
||||
and you can perfectly ship a game that looks like this (imagine you are
|
||||
looking at Final Fantasy quality art btw, not this horrible attempt at 3D
|
||||
modelling). There may be very tiny bits left of self shadowing that no
|
||||
one cares about, so your inextinguishable greed kicks in again and you
|
||||
raise the Z-Slope Scale again:
|
||||
|
||||
.. image:: img/shadow_offset_5.png
|
||||
|
||||
Well, that was too much, shadows casted are way too thin and don't look
|
||||
good anymore. Well, though luck, the previous setting was good anyway,
|
||||
let's accept that perfection does not exist and move on to something
|
||||
else.
|
||||
|
||||
Important!
|
||||
~~~~~~~~~~
|
||||
|
||||
If you are using shadow maps with directional lights, make sure that
|
||||
the *view distance* of the *camera* is set to an *optimal range*. This
|
||||
means, if the distance between your camera and the visible end of the
|
||||
scene is 100, then set the view distance to that value. If a greater
|
||||
than necessary value is used, the shadow maps will lose detail as they
|
||||
will try to cover a bigger area.
|
||||
|
||||
So, always make sure to use the optimal range!
|
||||
|
||||
Shadow filtering
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Raw shadows are blocky. Increasing their resolution just makes smaller
|
||||
blocks, but they are still blocks.
|
||||
|
||||
Godot offers a few ways to filter them (shadow in the example is
|
||||
low-resolution on purpose!):
|
||||
|
||||
.. image:: img/shadow_filter_options.png
|
||||
|
||||
PCF5 and PCF13 are simple texture-space filtering. Will make the texture
|
||||
a little more acceptable but still needs considerable resolution for it
|
||||
to look good.
|
||||
|
||||
ESM is a more complex filter and has a few more tweaking parameters. ESM
|
||||
uses shadow blurring (amount of blur passes and multiplier can be
|
||||
adjusted).
|
||||