着色语言

前言

Godot 使用类似于 GLSL ES 3.0 的着色语言。支持大多数数据类型和函数,并且可能会随着时间的推移添加剩余的几种类型和函数。

如果你已经熟悉 GLSL,Godot 着色器迁移指南是一个帮助你从常规 GLSL 转换到 Godot 着色语言的资源。

数据类型

支持大多数GLSL ES 3.0数据类型:

类型

描述

void

Void数据类型, 只对不返回任何内容的函数有用.

bool

布尔数据类型,只能包含 truefalse

bvec2

布尔值的两个分量向量.

bvec3

布尔值的三分量向量.

bvec4

布尔值的四分量向量.

int

带正负的符号标量整数.

ivec2

有符号整数的双分量向量.

ivec3

有符号整数的三分量向量.

ivec4

有符号整数的四分量向量.

uint

无符号标量整数, 不能包含负数.

uvec2

无符号整数的两分量向量.

uvec3

无符号整数的三分量向量.

uvec4

无符号整数的四分量向量.

float

浮点标量.

vec2

浮点值的两分量向量.

vec3

浮点值的三分量向量.

vec4

浮点值的四分量向量.

mat2

2x2矩阵, 按主要顺序排列.

mat3

3x3矩阵, 在列的主要顺序.

mat4

4x4矩阵, 按主要顺序排列.

sampler2D

用于绑定2D纹理的采样器类型, 以浮点形式读取.

isampler2D

用于绑定2D纹理的采样器类型, 它们被读取为有符号整数.

usampler2D

用于绑定2D纹理的采样器类型, 读取为无符号整数.

sampler2DArray

用于绑定2D纹理数组的采样器类型, 以浮点数形式读取.

isampler2DArray

用于绑定2D纹理数组的采样器类型, 以有符号整数形式读取.

usampler2DArray

用于绑定2D纹理数组的采样器类型, 以无符号整数形式读取.

sampler3D

用于绑定3D纹理的采样器类型, 以浮点形式读取.

isampler3D

用于绑定3D纹理的采样器类型, 以有符号整数形式读取.

usampler3D

用于绑定3D纹理的采样器类型, 以无符号整数形式读取.

samplerCube

用于绑定立方体贴图的采样器类型,作为 float 读取。

samplerCubeArray

用于绑定立方体贴图数组的采样器类型,作为 float 读取。

注释

The shading language supports the same comment syntax as used in C# and C++:

  1. // Single-line comment.
  2. int a = 2; // Another single-line comment.
  3. /*
  4. Multi-line comment.
  5. The comment ends when the ending delimiter is found
  6. (here, it's on the line below).
  7. */
  8. int b = 3;

Additionally, you can use documentation comments that are displayed in the inspector when hovering a shader parameter. Documentation comments are currently only supported when placed immediately above a uniform declaration. These documentation comments only support the multiline comment syntax and must use two leading asterisks (/**) instead of just one (/*):

  1. /**
  2. * This is a documentation comment.
  3. * These lines will appear in the inspector when hovering the shader parameter
  4. * named "Something".
  5. * You can use [b]BBCode[/b] [i]formatting[/i] in the comment.
  6. */
  7. uniform int something = 1;

The asterisks on the follow-up lines are not required, but are recommended as per the 着色器风格指南. These asterisks are automatically stripped by the inspector, so they won’t appear in the tooltip.

类型转换

就像GLSL ES 3.0一样, 不允许在标量和相同大小但不同类型的向量之间进行隐式转换. 也不允许铸造不同大小的类型. 转换必须通过构造函数明确完成.

示例:

  1. float a = 2; // invalid
  2. float a = 2.0; // valid
  3. float a = float(2); // valid

默认整数常量是有符号的, 所以转换为无符号总是需要强制类型转换:

  1. int a = 2; // valid
  2. uint a = 2; // invalid
  3. uint a = uint(2); // valid

成员

向量类型的单个标量成员通过 “x” , “y” , “z” 和 “w” 成员访问. 另外, 使用 “r” , “g” , “b” 和 “a” 也可以, 而且是等效的. 使用最适合你的需求的方法.

对于矩阵,使用 m[column][row] 索引语法来访问每个标量,或者 m[idx] 按行索引来访问一个向量。例如,为了访问 mat4 中一个对象的 y 位置,使用 m[3][1]

构建

向量类型的构造必须始终通过:

  1. // The required amount of scalars
  2. vec4 a = vec4(0.0, 1.0, 2.0, 3.0);
  3. // Complementary vectors and/or scalars
  4. vec4 a = vec4(vec2(0.0, 1.0), vec2(2.0, 3.0));
  5. vec4 a = vec4(vec3(0.0, 1.0, 2.0), 3.0);
  6. // A single scalar for the whole vector
  7. vec4 a = vec4(0.0);

构建矩阵类型需要与矩阵相同维度的向量. 你也可以使用 matx(float) 语法构建一个对角矩阵. 相应地, mat4(1.0) 是一个单位矩阵.

  1. mat2 m2 = mat2(vec2(1.0, 0.0), vec2(0.0, 1.0));
  2. mat3 m3 = mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0));
  3. mat4 identity = mat4(1.0);

矩阵也可以由另一维度的矩阵建立。有两种规则:

1. If a larger matrix is constructed from a smaller matrix, the additional rows and columns are set to the values they would have in an identity matrix. 2. If a smaller matrix is constructed from a larger matrix, the top, left submatrix of the larger matrix is used.

  1. mat3 basis = mat3(MODEL_MATRIX);
  2. mat4 m4 = mat4(basis);
  3. mat2 m2 = mat2(m4);

混写Swizzling

