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形式读取 |
和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); // 合法
向量中的分量值可以使用“x”, “y”, “z” 或者“w”来访问,同时也可已使用“r”, “g”, “b” 和“a”来访问,二者是等效的。哪一个更加直观方便就可以使用哪一个。
对于矩阵(matrices),可以使用m[row][colum]
的形式访问其每一个元素,或者以m[idx]
的形式使用行索引(row index)访问一个行向量。例如访问一个mat4(4x4的矩阵)中的位置y,我们可以这样做m[3][1]
。
构造向量类型可以按照如下例子传参数:
// 传递所需数量的分量参数
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);
矩阵可以由不同维度的矩阵创建,但是要注意两个原则:
如果用一个小维度矩阵创建一个大维度矩阵,那么剩余的部分,将由大维度矩阵的单位矩阵相对应值填充
如果用一个大维度矩阵创建一个小维度矩阵,那么将截取大维度矩阵左上角的子矩阵
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; // 用vec4的分量“混写”构造一个vec3
vec3 b = a.ggg; // 依然合法; 用vec4的单一分量“混写”构造一个vec3
vec3 b = a.bgr; // 分量的顺序是无关紧要的
vec3 b = a.xyz; // 用xyzw依然等效
float c = b.w; // 非法, 因为作为vec3的b中不包含"w"分量.
可以对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,而不要指定精度,除非你真的需要。
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) | || |
Godot着色器语言支持大多数常见的过程控制形式:
// if and else
if (cond) {
} else {
}
// for loops
for (int i = 0; i < 10; i++) {
}
// while
while (true) {
}
注意:在现代GPU中,死循环是可以存在的,并且它可能会冻结你的程序(包括编辑器)。Godot无法保护你远离死循环,所以请小心不要犯这种错误。
在片元(fragment)和光处理函数中可以使用discard
关键字。它将意味着片元被弃用。
在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;
}
从顶点处理器函数(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;
}
某些值会在着色器管线(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变量,它们对于整个着色器来说是全局的(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);
译者注:以下部分内容涉及大量数学专业名词,能力有限不确保翻译准确,建议大家以英文版为准
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的绝对导数之和 |