900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Godot着色器语言

Godot着色器语言

时间:2024-08-08 04:23:22

相关推荐

Godot着色器语言

引言

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

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

数据类型

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

类型转换(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);

矩阵可以由不同维度的矩阵创建,但是要注意两个原则:

如果用一个小维度矩阵创建一个大维度矩阵,那么剩余的部分,将由大维度矩阵的单位矩阵相对应值填充

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

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的分量“混写”构造一个vec3vec3 b = a.ggg; // 依然合法; 用vec4的单一分量“混写”构造一个vec3vec3 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)排序的运算符列表:

分支控制(Flow control)

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

// if and elseif (cond) {​} else {​}​// for loopsfor (int i = 0; i < 10; i++) {​}​// whilewhile (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;}

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

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

着色器提示的列表如下:

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

**注意:**在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所不支持的函数列表。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。