shader_preprocessor.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. .. _doc_shader_preprocessor:
  2. Shader preprocessor
  3. ===================
  4. Why use a shader preprocessor?
  5. ------------------------------
  6. In programming languages, a *preprocessor* allows changing the code before the
  7. compiler reads it. Unlike the compiler, the preprocessor does not care about
  8. whether the syntax of the preprocessed code is valid. The preprocessor always
  9. performs what the *directives* tell it to do. A directive is a statement
  10. starting with a hash symbol (``#``). It is not a *keyword* of the shader
  11. language (such as ``if`` or ``for``), but a special kind of token within the
  12. language.
  13. From Godot 4.0 onwards, you can use a shader preprocessor within text-based
  14. shaders. The syntax is similar to what most GLSL shader compilers support
  15. (which in turn is similar to the C/C++ preprocessor).
  16. .. note::
  17. The shader preprocessor is not available in :ref:`visual shaders <doc_visual_shaders>`.
  18. If you need to introduce preprocessor statements to a visual shader, you can
  19. convert it to a text-based shader using the **Convert to Shader** option in
  20. the VisualShader inspector resource dropdown. This conversion is a one-way
  21. operation; text shaders cannot be converted back to visual shaders.
  22. Directives
  23. ----------
  24. General syntax
  25. ^^^^^^^^^^^^^^
  26. - Preprocessor directives do not use brackets (``{}``), but can use parentheses.
  27. - Preprocessor directives **never** end with semicolons (with the exception of ``#define``,
  28. where this is allowed but potentially dangerous).
  29. - Preprocessor directives can span several lines by ending each line with a
  30. backslash (``\``). The first line break *not* featuring a backslash will end
  31. the preprocessor statement.
  32. #define
  33. ^^^^^^^
  34. **Syntax:** ``#define <identifier> [replacement_code]``.
  35. Defines the identifier after that directive as a macro, and replaces all
  36. successive occurrences of it with the replacement code given in the shader.
  37. Replacement is performed on a "whole words" basis, which means no replacement is
  38. performed if the string is part of another string (without any spaces separating
  39. it).
  40. Defines with replacements may also have one or more *arguments*, which can then
  41. be passed when referencing the define (similar to a function call).
  42. If the replacement code is not defined, the identifier may only be used with
  43. ``#ifdef`` or ``#ifndef`` directives.
  44. Compared to constants (``const CONSTANT = value;``), ``#define`` can be used
  45. anywhere within the shader (including in uniform hints).
  46. ``#define`` can also be used to insert arbitrary shader code at any location,
  47. while constants can't do that.
  48. .. FIXME: An upstream bug (https://github.com/pygments/pygments/pull/2350), fixed but not published yet.
  49. .. code-block:: none
  50. shader_type spatial;
  51. // Notice the lack of semicolon at the end of the line, as the replacement text
  52. // shouldn't insert a semicolon on its own.
  53. // If the directive ends with a semicolon, the semicolon is inserted in every usage
  54. // of the directive, even when this causes a syntax error.
  55. #define USE_MY_COLOR
  56. #define MY_COLOR vec3(1, 0, 0)
  57. // Replacement with arguments.
  58. // All arguments are required (no default values can be provided).
  59. #define BRIGHTEN_COLOR(r, g, b) vec3(r + 0.5, g + 0.5, b + 0.5)
  60. // Multiline replacement using backslashes for continuation:
  61. #define SAMPLE(param1, param2, param3, param4) long_function_call( \
  62. param1, \
  63. param2, \
  64. param3, \
  65. param4 \
  66. )
  67. void fragment() {
  68. #ifdef USE_MY_COLOR
  69. ALBEDO = MY_COLOR;
  70. #endif
  71. }
  72. Defining a ``#define`` for an identifier that is already defined results in an
  73. error. To prevent this, use ``#undef <identifier>``.
  74. #undef
  75. ^^^^^^
  76. **Syntax:** ``#undef identifier``
  77. The ``#undef`` directive may be used to cancel a previously defined ``#define`` directive:
  78. .. code-block:: glsl
  79. #define MY_COLOR vec3(1, 0, 0)
  80. vec3 get_red_color() {
  81. return MY_COLOR;
  82. }
  83. #undef MY_COLOR
  84. #define MY_COLOR vec3(0, 1, 0)
  85. vec3 get_green_color() {
  86. return MY_COLOR;
  87. }
  88. // Like in most preprocessors, undefining a define that was not previously defined is allowed
  89. // (and won't print any warning or error).
  90. #undef THIS_DOES_NOT_EXIST
  91. Without ``#undef`` in the above example, there would be a macro redefinition error.
  92. #if
  93. ^^^
  94. **Syntax:** ``#if <condition>``
  95. The ``#if`` directive checks whether the ``condition`` passed. If it evaluates
  96. to a non-zero value, the code block is included, otherwise it is skipped.
  97. To evaluate correctly, the condition must be an expression giving a simple
  98. floating-point, integer or boolean result. There may be multiple condition
  99. blocks connected by ``&&`` (AND) or ``||`` (OR) operators. It may be continued
  100. by a ``#else`` block, but **must** be ended with the ``#endif`` directive.
  101. .. code-block:: glsl
  102. #define VAR 3
  103. #define USE_LIGHT 0 // Evaluates to `false`.
  104. #define USE_COLOR 1 // Evaluates to `true`.
  105. #if VAR == 3 && (USE_LIGHT || USE_COLOR)
  106. // Condition is `true`. Include this portion in the final shader.
  107. #endif
  108. Using the ``defined()`` *preprocessor function*, you can check whether the
  109. passed identifier is defined a by ``#define`` placed above that directive. This
  110. is useful for creating multiple shader versions in the same file. It may be
  111. continued by a ``#else`` block, but must be ended with the ``#endif`` directive.
  112. The ``defined()`` function's result can be negated by using the ``!`` (boolean NOT)
  113. symbol in front of it. This can be used to check whether a define is *not* set.
  114. .. code-block:: glsl
  115. #define USE_LIGHT
  116. #define USE_COLOR
  117. // Correct syntax:
  118. #if defined(USE_LIGHT) || defined(USE_COLOR) || !defined(USE_REFRACTION)
  119. // Condition is `true`. Include this portion in the final shader.
  120. #endif
  121. Be careful, as ``defined()`` must only wrap a single identifier within parentheses, never more:
  122. .. code-block:: glsl
  123. // Incorrect syntax (parentheses are not placed where they should be):
  124. #if defined(USE_LIGHT || USE_COLOR || !USE_REFRACTION)
  125. // This will cause an error or not behave as expected.
  126. #endif
  127. .. tip::
  128. In the shader editor, preprocessor branches that evaluate to ``false`` (and
  129. are therefore excluded from the final compiled shader) will appear grayed
  130. out. This does not apply to run-time ``if`` statements.
  131. **#if preprocessor versus if statement: Performance caveats**
  132. The :ref:`shading language <doc_shading_language>` supports run-time ``if`` statements:
  133. .. code-block:: glsl
  134. uniform bool USE_LIGHT = true;
  135. if (USE_LIGHT) {
  136. // This part is included in the compiled shader, and always run.
  137. } else {
  138. // This part is included in the compiled shader, but never run.
  139. }
  140. If the uniform is never changed, this behaves identical to the following usage
  141. of the ``#if`` preprocessor statement:
  142. .. code-block:: glsl
  143. #define USE_LIGHT
  144. #if defined(USE_LIGHT)
  145. // This part is included in the compiled shader, and always run.
  146. #else
  147. // This part is *not* included in the compiled shader (and therefore never run).
  148. #endif
  149. However, the ``#if`` variant can be faster in certain scenarios. This is because
  150. all run-time branches in a shader are still compiled and variables within
  151. those branches may still take up register space, even if they are never run in
  152. practice.
  153. Modern GPUs are `quite effective <https://medium.com/@jasonbooth_86226/branching-on-a-gpu-18bfc83694f2>`__
  154. at performing "static" branching. "Static" branching refers to ``if`` statements where
  155. *all* pixels/vertices evaluate to the same result in a given shader invocation. However,
  156. high amounts of :abbr:`VGPRs (Vector General-Purpose Register)` (which can be caused by
  157. having too many branches) can still slow down shader execution significantly.
  158. #elif
  159. ^^^^^
  160. The ``#elif`` directive stands for "else if" and checks the condition passed if
  161. the above ``#if`` evaluated to ``false``. ``#elif`` can only be used within an
  162. ``#if`` block. It is possible to use several ``#elif`` statements after an ``#if`` statement.
  163. .. code-block:: glsl
  164. #define VAR 2
  165. #if VAR == 0
  166. // Not included.
  167. #elif VAR == 1
  168. // Not included.
  169. #elif VAR == 2
  170. // Condition is `true`. Include this portion in the final shader.
  171. #else
  172. // Not included.
  173. #endif
  174. Like with ``#if``, the ``defined()`` preprocessor function can be used:
  175. .. code-block:: glsl
  176. #define SHADOW_QUALITY_MEDIUM
  177. #if defined(SHADOW_QUALITY_HIGH)
  178. // High shadow quality.
  179. #elif defined(SHADOW_QUALITY_MEDIUM)
  180. // Medium shadow quality.
  181. #else
  182. // Low shadow quality.
  183. #endif
  184. #ifdef
  185. ^^^^^^
  186. **Syntax:** ``#ifdef <identifier>``
  187. This is a shorthand for ``#if defined(...)``. Checks whether the passed
  188. identifier is defined by ``#define`` placed above that directive. This is useful
  189. for creating multiple shader versions in the same file. It may be continued by a
  190. ``#else`` block, but must be ended with the ``#endif`` directive.
  191. .. code-block:: glsl
  192. #define USE_LIGHT
  193. #ifdef USE_LIGHT
  194. // USE_LIGHT is defined. Include this portion in the final shader.
  195. #endif
  196. The processor does *not* support ``#elifdef`` as a shortcut for ``#elif defined(...)``.
  197. Instead, use the following series of ``#ifdef`` and ``#else`` when you need more
  198. than two branches:
  199. .. code-block:: glsl
  200. #define SHADOW_QUALITY_MEDIUM
  201. #ifdef SHADOW_QUALITY_HIGH
  202. // High shadow quality.
  203. #else
  204. #ifdef SHADOW_QUALITY_MEDIUM
  205. // Medium shadow quality.
  206. #else
  207. // Low shadow quality.
  208. #endif // This ends `SHADOW_QUALITY_MEDIUM`'s branch.
  209. #endif // This ends `SHADOW_QUALITY_HIGH`'s branch.
  210. #ifndef
  211. ^^^^^^^
  212. **Syntax:** ``#ifndef <identifier>``
  213. This is a shorthand for ``#if !defined(...)``. Similar to ``#ifdef``, but checks
  214. whether the passed identifier is **not** defined by ``#define`` before that
  215. directive.
  216. This is the exact opposite of ``#ifdef``; it will always match in situations
  217. where ``#ifdef`` would never match, and vice versa.
  218. .. code-block:: glsl
  219. #define USE_LIGHT
  220. #ifndef USE_LIGHT
  221. // Evaluates to `false`. This portion won't be included in the final shader.
  222. #endif
  223. #ifndef USE_COLOR
  224. // Evaluates to `true`. This portion will be included in the final shader.
  225. #endif
  226. #else
  227. ^^^^^
  228. **Syntax:** ``#else``
  229. Defines the optional block which is included when the previously defined ``#if``,
  230. ``#elif``, ``#ifdef`` or ``#ifndef`` directive evaluates to false.
  231. .. code-block:: glsl
  232. shader_type spatial;
  233. #define MY_COLOR vec3(1.0, 0, 0)
  234. void fragment() {
  235. #ifdef MY_COLOR
  236. ALBEDO = MY_COLOR;
  237. #else
  238. ALBEDO = vec3(0, 0, 1.0);
  239. #endif
  240. }
  241. #endif
  242. ^^^^^^
  243. **Syntax:** ``#endif``
  244. Used as terminator for the ``#if``, ``#ifdef``, ``#ifndef`` or subsequent ``#else`` directives.
  245. #include
  246. ^^^^^^^^
  247. **Syntax:** ``#include "path"``
  248. The ``#include`` directive includes the *entire* content of a shader include
  249. file in a shader. ``"path"`` can be an absolute ``res://`` path or relative to
  250. the current shader file. Relative paths are only allowed in shaders that are
  251. saved to ``.gdshader`` or ``.gdshaderinc`` files, while absolute paths can be
  252. used in shaders that are built into a scene/resource file.
  253. This directive may be used in any place, but is recommended at
  254. the beginning of the shader file, after the ``shader_type`` to prevent possible
  255. errors. The shader include may be created by using a **File > Create Shader
  256. Include** menu option of the shader editor.
  257. ``#include`` is useful for creating libraries of helper functions (or macros)
  258. and reducing code duplication. When using ``#include``, be careful about naming
  259. collisions, as redefining functions or macros is not allowed.
  260. ``#include`` is subject to several restrictions:
  261. - Only shader include resources (ending with ``.gdshaderinc``) can be included.
  262. ``.gdshader`` files cannot be included by another shader, but a
  263. ``.gdshaderinc`` file can include other ``.gdshaderinc`` files.
  264. - Cyclic dependencies are **not** allowed and will result in an error.
  265. - To avoid infinite recursion, include depth is limited to 25 steps.
  266. Example shader include file:
  267. .. code-block:: glsl
  268. // fancy_color.gdshaderinc
  269. // While technically allowed, there is usually no `shader_type` declaration in include files.
  270. vec3 get_fancy_color() {
  271. return vec3(0.3, 0.6, 0.9);
  272. }
  273. Example base shader (using the include file we created above):
  274. .. code-block:: glsl
  275. // material.gdshader
  276. shader_type spatial;
  277. #include "res://fancy_color.gdshaderinc"
  278. void fragment() {
  279. // No error, as we've included a definition for `get_fancy_color()` via the shader include.
  280. COLOR = get_fancy_color();
  281. }
  282. #pragma
  283. ^^^^^^^
  284. **Syntax:** ``#pragma value``
  285. The ``#pragma`` directive provides additional information to the preprocessor or compiler.
  286. Currently, it may have only one value: ``disable_preprocessor``. If you don't need
  287. the preprocessor, use that directive to speed up shader compilation by excluding
  288. the preprocessor step.
  289. .. code-block:: glsl
  290. #pragma disable_preprocessor
  291. #if USE_LIGHT
  292. // This causes a shader compilation error, as the `#if USE_LIGHT` and `#endif`
  293. // are included as-is in the final shader code.
  294. #endif