Godot着色器语言

引言

Godot 使用的了一种非常接近GLSL ES 3.0的着色器语言,并且支持其绝大多数的数据类型和函数,尚未完全支持的部分也会逐渐增加进去。

如果你对GLSL熟悉的话,可以直接阅读 《Godot Shader Migration Guide》 以帮助你从标准GLSL过渡到Godot Shader。

数据类型

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

类型 描述
void 空类型
bool 布尔型
bvec2 2维布尔
bvec3 3维布尔
bvec4 4维布尔
int 有符号整型
ivec2 2维整型
ivec3 3维整型
ivec4 4维整型
uint 无符号整型
uvec2 2维无符号整型
uvec3 3维无符号整型
uvec4 4维无符号整型
mat2 2维矩阵
mat3 3维矩阵
mat4 4维矩阵
sampler2D 2维采样 用于绑定2维材质,以float形式读取
isampler2D 2维整型采样 用于绑定2维材质,以int形式读取
usampler2D 2维无符号整型采样 用于绑定2维材质,以uint形式读取
samplerCude 3维采样 用于绑定3维立方贴图,以float形式读取
类型转换(Casting)

和GLSL ES 3.0一样,无论是标量(Scalar)还是向量(Vector),即使维度(size)相同,但如果类型不同,也是无法进行隐式(implicit)类型转换。如果连维度都不同,则更加不能够隐式转换。所有的类型转换必须是显式(explicit)的且基于构造函数来实现。

例子

float a = 2; // 非法
float a = 2.0; // 合法
float a = float(2); // 合法

默认的整型是有符号的,因此要赋值给无符号整型也需要进行类型转换

int a = 2; // 合法
uint a = 2; // 非法
uint a = uint(2); // 合法
成员变量(Members)

向量中的分量值可以使用“x”, “y”, “z” 或者“w”来访问,同时也可已使用“r”, “g”, “b” 和“a”来访问,二者是等效的。哪一个更加直观方便就可以使用哪一个。

对于矩阵(matrices),可以使用m[row][colum]的形式访问其每一个元素,或者以m[idx]的形式使用行索引(row index)访问一个行向量。例如访问一个mat4(4x4的矩阵)中的位置y,我们可以这样做m[3][1]

构造(Constructing)

构造向量类型可以按照如下例子传参数:

// 传递所需数量的分量参数
vec4 a = vec4(0.0, 1.0, 2.0, 3.0);
// 传递互补的 向量 及/或 标量
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);
// 也可以为整个向量传一个值
vec4 a = vec4(0.0);