只要结果是另一种向量类型(或标量), 就可以以任何顺序获得组件的组合. 这一点展示起来比解释起来容易:

  1. vec4 a = vec4(0.0, 1.0, 2.0, 3.0);
  2. vec3 b = a.rgb; // Creates a vec3 with vec4 components.
  3. vec3 b = a.ggg; // Also valid; creates a vec3 and fills it with a single vec4 component.
  4. vec3 b = a.bgr; // "b" will be vec3(2.0, 1.0, 0.0).
  5. vec3 b = a.xyz; // Also rgba, xyzw are equivalent.
  6. vec3 b = a.stp; // And stpq (for texture coordinates).
  7. float c = b.w; // Invalid, because "w" is not present in vec3 b.
  8. vec3 c = b.xrt; // Invalid, mixing different styles is forbidden.
  9. b.rrr = a.rgb; // Invalid, assignment with duplication.
  10. b.bgr = a.rgb; // Valid assignment. "b"'s "blue" component will be "a"'s "red" and vice versa.

精度

可以为数据类型添加精度修饰符;将它们用于 uniform、变量、参数、varying:

  1. lowp vec4 a = vec4(0.0, 1.0, 2.0, 3.0); // low precision, usually 8 bits per component mapped to 0-1
  2. mediump vec4 a = vec4(0.0, 1.0, 2.0, 3.0); // medium precision, usually 16 bits or half float
  3. highp vec4 a = vec4(0.0, 1.0, 2.0, 3.0); // high precision, uses full float or integer range (default)

对某些操作使用较低的精度可以加快相关的数学运算(以较低的精度为代价). 这在顶点处理器功能中很少需要(大部分时间都需要全精度), 但在片段处理器中经常需要.

一些架构(主要是移动架构)可以从中受益匪浅, 但也有缺点, 比如在不同精度之间转换的额外开销. 请参考目标架构的文档以获得更多信息. 在许多情况下, 移动驱动会导致不一致或意外的行为, 除非有必要, 最好避免指定精度.

数组

Arrays are containers for multiple variables of a similar type.

局部数组

局部数组在函数中声明. 它们可以使用所有允许的数据类型, 但采样器除外. 数组声明遵循C-style的语法. [const] + [precision] + typename + identifier + [array size].

  1. void fragment() {
  2. float arr[3];
  3. }

它们可以在开始时进行初始化, 例如:

  1. float float_arr[3] = float[3] (1.0, 0.5, 0.0); // first constructor
  2. int int_arr[3] = int[] (2, 1, 0); // second constructor
  3. vec2 vec2_arr[3] = { vec2(1.0, 1.0), vec2(0.5, 0.5), vec2(0.0, 0.0) }; // third constructor
  4. bool bool_arr[] = { true, true, false }; // fourth constructor - size is defined automatically from the element count

你可以在一个表达式中声明多个数组(即使大小不同):

  1. float a[3] = float[3] (1.0, 0.5, 0.0),
  2. b[2] = { 1.0, 0.5 },
  3. c[] = { 0.7 },
  4. d = 0.0,
  5. e[5];

要访问一个数组元素, 请使用索引语法:

  1. float arr[3];
  2. arr[0] = 1.0; // setter
  3. COLOR.r = arr[0]; // getter

数组有一个内置函数 .length()``(不要与内置的 ``length() 函数混淆). 它不接受任何参数, 作用是返回数组的大小.

  1. float arr[] = { 0.0, 1.0, 0.5, -1.0 };
  2. for (int i = 0; i < arr.length(); i++) {
  3. // ...
  4. }

备注

If you use an index either below 0 or greater than array size - the shader will crash and break rendering. To prevent this, use length(), if, or clamp() functions to ensure the index is between 0 and the array’s length. Always carefully test and check your code. If you pass a constant expression or a number, the editor will check its bounds to prevent this crash.

Global arrays

你可以在全局空间声明数组,例如:

  1. shader_type spatial;
  2. const lowp vec3 v[1] = lowp vec3[1] ( vec3(0, 0, 1) );
  3. void fragment() {
  4. ALBEDO = v[0];
  5. }

备注

全局数组必须声明为全局常量,否则就可以声明为与本地数组相同的全局常量。

常量

在变量声明前使用 const 关键字, 可以使该变量成为不可变的, 这意味着它不能被修改. 所有的基本类型, 除了采样器, 都可以被声明为常量. 访问和使用常量值的速度比使用uniform的速度略快. 常量必须在其声明时被初始化.

  1. const vec2 a = vec2(0.0, 1.0);
  2. vec2 b;
  3. a = b; // invalid
  4. b = a; // valid

常量不能被修改, 另外也不能有提示, 但可以在一个表达式中声明多个常量(如果它们具有相同的类型), 如

  1. const vec2 V1 = vec2(1, 1), V2 = vec2(2, 2);

与变量类似, 数组也可以用 const 来声明.

  1. const float arr[] = { 1.0, 0.5, 0.0 };
  2. arr[0] = 1.0; // invalid
  3. COLOR.r = arr[0]; // valid

常量可以在全局(在任何函数之外)或局部(在一个函数之内)进行声明. 当你想在整个着色器中访问一个不需要修改的值时, 全局常量很有用. 像uniform一样, 全局常量在所有着色器阶段之间共享, 但它们在着色器之外是不可访问的.

  1. shader_type spatial;
  2. const float PI = 3.14159265358979323846;

float ``类型常量的初始化必须在小数部分后使用. 符号或使用科学符号。还支持可选的 ``f 后缀。

  1. float a = 1.0;
  2. float b = 1.0f; // same, using suffix for clarity
  3. float c = 1e-1; // gives 0.1 by using the scientific notation

