着色语言
简介
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()``、``if``或``clamp()``函数来确保索引在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);
内置函数
支持大量的内置函数,符合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 |
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) |
|
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) | 限制在 |
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) |
|
vec_type step (float a, vec_type b) |
|
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) | 如果标量或向量分量是 |
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) | 向量之间的距离,即 |
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) | 如果 |
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) | 任何组件都是 |
bool 全部 (bvec_type x) | 所有组件都是 |
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) | 使用局部微分法进行 |
vec_type dFdy (vec_type p) | 使用局部微分 |
vec_type fwidth (vec_type p) |
|