Up to date

This page is up to date for Godot 4.3. If you still find outdated information, please open an issue.

着色语言

前言

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

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

数据类型

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

类型

描述

void

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

bool

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

bvec2

布尔的两分量向量。

bvec3

布尔的三分量向量。

bvec4

布尔的四分量向量。

int

32 bit signed scalar integer.

ivec2

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

ivec3

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

ivec4

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

uint

无符号标量整数;不能包含负数。

uvec2

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

uvec3

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

uvec4

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

float

32 bit floating-point scalar.

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

用于绑定被读取为浮点数的立方体贴图的采样器类型。

samplerCubeArray

Sampler type for binding Cubemap arrays, which are read as float. Only supported in Forward+ and Mobile, not Compatibility.

警告

Local variables are not initialized to a default value such as 0.0. If you use a variable without assigning it first, it will contain whatever value was already present at that memory location, and unpredictable visual glitches will appear. However, uniforms and varyings are initialized to a default value.

注释

着色语言支持与 C# 和 C++ 使用的相同的注释语法:

// Single-line comment.
int a = 2;  // Another single-line comment.

/*
Multi-line comment.
The comment ends when the ending delimiter is found
(here, it's on the line below).
*/
int b = 3;

此外,你还可以使用当将鼠标悬停在着色器参数上时显示在检查器中的文档注释。当前,仅当将文档注释放置在 uniform 声明正上方时,才支持该注释。这些文档注释仅支持多行注释语法,并且必须使用两个前导星号(/**),而不是仅使用一个(/*):

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

后续行上的星号不是必需的,但根据《着色器风格指南》建议使用。这些星号会被检查器自动删除,因此它们不会出现在工具提示中。

类型转换

与 GLSL ES 3.0 一样,不允许在大小相同但类型不同的标量和向量之间进行隐式转换。也不允许强制转换不同大小的类型。转换必须通过构造函数显式完成。

示例:

float a = 2; // invalid
float a = 2.0; // valid
float a = float(2); // valid

默认整数常量是有符号的,因此转换为无符号时始终需要强制类型转换:

int a = 2; // valid
uint a = 2; // invalid
uint a = uint(2); // valid

成员

向量类型的单个标量成员可通过“x”、“y”、“z”和“w”成员访问。或者,使用“r”、“g”、“b”和“a”也行且效果相同。使用最适合你需求的方式。

For matrices, use the m[column][row] indexing syntax to access each scalar, or m[column] to access a vector by column index. For example, for accessing the y-component of the translation from a mat4 transform matrix (4th column, 2nd line) you use m[3][1] or m[3].y.

构造

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

// The required amount of scalars
vec4 a = vec4(0.0, 1.0, 2.0, 3.0);
// Complementary vectors and/or scalars
vec4 a = vec4(vec2(0.0, 1.0), vec2(2.0, 3.0));
vec4 a = vec4(vec3(0.0, 1.0, 2.0), 3.0);
// A single scalar for the whole vector
vec4 a = vec4(0.0);

Construction of matrix types requires vectors of the same dimension as the matrix, interpreted as columns. You can also build a diagonal matrix using matx(float) syntax. Accordingly, mat4(1.0) is an identity matrix.

mat2 m2 = mat2(vec2(1.0, 0.0), vec2(0.0, 1.0));
mat3 m3 = mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0));
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.

mat3 basis = mat3(MODEL_MATRIX);
mat4 m4 = mat4(basis);
mat2 m2 = mat2(m4);

调换

只要结果是另一种向量类型(或标量),就可以按任意顺序获得组件的任意组合。百闻不如一见:

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

精度

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

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

对某些操作使用较低的精度可以加快所涉及的数学运算速度(但代价是精度较低)。这在顶点处理函数中鲜有需要(大多数情况下需要全精度),但在片段处理函数中通常很有用。

某些架构(主要是移动架构)可以从中受益匪浅,但也存在一些缺点,例如精度转换的额外开销。有关更多信息,请参阅目标架构的文档。在许多情况下,移动驱动程序会导致不一致或意外的行为,除非必要,否则最好避免指定精度。

数组

数组是用于多个相似类型的变量的容器。

局部数组

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

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

它们可以在开始时被初始化,像这样:

float float_arr[3] = float[3] (1.0, 0.5, 0.0); // first constructor

int int_arr[3] = int[] (2, 1, 0); // second constructor

vec2 vec2_arr[3] = { vec2(1.0, 1.0), vec2(0.5, 0.5), vec2(0.0, 0.0) }; // third constructor

bool bool_arr[] = { true, true, false }; // fourth constructor - size is defined automatically from the element count

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

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

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

float arr[3];

arr[0] = 1.0; // setter

COLOR.r = arr[0]; // getter

数组还有一个内置函数 .length()(不要与内置函数 length() 混淆)。它不接受任何参数,并将返回数组的大小。

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

备注

如果你使用的索引小于 0 或大于数组大小——着色器将崩溃并中断渲染。为防止这种情况,请使用 length()ifclamp() 函数来确保索引介于 0 和数组长度之间。务必仔细测试和检查你的代码。如果你传递一个常量表达式或数字,编辑器将检查其边界以防止这种崩溃。

全局数组

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

shader_type spatial;

const lowp vec3 v[1] = lowp vec3[1] ( vec3(0, 0, 1) );

void fragment() {
  ALBEDO = v[0];
}

备注

全局数组必须被声明为全局常量,否则可以将其声明为与局部数组相同。

常量

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

const vec2 a = vec2(0.0, 1.0);
vec2 b;

a = b; // invalid
b = a; // valid

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

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

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

const float arr[] = { 1.0, 0.5, 0.0 };

arr[0] = 1.0; // invalid

COLOR.r = arr[0]; // valid

常量既可以被全局声明(在任何函数之外),也可以被本地声明(在函数内部)。当你想要访问整个着色器中不需要修改的值时,全局常量非常有用。与 uniform 一样,全局常量在所有着色器阶段之间共享,但在着色器外部无法访问。

shader_type spatial;

const float GOLDEN_RATIO = 1.618033988749894;

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

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

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

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

结构体

结构体是一种复合类型,可以对着色器代码进行更好的抽象。你可以在全局范围内声明它们,如下所示:

struct PointLight {
    vec3 position;
    vec3 color;
    float intensity;
};

声明后,你可以像这样实例化和初始化它们:

void fragment()
{
    PointLight light;
    light.position = vec3(0.0);
    light.color = vec3(1.0, 0.0, 0.0);
    light.intensity = 0.5;
}

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

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

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

shader_type spatial;

...

struct Scene {
    PointLight lights[2];
};

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)));

void fragment()
{
    ALBEDO = scene.lights[0].color;
}

也可以把它们传递给函数:

shader_type canvas_item;

...

Scene construct_scene(PointLight light1, PointLight light2) {
    return Scene({light1, light2});
}

void fragment()
{
    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;
}

运算符

Godot 着色语言支持与 GLSL ES 3.0 相同的运算符集。以下是按优先顺序列出的运算符列表:

优先级

运算符

1(最高)

括号分组

()

2

一元

+, -, !, ~

3

乘除余

/, *, %

4

加减法

+, -

5

按位移位

<<, >>

6

关系比较

<, >, <=, >=

7

相等比较

==, !=

8

按位与

&

9

按位异或

^

10

按位或

|

11

逻辑与

&&

12(最低)

逻辑或

||

控制流

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

// `if` and `else`.
if (cond) {

} else {

}

// Ternary operator.
// This is an expression that behaves like `if`/`else` and returns the value.
// If `cond` evaluates to `true`, `result` will be `9`.
// Otherwise, `result` will be `5`.
int result = cond ? 9 : 5;

// `switch`.
switch (i) { // `i` should be a signed integer expression.
    case -1:
        break;
    case 0:
        return; // `break` or `return` to avoid running the next `case`.
    case 1: // Fallthrough (no `break` or `return`): will run the next `case`.
    case 2:
        break;
    //...
    default: // Only run if no `case` above matches. Optional.
        break;
}

// `for` loop. Best used when the number of elements to iterate on
// is known in advance.
for (int i = 0; i < 10; i++) {

}

// `while` loop. Best used when the number of elements to iterate on
// is not known in advance.
while (cond) {

}

// `do while`. Like `while`, but always runs at least once even if `cond`
// never evaluates to `true`.
do {

} while (cond);

请记住,在现代 GPU 中,无限循环可以存在,并可能冻结你的应用程序(包括编辑器)。Godot 无法保护你免受这种影响,因此请小心,不要犯这种错误!

此外,将浮点值与数字进行比较时,请确保将它们与一个范围而不是一个精确数字进行比较。

类似 if (value == 0.3) 的比较可能不会评估为 true。浮点数学通常是近似的,可能会与预期不符。它还可能根据硬件的不同而表现不同。

不要这样做。

float value = 0.1 + 0.2;

// May not evaluate to `true`!
if (value == 0.3) {
    // ...
}

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

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

有关更多信息,请参阅 floating-point-gui.de

丢弃

片段和灯光函数可以使用 discard 关键字。如果使用了,则该片段将被丢弃,并且不会写入任何内容。

请注意,使用 discard 会降低性能,因为它会阻止预深度阶段在使用着色器的任何表面上起作用。此外,被丢弃的像素仍需在顶点着色器中渲染,这意味着,与一开始就不渲染任何对象相比,在所有像素上使用 discard 的着色器的渲染成本仍然更高。

函数

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

ret_type func_name(args) {
    return ret_type; // if returning a value
}

// a more specific example:

int sum2(int a, int b) {
    return a + b;
}

你只能使用已在调用它们的函数上方(编辑器中较高位置)定义的函数。重新定义已在上方定义的函数(或使用内置函数名称)将导致错误。

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

  • in:表示该参数仅供读取(默认)。

  • out:表示该参数仅供写入。

  • inout:表示参数完全通过引用传递。

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

以下为示例:

void sum2(int a, int b, inout int result) {
    result = a + b;
}

备注

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

Varying

要从顶点处理器函数往片段(或者灯光)处理器函数里发送数据,可以使用 varying。它们在顶点处理器中为每个图元顶点设置,并且该值对片段处理器中的每个像素进行插值。

shader_type spatial;

varying vec3 some_color;

void vertex() {
    some_color = NORMAL; // Make the normal the color.
}

void fragment() {
    ALBEDO = some_color;
}

void light() {
    DIFFUSE_LIGHT = some_color * 100; // optionally
}

Varying 也可以是一个数组:

shader_type spatial;

varying float var_arr[3];

void vertex() {
    var_arr[0] = 1.0;
    var_arr[1] = 0.0;
}

void fragment() {
    ALBEDO = vec3(var_arr[0], var_arr[1], var_arr[2]); // red color
}

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

shader_type spatial;

varying vec3 some_light;

void fragment() {
    some_light = ALBEDO * 100.0; // Make a shining light.
}

void light() {
    DIFFUSE_LIGHT = some_light;
}

请注意,在自定义函数或灯光处理器函数中可能无法为 varying 赋值,例如:

shader_type spatial;

varying float test;

void foo() {
    test = 0.0; // Error.
}

void vertex() {
    test = 0.0;
}

void light() {
    test = 0.0; // Error too.
}

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

插值限定符

某些值在着色管道期间进行插值。你可以使用插值限定符来修改这些插值的方式。

shader_type spatial;

varying flat vec3 our_color;

void vertex() {
    our_color = COLOR.rgb;
}

void fragment() {
    ALBEDO = our_color;
}

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

限定符

描述

flat

该值未插值。

smooth

该值以透视校正方式进行插值。这是默认值。

Uniform

可以将值传递给着色器。这些值对于整个着色器而言都是全局的,被称为 uniform。当一个着色器稍后被分配给一个材质时,uniform 将在其中显示为可编辑参数。uniform 不能从着色器内部写入。

shader_type spatial;

uniform float some_value;

uniform vec3 colors[3];

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

material.set_shader_parameter("some_value", some_value)

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

备注

set_shader_parameter 的第一个参数是着色器中的 uniform 的名称。它必须与着色器中的 uniform 的名称完全匹配,否则将无法被识别。

备注

There is a limit to the total size of shader uniforms that you can use in a single shader. On most desktop platforms, this limit is 65536 bytes, or 4096 vec4 uniforms. On mobile platforms, the limit is typically 16384 bytes, or 1024 vec4 uniforms. Vector uniforms smaller than a vec4, such as vec2 or vec3, are padded to the size of a vec4. Scalar uniforms such as int or float are not padded, and bool is padded to the size of an int.

Arrays count as the total size of their contents. If you need a uniform array that is larger than this limit, consider packing the data into a texture instead, since the contents of a texture do not count towards this limit, only the size of the sampler uniform.

除了 void 之外的任何 GLSL 类型都可以是 uniform。此外,Godot 还提供了可选的着色器提示,以使编译器了解 uniform 的用途,以及编辑器应如何允许用户修改它。

shader_type spatial;

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

重要的是要理解,作为颜色提供的纹理需要提示以用于正确的 sRGB -> 线性转换(即 source_color),因为 Godot 的 3D 引擎将在线性颜色空间中渲染。如果不这样做,纹理将显得褪色。

备注

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

以下是完整的提示列表:

类型

提示

描述

vec3、vec4

source_color

用作颜色。

int、float

hint_range(min, max[, step])

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

sampler2D

source_color

用作反照颜色。

sampler2D

hint_normal

用作法线贴图。

sampler2D

hint_default_white

作为值或反照颜色,默认为不透明白色。

sampler2D

hint_default_black

作为值或反照颜色,默认为不透明黑色。

sampler2D

hint_default_transparent

作为值或反照颜色,默认为透明黑色。

sampler2D

hint_anisotropy

作为 FlowMap,默认为右。

sampler2D

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

用于导入时的粗糙度限制器(尝试减少镜面锯齿)。_normal是引导粗糙度限制器的法线贴图,在具有高频细节的区域中粗糙度会增加。

sampler2D

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

启用指定的纹理过滤。

sampler2D

repeat[_enable, _disable]

启用纹理重复。

sampler2D

hint_screen_texture

纹理是屏幕纹理。

sampler2D

hint_depth_texture

纹理是深度纹理。

sampler2D

hint_normal_roughness_texture

纹理是法线粗糙度纹理(仅在 Forward+ 中受支持)。

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

GLSL 类型

GDScript 类型

注意

bool

bool

bvec2

int

按位打包整数,其中位 0 (LSB) 对应 x。

例如,值为 (bx, by) 的 bvec2 可以按以下方式创建:

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

bvec3

int

按位打包整数,其中位 0 (LSB) 对应 x。

bvec4

int

按位打包整数,其中位 0 (LSB) 对应 x。

int

int

ivec2

Vector2i

ivec3

Vector3i

ivec4

Vector4i

uint

int

uvec2

Vector2i

uvec3

Vector3i

uvec4

Vector4i

float

float

vec2

Vector2

vec3

Vector3Color

使用 Color 时会将其解释为 (r, g, b)。

vec4

Vector4ColorRect2PlaneQuaternion

使用 Color 时会将其解释为 (r, g, b, a)。

使用 Rect2 时会将其解释为 (position.x, position.y, size.x, size.y)。

使用 Plane 时会将其解释为 (normal.x, normal.y, normal.z, d)。

mat2

Transform2D

mat3

Basis

mat4

ProjectionTransform3D

使用 Transform3D 时,向量 w 为单位向量。

sampler2D

Texture2D

isampler2D

Texture2D

usampler2D

Texture2D

sampler2DArray

Texture2DArray

isampler2DArray

Texture2DArray

usampler2DArray

Texture2DArray

sampler3D

Texture3D

isampler3D

Texture3D

usampler3D

Texture3D

samplerCube

Cubemap

See 更改导入类型 for instructions on importing cubemaps for use in Godot.

samplerCubeArray

CubemapArray

Only supported in Forward+ and Mobile, not Compatibility.

备注

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

警告

As with the last note, no error will be thrown if the typing does not match while setting a shader uniform, this unintuitively includes setting a (GDscript) 64 bit int/float into a Godot shader language int/float (32 bit). This may lead to unintentional consequences in cases where high precision is required.

Uniform 也可以分配默认值:

shader_type spatial;

uniform vec4 some_vector = vec4(0.0);
uniform vec4 some_color : source_color = vec4(1.0);

请注意,同时添加默认值和提示时,默认值应该写在提示的后面。

如果你需要在检查器中将多个 uniform 放进某个特定的分类里,就可以像这样使用 group_uniform 关键字:

group_uniforms MyGroup;
uniform sampler2D test;

结束分组的方法是:

group_uniforms;

这一语法还支持子分组(在此之前不需要声明基础分组):

group_uniforms MyGroup.MySubgroup;

全局 Uniform

有时你会想要统一修改很多不同着色器中的某个参数。使用普通的 uniform 就会很麻烦,因为你需要记录这些着色器,并且需要一个个地设 uniform。使用全局 uniform 就可以创建并更新所有着色器中均可以使用的 uniform,所有类型的着色器都适用(canvas_itemspatialparticlesskyfog)。

全局 uniform 适用于能够影响场景中大量对象的环境效果,例如玩家在附近时的植被弯曲效果、物体随风移动的效果等。

要创建全局 uniform,请打开项目设置,切换到着色器全局量选项卡。为 uniform 指定名称(区分大小写)和类型,然后点击对话框右上角的添加。点击 uniform 列表中的值即可编辑 uniform 的取值:

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

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

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

shader_type canvas_item;

global uniform vec4 my_color;

void fragment() {
    COLOR = my_color.rgb;
}

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

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

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

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

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

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

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

警告

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

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

单实例 uniform

备注

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

备注

使用兼容渲染器时不支持单实例 uniform。

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.

单实例 uniform 设置在每个 GeometryInstance3D 上,而不是在每个材质实例上。在处理指定了多种材质的网格或多重网格设置时,请考虑这一点。

shader_type spatial;

// Provide a hint to edit as a color. Optionally, a default value can be provided.
// If no default value is provided, the type's default is used (e.g. opaque black for colors).
instance uniform vec4 my_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);

void fragment() {
    ALBEDO = my_color.rgb;
}

在保存着色器后,你可以在检查器中更改单实例 uniform 的值:

在检查器中的 GeometryInstance3D 部分设置单实例 uniform 的值

在检查器中的 GeometryInstance3D 部分设置单实例 uniform 的值

在运行时也可以通过在继承自 GeometryInstance3D: 的节点上调用 set_instance_shader_parameter 方法修改单实例 uniform 的值:

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

在使用单实例 uniform 时,你应该注意一些限制:

  • 单实例 uniform 不支持纹理,仅可以是常规的标量和向量类型。作为解决方法,你可以传递一个纹理数组作为常规 uniform,之后传递一个单实例 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:

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

内置变量

有大量类似 UVCOLORVERTEX 的内置变量可用。具体有哪些变量可用取决于着色器的类型(spatialcanvas_itemparticle)和所在的函数(vertexfragmentlight)。可用的内置变量列表见对应的页面:

内置函数

支持大量内置函数,符合 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)

分数(返回``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)

根据 cab 之间进行埃尔米特插值。

bvec_type isnan (vec_type x)

Returns true if scalar or vector component is NaN.

bvec_type isinf (vec_type x)

Returns true if scalar or vector component is INF.

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)

Distance between vectors i.e 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)

获取纹理的大小。

LOD 将决定使用什么 mipmap 等级。LOD 值为 0 时将使用全分辨率材质。

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纹理的大小。

如果纹理没有分配给一个采样器,则返回``1``(Godot总是在内部分配一个纹理给一个空的采样器)。

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)

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

LOD 将决定使用什么 mipmap 等级。LOD 值为 0 时将使用全分辨率材质。

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])

在纹理中收集四个纹素。可以使用 comps 来定义要返回 (x, y, z, w) 中的哪个分量,取值范围为 0..3。未提供 comps 时使用 0(即 x 分量)。

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)

xy 的导数绝对值之和,等同于 abs(dFdx(p)) + abs(dFdy(p))

vec_type fwidthCoarse (vec_type p)

xy 的导数绝对值之和,等同于 abs(dFdxCoarse(p)) + abs(dFdyCoarse(p))。该函数在 gl_compatibility 配置下不可用。

vec_type fwidthFine (vec_type p)

xy 的导数绝对值之和,等同于 abs(dFdxFine(p)) + abs(dFdyFine(p))。该函数在 gl_compatibility 配置下不可用。

uint packHalf2x16 (vec2 v)

vec2 unpackHalf2x16 (uint v)

将两个 32 位浮点数转换为 16 位,并将它们打包进一个 32 位无符号整数中,反之亦然。

uint packUnorm2x16 (vec2 v)

vec2 unpackUnorm2x16 (uint v)

将两个 32 位浮点数(限制在 0..1 的范围内)转换为 16 位,并将它们打包进一个 32 位无符号整数中,反之亦然。

uint packSnorm2x16 (vec2 v)

vec2 unpackSnorm2x16 (uint v)

将两个 32 位浮点数(限制在 -1..1 的范围内)转换为 16 位,并将它们打包进一个 32 位无符号整数中,反之亦然。

uint packUnorm4x8 (vec4 v)

vec4 unpackUnorm4x8 (uint v)

将四个 32 位浮点数(限制在 0..1 的范围内)转换为 8 位,并将它们打包进一个 32 位无符号整数中,反之亦然。

uint packSnorm4x8 (vec4 v)

vec4 unpackSnorm4x8 (uint v)

将四个 32 位浮点数(限制在 -1..1 的范围内)转换为 8 位,并将它们打包进一个 32 位无符号整数中,反之亦然。

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

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

提取整数的某一范围中的比特位。

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)

将比特位插入到整数的某一范围中。

ivec_type bitfieldReverse (ivec_type value)

uvec_type bitfieldReverse (uvec_type value)

将整数的比特位顺序反转。

ivec_type bitCount (ivec_type value)

uvec_type bitCount (uvec_type value)

计算整数中为 1 的比特位的数量。

ivec_type findLSB (ivec_type value)

uvec_type findLSB (uvec_type value)

找出整数中为 1 的最低有效比特位的索引。

ivec_type findMSB (ivec_type value)

uvec_type findMSB (uvec_type value)

找出整数中为 1 的最高有效比特位的索引。

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)

将两个 32 位数相乘,得到 64 位结果。x 为第一个数。y 为第二个数。msb 中包含较高的有效比特位。lsb 中包含较低的有效比特位。

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

将两个无符号整数相加,能够产生进位。

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

将两个无符号整数相减,能够产生借位。

vec_type ldexp (vec_type x, out ivec_type exp)

根据值和指数构成浮点数。

如果该浮点数类型无法表示得到的积,则结果未定义。

vec_type frexp (vec_type x, out ivec_type exp)

将浮点数(x)拆分为尾数(范围为 [0.5, 1.0])和整数形式的指数。

如果 x 等于零,则尾数和指数均为零。如果 x 为无穷或 NaN,则结果未定义。