uint``(无符号 int)类型的常量必须有后缀 ``u,以区别于有符号整数。或者,也可以使用 ``uint(x)``内置转换函数来实现这一点。

  1. uint a = 1u;
  2. uint b = uint(1);

结构体

结构体是一种复合类型,可以对着色器代码进行更好的抽象。你可以像这样在全局作用域进行声明:

  1. struct PointLight {
  2. vec3 position;
  3. vec3 color;
  4. float intensity;
  5. };

声明后可以这样进行实例化和初始化:

  1. void fragment()
  2. {
  3. PointLight light;
  4. light.position = vec3(0.0);
  5. light.color = vec3(1.0, 0.0, 0.0);
  6. light.intensity = 0.5;
  7. }

或者使用结构体的构造函数达到同样的效果:

  1. PointLight light = PointLight(vec3(0.0), vec3(1.0, 0.0, 0.0), 0.5);

结构体中可以包含其他结构体或者数组,你还可以把它们作为全局常量实例化:

  1. shader_type spatial;
  2. ...
  3. struct Scene {
  4. PointLight lights[2];
  5. };
  6. const Scene scene = Scene(PointLight[2](PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), 1.0), PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), 1.0)));
  7. void fragment()
  8. {
  9. ALBEDO = scene.lights[0].color;
  10. }

你还可以把它们传递给函数:

  1. shader_type canvas_item;
  2. ...
  3. Scene construct_scene(PointLight light1, PointLight light2) {
  4. return Scene({light1, light2});
  5. }
  6. void fragment()
  7. {
  8. COLOR.rgb = construct_scene(PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), 1.0), PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 1.0), 1.0)).lights[0].color;
  9. }

运算符

Godot 着色器语言支持与GLSL ES 3.0相同的运算符集. 下面是它们的优先级列表:

优先级

运算符

1(最高)

括号分组

()

2

单目

+, -, !, ~

3

乘除法

/, *, %

4

加减法

+, -

5

移位

<<, >>

6

关系比较

<, >, <=, >=

7

相等比较

==, !=

8

按位与

&

9

按位异或

^

10

按位或

|

11

逻辑与

&&

12(最低)

逻辑或

||

流控制

Godot 着色器语言支持最常见的控制流类型:

  1. // `if` and `else`.
  2. if (cond) {
  3. } else {
  4. }
  5. // Ternary operator.
  6. // This is an expression that behaves like `if`/`else` and returns the value.
  7. // If `cond` evaluates to `true`, `result` will be `9`.
  8. // Otherwise, `result` will be `5`.
  9. int result = cond ? 9 : 5;
  10. // `switch`.
  11. switch (i) { // `i` should be a signed integer expression.
  12. case -1:
  13. break;
  14. case 0:
  15. return; // `break` or `return` to avoid running the next `case`.
  16. case 1: // Fallthrough (no `break` or `return`): will run the next `case`.
  17. case 2:
  18. break;
  19. //...
  20. default: // Only run if no `case` above matches. Optional.
  21. break;
  22. }
  23. // `for` loop. Best used when the number of elements to iterate on
  24. // is known in advance.
  25. for (int i = 0; i < 10; i++) {
  26. }
  27. // `while` loop. Best used when the number of elements to iterate on
  28. // is not known in advance.
  29. while (cond) {
  30. }
  31. // `do while`. Like `while`, but always runs at least once even if `cond`
  32. // never evaluates to `true`.
  33. do {
  34. } while (cond);

Keep in mind that in modern GPUs, an infinite loop can exist and can freeze your application (including editor). Godot can’t protect you from this, so be careful not to make this mistake!

此外,在将浮点数值与数字进行比较时,请确保将其与*范围*而非精确数字进行比较。

if (value == 0.3) 这样的比较可能不会求得``true``。浮点运算通常是近似的,可能违背预期。根据硬件的不同,它的表现也可能不同。

不要 写 “of the X”。

  1. float value = 0.1 + 0.2;
  2. // May not evaluate to `true`!
  3. if (value == 0.3) {
  4. // ...
  5. }

相反,应始终使用ε进行范围比较。浮点数越大(浮点数越不精确),ε值就应该越大。

  1. const float EPSILON = 0.0001;
  2. if (value >= 0.3 - EPSILON && value <= 0.3 + EPSILON) {
  3. // ...
  4. }

See floating-point-gui.de for more information.

丢弃

Fragment and light functions can use the discard keyword. If used, the fragment is discarded and nothing is written.

请注意,使用 discard 时会产生性能代价,因为它会阻止深度预传递在使用着色器的任何表面上生效。此外,被丢弃的像素仍需在顶点着色器中进行渲染,这意味着对所有像素都使用 discard 的着色器与不渲染任何对象相比,渲染成本仍然更高。

函数

可以在Godot着色器中定义函数. 它们使用以下语法:

  1. ret_type func_name(args) {
  2. return ret_type; // if returning a value
  3. }
  4. // a more specific example:
  5. int sum2(int a, int b) {
  6. return a + b;
  7. }

You can only use functions that have been defined above (higher in the editor) the function from which you are calling them. Redefining a function that has already been defined above (or is a built-in function name) will cause an error.

函数参数可以有特殊的限定符:

  • in : 表示参数仅用于读取(默认).

  • out : 表示该参数只用于写入.

  • inout : 表示该参数以引用传递.

  • const:表示参数是常量,不能更改,可与 in 限定符结合使用。

示例:

  1. void sum2(int a, int b, inout int result) {
  2. result = a + b;
  3. }

备注

与 GLSL 不同,Godot 的着色器语言不支持函数重载。这意味着一个函数不能用不同的参数类型或参数个数定义多次。作为一种变通方法,可以为接受不同数量或不同类型参数的函数使用不同的名称。

