Skip to content

Commit 0e369eb

Browse files
committed
Document global and per-instance uniforms in Shading language
1 parent 66679c7 commit 0e369eb

File tree

3 files changed

+148
-0
lines changed

3 files changed

+148
-0
lines changed

tutorials/shaders/shader_reference/shading_language.rst

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,154 @@ 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 many different shaders at once.
846+
With a regular uniform this takes a lot of work as all these shaders need to be
847+
tracked and the uniform needs to be set for each of them. Global uniforms allow
848+
you to create and update uniforms that will be available in all shaders.
849+
850+
Global uniforms are especially useful for environmental effects that affect many
851+
objects in a scene, like having foliage bend when the player is nearby, or having
852+
objects move with the wind.
853+
854+
All these use cases are feasible thanks to global uniforms, which can be used in
855+
every shader type (``canvas_item``, ``spatial``, ``particles``, ``sky`` and
856+
``fog``).
857+
858+
To create a global uniform, open the **Project Settings** then go to the
859+
**Shader Globals** tab. Specify a name for the uniform (case-sensitive) and a
860+
type, then click **Add** in the top-right corner of the dialog. You can then
861+
edit the value assigned to the uniform by clicking the value in the list of
862+
uniforms:
863+
864+
.. figure:: img/shading_language_adding_global_uniforms.webp
865+
:align: center
866+
:alt: Adding a global uniform in the Shader Globals tab of the Project Settings
867+
868+
Adding a global uniform in the Shader Globals tab of the Project Settings
869+
870+
After creating a global uniform, you can use it in a shader as follows:
871+
872+
::
873+
874+
shader_type canvas_item;
875+
876+
global uniform vec4 my_color;
877+
878+
void fragment() {
879+
COLOR = my_color.rgb;
880+
}
881+
882+
Note that the global uniform *must* exist in the Project Settings at the time
883+
the shader is saved, or compilation will fail.
884+
885+
To change the value of a global uniform at run-time, use the
886+
:ref:`RenderingServer.global_shader_parameter_set <class_RenderingServer_method_global_shader_parameter_set>`
887+
method in a script:
888+
889+
::
890+
891+
RenderingServer.global_shader_parameter_set("my_color", Color(0.3, 0.6, 1.0))
892+
893+
Assigning global uniform values can be done as many times as desired without
894+
impacting performance, as setting data doesn't require synchronization between
895+
the CPU and GPU.
896+
897+
You can also add or remove global uniforms at run-time:
898+
899+
::
900+
901+
RenderingServer.global_shader_parameter_add("my_color", RenderingServer.GLOBAL_VAR_TYPE_COLOR, Color(0.3, 0.6, 1.0))
902+
RenderingServer.global_shader_parameter_remove("my_color")
903+
904+
Adding or removing global uniforms at run-time has a performance cost, although
905+
it's not as pronounced compared to getting global uniform values from a script
906+
(see the warning below).
907+
908+
.. warning::
909+
910+
While you *can* query the value of a global uniform at run-time in a script
911+
using ``RenderingServer.global_shader_parameter_get("uniform_name")``, this
912+
has a large performance penalty as the rendering thread needs to synchronize
913+
with the calling thread.
914+
915+
Therefore, it's not recommended to read global shader uniform values
916+
continuously in a script. If you need to read values in a script after
917+
setting them, consider creating an :ref:`autoload <doc_singletons_autoload>`
918+
where you store the values you need to query at the same time you're setting
919+
them as global uniforms.
920+
921+
.. _doc_shading_language_per_instance_uniforms:
922+
923+
Per-instance uniforms
924+
^^^^^^^^^^^^^^^^^^^^^
925+
926+
.. note::
927+
928+
Per-instance uniforms are only available in ``spatial`` (3D) shaders.
929+
930+
Sometimes, you want to modify a parameter on each node using the material. As an
931+
example, in a forest full of trees, when you want each tree to have a slightly
932+
different color that is editable by hand. Without per-instance uniforms, this
933+
requires creating a unique material for each tree (each with a slightly
934+
different hue). This makes material management more complex, and also has a
935+
performance overhead due to the scene requiring more unique material instances.
936+
Vertex colors could also be used here, but they'd require creating unique copies
937+
of the mesh for each different color, which also has a performance overhead.
938+
939+
Per-instance uniforms are set on each GeometryInstance3D, rather than on each
940+
Material instance. Take this into account when working with meshes that have
941+
multiple materials assigned to them, or MultiMesh setups.
942+
943+
::
944+
945+
shader_type spatial;
946+
947+
// Provide a hint to edit as a color. Optionally, a default value can be provided.
948+
// If no default value is provided, the type's default is used (e.g. opaque black for colors).
949+
instance uniform vec4 my_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
950+
951+
void fragment() {
952+
ALBEDO = my_color.rgb;
953+
}
954+
955+
After saving the shader, you can change the per-instance uniform's value using
956+
the inspector:
957+
958+
.. figure:: img/shading_language_per_instance_uniforms_inspector.webp
959+
:align: center
960+
:alt: Setting a per-instance uniform's value in the GeometryInstance3D section of the inspector
961+
962+
Setting a per-instance uniform's value in the GeometryInstance3D section of the inspector
963+
964+
Per-instance uniform values can also be set at run-time using
965+
`set_instance_shader_parameter<class_GeometryInstance3D_method_set_instance_shader_parameter>`
966+
method on a node that inherits from :ref:`class_GeometryInstance3D`:
967+
968+
::
969+
970+
$MeshInstance3D.set_instance_shader_parameter("my_color", Color(0.3, 0.6, 1.0))
971+
972+
When using per-instance uniforms, there are some restrictions you should be aware of:
973+
974+
- **Per-instance uniforms do not support textures**, only regular scalar and
975+
vector types. As a workaround, you can pass a texture array as a regular
976+
uniform, then pass the index of the texture to be drawn using a per-instance
977+
uniform.
978+
- There is a practical maximum limit of 16 instance uniforms per shader.
979+
- If your mesh uses multiple materials, the parameters for the first mesh
980+
material found will "win" over the subsequent ones, unless they have the same
981+
name, index *and* type. In this case, all parameters are affected correctly.
982+
- If you run into the above situation, you can avoid clashes by manually
983+
specifying the index (0-15) of the instance uniform by using the
984+
``instance_index`` hint:
985+
986+
::
987+
988+
instance uniform vec4 my_color : source_color, instance_index(5);
989+
842990
Built-in variables
843991
------------------
844992

0 commit comments

Comments
 (0)