Skip to content

Commit 7f4ee8c

Browse files
authored
Merge pull request #11816 from Calinou/lights-and-shadows-add-area-lights
Add documentation for area lights in 3D lights and shadows
2 parents 937d70e + 240eb88 commit 7f4ee8c

5 files changed

Lines changed: 93 additions & 1 deletion

File tree

engine_details/architecture/internal_rendering_architecture.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,10 @@ planned in a future release.
498498
Clustering is also used for reflection probes and decal rendering in the
499499
Forward+ renderer.
500500

501+
Area lights make use of the
502+
`Linearly Transformed Cosines <https://eheitzresearch.wordpress.com/757-2/>`__
503+
technique.
504+
501505
Shadow mapping
502506
~~~~~~~~~~~~~~
503507

122 KB
Loading
201 KB
Loading

tutorials/3d/lights_and_shadows.rst

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,87 @@ With the projector texture below, the following result is obtained:
373373
working entirely. If you need shadows for wider lights, use an omni light
374374
instead.
375375

376+
Area light
377+
----------
378+
379+
Sometimes, you want lighting to come from a large area instead of a single
380+
point. Area lights are useful for simulating soft, diffuse lighting, such as
381+
light coming from a window or a lit billboard. This type of light is expensive
382+
to render in real-time, so it should be used sparingly, especially when shadows
383+
are enabled.
384+
385+
Godot provides the :ref:`class_AreaLight3D` node for this purpose, which emits
386+
light from a rectangular area. The node only emits light and has no other visual
387+
representation in the scene. The screenshots below use a :ref:`class_Sprite3D`
388+
node as a child of the area light for visualization purposes.
389+
390+
Area lights can also cast shadows, with variable penumbra simulated using
391+
:ref:`PCSS <doc_lights_and_shadows_pcss_recommendations>` by default. The size
392+
of this penumbra can be controlled with the Light3D **Size** property. This
393+
effect can be quite demanding, so it can be turned off by setting **Size** to
394+
``0.0``.
395+
396+
.. image:: img/lights_and_shadows_area_example.webp
397+
398+
.. note::
399+
400+
Since area lights are difficult to simulate in a real-time rasterized
401+
renderer, they come with a number of limitations.
402+
403+
For small light sources, you will likely get better results when using point
404+
lights. Shadows from area lights are crude approximations, as they are
405+
calculated as if they were point lights, and may appear to be distorted at
406+
the edges. To get a better result, make sure the meshes in the light's range
407+
are sufficiently subdivided.
408+
409+
Area lights suffer from light leaking on the backside of geometry closely in
410+
front of them at grazing angles, so be careful with where you place them.
411+
412+
Lastly, not all material features are fully supported; area lights are
413+
practically limited to Lambertian diffuse and GGX specular shading, while
414+
anisotropic materials will appear as if isotropic. Vertex shading is also
415+
not implemented for area lights.
416+
417+
Area lights emit light in a rectangular area defined by the **Area > Size**
418+
property (not to be confused with the generic Light3D **Size** property). To get
419+
a physically accurate result, you should resize this area to match the size of
420+
the real-life light source you are trying to simulate. For example, if you are
421+
simulating a 1-meter neon tube that is 10 centimeters wide, set the area
422+
size to ``(1, 0.1)`` and adjust the energy accordingly.
423+
424+
By default, the light's energy is normalized: the larger the area, the weaker
425+
the light. This allows you to change the area size without needing to adjust the
426+
energy to compensate, which is useful for animation. You can disable this
427+
behavior by unchecking **Area > Normalize Energy** if you want the energy to be
428+
independent of the area size.
429+
430+
The rectangular area can optionally be textured. This can be effectively used to
431+
change the light's shape into any 2D shape, or tint it in different colors. The
432+
texture's alpha channel is treated as black (no light coming through). The area
433+
light's texture will be visible in reflections according to the surface's
434+
roughness. This behavior is different from omni/spot projectors, as it does not
435+
project the texture directly onto all diffuse lighting.
436+
437+
When using a textures that are transparent or black toward the edges, you might
438+
want to leave a gap of a few pixels to make sure the texture is blurred
439+
smoothly.
440+
441+
.. image:: img/lights_and_shadows_area_texture.webp
442+
443+
.. note::
444+
445+
Changing the area light's texture at runtime can be expensive, especially if
446+
the texture is large.
447+
448+
To reduce the performance impact of switching textures at runtime, make sure
449+
each dimension of an area texture is either a multiple of 128 pixels, or a
450+
power of two. This removes the need for a scaling pass, which slows down
451+
texture changes. The textures don't necessarily have to be square to be
452+
optimal. Examples of optimal texture sizes include 32×64, 128×128, and
453+
256×384.
454+
455+
Textured area lights are not supported in the Compatibility renderer.
456+
376457
.. _doc_lights_and_shadows_shadow_atlas:
377458

378459
Shadow atlas

tutorials/shaders/shader_reference/spatial_shader.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,14 @@ Below is an example of a custom ``light()`` function using a Lambertian lighting
552552
.. code-block:: glsl
553553
554554
void light() {
555-
DIFFUSE_LIGHT += clamp(dot(NORMAL, LIGHT), 0.0, 1.0) * ATTENUATION * LIGHT_COLOR / PI;
555+
if (LIGHT_IS_AREA) {
556+
// Area light GGX shading.
557+
DIFFUSE_LIGHT += LIGHT_AREA_DIFFUSE_MULTIPLIER * ATTENUATION * LIGHT_COLOR;
558+
SPECULAR_LIGHT += LIGHT_AREA_SPECULAR_MULTIPLIER * ATTENUATION * LIGHT_COLOR * SPECULAR_AMOUNT;
559+
} else {
560+
// Used for all other light types (directional, omni, spot).
561+
DIFFUSE_LIGHT += clamp(dot(NORMAL, LIGHT), 0.0, 1.0) * ATTENUATION * LIGHT_COLOR / PI;
562+
}
556563
}
557564
558565
If you want the lights to add together, add the light contribution to ``DIFFUSE_LIGHT`` using ``+=``, rather than overwriting it.

0 commit comments

Comments
 (0)