Varying

要从顶点处理器函数往片段(或者灯光)处理器函数里发送数据,可以使用 varying顶点处理器中的每一个图元顶点都是 varying 的,会为片段处理器中的每一个像素做插值。

  1. shader_type spatial;
  2. varying vec3 some_color;
  3. void vertex() {
  4. some_color = NORMAL; // Make the normal the color.
  5. }
  6. void fragment() {
  7. ALBEDO = some_color;
  8. }
  9. void light() {
  10. DIFFUSE_LIGHT = some_color * 100; // optionally
  11. }

Varying 也可以是数组:

  1. shader_type spatial;
  2. varying float var_arr[3];
  3. void vertex() {
  4. var_arr[0] = 1.0;
  5. var_arr[1] = 0.0;
  6. }
  7. void fragment() {
  8. ALBEDO = vec3(var_arr[0], var_arr[1], var_arr[2]); // red color
  9. }

也可以使用 varying 关键字将数据从片段处理器送往灯光处理器。在 fragment 函数中赋值,然后在 light 函数中使用即可。

  1. shader_type spatial;
  2. varying vec3 some_light;
  3. void fragment() {
  4. some_light = ALBEDO * 100.0; // Make a shining light.
  5. }
  6. void light() {
  7. DIFFUSE_LIGHT = some_light;
  8. }

注意,在自定义函数或灯光处理器中是不能为 varying 赋值的:

  1. shader_type spatial;
  2. varying float test;
  3. void foo() {
  4. test = 0.0; // Error.
  5. }
  6. void vertex() {
  7. test = 0.0;
  8. }
  9. void light() {
  10. test = 0.0; // Error too.
  11. }

加入这一限制的目的是为了防止在初始化前进行错误的使用。

插值限定符

在着色管线期间内插某些值. 你可以使用 插值限定符 修改这些插值的完成方式.

  1. shader_type spatial;
  2. varying flat vec3 our_color;
  3. void vertex() {
  4. our_color = COLOR.rgb;
  5. }
  6. void fragment() {
  7. ALBEDO = our_color;
  8. }

有两种可能的插值限定符:

限定符

描述

flat

该值未插值.

smooth

该值以透视正确的方式进行插值. 这是默认值.

Uniform

可以将值传递给着色器。这些值对整个着色器来说是全局的,被称为 uniform。当一个着色器后来被分配给一个材质时,uniform 将作为可编辑的参数出现在其中。uniform 不能从着色器内部写入。

  1. shader_type spatial;
  2. uniform float some_value;
  3. uniform vec3 colors[3];

你可以在编辑器中设置材质中的 uniform。或者你可以通过 GDScript 来设置它们:

  1. material.set_shader_parameter("some_value", some_value)
  2. material.set_shader_parameter("colors", [Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)])

备注

The first argument to set_shader_parameter is the name of the uniform in the shader. It must match exactly to the name of the uniform in the shader or else it will not be recognized.

除了 void 之外,任何 GLSL 类型都可以成为 uniform。此外,Godot 还提供了可选的着色器提示,以使编译器了解 uniform 是用来干什么的,以及编辑器应该让用户进行何种修改。

  1. shader_type spatial;
  2. uniform vec4 color : source_color;
  3. uniform float amount : hint_range(0, 1);
  4. uniform vec4 other_color : source_color = vec4(1.0); // Default values go after the hint.
  5. uniform sampler2D image : source_color;

It’s important to understand that textures that are supplied as color require hints for proper sRGB -> linear conversion (i.e. source_color), as Godot’s 3D engine renders in linear color space. If this is not done, the texture will appear washed out.

备注

如果启用了**渲染 > 视口 > HDR 2D**项目设置,2D 渲染器也会以线性色彩空间进行渲染,因此``source_color``也必须在``canvas_item``着色器中使用。如果禁用了 2D HDR,source_color 将继续在``canvas_item``着色器中正常工作,因此建议无论如何都使用它。

以下是完整的提示列表:

类型

提示

描述

vec3, vec4

source_color

用作颜色。

int、float

hint_range(min,max [,step] )

限制取值范围(最小值/最大值/步长)。

sampler2D

source_color

Used as albedo color.

sampler2D

hint_normal

用作法线贴图。

sampler2D

hint_default_white

As value or albedo color, default to opaque white.

sampler2D

hint_default_black

As value or albedo color, default to opaque black.

sampler2D

hint_default_transparent

As value or albedo color, default to transparent black.

sampler2D

hint_anisotropy

作为 FlowMap,默认为右。

sampler2D

hint_roughness[_r, _g, _b, _a, _normal, _gray]

Used for roughness limiter on import (attempts reducing specular aliasing). _normal is a normal map that guides the roughness limiter, with roughness increasing in areas that have high-frequency detail.

sampler2D

filter[_nearest, _linear][_mipmap][_anisotropic]

Enabled specified texture filtering.

sampler2D

repeat[_enable, _disable]

启用纹理重复。

sampler2D

hint_screen_texture

纹理是屏幕纹理。

sampler2D

hint_depth_texture

纹理是深度纹理。

sampler2D

hint_normal_roughness_texture

Texture is the normal roughness texture (only supported in Forward+).

GDScript 使用的变量类型与 GLSL 不同,所以当把变量从 GDScript 传递到着色器时,Godot 会自动转换类型。以下是相应类型的表格:

GLSL 类型

GDScript 类型

注意

bool

bool

bvec2

int

Bitwise packed int where bit 0 (LSB) corresponds to x.

For example, a bvec2 of (bx, by) could be created in the following way:

  1. bvec2_input: int = (int(bx)) | (int(by) << 1)

