Skip to content

Commit 1e02b90

Browse files
committed
Document global and per-instance uniforms in Shading language
1 parent b3f571c commit 1e02b90

File tree

3 files changed

+185
-0
lines changed

3 files changed

+185
-0
lines changed

tutorials/shaders/shader_reference/shading_language.rst

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,191 @@ The syntax also supports subgroups (it's not mandatory to declare the base group
839839

840840
group_uniforms MyGroup.MySubgroup;
841841

842+
Global uniforms
843+
^^^^^^^^^^^^^^^
844+
845+
Sometimes, you want to modify a parameter in a lot of instances of a material.
846+
This takes a lot of work as all these instances need to be tracked and the
847+
uniform needs to be set for each of them.
848+
849+
Example use cases include:
850+
851+
1. **Providing player information to all relevant shaders.** You may want to let
852+
your shaders know where the player is. As an example, the grass and some
853+
bushes will bend when the player is close, simulating being pushed.
854+
2. **Modifying the world without actually modifying it.** Modern games have a lot
855+
of grass, yet you can do precise cuts to it, burn it, etc. How do they do it?
856+
Is every bit of grass a mesh and an object? Not really, games generally just
857+
use a texture aligned to the world (that often moves with you), with different
858+
colors meaning different things. In this case they can use texture channels to
859+
specify that the grass has been cut, burnt, etc. The vertex shader can make
860+
the vertices disappear, or change the color based on this global uniform
861+
texture.
862+
3. **Controlling the weather and environment.** Nowadays, games have realistic
863+
weather, with leaves and trees moving with the wind. Do they make animations
864+
for each piece of grass? Not really, you can save the wind strength and
865+
direction in a global uniform, then procedurally move the foliage with
866+
different speed and intensity. This can even affect particle system shaders,
867+
making fire and smoke propagate in the direction of the wind. Shooters often
868+
have what is called a turbulence texture, which is a texture that contains
869+
the local wind direction around the player. All relevant shaders can access
870+
it and it's what allows explosions to move trees and grass around.
871+
4. **Making regular materials interact with the environment.** This is often
872+
overlooked. We think materials are edited and that's it, but that's not
873+
always the case. Imagine it starts raining and you want your objects to
874+
become wet. You need to change the metallic and roughness factors. For
875+
floors, you want to draw droplets splashing. For walls, you want to draw the
876+
water pouring down. You could control this with regular uniforms, but it
877+
would be more time-consuming to set this on every material when it starts
878+
raining.
879+
5. **Providing team colors.** In team-based games, you can use global uniforms
880+
to provide "friendly" and "enemy" colors that can automatically be used
881+
everywhere relevant (player materials, map textures, special effects, GUI
882+
elements, ...). This can be used to let players choose team colors freely, for
883+
better accessibility. The "friendly" and "enemy" states themselves can be
884+
determined by using a :ref:`per-instance uniform
885+
<doc_shading_language_per_instance_uniforms>` that indicates the instance's
886+
current team.
887+
888+
Gqlobal uniforms can help you add a lot of detail to your game. In Godot, they
889+
work for every shader type, including the recently introduced sky shaders.
890+
891+
All these use cases are feasible thanks to global uniforms, which can be used in
892+
every shader type (``canvas_item``, ``spatial``, ``particles``, ``sky`` and
893+
``fog``).
894+
895+
To create a global uniform, open the **Project Settings** then go to the
896+
**Shader Globals** tab. Specify a name for the uniform (case-sensitive) and a
897+
type, then click **Add** in the top-right corner of the dialog. You can then
898+
edit the value assigned to the uniform by clicking the value in the list of
899+
uniforms:
900+
901+
.. figure:: img/shading_language_adding_global_uniforms.webp
902+
:align: center
903+
:alt: Adding a global uniform in the Shader Globals tab of the Project Settings
904+
905+
Adding a global uniform in the Shader Globals tab of the Project Settings
906+
907+
After creating a global uniform, you can use it in a shader as follows:
908+
909+
::
910+
911+
shader_type canvas_item;
912+
913+
global uniform vec4 my_color;
914+
915+
void fragment() {
916+
COLOR = my_color.rgb;
917+
}
918+
919+
Note that the global uniform *must* exist in the Project Settings at the time
920+
the shader is saved, or compilation will fail.
921+
922+
To change the value of a global uniform at run-time, use the
923+
:ref:`RenderingServer.global_shader_parameter_set <class_RenderingServer_method_global_shader_parameter_set>`
924+
method in a script:
925+
926+
::
927+
928+
RenderingServer.global_shader_parameter_set("my_color", Color(0.3, 0.6, 1.0))
929+
930+
Assigning global uniform values can be done as many times as desired without
931+
impacting performance, as setting data doesn't require synchronization between
932+
the CPU and GPU.
933+
934+
You can also add or remove global uniforms at run-time:
935+
936+
::
937+
938+
RenderingServer.global_shader_parameter_add("my_color", RenderingServer.GLOBAL_VAR_TYPE_COLOR, Color(0.3, 0.6, 1.0))
939+
RenderingServer.global_shader_parameter_remove("my_color")
940+
941+
Adding or removing global uniforms at run-time has a performance cost, although
942+
it's not as pronounced comparing to getting global uniform values from a script
943+
(see the warning below).
944+
945+
.. warning::
946+
947+
While you *can* query the value of a global uniform at run-time in a script
948+
using ``RenderingServer.global_shader_parameter_set("uniform_name")``, this
949+
has a large performance penalty as the CPU must wait for the GPU to be
950+
synchronized every time the value is queried.
951+
952+
Therefore, it's not recommended to read global shader uniform values
953+
continuously in a script. If you need to read values in a script after
954+
setting them, consider creating an :ref:`autoload <doc_singletons_autoload>`
955+
where you store the values you need to query at the same time you're setting
956+
them as global uniforms.
957+
958+
.. _doc_shading_language_per_instance_uniforms:
959+
960+
Per-instance uniforms
961+
^^^^^^^^^^^^^^^^^^^^^
962+
963+
.. note::
964+
965+
Per-instance uniforms are only available in ``spatial`` (3D) shaders.
966+
967+
Sometimes, you want to modify a parameter on each node using the material. As an
968+
example, in a forest full of trees, when you want each tree to have a slightly
969+
different color that is editable by hand. Without per-instance uniforms, this
970+
requires creating a unique material for each tree (each with a slightly
971+
different hue). This makes material management more complex, and also has a
972+
performance overhead due to the scene requiring more unique material instances.
973+
Vertex colors could also be used here, but they'd require creating unique copies
974+
of the mesh for each different color, which also has a performance overhead.
975+
976+
Per-instance uniforms are set on each GeometryInstance3D, rather than on each
977+
Material instance. Take this into account when working with meshes that have
978+
multiple materials assigned to them, or MultiMesh setups.
979+
980+
::
981+
982+
shader_type spatial;
983+
984+
// Provide a hint to edit as a color. Optionally, a default value can be provided.
985+
// If no default value is provided, the type's default is used (e.g. opaque black for colors).
986+
instance uniform vec4 my_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
987+
988+
void fragment() {
989+
ALBEDO = my_color.rgb;
990+
}
991+
992+
After saving the shader, you can change the per-instance uniform's value using
993+
the inspector:
994+
995+
.. figure:: img/shading_language_per_instance_uniforms_inspector.webp
996+
:align: center
997+
:alt: Setting a per-instance uniform's value in the GeometryInstance3D section of the inspector
998+
999+
Setting a per-instance uniform's value in the GeometryInstance3D section of the inspector
1000+
1001+
Per-instance uniform values can also be set at run-time using
1002+
`set_instance_shader_parameter<class_GeometryInstance3D_method_set_instance_shader_parameter>`
1003+
method on a node that inherits from :ref:`class_GeometryInstance3D`:
1004+
1005+
::
1006+
1007+
$MeshInstance3D.set_instance_shader_parameter("my_color", Color(0.3, 0.6, 1.0))
1008+
1009+
When using per-instance uniforms, there are some restrictions you should be aware of:
1010+
1011+
- **Per-instance uniforms do not support textures**, only regular scalar and
1012+
vector types. As a workaround, you can pass a texture array as a regular
1013+
uniform, then pass the index of the texture to be drawn using a per-instance
1014+
uniform.
1015+
- There is a practical maximum limit of 16 instance uniforms per shader.
1016+
- If your mesh uses multiple materials, the parameters for the first mesh
1017+
material found will "win" over the subsequent ones, unless they have the same
1018+
name, index *and* type. In this case, all parameters are affected correctly.
1019+
- If you run into the above situation, you can avoid clashes by manually
1020+
specifying the index (0-15) of the instance uniform by using the
1021+
``instance_index`` hint:
1022+
1023+
::
1024+
1025+
instance uniform vec4 my_color : source_color, instance_index(5);
1026+
8421027
Built-in variables
8431028
------------------
8441029

0 commit comments

Comments
 (0)