构造矩阵要求向量的维度和矩阵维精度(Precision)度相同,当然你也可以使用matx(float)的形式构造一个对角矩阵(diagonal matrix),例如mat4(1.0)代表一个4维单位矩阵(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. 如果用一个小维度矩阵创建一个大维度矩阵,那么剩余的部分,将由大维度矩阵的单位矩阵相对应值填充

  2. 如果用一个大维度矩阵创建一个小维度矩阵,那么将截取大维度矩阵左上角的子矩阵

mat3 basis = mat3(WORLD_MATRIX);
mat4 m4 = mat4(basis);
mat2 m2 = mat2(m4);
混写(Swizzling)

(注:Swizzling直译是旋转,在此处的意译取网上的一种翻译"混写")

混写是指可以获取向量分量任意顺序组合,只要(组合的)结果依然是向量或者标量,举个例子更好理解:

vec4 a = vec4(0.0, 1.0, 2.0, 3.0);
vec3 b = a.rgb; // 用vec4的分量“混写”构造一个vec3
vec3 b = a.ggg; // 依然合法; 用vec4的单一分量“混写”构造一个vec3
vec3 b = a.bgr; // 分量的顺序是无关紧要的
vec3 b = a.xyz; // 用xyzw依然等效
float c = b.w; // 非法, 因为作为vec3的b中不包含"w"分量.
精度(Precision)

可以对uniform, variable, argument 以及 varying等数据添加精度修改器(modifier):

lowp vec4 a = vec4(0.0, 1.0, 2.0, 3.0); // 低精度, 每分量8字节并映射到0-1区间
mediump vec4 a = vec4(0.0, 1.0, 2.0, 3.0); // 中等精度,每分量16字节或半长浮点精度
highp vec4 a = vec4(0.0, 1.0, 2.0, 3.0); // 高精度, 全长浮点精度或整型值域(默认)

对于某些运算以损失精度为代价,使用较低精度,可以换取一些数学运算方面的提速。注意:在顶点处理函数(vertex processor function)几乎不会这样做(此时一般都采用高精度),但是在片元处理器中,使用较低精度是很有效的。

记住,以移动设备为主的一些架构,在这个机制上收益匪浅,但也存在一些约束(主要是不同精度间的转换也存在一些计算量)。请阅读针对目标架构的相关文档获取更多信息。不过说实话,移动设备的驱动Bug很多,所以要避免麻烦的话,请使用简单的shader,而不要指定精度,除非你真的需要。

运算符(Operators)

Godot 着色器语言支持和GLSL ES 3.0一样的运算符集。下面是按照优先级(precedence)排序的运算符列表:

优先级 类目 运算符
1 (最高) 括号(parenthetical grouping) ()
2 一元运算符(unary) +, -, !, ~
3 乘法类(multiplicative) /, *, %
4 加法类(additive) +, -
5 按位移动(bit-wise shift) <<, >>
6 逻辑(relational) <, >, <=, >=`
7 相等(equality) ==, !=
8 按位与(bit-wise and) &
9 逻辑异或(bit-wise exclusive or) ^
10 按位或(bit-wise inclusive or) |
11 逻辑与(logical and) &&
12 (最低) 逻辑或(logical inclusive or) ||
分支控制(Flow control)

Godot着色器语言支持大多数常见的过程控制形式:

// if and else
if (cond) {
​
} else {
​
}
​
// for loops
for (int i = 0; i < 10; i++) {
​
}
​
// while
while (true) {
​
}

注意:在现代GPU中,死循环是可以存在的,并且它可能会冻结你的程序(包括编辑器)。Godot无法保护你远离死循环,所以请小心不要犯这种错误。

丢弃(Discarding)

在片元(fragment)和光处理函数中可以使用discard关键字。它将意味着片元被弃用。

函数(Functions)

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

ret_type func_name(args) {
 return ret_type; // if returning a value
}
​
// 来个更具体的例子:
​
int sum2(int a, int b) {
 return a + b;
}

注意:当一个函数B要调用函数A时,函数A一定在函数B之前。

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

in : 只读

out:只写

inout:引用型

例如:

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

从顶点处理器函数(vertex processor function)向片元处理器函数(fragment processor function)传递参数时,会用到变元。在顶点处理器中每一个初始顶点(primitive vertex)会被设置变元。在片元处理器中,变元的值是对每一个像素的插值()interpolated。

shader_type spatial;
​
varying vec3 some_color;
void vertex() {
 some_color = NORMAL; // Make the normal the color.
}
​
void fragment() {
 ALBEDO = some_color;
}
插值限定符(Interpolation qualifiers)

某些值会在着色器管线(shading pipeline)中被插值。你可以使用插值限定符来修正这些插值是如何进行的。

shader_type spatial;
​
varying flat vec3 our_color;
​
void vertex() {
 our_color = COLOR.rgb;
}
​
void fragment() {
 ALBEDO = our_color;
}

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

限定符 描述
flat 不插值
smooth 以透视修正(perspective-correct)的方式插值。 此值为默认值。
Uniform变量

(程序)向着色器传递值是可以实现的。这些值被称为uniform变量,它们对于整个着色器来说是全局的(global)。当一个着色器被指派给一个材质后,uniform变量会作为可编辑参数显示在材质的编辑器上。注意:uniform变量无法由内而外写入

shader_type spatial;
​
uniform float some_value;

你可以在编辑器中的材质栏中设置uniform变量,也可以通过GDScript

material.set_shader_param("some_value", some_value)

注意:set_shader_param的第一个参数是shader中uniform变量的变量名,它必须和shader中的uniform名字严格匹配,否则将不会被识别。

除void以外的任何GLSL类型都可以作为一个uniform变量。特别地,Godot提供了一种可选的着色器提示(shader hint),来使编译器理解这个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);

着色器提示的列表如下:

类型 提示 Description
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 作为流向图(flowmap)使用,默认向右

GDScript使用不同的数据类型体系,所以当从GDScript传递变量到shader时,Godot会自动转换类型。下面是二者的类型对照表:

GDScript type GLSL type
bool bool
int int
float float
Vector2 vec2
Vector3 vec3
Color vec4
Transform mat4
Transform2D mat4

**注意:**在GDScript设置uniform变量的时候,如果二者的类型不匹配,godot不会抛出任何异常。只是你的着色器会产生一些未预期的行为。

因为Godot的3D 引擎使用的是线性色彩空间(linear color space),所以有必要知道用来充当颜色的纹理(比如慢反射色),需要被设置为sRGB->linear。

Uniform变量也可以指定默认值:

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

译者注:以下部分内容涉及大量数学专业名词,能力有限不确保翻译准确,建议大家以英文版为准

内置函数(Built-in functions)

Godot提供大量的内置函数,这些函数的形式和GLSL ES 3.0一致。函数的参数及返回值可以是标量也可以是向量。

注意:在文档Differences between GLES2 and GLES3 doc 可以查到GLES2所不支持的函数列表。

函数 描述
vec_type radians ( vec_type ) 将角度转为弧度
vec_type degrees ( vec_type ) 将弧度转为角度
vec_type sin ( vec_type ) 正弦
vec_type cos ( vec_type ) 余弦
vec_type tan ( vec_type ) 正切
vec_type asin ( vec_type ) 反正弦
vec_type acos ( vec_type ) 反余
vec_type atan ( vec_type ) 反正切
vec_type atan ( vec_type x, vec_type y ) Arc-Tangent to convert vector to angle
vec_type sinh ( vec_type ) 双曲正弦
vec_type cosh ( vec_type ) 双曲余弦
vec_type tanh ( vec_type ) 双曲正切
vec_type asinh ( vec_type ) 反双曲正弦
vec_type acosh ( vec_type ) 反双曲余弦
vec_type atanh ( vec_type ) 反双曲正切
vec_type pow ( vec_type, vec_type ) 幂运算
vec_type exp ( vec_type ) e基指数
vec_type exp2 ( vec_type ) 2基指数
vec_type log ( vec_type ) e基(自然)对数
vec_type log2 ( vec_type ) 2基对数
vec_type sqrt ( vec_type ) 平方根
vec_type inversesqrt ( vec_type ) 平方根倒数
vec_type abs ( vec_type ) 绝对值
vec_int_type abs ( vec_int_type ) 绝对值
vec_type sign ( vec_type ) Sign
vec_int_type sign ( vec_int_type ) Sign
vec_type floor ( vec_type ) 向下取整
vec_type round ( vec_type ) 四舍五入
vec_type roundEven ( vec_type ) 四舍五入到临近偶数(Round nearest even)
vec_type trunc ( vec_type ) 截断
vec_type ceil ( vec_type ) 向上取整
vec_type fract ( vec_type ) 取小数部分
vec_type mod ( vec_type, vec_type ) 取余
vec_type mod ( vec_type, float ) 取余
vec_type modf ( vec_type x, out vec_type i ) Fractional of x, with i has integer part
vec_scalar_type min ( vec_scalar_type a, vec_scalar_type b ) 最小值
vec_scalar_type max ( vec_scalar_type a, vec_scalar_type b ) 最大值
vec_scalar_type clamp ( vec_scalar_type value, vec_scalar_type min, vec_scalar_type max ) 约束至最大值与最小值之间
vec_type mix ( vec_type a, vec_type b, float c ) 线性插值 (Scalar Coef.)
vec_type mix ( vec_type a, vec_type b, vec_type c ) 线性插值 (Vector Coef.)
vec_type mix ( vec_type a, vec_type b, bool c ) 线性插值 (Bool Selection)
vec_type mix ( vec_type a, vec_type b, vec_bool_type c ) 线性插值 (Bool-Vector Selection)
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 ) 艾米插值
vec_bool_type isnan ( vec_type ) 当标量或者向量分量为nan时,返回true
vec_bool_type isinf ( vec_type ) 当标量或者向量分量为inf时,返回true
vec_int_type floatBitsToInt ( vec_type ) 将Float按字节复制成Int, 不做类型转换
vec_uint_type floatBitsToUint ( vec_type ) 将Float按字节复制成UInt, 不做类型转换
vec_type intBitsToFloat ( vec_int_type ) 将Int按字节复制成Float, 不做类型转换
vec_type uintBitsToFloat ( vec_uint_type ) 将UInt按字节复制成Float, 不做类型转换
float length ( vec_type ) 向量长度
float distance ( vec_type, vec_type ) 向量间距离
float dot ( vec_type, vec_type ) 点积(Dot Product)
vec3 cross ( vec3, vec3 ) 叉积(Cross Product)
vec_type normalize ( vec_type ) 标准化成UInt长度
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 ) If dot(Nref, I) < 0, return N, otherwise –N
mat_type matrixCompMult ( mat_type, mat_type ) Matrix Component Multiplication
mat_type outerProduct ( vec_type, vec_type ) 矩阵外积
mat_type transpose ( mat_type ) 转置矩阵
float determinant ( mat_type ) 矩阵行列式
mat_type inverse ( mat_type ) 逆矩阵
vec_bool_type lessThan ( vec_scalar_type, vec_scalar_type ) Bool vector cmp on < int/uint/float vectors
vec_bool_type greaterThan ( vec_scalar_type, vec_scalar_type ) Bool vector cmp on > int/uint/float vectors
vec_bool_type lessThanEqual ( vec_scalar_type, vec_scalar_type ) Bool vector cmp on <= int/uint/float vectors
vec_bool_type greaterThanEqual ( vec_scalar_type, vec_scalar_type ) Bool vector cmp on >= int/uint/float vectors
vec_bool_type equal ( vec_scalar_type, vec_scalar_type ) Bool vector cmp on == int/uint/float vectors
vec_bool_type notEqual ( vec_scalar_type, vec_scalar_type ) Bool vector cmp on != int/uint/float vectors
bool any ( vec_bool_type ) 有任何一个分量为true,则值为true
bool all ( vec_bool_type ) 所有分量均为true
bool not ( vec_bool_type ) 所有分量均为false
ivec2 textureSize ( sampler2D_type s, int lod ) 获取纹理大小
ivec2 textureSize ( samplerCube s, int lod ) 获取立方映射(cubemap)的大小
vec4_type texture ( sampler2D_type s, vec2 uv [, float bias] ) Perform a 2D texture read
vec4_type texture ( samplerCube s, vec3 uv [, float bias] ) Perform a Cube texture read
vec4_type textureProj ( sampler2D_type s, vec3 uv [, float bias] ) Perform a texture read with projection
vec4_type textureProj ( sampler2D_type s, vec4 uv [, float bias] ) Perform a texture read with projection
vec4_type textureLod ( sampler2D_type s, vec2 uv, float lod ) Perform a 2D texture read at custom mipmap
vec4_type textureLod ( samplerCube s, vec3 uv, float lod ) Perform a Cube texture read at custom mipmap
vec4_type textureProjLod ( sampler2D_type s, vec3 uv, float lod ) Perform a texture read with projection/lod
vec4_type textureProjLod ( sampler2D_type s, vec4 uv, float lod ) Perform a texture read with projection/lod
vec4_type texelFetch ( sampler2D_type s, ivec2 uv, int lod ) 用整数坐标获取一个纹理影像元件(texel)
vec_type dFdx ( vec_type ) 用局部差分对x求导
vec_type dFdy ( vec_type ) 用局部差分对y求导
vec_type fwidth ( vec_type ) x和y的绝对导数之和

你可能感兴趣的:(Godot笔记,我的译文,#,Godot,实践)