bvec3

int

Bitwise packed int where bit 0 (LSB) corresponds to x.

bvec4

int

Bitwise packed int where bit 0 (LSB) corresponds to x.

int

int

ivec2

Vector2i

ivec3

Vector3i

ivec4

Vector4i

uint

int

uvec2

Vector2i

uvec3

Vector3i

uvec4

Vector4i

float

float

vec2

Vector2

vec3

Vector3, Color

When Color is used, it will be interpreted as (r, g, b).

vec4

Vector4, Color, Rect2, Plane, Quaternion

When Color is used, it will be interpreted as (r, g, b, a).

When Rect2 is used, it will be interpreted as (position.x, position.y, size.x, size.y).

When Plane is used it will be interpreted as (normal.x, normal.y, normal.z, d).

mat2

Transform2D

mat3

Basis

mat4

Projection, Transform3D

When a Transform3D is used, the w Vector is set to the identity.

sampler2D

Texture2D

isampler2D

Texture2D

usampler2D

Texture2D

sampler2DArray

Texture2DArray

isampler2DArray

Texture2DArray

usampler2DArray

Texture2DArray

sampler3D

Texture3D

isampler3D

Texture3D

usampler3D

Texture3D

samplerCube

Cubemap

samplerCubeArray

CubemapArray

备注

当从 GDScript 中设置着色器 uniform 时要小心,如果类型不匹配,不会产生错误。你的着色器只会表现出未定义的行为。

Uniform 也可以分配默认值:

  1. shader_type spatial;
  2. uniform vec4 some_vector = vec4(0.0);
  3. uniform vec4 some_color : source_color = vec4(1.0);

Note that when adding a default value and a hint, the default value goes after the hint.

If you need to make multiple uniforms to be grouped in the specific category of an inspector, you can use a group_uniform keyword like:

  1. group_uniforms MyGroup;
  2. uniform sampler2D test;

You can close the group by using:

  1. group_uniforms;

The syntax also supports subgroups (it’s not mandatory to declare the base group before this):

  1. group_uniforms MyGroup.MySubgroup;

全局 Uniform

Sometimes, you want to modify a parameter in many different shaders at once. With a regular uniform, this takes a lot of work as all these shaders need to be tracked and the uniform needs to be set for each of them. Global uniforms allow you to create and update uniforms that will be available in all shaders, in every shader type (canvas_item, spatial, particles, sky and fog).

Global uniforms are especially useful for environmental effects that affect many objects in a scene, like having foliage bend when the player is nearby, or having objects move with the wind.

To create a global uniform, open the Project Settings then go to the Shader Globals tab. Specify a name for the uniform (case-sensitive) and a type, then click Add in the top-right corner of the dialog. You can then edit the value assigned to the uniform by clicking the value in the list of uniforms:

在“项目设置”的“着色器全局量”中添加全局 uniform

在“项目设置”的“着色器全局量”中添加全局 uniform

创建全局 uniform 之后,在着色器中的使用方法如下:

  1. shader_type canvas_item;
  2. global uniform vec4 my_color;
  3. void fragment() {
  4. COLOR = my_color.rgb;
  5. }

请注意,保存着色器的时候该全局 uniform 必须在“项目设置”中存在,否则编译就会失败。虽然可以在着色器代码中使用 global uniform vec4 my_color = ... 赋默认值,但是这个默认值会被忽略,因为全局 uniform 必须在“项目设置”中定义。

要在运行时修改全局 uniform 的值,请在脚本中使用 RenderingServer.global_shader_parameter_set 方法:

  1. RenderingServer.global_shader_parameter_set("my_color", Color(0.3, 0.6, 1.0))

全局 uniform 可以重复赋值,不会影响性能,因为设置数据不需要在 CPU 和 GPU 之间进行同步。

你还可以在运行时添加和移除全局 uniform:

  1. RenderingServer.global_shader_parameter_add("my_color", RenderingServer.GLOBAL_VAR_TYPE_COLOR, Color(0.3, 0.6, 1.0))
  2. RenderingServer.global_shader_parameter_remove("my_color")

在运行时添加和移除全局 uniform 存在一定的性能开销,但是不会像从脚本中获取全局 uniform 值的开销一样大(见下面的警告)。

警告

运行时,虽然可以在脚本中使用 RenderingServer.global_shader_parameter_get("uniform_name") 来查询全局 uniform 的取值,但是这样做有很大的性能开销,因为需要进行调用线程与渲染线程的同步。

因此,不建议在脚本中频繁读取全局着色器 uniform 的取值。如果你需要在设值之后用脚本读取,请考虑创建一个自动加载,在设置需要查询的全局 uniform 的同时保存对应的值。

单实例 uniform

备注

只有 spatial(3D)着色器中才可以使用单实例 uniform。

备注

Per-instance uniforms are not supported when using the Compatibility renderer.

Sometimes, you want to modify a parameter on each node using the material. As an example, in a forest full of trees, when you want each tree to have a slightly different color that is editable by hand. Without per-instance uniforms, this requires creating a unique material for each tree (each with a slightly different hue). This makes material management more complex, and also has a performance overhead due to the scene requiring more unique material instances. Vertex colors could also be used here, but they’d require creating unique copies of the mesh for each different color, which also has a performance overhead.

Per-instance uniforms are set on each GeometryInstance3D, rather than on each Material instance. Take this into account when working with meshes that have multiple materials assigned to them, or MultiMesh setups.

  1. shader_type spatial;
  2. // Provide a hint to edit as a color. Optionally, a default value can be provided.
  3. // If no default value is provided, the type's default is used (e.g. opaque black for colors).
  4. instance uniform vec4 my_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
  5. void fragment() {
  6. ALBEDO = my_color.rgb;
  7. }

