Add a page documenting Godot's internal rendering architecture

This is intended for new and returning engine contributors.
This commit is contained in:
Hugo Locurcio
2022-08-28 19:38:41 +02:00
parent d0b68537e6
commit 00381a521b
3 changed files with 792 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

View File

@@ -19,6 +19,7 @@ This section covers the basics that you will encounter in (almost) every source
variant_class
object_class
inheritance_class_tree
internal_rendering_architecture
Extending Godot by modifying its source code
--------------------------------------------

View File

@@ -0,0 +1,791 @@
.. _doc_internal_rendering_architecture:
Internal rendering architecture
===============================
This page is a high-level overview of Godot 4's internal renderer design.
It does not apply to previous Godot versions.
The goal of this page is to document design decisions taken to best suit
:ref:`Godot's design philosophy <doc_best_practices_for_engine_contributors>`,
while providing a starting point for new rendering contributors.
If you have questions about rendering internals not answered here, feel free to
ask in the ``#rendering`` channel of the
`Godot Contributors Chat <https://chat.godotengine.org/channel/rendering>`__.
.. note::
If you have difficulty understanding concepts on this page, it is
recommended to go through an OpenGL tutorial such as
`LearnOpenGL <https://learnopengl.com/>`__.
Modern low-level APIs (Vulkan/Direct3D 12) require intermediate
knowledge of higher-level APIs (OpenGL/Direct3D 11) to be used
effectively. Thankfully, contributors rarely need to work directly with
low-level APIs. Godot's renderers are built entirely on OpenGL and
RenderingDevice, which is our abstraction over Vulkan/Direct3D 12.
.. _doc_internal_rendering_architecture_methods:
Rendering methods
-----------------
Forward+
^^^^^^^^
This is a forward renderer that uses a *clustered* approach to lighting.
Clustered lighting uses a compute shader to group lights into a 3D frustum
aligned grid. Then, at render time, pixels can lookup what lights affect the
grid cell they are in and only run light calculations for lights that might
affect that pixel.
This approach can greatly speed up rendering performance on desktop hardware,
but is substantially less efficient on mobile.
Forward Mobile
^^^^^^^^^^^^^^
This is a forward renderer that uses a traditional single-pass approach to lighting.
Intended for mobile platforms, but can also run on desktop platforms. This
rendering method is optimized to perform well on mobile GPUs. Mobile GPUs have a
very different architecture compared to desktop GPUs due to their unique
constraints around battery usage, heat, and overall bandwidth limitations of
reading and writing data. Compute shaders also have very limited support or
aren't supported at all. As a result, the mobile renderer purely uses
raster-based shaders (fragment/vertex).
Unlike desktop GPUs, mobile GPUs perform *tile-based rendering*. Instead of
rendering the whole image as a single unit, the image is divided in smaller
tiles that fit within the faster internal memory of the mobile GPU. Each tile is
rendered and then written out to the destination texture. This all happens
automatically on the graphics driver.
The problem is that this introduces bottlenecks in our traditional approach. For
desktop rendering, we render all opaque geometry, then handle the background,
then transparent geometry, then post-processing. Each pass will need to read the
current result into tile memory, perform its operations and then write it out
again. We then wait for all tiles to be completed before moving on to the next
pass.
The first important change in the mobile renderer is that the mobile renderer
does not use the RGBA16F texture formats that the desktop renderer does.
Instead, it is using a R10G10B10A2 UNORM texture format. This halves the bandwidth
required and has further improvements as mobile hardware often further optimizes
for 32-bit formats. The tradeoff is that the mobile renderer has limited HDR
capabilities due to the reduced precision and maximum values in the color data.
The second important change is the use of sub-passes whenever possible.
Sub-passes allows us to perform the rendering steps end-to-end per tile saving
on the overhead introduced by reading from and writing to the tiles between each
rendering pass. The ability to use sub-passes is limited by the inability to
read neighboring pixels, as we're constrained to working within a single tile.
This limitation of subpasses results in not being able to implement features
such as glow and depth of field efficiently. Similarly, if there is a
requirement to read from the screen texture or depth texture, we must fully
write out the rendering result limiting our ability to use sub-passes. When such
features are enabled, a mix of sub-passes and normal passes are used, and these
features result in a notable performance penalty.
On desktop platforms, the use of sub-passes won't have any impact on
performance. However, this rendering method can still perform better than
Clustered Forward in simple scenes thanks to its lower complexity and lower
bandwidth usage. This is especially noticeable on low-end GPUs, integrated
graphics or in VR applications.
Given its low-end focus, this rendering method does not provide high-end
rendering features such as SDFGI and :ref:`doc_volumetric_fog`. Several
post-processing effects are also not available.
.. _doc_internal_rendering_architecture_compatibility:
Compatibility
^^^^^^^^^^^^^
.. note::
This is the only rendering method available when using the OpenGL driver.
This rendering method is not available when using Vulkan or Direct3D 12.
This is a traditional (non-clustered) forward renderer. It's intended for old
GPUs that don't have Vulkan support, but still works very efficiently on newer
hardware. Specifically, it is optimized for older and lower-end mobile devices
However, many optimizations carry over making it a good choice for older and
lower-end desktop as well.
Like the Mobile renderer, the Compatibility renderer uses an R10G10B10A2 UNORM
texture for 3D rendering. Unlike the mobile renderer, colors are tonemapped and
stored in sRGB format so there is no HDR support. This avoids the need for a
tonemapping pass and allows us to use the lower bit texture without substantial
banding.
The Compatibility renderer uses a traditional forward single-pass approach to
drawing objects with lights, but it uses a multi-pass approach to draw lights
with shadows. Specifically, in the first pass, it can draw multiple lights
without shadows and up to one DirectionalLight3D with shadows. In each
subsequent pass, it can draw up to one OmniLight3D, one SpotLight3D and one
DirectionalLight3D with shadows. Lights with shadows will affect the scene
differently than lights without shadows, as the lighting is blended in sRGB space
instead of linear space. This difference in lighting will impact how the scene
looks and needs to be kept in mind when designing scenes for the Compatibility
renderer.
Given its low-end focus, this rendering method does not provide high-end
rendering features (even less so compared to Forward Mobile). Most
post-processing effects are not available.
Why not deferred rendering?
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Forward rendering generally provides a better tradeoff for performance versus
flexibility, especially when a clustered approach to lighting is used. While
deferred rendering can be faster in some cases, it's also less flexible and
requires using hacks to be able to use MSAA. Since games with a less realistic
art style can benefit a lot from MSAA, we chose to go with forward rendering for
Godot 4 (like Godot 3).
That said, parts of the forward renderer *are* performed with a deferred approach
to allow for some optimizations when possible. This applies to VoxelGI and SDFGI
in particular.
A clustered deferred renderer may be developed in the future. This renderer
could be used in situations where performance is favored over flexibility.
Rendering drivers
-----------------
Godot 4 supports the following graphics APIs:
Vulkan
^^^^^^
This is the main driver in Godot 4, with most of the development focus going
towards this driver.
Vulkan 1.0 is required as a baseline, with optional Vulkan 1.1 and 1.2 features
used when available. `volk <https://github.com/zeux/volk>`__ is used as a Vulkan
loader, and
`Vulkan Memory Allocator <https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator>`__
is used for memory management.
Both the Forward+ and Mobile
:ref:`doc_internal_rendering_architecture_methods` are supported when using the
Vulkan driver.
**Vulkan context creation:**
- `drivers/vulkan/vulkan_context.cpp <https://github.com/godotengine/godot/blob/4.0/drivers/vulkan/vulkan_context.cpp>`__
Direct3D 12
^^^^^^^^^^^
Like Vulkan, the Direct3D 12 driver targets modern platforms only. It is
designed to target both Windows and Xbox (whereas Vulkan can't be used directly on Xbox).
Both the Forward+ and Mobile :ref:`doc_internal_rendering_architecture_methods` can be
used with Direct3D 12.
:ref:`doc_internal_rendering_architecture_core_shaders` are shared with the
Vulkan renderer. Shaders are transpiled from GLSL to HLSL using
Mesa NIR (`more information <https://godotengine.org/article/d3d12-adventures-in-shaderland/>`__).
This means you don't need to know HLSL to work on the Direct3D 12 renderer,
although knowing the language's basics is recommended to ease debugging.
**As of May 2023, this driver is still in development and is not merged in
Godot 4.0 or the master branch.** While Direct3D 12 allows supporting
Direct3D-exclusive features on Windows 11 such as windowed optimizations and
Auto HDR, Vulkan is still recommended for most projects. See the
`pull request that introduced Direct3D 12 support <https://github.com/godotengine/godot/pull/70315>`__
for more information.
Metal
^^^^^
Godot supports Metal rendering via `MoltenVK <https://github.com/KhronosGroup/MoltenVK>`__,
as macOS and iOS do not support Vulkan natively.
This is done automatically when specifying the Vulkan driver in the Project Settings.
MoltenVK makes driver maintenance easy at the cost of some performance overhead.
Also, MoltenVK has several limitations that a native Metal driver implementation
wouldn't have. Both the clustered and mobile
:ref:`doc_internal_rendering_architecture_methods` can be used with a Metal
backend via MoltenVK.
A native Metal driver is planned in the future for better performance and
compatibility.
OpenGL
^^^^^^
This driver uses OpenGL ES 3.0 and targets legacy and low-end devices that don't
support Vulkan. OpenGL 3.3 Core Profile is used on desktop platforms to run this
driver, as most graphics drivers on desktop don't support OpenGL ES.
WebGL 2.0 is used for web exports.
Only the :ref:`doc_internal_rendering_architecture_compatibility` rendering
method can be used with the OpenGL driver.
:ref:`doc_internal_rendering_architecture_core_shaders` are entirely different
from the Vulkan renderer.
**As of May 2023, this driver is still in development.** Many features
are still not implemented, especially in 3D.
Summary of rendering drivers/methods
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The following rendering API + rendering method combinations are currently possible:
- Vulkan + Forward+
- Vulkan + Forward Mobile
- Direct3D 12 + Forward+
- Direct3D 12 + Forward Mobile
- Metal + Forward+ (via MoltenVK)
- Metal + Forward Mobile (via MoltenVK)
- OpenGL + Compatibility
Each combination has its own limitations and performance characteristics. Make
sure to test your changes on all rendering methods if possible before opening a
pull request.
RenderingDevice abstraction
---------------------------
.. note::
The OpenGL driver does not use the RenderingDevice abstraction.
To make the complexity of modern low-level graphics APIs more manageable,
Godot uses its own abstraction called RenderingDevice.
This means that when writing code for modern rendering methods, you don't
actually use the Vulkan or Direct3D 12 APIs directly. While this is still
lower-level than an API like OpenGL, this makes working on the renderer easier,
as RenderingDevice will abstract many API-specific quirks for you. The
RenderingDevice presents a similar level of abstraction as Metal or WebGPU.
**Vulkan RenderingDevice implementation:**
- `drivers/vulkan/rendering_device_vulkan.cpp <https://github.com/godotengine/godot/blob/4.0/drivers/vulkan/rendering_device_vulkan.cpp>`__
Core rendering classes architecture
-----------------------------------
This diagram represents the structure of rendering classes in Godot, including the RenderingDevice abstraction:
.. image:: img/rendering_architecture_diagram.webp
`View at full size <https://raw.githubusercontent.com/godotengine/godot-docs/4.0/contributing/development/core_and_modules/img/rendering_architecture_diagram.webp>`__
.. _doc_internal_rendering_architecture_core_shaders:
Core shaders
------------
While shaders in Godot projects are written using a
:ref:`custom language inspired by GLSL <doc_shading_language>`, core shaders are
written directly in GLSL.
These core shaders are embedded in the editor and export template binaries at
compile-time. To see any changes you've made to those GLSL shaders, you need to
recompile the editor or export template binary.
Some material features such as height mapping, refraction and proximity fade are
not part of core shaders, and are performed in the default BaseMaterial3D using
the Godot shader language instead (not GLSL). This is done by procedurally
generating the required shader code depending on the features enabled in the
material.
By convention, shader files with ``_inc`` in their name are included in other
GLSL files for better code reuse. Standard GLSL preprocessing is used to achieve
this.
.. warning::
Core material shaders will be used by every material in the scene both
with the default BaseMaterial3D and custom shaders. As a result, these
shaders must be kept as simple as possible to avoid performance issues and
ensure shader compilation doesn't become too slow.
If you use ``if`` branching in a shader, performance may decrease as
:abbr`VGPR (Vector General-Purpose Register)` usage will increase in the
shader. This happens even if all pixels evaluate to ``true`` or ``false`` in
a given frame.
If you use ``#if`` preprocessor branching, the number of required shader
versions will increase in the scene. In a worst-case scenario, adding a
single boolean ``#define`` can *double* the number of shader versions that
may need to be compiled in a given scene. In some cases, Vulkan
specialization constants can be used as a faster (but more limited)
alternative.
This means there is a high barrier to adding new built-in material features
in Godot, both in the core shaders and BaseMaterial3D. While BaseMaterial3D
can make use of dynamic code generation to only include the shader code if
the feature is enabled, it'll still require generating more shader versions
when these features are used in a project. This can make shader compilation
stutter more noticeable in complex 3D scenes.
See
`The Shader Permutation Problem <https://therealmjp.github.io/posts/shader-permutations-part1/>`__
and
`Branching on a GPU <https://medium.com/@jasonbooth_86226/branching-on-a-gpu-18bfc83694f2>`__
blog posts for more information.
**Core GLSL material shaders:**
- Forward+: `servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl>`__
- Forward Mobile: `servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl>`__
- Compatibility: `drivers/gles3/shaders/scene.glsl <https://github.com/godotengine/godot/blob/4.0/drivers/gles3/shaders/scene.glsl>`__
**Material shader generation:**
- `scene/resources/material.cpp <https://github.com/godotengine/godot/blob/4.0/scene/resources/material.cpp>`__
**Other GLSL shaders for Forward+ and Forward Mobile rendering methods:**
- `servers/rendering/renderer_rd/shaders/ <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/>`__
- `modules/lightmapper_rd/ <https://github.com/godotengine/godot/blob/4.0/modules/lightmapper_rd>`__
**Other GLSL shaders for the Compatibility rendering method:**
- `drivers/gles3/shaders/ <https://github.com/godotengine/godot/blob/4.0/drivers/gles3/shaders/>`__
2D and 3D rendering separation
------------------------------
.. note::
The following is only applicable in the Forward+ and Forward Mobile
rendering methods, not in Compatibility. Multiple Viewports can be used to
emulate this when using the Compatibility backend, or to perform 2D
resolution scaling.
2D and 3D are rendered to separate buffers, as 2D rendering in Godot is performed
in :abbr:`LDR (Low Dynamic Range)` sRGB-space while 3D rendering uses
:abbr:`HDR (High Dynamic Range)` linear space.
3D resolution scaling is performed differently depending on whether bilinear or
FSR 1.0 scaling is used. When bilinear scaling is used, no special upscaling
shader is run. Instead, the viewport's texture is stretched and displayed with a
linear sampler (which makes the filtering happen directly on the hardware). This
allows maximizing the performance of bilinear 3D scaling.
The ``configure()`` function in RenderSceneBuffersRD reallocates the 2D/3D
buffers when the resolution or scaling changes.
Dynamic resolution scaling isn't supported yet, but is planned in a future Godot
release.
**2D and 3D rendering buffer configuration C++ code:**
- `servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp>`__
2D rendering techniques
-----------------------
2D light rendering is performed in a single pass to allow for better performance
with large amounts of lights.
The Forward+ and Mobile rendering methods don't feature 2D batching yet, but
it's planned for a future release.
The Compatibility backend features 2D batching to improve performance, which is
especially noticeable with lots of text on screen.
MSAA can be enabled in 2D to provide "automatic" line and polygon antialiasing,
but FXAA does not affect 2D rendering as it's calculated before 2D rendering
begins. Godot's 2D drawing methods such as the Line2D node or some CanvasItem
``draw_*()`` methods provide their own way of antialiasing based on triangle
strips and vertex colors, which don't require MSAA to work.
A 2D signed distance field representing LightOccluder2D nodes in the viewport is
automatically generated if an user shader requests it. This can be used for
various effects in custom shaders, such as 2D global illumination. It is also
used to calculate particle collisions in 2D.
**2D SDF generation GLSL shader:**
- `https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl <servers/rendering/renderer_rd/shaders/canvas_sdf.glsl>`__
3D rendering techniques
-----------------------
Batching and instancing
^^^^^^^^^^^^^^^^^^^^^^^
In the Forward+ backend, Vulkan instancing is used to group rendering
of identical objects for performance. This is not as fast as static mesh
merging, but it still allows instances to be culled individually.
Light, decal and reflection probe rendering
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
Reflection probe and decal rendering are currently not available in the
Compatibility backend.
As its name implies, the Forward+ backend uses clustered lighting. This
allows using as many lights as you want; performance largely depends on screen
coverage. Shadow-less lights can be almost free if they don't occupy much space
on screen.
All rendering methods also support rendering up to 8 directional lights at the
same time (albeit with lower shadow quality when more than one light has shadows
enabled).
The Forward Mobile backend uses a single-pass lighting approach, with a
limitation of 8 OmniLights + 8 SpotLights affecting each Mesh *resource* (plus a
limitation of 256 OmniLights + 256 SpotLights in the camera view). These limits
are hardcoded and can't be adjusted in the project settings.
The Compatibility backend uses a hybrid single-pass + multi-pass lighting
approach. Lights without shadows are rendered in a single pass. Lights with
shadows are rendered in multiple passes. This is required for performance
reasons on mobile devices. As a result, performance does not scale well with
many shadow-casting lights. It is recommended to only have a handful of lights
with shadows in the camera frustum at a time and for those lights to be spread
apart so that each object is only touched by 1 or 2 shadowed lights at a time.
The maximum number of lights visible at once can be adjusted in the project
settings.
In all 3 methods, lights without shadows are much cheaper than lights with
shadows. To improve performance, lights are only updated when the light is
modified or when objects in its radius are modified. Godot currently doesn't
separate static shadow rendering from dynamic shadow rendering, but this is
planned in a future release.
Clustering is also used for reflection probes and decal rendering in the
Forward+ backend.
Shadow mapping
^^^^^^^^^^^^^^
Both Forward+ and Forward Mobile methods use
:abbr:`PCF (Percentage Closer Filtering)` to filter shadow maps and create a
soft penumbra. Instead of using a fixed PCF pattern, these methods use a vogel
disk pattern which allows for changing the number of samples and smoothly
changing the quality.
Godot also supports percentage-closer soft shadows (PCSS) for more realistic
shadow penumbra rendering. PCSS shadows are limited to the Forward+
backend as they're too demanding to be usable in the Forward Mobile backend.
PCSS also uses a vogel-disk shaped kernel.
Additionally, both shadow-mapping techniques rotate the kernel on a per-pixel
basis to help soften under-sampling artifacts.
The Compatibility backend doesn't support shadow mapping for any light types yet.
Temporal antialiasing
^^^^^^^^^^^^^^^^^^^^^
.. note::
Only available in the Forward+ backend, not the Forward Mobile or
Compatibility methods.
Godot uses a custom TAA implementation based on the old TAA implementation from
`Spartan Engine <https://github.com/PanosK92/SpartanEngine>`__.
Temporal antialiasing requires motion vectors to work. If motion vectors
are not correctly generated, ghosting will occur when the camera or objects move.
Motion vectors are generated on the GPU in the main material shader. This is
done by running the vertex shader corresponding to the previous rendered frame
(with the previous camera transform) in addition to the vertex shader for the
current rendered frame, then storing the difference between them in a color buffer.
Using `FSR 2.0 <https://github.com/GPUOpen-Effects/FidelityFX-FSR2>`__ instead
of a custom TAA implementation is planned in a future release.
**TAA resolve:**
- `servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl>`__
Global illumination
^^^^^^^^^^^^^^^^^^^
.. note::
VoxelGI and SDFGI are only available in the Forward+ backend, not the
Forward Mobile or Compatibility methods.
LightmapGI *baking* is only available in the Forward+ and Forward Mobile
methods, and can only be performed within the editor (not in an exported
project). LightmapGI *rendering* will eventually be supported by the
Compatibility backend.
Godot supports voxel-based GI (VoxelGI), signed distance field GI (SDFGI) and
lightmap baking and rendering (LightmapGI). These techniques can be used
simultaneously if desired.
Lightmap baking happens on the GPU using Vulkan compute shaders. The GPU-based
lightmapper is implemented in the LightmapperRD class, which inherits from the
Lightmapper class. This allows for implementing additional lightmappers, paving
the way for a future port of the CPU-based lightmapper present in Godot 3.x.
This would allow baking lightmaps while using the Compatibility backend.
**Core GI C++ code:**
- `servers/rendering/renderer_rd/environment/gi.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/environment/gi.cpp>`__
- `scene/3d/voxel_gi.cpp <https://github.com/godotengine/godot/blob/4.0/scene/3d/voxel_gi.cpp>`__ - VoxelGI node
- `editor/plugins/voxel_gi_editor_plugin.cpp <https://github.com/godotengine/godot/blob/4.0/editor/plugins/voxel_gi_editor_plugin.cpp>`__ - Editor UI for the VoxelGI node
**Core GI GLSL shaders:**
- `servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl>`__
- `servers/rendering/renderer_rd/shaders/environment/voxel_gi_debug.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/voxel_gi_debug.glsl>`__ - VoxelGI debug draw mode
- `servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl>`__ - SDFGI Cascades debug draw mode
- `servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl>`__ - SDFGI Probes debug draw mode
- `servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl>`__
- `servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl>`__
- `servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl>`__
**Lightmapper C++ code:**
- `scene/3d/lightmap_gi.cpp <https://github.com/godotengine/godot/blob/4.0/scene/3d/lightmap_gi.cpp>`__ - LightmapGI node
- `editor/plugins/lightmap_gi_editor_plugin.cpp <https://github.com/godotengine/godot/blob/4.0/editor/plugins/lightmap_gi_editor_plugin.cpp>`__ - Editor UI for the LightmapGI node
- `scene/3d/lightmapper.cpp <https://github.com/godotengine/godot/blob/4.0/scene/3d/lightmapper.cpp>`__ - Abstract class
- `modules/lightmapper_rd/lightmapper_rd.cpp <https://github.com/godotengine/godot/blob/4.0/modules/lightmapper_rd/lightmapper_rd.cpp>`__ - GPU-based lightmapper implementation
**Lightmapper GLSL shaders:**
- `modules/lightmapper_rd/lm_raster.glsl <https://github.com/godotengine/godot/blob/4.0/modules/lightmapper_rd/lm_raster.glsl>`__
- `modules/lightmapper_rd/lm_compute.glsl <https://github.com/godotengine/godot/blob/4.0/modules/lightmapper_rd/lm_compute.glsl>`__
- `modules/lightmapper_rd/lm_blendseams.glsl <https://github.com/godotengine/godot/blob/4.0/modules/lightmapper_rd/lm_blendseams.glsl>`__
Depth of field
^^^^^^^^^^^^^^
.. note::
Only available in the Forward+ and Forward Mobile methods, not the
Compatibility backend.
The Forward+ and Forward Mobile methods use different approaches to
DOF rendering, with different visual results. This is done to best
match the performance characteristics of the target hardware. In Clustered
Forward, DOF is performed using a compute shader. In Forward Mobile, DOF is
performed using a fragment shader (raster).
Box, hexagon and circle bokeh shapes are available (from fastest to slowest).
Depth of field can optionally be jittered every frame to improve its appearance
when temporal antialiasing is enabled.
**Depth of field C++ code:**
- `servers/rendering/renderer_rd/effects/bokeh_dof.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/effects/bokeh_dof.cpp>`__
**Depth of field GLSL shader (compute - used for Forward+):**
- `servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl>`__
**Depth of field GLSL shader (raster - used for Forward Mobile):**
- `servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl>`__
Screen-space effects (SSAO, SSIL, SSR, SSS)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
Only available in the Forward+ backend, not the Forward Mobile or
Compatibility methods.
The Forward+ backend supports screen-space ambient occlusion,
screen-space indirect lighting, screen-space reflections and subsurface scattering.
SSAO uses an implementation derived from Intel's
`ASSAO <https://www.intel.com/content/www/us/en/developer/articles/technical/adaptive-screen-space-ambient-occlusion.html>`__
(converted to Vulkan). SSIL is derived from SSAO to provide high-performance
indirect lighting.
When both SSAO and SSIL are enabled, parts of SSAO and SSIL are shared to reduce
the performance impact.
SSAO and SSIL are performed at half resolution by default to improve performance.
SSR is always performed at half resolution to improve performance.
**Screen-space effects C++ code:**
- `servers/rendering/renderer_rd/effects/ss_effects.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/effects/ss_effects.cpp>`__
**Screen-space ambient occlusion GLSL shader:**
- `servers/rendering/renderer_rd/shaders/effects/ssao.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssao.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl>`__
**Screen-space indirect lighting GLSL shader:**
- `servers/rendering/renderer_rd/shaders/effects/ssil.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssil.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl>`__
**Screen-space reflections GLSL shader:**
- `servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl>`__
- `servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl>`__
**Subsurface scattering GLSL:**
- `servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl>`__
Sky rendering
^^^^^^^^^^^^^
.. seealso::
:ref:`doc_sky_shader`
Godot supports using shaders to render the sky background. The radiance map
(which is used to provide ambient light and reflections for PBR materials) is
automatically updated based on the sky shader.
The SkyMaterial resources such as ProceduralSkyMaterial, PhysicalSkyMaterial and
PanoramaSkyMaterial generate a built-in shader for sky rendering. This is
similar to what BaseMaterial3D provides for 3D scene materials.
A detailed technical implementation can be found in the
`Custom sky shaders in Godot 4.0 <https://godotengine.org/article/custom-sky-shaders-godot-4-0>`__
article.
**Sky rendering C++ code:**
- `servers/rendering/renderer_rd/environment/sky.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/environment/sky.cpp>`__ - Sky rendering
- `scene/resources/sky.cpp <https://github.com/godotengine/godot/blob/4.0/scene/resources/sky.cpp>`__ - Sky resource (not to be confused with sky rendering)
- `scene/resources/sky_material.cpp <https://github.com/godotengine/godot/blob/4.0/scene/resources/sky_material.cpp>`__ SkyMaterial resources (used in the Sky resource)
**Sky rendering GLSL shader:**
Volumetric fog
^^^^^^^^^^^^^^
.. note::
Only available in the Forward+ backend, not the Forward Mobile or
Compatibility methods.
.. seealso::
:ref:`doc_fog_shader`
Godot supports a frustum-aligned voxel (froxel) approach to volumetric fog
rendering. As opposed to a post-processing filter, this approach is more
general-purpose as it can work with any light type. Fog can also use shaders for
custom behavior, which allows animating the fog or using a 3D texture to
represent density.
The FogMaterial resource generates a built-in shader for FogVolume nodes. This is
similar to what BaseMaterial3D provides for 3D scene materials.
A detailed technical explanation can be found in the
`Fog Volumes arrive in Godot 4.0 <https://godotengine.org/article/fog-volumes-arrive-in-godot-4>`__
article.
**Volumetric fog C++ code:**
- `servers/rendering/renderer_rd/environment/fog.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/environment/fog.cpp>`__ - General volumetric fog
- `scene/3d/fog_volume.cpp <https://github.com/godotengine/godot/blob/4.0/scene/3d/fog_volume.cpp>`__ - FogVolume node
- `scene/resources/fog_material.cpp <https://github.com/godotengine/godot/blob/4.0/scene/resources/fog_material.cpp>`__ - FogMaterial resource (used by FogVolume)
**Volumetric fog GLSL shaders:**
- `servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl>`__
- `servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl>`__
Occlusion culling
^^^^^^^^^^^^^^^^^
While modern GPUs can handle drawing a lot of triangles, the number of draw
calls in complex scenes can still be a bottleneck (even with Vulkan and Direct3D
12).
Godot 4 supports occlusion culling to reduce overdraw (when the depth prepass
is disabled) and reduce vertex throughput.
This is done by rasterizing a low-resolution buffer on the CPU using
`Embree <https://github.com/embree/embree>`__. The buffer's resolution depends
on the number of CPU threads on the system, as this is done in parallel.
This buffer includes occluder shapes that were baked in the editor or created at
run-time.
As complex occluders can introduce a lot of strain on the CPU, baked occluders
can be simplified automatically when generated in the editor.
Godot's occlusion culling doesn't support dynamic occluders yet, but
OccluderInstance3D nodes can still have their visibility toggled or be moved.
However, this will be slow when updating complex occluders this way. Therefore,
updating occluders at run-time is best done only on simple occluder shapes such
as quads or cuboids.
This CPU-based approach has a few advantages over other solutions, such as
portals and rooms or a GPU-based culling solution:
- No manual setup required (but can be tweaked manually for best performance).
- No frame delay, which is problematic in cutscenes during camera cuts or when
the camera moves fast behind a wall.
- Works the same on all rendering drivers and methods, with no unpredictable
behavior depending on the driver or GPU hardware.
Occlusion culling is performed by registering occluder meshes, which is done
using OccluderInstance3D *nodes* (which themselves use Occluder3D *resources*).
RenderingServer then performs occlusion culling by calling Embree in
RendererSceneOcclusionCull.
**Occlusion culling C++ code:**
- `scene/3d/occluder_instance_3d.cpp <https://github.com/godotengine/godot/blob/4.0/scene/3d/occluder_instance_3d.cpp>`__
- `servers/rendering/renderer_scene_occlusion_cull.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_scene_occlusion_cull.cpp>`__
Visibility range (LOD)
^^^^^^^^^^^^^^^^^^^^^^^
Godot supports manually authored hierarchical level of detail (HLOD), with
distances specified by the user in the inspector.
In RenderingSceneCull, the ``_scene_cull()`` and ``_render_scene()`` functions
are where most of the LOD determination happens. Each viewport can render the
same mesh with different LODs (to allow for split screen rendering to look correct).
**Visibility range C++ code:**
- `servers/rendering/renderer_scene_cull.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_scene_cull.cpp>`__
Automatic mesh LOD
^^^^^^^^^^^^^^^^^^
The ImporterMesh class is used for the 3D mesh import workflow in the editor.
Its ``generate_lods()`` function handles generating using the
`meshoptimizer <https://meshoptimizer.org/>`__ library.
LOD mesh generation also generates shadow meshes at the same time. These are
meshes that have their vertices welded regardless of smoothing and materials.
This is used to improve shadow rendering performance by lowering the vertex
throughput required to render shadows.
The RenderingSceneCull class's ``_render_scene()`` function determines which
mesh LOD should be used when rendering. Each viewport can render the
same mesh with different LODs (to allow for split screen rendering to look correct).
The mesh LOD is automatically chosen based on a screen coverage metric. This
takes resolution and camera FOV changes into account without requiring user
intervention. The threshold multiplier can be adjusted in the project settings.
To improve performance, shadow rendering and reflection probe rendering also choose
their own mesh LOD thresholds (which can be different from the main scene rendering).
**Mesh LOD generation on import C++ code:**
- `scene/resources/importer_mesh.cpp <https://github.com/godotengine/godot/blob/4.0/scene/resources/importer_mesh.cpp>`__
**Mesh LOD determination C++ code:**
- `servers/rendering/renderer_scene_cull.cpp <https://github.com/godotengine/godot/blob/4.0/servers/rendering/renderer_scene_cull.cpp>`__