着色语言

简介

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

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

数据类型

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

类型

描述

void

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

bool

布尔数据类型, 只能包含 "true" 或 "false".

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

用于绑定Cubemaps的采样器类型, 读取为浮点数.

转换

就像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" 也可以, 而且是等效的. 使用最适合你的需求的方法.

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

建设

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

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

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

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

矩阵也可以由另一维的矩阵建立. 有两条规则. 如果一个较大的矩阵是由一个较小的矩阵构建的, 那么额外的行和列将被设置为它们在同一矩阵中的值. 如果一个较小的矩阵是由一个较大的矩阵构建的, 则使用较大矩阵的顶部和左矩阵.

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

Swizzling

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

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.

精确

可以为数据类型添加精度修饰符;将它们用于 uniforms, variables, arguments 和varyings:

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 (default)

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

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

数组

数组是存放多个相似类型变量的容器. 注意: 从godot3.2开始, 只实现了局部数组和可变数组.

局部数组

局部数组在函数中声明. 它们可以使用所有允许的数据类型, 但采样器除外. 数组声明遵循C-style的语法.``[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和数组的长度之间. 总是仔细测试和检查你的代码. 如果你传递了一个常量表达式或一个简单的数字, 编辑器会检查它的边界以防止这种崩溃.

常量

在变量声明前使用 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 PI = 3.14159265358979323846;

运算符

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

优先级

操作符

1 (最高)

括号分组

()

2

unary

+, -, !, ~

3

multiplicative

/, *, %

4

additive

+, -

5

逐位移位

<<, >>

6

相关的

<, >, <=, >=

7

平等

==, !=

8

按位与

&

9

按位异或

^

10

按位或

|

11

逻辑与

&&

12(最低)

逻辑或

||

流控制

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

// if and else
if (cond) {

} else {

}

// switch
switch(i) { // signed integer expression
    case -1:
        break;
    case 0:
        return; // break or return
    case 1: // pass-through
    case 2:
        break;
    //...
    default: // optional
        break;
}

// for loops
for (int i = 0; i < 10; i++) {

}

// while
while (true) {

}

// do while
do {

} while(true);

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

警告

当导出 GLES2 项目到 HTML5时, WebGL 1.0将被使用. WebGL 1.0不支持动态循环, 所以使用这些的着色器将不会工作.

丢弃

片段和灯光功能可以使用 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 : 表示该参数以引用传递.

示例:

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

Varyings

为了从顶点向片段处理器函数发送数据,*varyings* 被使用. 它们设置 vertex processor 中的每个原始顶点, 其数值则为片段处理器中的每个像素插值.

shader_type spatial;

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

void fragment() {
    ALBEDO = some_color;
}

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
}

插值限定符

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

shader_type spatial;

varying flat vec3 our_color;

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

void fragment() {
    ALBEDO = our_color;
}

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

限定符

描述

flat

该值未插值.

smooth

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

Uniforms

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

shader_type spatial;

uniform float some_value;

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

material.set_shader_param("some_value", some_value)

注解

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

除了 void 之外, 任何GLSL类型都可以成为uniform. 此外,Godot还提供了可选的着色器提示, 以使编译器了解uniform是用来干什么的.

shader_type spatial;

uniform vec4 color : hint_color;
uniform float amount : hint_range(0, 1);
uniform vec4 other_color : hint_color = vec4(1.0);

重要的是要明白, 以颜色形式提供的纹理需要适当的sRGB->线性转换的提示(即 hint_albedo), 因为Godot的3D引擎在线性颜色空间中渲染.

以下提示的完整列表:

类型

暗示

描述

vec4

hint_color

用作颜色

int, float

hint_range(min,max [,step] )

用作范围(最小/最大/步)

sampler2D

hint_albedo

用作反射颜色, 默认为白色

sampler2D

hint_black_albedo

用作反射颜色, 默认为黑色

sampler2D

hint_normal

用作法线贴图

sampler2D

hint_white

作为值, 默认为白色.

sampler2D

hint_black

作为值, 默认为黑色

sampler2D

hint_aniso

作为流程图, 默认为右.

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

GDScript类型

GLSL类型

bool

bool

int

int

float

float

Vector2

vec2

Vector3

vec3

Color

vec4

Transform

mat4

Transform2D

mat4

注解

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

Uniforms也可以分配默认值:

shader_type spatial;

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

Built-in variables

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 build-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 命名法时, 它可以是标量或向量.

注解

关于GLES2后端无法使用的功能列表, 请参见 GLES2和GLES3之间的差异文档 .

函数

描述

vec_type 弧度 (vec_type 度)

将度数转换为弧度

vec_type ( vec_type 弧度)

将弧度转换为度数

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)

Power (undefined if x < 0 or if x = 0 and 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)

绝对

vec_type sign ( vec_type )

符号

ivec_type sign (ivec_type x)

符号

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

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)

最小值

vec_type max (vec_type a, vec_type b)

最大值

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

限制在 min..max

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, vec_type c)

线性插值(向量系数)

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

线性插值(布尔向量选择)

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)

Hermite插值

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

Hermite插值

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 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 归一化 (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 转置 (mat_type m)

转置矩阵

float determinant (mat_type m)

矩阵行列式

mat_type 取反 (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 任意 (bvec_type x)

任何组件都是 true

bool 全部 (bvec_type x)

所有组件都是 true

bvec_type not (bvec_type x)

反转布尔向量

ivec2 textureSize (sampler2D_type s, int lod)

获取2D纹理的大小

ivec3 textureSize (sampler2DArray_type s, int lod)

获取2D纹理数组的大小

ivec3 textureSize (sampler3D s, int lod)

获取3D纹理的大小

ivec2 textureSize (samplerCube s, int lod)

获取cubemap纹理的大小

vec4_type texture (sampler2D_type s, vec2 uv [, float bias])

执行2D纹理读取

vec4_type texture (sampler2DArray_type s, vec3 uv [, float bias])

执行2D纹理数组读取

vec4_type texture (sampler3D_type s, vec3 uv [, float bias])

执行3D纹理读取

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

执行立方体贴图纹理读取

vec4_type textureProj (sampler2D_type s, vec3 uv [, float bias])

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

vec4_type textureProj (sampler2D_type s, vec4 uv [, float bias])

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

vec4_type textureProj (sampler3D_type s, vec4 uv [, float bias])

执行带投影的3D纹理读取

vec4_type textureLod (sampler2D_type s, vec2 uv, float lod)

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

vec4_type textureLod (sampler2DArray_type s, vec3 uv, float lod)

执行在自定义mipmap处2D纹理阵列读取

vec4_type textureLod (sampler3D_type s, vec3 uv, float lod)

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

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

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

vec4_type textureProjLod (sampler2D_type s, vec3 uv, float lod)

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

vec4_type textureProjLod (sampler2D_type s, vec4 uv, float lod)

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

vec4_type textureProjLod (sampler3D_type s, vec4 uv, float lod)

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

vec4_type texelFetch (sampler2D_type s, ivec2 uv, int lod)

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

vec4_type texelFetch (sampler2DArray_type s, ivec3 uv, int lod)

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

vec4_type texelFetch (sampler3D_type s, ivec3 uv, int lod)

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

vec_type dFdx (vec_type p)

使用局部微分法进行 x 的微分.

vec_type dFdy (vec_type p)

使用局部微分 y 的微分

vec_type fwidth (vec_type p)

xy 的绝对导数之和