After saving the shader, you can change the per-instance uniform’s value using the inspector:

Setting a per-instance uniform's value in the GeometryInstance3D section of the inspector

Setting a per-instance uniform’s value in the GeometryInstance3D section of the inspector

Per-instance uniform values can also be set at run-time using set_instance_shader_parameter method on a node that inherits from GeometryInstance3D:

  1. $MeshInstance3D.set_instance_shader_parameter("my_color", Color(0.3, 0.6, 1.0))

When using per-instance uniforms, there are some restrictions you should be aware of:

  • Per-instance uniforms do not support textures, only regular scalar and vector types. As a workaround, you can pass a texture array as a regular uniform, then pass the index of the texture to be drawn using a per-instance uniform.

  • There is a practical maximum limit of 16 instance uniforms per shader.

  • If your mesh uses multiple materials, the parameters for the first mesh material found will “win” over the subsequent ones, unless they have the same name, index and type. In this case, all parameters are affected correctly.

  • If you run into the above situation, you can avoid clashes by manually specifying the index (0-15) of the instance uniform by using the instance_index hint:

  1. instance uniform vec4 my_color : source_color, instance_index(5);

内置变量

A large number of built-in variables are available, like UV, COLOR and VERTEX. What variables are available depends on the type of shader (spatial, canvas_item or particle) and the function used (vertex, fragment or light). For a list of the built-in variables that are available, please see the corresponding pages:

内置函数

支持大量的内置函数, 符合GLSL ES 3.0. 当使用 vec_type (float), vec_int_type, vec_uint_type, vec_bool_type 命名法时, 它可以是标量或向量.

函数

描述/返回值

vec_type radians (vec_type degrees度)

将度数转换为弧度。

vec_type degrees ( vec_type radians弧度)

将弧度转换为度数。

vec_type sin (vec_type x)

正弦。

vec_type cos (vec_type x)

余弦。

vec_type tan (vec_type x)

正切。

vec_type asin (vec_type x)

反正弦。

vec_type acos (vec_type x)

反余弦。

vec_type atan (vec_type y_over_x)

反正切。

vec_type atan (vec_type y, vec_type x)

反正切。

vec_type sinh (vec_type x)

双曲正弦。

vec_type cosh (vec_type x)

双曲余弦。

vec_type tanh (vec_type x)

双曲正切。

vec_type asinh (vec_type x)

反双曲正弦。

vec_type acosh (vec_type x)

反双曲余弦。

vec_type atanh (vec_type x)

反双曲正切。

vec_type pow (vec_type x, vec_type y)

幂(x < 0 或 x = 0 且 y <= 0 时未定义)。

vec_type exp (vec_type x)

基数 e 的指数。

vec_type exp2 (vec_type x)

基数 2 的指数。

vec_type log (vec_type x)

自然对数。

vec_type log2 (vec_type x)

基数 2 的对数。

vec_type sqrt (vec_type x)

平方根。

vec_type inversesqrt (vec_type x)

反平方根。

vec_type abs (vec_type x)

ivec_type abs (ivec_type x)

Absolute value (returns positive value if negative).

vec_type sign ( vec_type )

ivec_type sign (ivec_type x)

Sign (returns 1.0 if positive, -1.0 if negative, 0.0 if zero).

vec_type floor (vec_type x)

向下舍入为整数。

vec_type round (vec_type x)

舍入到最接近的整数。

vec_type roundEven (vec_type x)

舍入到最接近的偶数。

vec_type trunc (vec_type x)

截断。

vec_type ceil (vec_type x)

向上舍入为整数。

vec_type fract (vec_type x)

Fractional (returns x - floor(x)).

vec_type mod (vec_type x, vec_type y)

vec_type mod (vec_type x, float y)

模(除法余数)。

vec_type modf (vec_type x, out vec_type i)

x 的小数部分,i 为整数部分。

vec_type min (vec_type a, vec_type b)

ab 之间的较小值。

vec_type max (vec_type a, vec_type b)

ab 之间的较大值。

vec_type clamp (vec_type x, vec_type min, vec_type max)

Clamp x between min and max (inclusive).

float mix (float a, float b, float c)

vec_type mix (vec_type a, vec_type b, float c)

vec_type mix (vec_type a, vec_type b, bvec_type c)

根据 cab 之间进行线性插值。

vec_type fma (vec_type a, vec_type b, vec_type c)

Performs a fused multiply-add operation: (a * b + c) (faster than doing it manually).

vec_type step (vec_type a, vec_type b)

b[i] < a[i] ? 0.0 : 1.0

vec_type step (float a, vec_type b)

b[i] < a ? 0.0 : 1.0

vec_type smoothstep (vec_type a, vec_type b, vec_type c)

vec_type smoothstep (float a, float b, vec_type c)

Hermite interpolate between a and b by c.

bvec_type isnan (vec_type x)

如果标量或向量分量是 NaN 则返回 true

bvec_type isinf (vec_type x)

如果标量或向量分量是 INF , 则返回 true

ivec_type floatBitsToInt (vec_type x)

Float->Int 位复制,无转换。

uvec_type floatBitsToUint (vec_type x)

Float->UInt 位复制,无转换。

vec_type intBitsToFloat (ivec_type x)

Int-> Float 位复制,无转换。

vec_type uintBitsToFloat (uvec_type x)

UInt->Float 位复制,无转换。

float length (vec_type x)

向量长度。

float distance (vec_type a, vec_type b)

向量间距,即 length(a - b)

float dot (vec_type a, vec_type b)

点积。

vec3 cross (vec3 a, vec3 b)

叉积。

