Godot 使用的了一种非常接近GLSL ES 3.0的着色器语言,并且支持其绝大多数的数据类型和函数,尚未完全支持的部分也会逐渐增加进去。
如果你对GLSL熟悉的话,可以直接阅读 《Godot Shader Migration Guide》 以帮助你从标准GLSL过渡到Godot Shader。
数据类型支持绝大多数GLSL ES 3.0数据类型:
类型描述void空类型bool布尔型bvec22维布尔bvec33维布尔bvec44维布尔int有符号整型ivec22维整型ivec33维整型ivec44维整型uint无符号整型uvec22维无符号整型uvec33维无符号整型uvec44维无符号整型mat22维矩阵mat33维矩阵mat44维矩阵sampler2D2维采样 用于绑定2维材质,以float形式读取isampler2D2维整型采样 用于绑定2维材质,以int形式读取usampler2D2维无符号整型采样 用于绑定2维材质,以uint形式读取samplerCude3维采样 用于绑定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]
。
构造向量类型可以按照如下例子传参数:
// 传递所需数量的分量参数
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)
(注: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
关键字。它将意味着片元被弃用。
在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);
着色器提示的列表如下:
类型提示Descriptionvec4hint_color作为颜色使用int, floathint_range(min,max [,step] )作为范围使用sampler2Dhint_albedo作为慢反射颜色使用,默认为白色sampler2Dhint_black_albedo作为慢反射颜色使用,默认为黑色sampler2Dhint_normal作为法线贴图使用sampler2Dhint_white作为值使用,默认为白色sampler2Dhint_black作为值使用,默认为黑色sampler2Dhint_aniso作为流向图(flowmap)使用,默认向右GDScript使用不同的数据类型体系,所以当从GDScript传递变量到shader时,Godot会自动转换类型。下面是二者的类型对照表:
GDScript typeGLSL typeboolboolintintfloatfloatVector2vec2Vector3vec3Colorvec4Transformmat4Transform2Dmat4**注意:**在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 anglevec_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 )Signvec_int_type sign ( vec_int_type )Signvec_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 partvec_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
时,返回truevec_bool_type isinf ( vec_type )当标量或者向量分量为inf
时,返回truevec_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 –Nmat_type matrixCompMult ( mat_type, mat_type )Matrix Component Multiplicationmat_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 vectorsvec_bool_type greaterThan ( vec_scalar_type, vec_scalar_type )Bool vector cmp on > int/uint/float vectorsvec_bool_type lessThanEqual ( vec_scalar_type, vec_scalar_type )Bool vector cmp on = int/uint/float vectorsvec_bool_type equal ( vec_scalar_type, vec_scalar_type )Bool vector cmp on == int/uint/float vectorsvec_bool_type notEqual ( vec_scalar_type, vec_scalar_type )Bool vector cmp on != int/uint/float vectorsbool any ( vec_bool_type )有任何一个分量为true,则值为truebool all ( vec_bool_type )所有分量均为truebool not ( vec_bool_type )所有分量均为falseivec2 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 readvec4_type texture ( samplerCube s, vec3 uv [, float bias] )Perform a Cube texture readvec4_type textureProj ( sampler2D_type s, vec3 uv [, float bias] )Perform a texture read with projectionvec4_type textureProj ( sampler2D_type s, vec4 uv [, float bias] )Perform a texture read with projectionvec4_type textureLod ( sampler2D_type s, vec2 uv, float lod )Perform a 2D texture read at custom mipmapvec4_type textureLod ( samplerCube s, vec3 uv, float lod )Perform a Cube texture read at custom mipmapvec4_type textureProjLod ( sampler2D_type s, vec3 uv, float lod )Perform a texture read with projection/lodvec4_type textureProjLod ( sampler2D_type s, vec4 uv, float lod )Perform a texture read with projection/lodvec4_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的绝对导数之和