vec_type normalize (vec_type x)

标准化为单位长度。

vec3 reflect (vec3 I, vec3 N)

反射。

vec3 refract (vec3 I, vec3 N, float eta)

折射。

vec_type faceforward (vec_type N, vec_type I, vec_type Nref)

如果 dot(Nref, I) <0, 则返回N, 否则返回-N。

mat_type matrixCompMult (mat_type x, mat_type y)

矩阵分量乘法。

mat_type outerProduct (vec_type column, vec_type row)

矩阵外积。

mat_type transpose (mat_type m)

转置矩阵。

float determinant (mat_type m)

矩阵行列式。

mat_type inverse (mat_type m)

逆矩阵。

bvec_type lessThan (vec_type x, vec_type y)

Bool vector 对比 < int/uint/float vectors。

bvec_type greaterThan (vec_type x, vec_type y)

Bool vector 对比 > int/uint/float vectors。

bvec_type lessThanEqual (vec_type x, vec_type y)

Bool vector 对比 <= int/uint/float vectors。

bvec_type greaterThanEqual (vec_type x, vec_type y)

Bool vector 对比 >= int/uint/float vectors。

bvec_type equal (vec_type x, vec_type y)

Bool vector 对比 == int/uint/float vectors。

bvec_type notEqual (vec_type x, vec_type y)

Bool vector 对比 != int/uint/float vectors。

bool any (bvec_type x)

true if any component is true, false otherwise.

bool all (bvec_type x)

true if all components are true, false otherwise.

bvec_type not (bvec_type x)

反转布尔向量。

ivec2 textureSize (gsampler2D s, int lod)

ivec3 textureSize (gsampler2DArray s, int lod)

ivec3 textureSize (gsampler3D s, int lod)

ivec2 textureSize (samplerCube s, int lod)

ivec2 textureSize (samplerCubeArray s, int lod)

获取纹理的大小。

The LOD defines which mipmap level is used. An LOD value of 0 will use the full resolution texture.

vec2 textureQueryLod (gsampler2D s, vec2 p)

vec3 textureQueryLod (gsampler2DArray s, vec2 p)

vec2 textureQueryLod (gsampler3D s, vec3 p)

vec2 textureQueryLod (samplerCube s, vec3 p)

Compute the level-of-detail that would be used to sample from a texture. The x component of the resulted value is the mipmap array that would be accessed. The y component is computed level-of-detail relative to the base level (regardless of the mipmap levels of the texture).

int textureQueryLevels (gsampler2D s)

int textureQueryLevels (gsampler2DArray s)

int textureQueryLevels (gsampler3D s)

int textureQueryLevels (samplerCube s)

获取cubemap纹理的大小。

If the texture is unassigned to a sampler, 1 is returned (Godot always internally assigns a texture even to an empty sampler).

gvec4_type texture (gsampler2D s, vec2 p [, float bias])

gvec4_type texture (gsampler2DArray s, vec3 p [, float bias])

gvec4_type texture (gsampler3D s, vec3 p [, float bias])

vec4 texture (samplerCube s, vec3 p [, float bias])

vec4 texture (samplerCubeArray s, vec4 p [, float bias])

执行纹理读取。

gvec4_type textureProj (gsampler2D s, vec3 p [, float bias])

gvec4_type textureProj (gsampler2D s, vec4 p [, float bias])

gvec4_type textureProj (gsampler3D s, vec4 p [, float bias])

执行带投影的纹理读取。

gvec4_type textureLod (gsampler2D s, vec2 p, float lod)

gvec4_type textureLod (gsampler2DArray s, vec3 p, float lod)

gvec4_type textureLod (gsampler3D s, vec3 p, float lod)

vec4 textureLod (samplerCube s, vec3 p, float lod)

vec4 textureLod (samplerCubeArray s, vec4 p, float lod)

在自定义 mipmap 上执行纹理读取。

The LOD defines which mipmap level is used. An LOD value of 0.0 will use the full resolution texture. If the texture lacks mipmaps, all LOD values will act like 0.0.

gvec4_type textureProjLod (gsampler2D s, vec3 p, float lod)

gvec4_type textureProjLod (gsampler2D s, vec4 p, float lod)

gvec4_type textureProjLod (gsampler3D s, vec4 p, float lod)

执行带投影/LOD的2D纹理读取。

The LOD defines which mipmap level is used. An LOD value of 0.0 will use the full resolution texture. If the texture lacks mipmaps, all LOD values will act like 0.0.

gvec4_type textureGrad (gsampler2D s, vec2 p, vec2 dPdx, vec2 dPdy)

gvec4_type textureGrad (gsampler2DArray s, vec3 p, vec2 dPdx, vec2 dPdy)

gvec4_type textureGrad (gsampler3D s, vec3 p, vec2 dPdx, vec2 dPdy)

vec4 textureGrad (samplerCube s, vec3 p, vec3 dPdx, vec3 dPdy)

vec4 textureGrad (samplerCubeArray s, vec3 p, vec3 dPdx, vec3 dPdy)

执行带显式渐变的纹理读取。

gvec4_type textureProjGrad (gsampler2D s, vec3 p, vec2 dPdx, vec2 dPdy)

gvec4_type textureProjGrad (gsampler2D s, vec4 p, vec2 dPdx, vec2 dPdy)

gvec4_type textureProjGrad (gsampler3D s, vec4 p, vec3 dPdx, vec3 dPdy)

Performs a texture read with projection/LOD and with explicit gradients.

gvec4_type texelFetch (gsampler2D s, ivec2 p, int lod)

gvec4_type texelFetch (gsampler2DArray s, ivec3 p, int lod)

gvec4_type texelFetch (gsampler3D s, ivec3 p, int lod)

使用整数坐标获取单个纹素。

The LOD defines which mipmap level is used. An LOD value of 0 will use the full resolution texture.

gvec4_type textureGather (gsampler2D s, vec2 p [, int comps])

gvec4_type textureGather (gsampler2DArray s, vec3 p [, int comps])

vec4 textureGather (samplerCube s, vec3 p [, int comps])

Gathers four texels from a texture. Use comps within range of 0..3 to define which component (x, y, z, w) is returned. If comps is not provided: 0 (or x-component) is used.

vec_type dFdx (vec_type p)

Derivative in x using local differencing. Internally, can use either dFdxCoarse or dFdxFine, but the decision for which to use is made by the GPU driver.

vec_type dFdxCoarse (vec_type p)

Calculates derivative with respect to x window coordinate using local differencing based on the value of p for the current fragment neighbour(s), and will possibly, but not necessarily, include the value for the current fragment. This function is not available on gl_compatibility profile.

vec_type dFdxFine (vec_type p)

Calculates derivative with respect to x window coordinate using local differencing based on the value of p for the current fragment and its immediate neighbour(s). This function is not available on gl_compatibility profile.

vec_type dFdy (vec_type p)

Derivative in y using local differencing. Internally, can use either dFdyCoarse or dFdyFine, but the decision for which to use is made by the GPU driver.

vec_type dFdyCoarse (vec_type p)

Calculates derivative with respect to y window coordinate using local differencing based on the value of p for the current fragment neighbour(s), and will possibly, but not necessarily, include the value for the current fragment. This function is not available on gl_compatibility profile.

vec_type dFdyFine (vec_type p)

Calculates derivative with respect to y window coordinate using local differencing based on the value of p for the current fragment and its immediate neighbour(s). This function is not available on gl_compatibility profile.

vec_type fwidth (vec_type p)

Sum of absolute derivative in x and y. This is the equivalent of using abs(dFdx(p)) + abs(dFdy(p)).

vec_type fwidthCoarse (vec_type p)

Sum of absolute derivative in x and y. This is the equivalent of using abs(dFdxCoarse(p)) + abs(dFdyCoarse(p)). This function is not available on gl_compatibility profile.

vec_type fwidthFine (vec_type p)

Sum of absolute derivative in x and y. This is the equivalent of using abs(dFdxFine(p)) + abs(dFdyFine(p)). This function is not available on gl_compatibility profile.

uint packHalf2x16 (vec2 v)

vec2 unpackHalf2x16 (uint v)

Convert two 32-bit floating-point numbers into 16-bit and pack them into a 32-bit unsigned integer and vice-versa.

uint packUnorm2x16 (vec2 v)

vec2 unpackUnorm2x16 (uint v)

Convert two 32-bit floating-point numbers (clamped within 0..1 range) into 16-bit and pack them into a 32-bit unsigned integer and vice-versa.

uint packSnorm2x16 (vec2 v)

vec2 unpackSnorm2x16 (uint v)

Convert two 32-bit floating-point numbers (clamped within -1..1 range) into 16-bit and pack them into a 32-bit unsigned integer and vice-versa.

uint packUnorm4x8 (vec4 v)

vec4 unpackUnorm4x8 (uint v)

Convert four 32-bit floating-point numbers (clamped within 0..1 range) into 8-bit and pack them into a 32-bit unsigned integer and vice-versa.

uint packSnorm4x8 (vec4 v)

vec4 unpackSnorm4x8 (uint v)

Convert four 32-bit floating-point numbers (clamped within -1..1 range) into 8-bit and pack them into a 32-bit unsigned integer and vice-versa.

ivec_type bitfieldExtract (ivec_type value, int offset, int bits)

uvec_type bitfieldExtract (uvec_type value, int offset, int bits)

Extracts a range of bits from an integer.

ivec_type bitfieldInsert (ivec_type base, ivec_type insert, int offset, int bits)

uvec_type bitfieldInsert (uvec_type base, uvec_type insert, int offset, int bits)

Insert a range of bits into an integer.

ivec_type bitfieldReverse (ivec_type value)

uvec_type bitfieldReverse (uvec_type value)

Reverse the order of bits in an integer.

ivec_type bitCount (ivec_type value)

uvec_type bitCount (uvec_type value)

Counts the number of 1 bits in an integer.

ivec_type findLSB (ivec_type value)

uvec_type findLSB (uvec_type value)

Find the index of the least significant bit set to 1 in an integer.

ivec_type findMSB (ivec_type value)

uvec_type findMSB (uvec_type value)

Find the index of the most significant bit set to 1 in an integer.

void imulExtended (ivec_type x, ivec_type y, out ivec_type msb, out ivec_type lsb)

void umulExtended (uvec_type x, uvec_type y, out uvec_type msb, out uvec_type lsb)

Multiplies two 32-bit numbers and produce a 64-bit result. x - the first number. y - the second number. msb - will contain the most significant bits. lsb - will contain the least significant bits.

uvec_type uaddCarry (uvec_type x, uvec_type y, out uvec_type carry)

Adds two unsigned integers and generates carry.

uvec_type usubBorrow (uvec_type x, uvec_type y, out uvec_type borrow)

Subtracts two unsigned integers and generates borrow.

vec_type ldexp (vec_type x, out ivec_type exp)

Assemble a floating-point number from a value and exponent.

If this product is too large to be represented in the floating-point type the result is undefined.

vec_type frexp (vec_type x, out ivec_type exp)

Splits a floating-point number(x) into significand (in the range of [0.5, 1.0]) and an integral exponent.

For x equals zero the significand and exponent are both zero. For x of infinity or NaN, the results are undefined.