着色语言
前言
Godot 使用类似于 GLSL ES 3.0 的着色语言。支持大多数数据类型和函数,并且可能会随着时间的推移添加剩余的几种类型和函数。
如果你已经熟悉 GLSL,Godot 着色器迁移指南是一个帮助你从常规 GLSL 转换到 Godot 着色语言的资源。
数据类型
支持大多数GLSL ES 3.0数据类型:
类型 | 描述 |
---|---|
void | Void数据类型, 只对不返回任何内容的函数有用. |
bool | 布尔数据类型,只能包含 |
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 | 用于绑定立方体贴图的采样器类型,作为 float 读取。 |
samplerCubeArray | 用于绑定立方体贴图数组的采样器类型,作为 float 读取。 |
类型转换
就像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[column][row]
索引语法来访问每个标量,或者 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);
Matrices can also be built from a matrix of another dimension. There are two rules:
1. If a larger matrix is constructed from a smaller matrix, the additional rows and columns are set to the values they would have in an identity matrix. 2. If a smaller matrix is constructed from a larger matrix, the top, left submatrix of the larger matrix is used.
mat3 basis = mat3(MODEL_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.
精度
可以为数据类型添加精度修饰符;将它们用于 uniform、变量、参数、varying:
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)
对某些操作使用较低的精度可以加快相关的数学运算(以较低的精度为代价). 这在顶点处理器功能中很少需要(大部分时间都需要全精度), 但在片段处理器中经常需要.
一些架构(主要是移动架构)可以从中受益匪浅, 但也有缺点, 比如在不同精度之间转换的额外开销. 请参考目标架构的文档以获得更多信息. 在许多情况下, 移动驱动会导致不一致或意外的行为, 除非有必要, 最好避免指定精度.
数组
Arrays are containers for multiple variables of a similar type.
局部数组
局部数组在函数中声明. 它们可以使用所有允许的数据类型, 但采样器除外. 数组声明遵循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++) {
// ...
}
备注
If you use an index either below 0 or greater than array size - the shader will crash and break rendering. To prevent this, use length()
, if
, or clamp()
functions to ensure the index is between 0 and the array’s length. Always carefully test and check your code. If you pass a constant expression or a number, the editor will check its bounds to prevent this crash.
Global arrays
You can declare arrays at global space like:
shader_type spatial;
const lowp vec3 v[1] = lowp vec3[1] ( vec3(0, 0, 1) );
void fragment() {
ALBEDO = v[0];
}
备注
Global arrays have to be declared as global constants, otherwise they can be declared the same as local arrays.
常量
在变量声明前使用 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;
Constants of the float
type must be initialized using .
notation after the decimal part or by using the scientific notation. The optional f
post-suffix is also supported.
float a = 1.0;
float b = 1.0f; // same, using suffix for clarity
float c = 1e-1; // gives 0.1 by using the scientific notation
Constants of the uint
(unsigned int) type must have a u
suffix to differentiate them from signed integers. Alternatively, this can be done by using the uint(x)
built-in conversion function.
uint a = 1u;
uint b = uint(1);
结构体
结构体是一种复合类型,可以对着色器代码进行更好的抽象。你可以像这样在全局作用域进行声明:
struct PointLight {
vec3 position;
vec3 color;
float intensity;
};
声明后可以这样进行实例化和初始化:
void fragment()
{
PointLight light;
light.position = vec3(0.0);
light.color = vec3(1.0, 0.0, 0.0);
light.intensity = 0.5;
}
或者使用结构体的构造函数达到同样的效果:
PointLight light = PointLight(vec3(0.0), vec3(1.0, 0.0, 0.0), 0.5);
结构体中可以包含其他结构体或者数组,你还可以把它们作为全局常量实例化:
shader_type spatial;
...
struct Scene {
PointLight lights[2];
};
const Scene scene = Scene(PointLight[2](PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), 1.0), PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), 1.0)));
void fragment()
{
ALBEDO = scene.lights[0].color;
}
你还可以把它们传递给函数:
shader_type canvas_item;
...
Scene construct_scene(PointLight light1, PointLight light2) {
return Scene({light1, light2});
}
void fragment()
{
COLOR.rgb = construct_scene(PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), 1.0), PointLight(vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 1.0), 1.0)).lights[0].color;
}
运算符
Godot 着色器语言支持与GLSL ES 3.0相同的操作符集. 下面是它们的优先级列表:
优先级 | 类 | 操作符 |
1(最高) | 括号分组 | () |
2 | 单目 | +, -, !, ~ |
3 | 乘除法 | /, *, % |
4 | 加减法 | +, - |
5 | 移位 | <<, >> |
6 | 关系比较 | <, >, <=, >= |
7 | 相等比较 | ==, != |
8 | 按位与 | & |
9 | 按位异或 | ^ |
10 | 按位或 | | |
11 | 逻辑与 | && |
12(最低) | 逻辑或 | || |
流控制
Godot 着色器语言支持最常见的控制流类型:
// `if` and `else`.
if (cond) {
} else {
}
// Ternary operator.
// This is an expression that behaves like `if`/`else` and returns the value.
// If `cond` evaluates to `true`, `result` will be `9`.
// Otherwise, `result` will be `5`.
int result = cond ? 9 : 5;
// `switch`.
switch (i) { // `i` should be a signed integer expression.
case -1:
break;
case 0:
return; // `break` or `return` to avoid running the next `case`.
case 1: // Fallthrough (no `break` or `return`): will run the next `case`.
case 2:
break;
//...
default: // Only run if no `case` above matches. Optional.
break;
}
// `for` loop. Best used when the number of elements to iterate on
// is known in advance.
for (int i = 0; i < 10; i++) {
}
// `while` loop. Best used when the number of elements to iterate on
// is not known in advance.
while (cond) {
}
// `do while`. Like `while`, but always runs at least once even if `cond`
// never evaluates to `true`.
do {
} while (cond);
Keep in mind that in modern GPUs, an infinite loop can exist and can freeze your application (including editor). Godot can’t protect you from this, so be careful not to make this mistake!
Also, when comparing floating-point values against a number, make sure to compare them against a range instead of an exact number.
A comparison like if (value == 0.3)
may not evaluate to true
. Floating-point math is often approximate and can defy expectations. It can also behave differently depending on the hardware.
不要 写 “of the X”。
float value = 0.1 + 0.2;
// May not evaluate to `true`!
if (value == 0.3) {
// ...
}
Instead, always perform a range comparison with an epsilon value. The larger the floating-point number (and the less precise the floating-point number), the larger the epsilon value should be.
const float EPSILON = 0.0001;
if (value >= 0.3 - EPSILON && value <= 0.3 + EPSILON) {
// ...
}
See floating-point-gui.de for more information.
丢弃
Fragment and light functions can use the discard
keyword. If used, the fragment is discarded and nothing is written.
Beware that discard
has a performance cost when used, as it will prevent the depth prepass from being effective on any surfaces using the shader. Also, a discarded pixel still needs to be rendered in the vertex shader, which means a shader that uses discard
on all of its pixels is still more expensive to render compared to not rendering any object in the first place.
函数
可以在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;
}
You can only use functions that have been defined above (higher in the editor) the function from which you are calling them. Redefining a function that has already been defined above (or is a built-in function name) will cause an error.
函数参数可以有特殊的限定符:
in : 表示参数仅用于读取(默认).
out : 表示该参数只用于写入.
inout : 表示该参数以引用传递.
const: Means the argument is a constant and cannot be changed, may be combined with in qualifier.
示例:
void sum2(int a, int b, inout int result) {
result = a + b;
}
备注
Unlike GLSL, Godot’s shader language does not support function overloading. This means that a function cannot be defined several times with different argument types or numbers of arguments. As a workaround, use different names for functions that accept a different number of arguments or arguments of different types.
Varying
要从顶点处理器函数往片段(或者灯光)处理器函数里发送数据,可以使用 varying。顶点处理器中的每一个图元顶点都是 varying 的,会为片段处理器中的每一个像素做插值。
shader_type spatial;
varying vec3 some_color;
void vertex() {
some_color = NORMAL; // Make the normal the color.
}
void fragment() {
ALBEDO = some_color;
}
void light() {
DIFFUSE_LIGHT = some_color * 100; // optionally
}
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
}
也可以使用 varying 关键字将数据从片段处理器送往灯光处理器。在 fragment 函数中赋值,然后在 light 函数中使用即可。
shader_type spatial;
varying vec3 some_light;
void fragment() {
some_light = ALBEDO * 100.0; // Make a shining light.
}
void light() {
DIFFUSE_LIGHT = some_light;
}
注意,在自定义函数或灯光处理器中是不能为 varying 赋值的:
shader_type spatial;
varying float test;
void foo() {
test = 0.0; // Error.
}
void vertex() {
test = 0.0;
}
void light() {
test = 0.0; // Error too.
}
加入这一限制的目的是为了防止在初始化前进行错误的使用。
插值限定符
在着色管线期间内插某些值. 你可以使用 插值限定符 修改这些插值的完成方式.
shader_type spatial;
varying flat vec3 our_color;
void vertex() {
our_color = COLOR.rgb;
}
void fragment() {
ALBEDO = our_color;
}
有两种可能的插值限定符:
限定符 | 描述 |
---|---|
flat | 该值未插值. |
smooth | 该值以透视正确的方式进行插值. 这是默认值. |
Uniform
可以将值传递给着色器。这些值对整个着色器来说是全局的,被称为 uniform。当一个着色器后来被分配给一个材质时,uniform 将作为可编辑的参数出现在其中。uniform 不能从着色器内部写入。
shader_type spatial;
uniform float some_value;
uniform vec3 colors[3];
你可以在编辑器中设置材质中的 uniform。或者你可以通过 GDScript 来设置它们:
material.set_shader_parameter("some_value", some_value)
material.set_shader_parameter("colors", [Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)])
备注
The first argument to set_shader_parameter
is the name of the uniform in the shader. It must match exactly to the name of the uniform in the shader or else it will not be recognized.
除了 void 之外,任何 GLSL 类型都可以成为 uniform。此外,Godot 还提供了可选的着色器提示,以使编译器了解 uniform 是用来干什么的,以及编辑器应该让用户进行何种修改。
shader_type spatial;
uniform vec4 color : source_color;
uniform float amount : hint_range(0, 1);
uniform vec4 other_color : source_color = vec4(1.0); // Default values go after the hint.
uniform sampler2D image : source_color;
It’s important to understand that textures that are supplied as color require hints for proper sRGB -> linear conversion (i.e. source_color
), as Godot’s 3D engine renders in linear color space. If this is not done, the texture will appear washed out.
备注
The 2D renderer also renders in linear color space if the Rendering > Viewport > HDR 2D project setting is enabled, so source_color
must also be used in canvas_item
shaders. If 2D HDR is disabled, source_color
will keep working correctly in canvas_item
shaders, so it’s recommend to use it either way.
以下是完整的提示列表:
类型 | 提示 | 描述 |
---|---|---|
vec3, vec4 | source_color | 用作颜色。 |
int、float | hint_range(min,max [,step] ) | 限制取值范围(最小值/最大值/步长)。 |
sampler2D | source_color | Used as albedo color. |
sampler2D | hint_normal | 用作法线贴图。 |
sampler2D | hint_default_white | As value or albedo color, default to opaque white. |
sampler2D | hint_default_black | As value or albedo color, default to opaque black. |
sampler2D | hint_default_transparent | As value or albedo color, default to transparent black. |
sampler2D | hint_anisotropy | 作为 FlowMap,默认为右。 |
sampler2D | hint_roughness[_r, _g, _b, _a, _normal, _gray] | Used for roughness limiter on import (attempts reducing specular aliasing). |
sampler2D | filter[_nearest, _linear][_mipmap][_anisotropic] | Enabled specified texture filtering. |
sampler2D | repeat[_enable, _disable] | 启用纹理重复。 |
sampler2D | hint_screen_texture | 纹理是屏幕纹理。 |
sampler2D | hint_depth_texture | 纹理是深度纹理。 |
sampler2D | hint_normal_roughness_texture | Texture is the normal roughness texture (only supported in Forward+). |
GDScript 使用的变量类型与 GLSL 不同,所以当把变量从 GDScript 传递到着色器时,Godot 会自动转换类型。以下是相应类型的表格:
GLSL 类型 | GDScript 类型 | 注意 |
---|---|---|
bool | bool | |
bvec2 | int | Bitwise packed int where bit 0 (LSB) corresponds to x. For example, a bvec2 of (bx, by) could be created in the following way:
|
bvec3 | int | Bitwise packed int where bit 0 (LSB) corresponds to x. |
bvec4 | int | Bitwise packed int where bit 0 (LSB) corresponds to x. |
int | int | |
ivec2 | Vector2i | |
ivec3 | Vector3i | |
ivec4 | Vector4i | |
uint | int | |
uvec2 | Vector2i | |
uvec3 | Vector3i | |
uvec4 | Vector4i | |
float | float | |
vec2 | Vector2 | |
vec3 | Vector3, Color | When Color is used, it will be interpreted as (r, g, b). |
vec4 | Vector4, Color, Rect2, Plane, Quaternion | When Color is used, it will be interpreted as (r, g, b, a). When Rect2 is used, it will be interpreted as (position.x, position.y, size.x, size.y). When Plane is used it will be interpreted as (normal.x, normal.y, normal.z, d). |
mat2 | Transform2D | |
mat3 | Basis | |
mat4 mat4 | Projection, Transform3D | When a Transform3D is used, the w Vector is set to the identity. |
sampler2D | Texture2D | |
isampler2D | Texture2D | |
usampler2D | Texture2D | |
sampler2DArray | Texture2DArray | |
isampler2DArray | Texture2DArray | |
usampler2DArray | Texture2DArray | |
sampler3D | Texture3D | |
isampler3D | Texture3D | |
usampler3D | Texture3D | |
samplerCube | Cubemap | |
samplerCubeArray | CubemapArray |
备注
当从 GDScript 中设置着色器 uniform 时要小心,如果类型不匹配,不会产生错误。你的着色器只会表现出未定义的行为。
Uniform 也可以分配默认值:
shader_type spatial;
uniform vec4 some_vector = vec4(0.0);
uniform vec4 some_color : source_color = vec4(1.0);
Note that when adding a default value and a hint, the default value goes after the hint.
If you need to make multiple uniforms to be grouped in the specific category of an inspector, you can use a group_uniform keyword like:
group_uniforms MyGroup;
uniform sampler2D test;
You can close the group by using:
group_uniforms;
The syntax also supports subgroups (it’s not mandatory to declare the base group before this):
group_uniforms MyGroup.MySubgroup;
Global uniforms
Sometimes, you want to modify a parameter in many different shaders at once. With a regular uniform, this takes a lot of work as all these shaders need to be tracked and the uniform needs to be set for each of them. Global uniforms allow you to create and update uniforms that will be available in all shaders, in every shader type (canvas_item
, spatial
, particles
, sky
and fog
).
Global uniforms are especially useful for environmental effects that affect many objects in a scene, like having foliage bend when the player is nearby, or having objects move with the wind.
To create a global uniform, open the Project Settings then go to the Shader Globals tab. Specify a name for the uniform (case-sensitive) and a type, then click Add in the top-right corner of the dialog. You can then edit the value assigned to the uniform by clicking the value in the list of uniforms:
Adding a global uniform in the Shader Globals tab of the Project Settings
After creating a global uniform, you can use it in a shader as follows:
shader_type canvas_item;
global uniform vec4 my_color;
void fragment() {
COLOR = my_color.rgb;
}
Note that the global uniform must exist in the Project Settings at the time the shader is saved, or compilation will fail. While you can assign a default value using global uniform vec4 my_color = ...
in the shader code, it will be ignored as the global uniform must always be defined in the Project Settings anyway.
To change the value of a global uniform at run-time, use the RenderingServer.global_shader_parameter_set method in a script:
RenderingServer.global_shader_parameter_set("my_color", Color(0.3, 0.6, 1.0))
Assigning global uniform values can be done as many times as desired without impacting performance, as setting data doesn’t require synchronization between the CPU and GPU.
You can also add or remove global uniforms at run-time:
RenderingServer.global_shader_parameter_add("my_color", RenderingServer.GLOBAL_VAR_TYPE_COLOR, Color(0.3, 0.6, 1.0))
RenderingServer.global_shader_parameter_remove("my_color")
Adding or removing global uniforms at run-time has a performance cost, although it’s not as pronounced compared to getting global uniform values from a script (see the warning below).
警告
While you can query the value of a global uniform at run-time in a script using RenderingServer.global_shader_parameter_get("uniform_name")
, this has a large performance penalty as the rendering thread needs to synchronize with the calling thread.
Therefore, it’s not recommended to read global shader uniform values continuously in a script. If you need to read values in a script after setting them, consider creating an autoload where you store the values you need to query at the same time you’re setting them as global uniforms.
Per-instance uniforms
备注
Per-instance uniforms are only available in spatial
(3D) shaders.
Sometimes, you want to modify a parameter on each node using the material. As an example, in a forest full of trees, when you want each tree to have a slightly different color that is editable by hand. Without per-instance uniforms, this requires creating a unique material for each tree (each with a slightly different hue). This makes material management more complex, and also has a performance overhead due to the scene requiring more unique material instances. Vertex colors could also be used here, but they’d require creating unique copies of the mesh for each different color, which also has a performance overhead.
Per-instance uniforms are set on each GeometryInstance3D, rather than on each Material instance. Take this into account when working with meshes that have multiple materials assigned to them, or MultiMesh setups.
shader_type spatial;
// Provide a hint to edit as a color. Optionally, a default value can be provided.
// If no default value is provided, the type's default is used (e.g. opaque black for colors).
instance uniform vec4 my_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
void fragment() {
ALBEDO = my_color.rgb;
}
After saving the shader, you can change the per-instance uniform’s value using the inspector:
Setting a per-instance uniform’s value in the GeometryInstance3D section of the inspector
Per-instance uniform values can also be set at run-time using set_instance_shader_parameter<class_GeometryInstance3D_method_set_instance_shader_parameter> method on a node that inherits from GeometryInstance3D:
$MeshInstance3D.set_instance_shader_parameter("my_color", Color(0.3, 0.6, 1.0))
When using per-instance uniforms, there are some restrictions you should be aware of:
Per-instance uniforms do not support textures, only regular scalar and vector types. As a workaround, you can pass a texture array as a regular uniform, then pass the index of the texture to be drawn using a per-instance uniform.
There is a practical maximum limit of 16 instance uniforms per shader.
If your mesh uses multiple materials, the parameters for the first mesh material found will “win” over the subsequent ones, unless they have the same name, index and type. In this case, all parameters are affected correctly.
If you run into the above situation, you can avoid clashes by manually specifying the index (0-15) of the instance uniform by using the
instance_index
hint:
instance uniform vec4 my_color : source_color, instance_index(5);
内置变量
A large number of built-in variables are available, like UV
, COLOR
and VERTEX
. What variables are available depends on the type of shader (spatial
, canvas_item
or particle
) and the function used (vertex
, fragment
or light
). For a list of the built-in variables that are available, please see the corresponding pages:
内置函数
支持大量的内置函数, 符合GLSL ES 3.0. 当使用 vec_type (float), vec_int_type, vec_uint_type, vec_bool_type 命名法时, 它可以是标量或向量.
函数 | Description / Return value |
---|---|
vec_type radians (vec_type degrees度) | 将度数转换为弧度。 |
vec_type degrees ( vec_type radians弧度) | 将弧度转换为度数。 |
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) | 幂( |
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) | Absolute value (returns positive value if negative). |
vec_type sign ( vec_type ) ivec_type sign (ivec_type x) | Sign (returns |
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 (returns |
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) | Clamp |
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, bvec_type c) | 根据 |
vec_type fma (vec_type a, vec_type b, vec_type c) | Performs a fused multiply-add operation: |
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) vec_type smoothstep (float a, float b, vec_type c) | Hermite interpolate between |
bvec_type isnan (vec_type x) | 如果标量或向量分量是 |
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 位复制,无转换。 |
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 normalize (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 transpose (mat_type m) | 转置矩阵。 |
float determinant (mat_type m) | 矩阵行列式。 |
mat_type inverse (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 any (bvec_type x) |
|
bool all (bvec_type x) |
|
bvec_type not (bvec_type x) | 反转布尔向量。 |
ivec2 textureSize (gsampler2D s, int lod) ivec3 textureSize (gsampler2DArray s, int lod) ivec3 textureSize (gsampler3D s, int lod) ivec2 textureSize (samplerCube s, int lod) ivec2 textureSize (samplerCubeArray s, int lod) | 获取纹理的大小。 The LOD defines which mipmap level is used. An LOD value of |
vec2 textureQueryLod (gsampler2D s, vec2 p) vec3 textureQueryLod (gsampler2DArray s, vec2 p) vec2 textureQueryLod (gsampler3D s, vec3 p) vec2 textureQueryLod (samplerCube s, vec3 p) | Compute the level-of-detail that would be used to sample from a texture. The |
int textureQueryLevels (gsampler2D s) int textureQueryLevels (gsampler2DArray s) int textureQueryLevels (gsampler3D s) int textureQueryLevels (samplerCube s) | 获取cubemap纹理的大小。 If the texture is unassigned to a sampler, |
gvec4_type texture (gsampler2D s, vec2 p [, float bias]) gvec4_type texture (gsampler2DArray s, vec3 p [, float bias]) gvec4_type texture (gsampler3D s, vec3 p [, float bias]) vec4 texture (samplerCube s, vec3 p [, float bias]) vec4 texture (samplerCubeArray s, vec4 p [, float bias]) | 执行纹理读取。 |
gvec4_type textureProj (gsampler2D s, vec3 p [, float bias]) gvec4_type textureProj (gsampler2D s, vec4 p [, float bias]) gvec4_type textureProj (gsampler3D s, vec4 p [, float bias]) | 执行带投影的纹理读取。 |
gvec4_type textureLod (gsampler2D s, vec2 p, float lod) gvec4_type textureLod (gsampler2DArray s, vec3 p, float lod) gvec4_type textureLod (gsampler3D s, vec3 p, float lod) vec4 textureLod (samplerCube s, vec3 p, float lod) vec4 textureLod (samplerCubeArray s, vec4 p, float lod) | 在自定义 mipmap 上执行纹理读取。 The LOD defines which mipmap level is used. An LOD value of |
gvec4_type textureProjLod (gsampler2D s, vec3 p, float lod) gvec4_type textureProjLod (gsampler2D s, vec4 p, float lod) gvec4_type textureProjLod (gsampler3D s, vec4 p, float lod) | 执行带投影/LOD的2D纹理读取。 The LOD defines which mipmap level is used. An LOD value of |
gvec4_type textureGrad (gsampler2D s, vec2 p, vec2 dPdx, vec2 dPdy) gvec4_type textureGrad (gsampler2DArray s, vec3 p, vec2 dPdx, vec2 dPdy) gvec4_type textureGrad (gsampler3D s, vec3 p, vec2 dPdx, vec2 dPdy) vec4 textureGrad (samplerCube s, vec3 p, vec3 dPdx, vec3 dPdy) vec4 textureGrad (samplerCubeArray s, vec3 p, vec3 dPdx, vec3 dPdy) | 执行带显式渐变的纹理读取。 |
gvec4_type textureProjGrad (gsampler2D s, vec3 p, vec2 dPdx, vec2 dPdy) gvec4_type textureProjGrad (gsampler2D s, vec4 p, vec2 dPdx, vec2 dPdy) gvec4_type textureProjGrad (gsampler3D s, vec4 p, vec3 dPdx, vec3 dPdy) | Performs a texture read with projection/LOD and with explicit gradients. |
gvec4_type texelFetch (gsampler2D s, ivec2 p, int lod) gvec4_type texelFetch (gsampler2DArray s, ivec3 p, int lod) gvec4_type texelFetch (gsampler3D s, ivec3 p, int lod) | 使用整数坐标获取单个纹素。 The LOD defines which mipmap level is used. An LOD value of |
gvec4_type textureGather (gsampler2D s, vec2 p [, int comps]) gvec4_type textureGather (gsampler2DArray s, vec3 p [, int comps]) vec4 textureGather (samplerCube s, vec3 p [, int comps]) | Gathers four texels from a texture. Use |
vec_type dFdx (vec_type p) | Derivative in |
vec_type dFdxCoarse (vec_type p) | Calculates derivative with respect to |
vec_type dFdxFine (vec_type p) | Calculates derivative with respect to |
vec_type dFdy (vec_type p) | Derivative in |
vec_type dFdyCoarse (vec_type p) | Calculates derivative with respect to |
vec_type dFdyFine (vec_type p) | Calculates derivative with respect to |
vec_type fwidth (vec_type p) | Sum of absolute derivative in |
vec_type fwidthCoarse (vec_type p) | Sum of absolute derivative in |
vec_type fwidthFine (vec_type p) | Sum of absolute derivative in |
uint packHalf2x16 (vec2 v) vec2 unpackHalf2x16 (uint v) | Convert two 32-bit floating-point numbers into 16-bit and pack them into a 32-bit unsigned integer and vice-versa. |
uint packUnorm2x16 (vec2 v) vec2 unpackUnorm2x16 (uint v) | Convert two 32-bit floating-point numbers (clamped within 0..1 range) into 16-bit and pack them into a 32-bit unsigned integer and vice-versa. |
uint packSnorm2x16 (vec2 v) vec2 unpackSnorm2x16 (uint v) | Convert two 32-bit floating-point numbers (clamped within -1..1 range) into 16-bit and pack them into a 32-bit unsigned integer and vice-versa. |
uint packUnorm4x8 (vec4 v) vec4 unpackUnorm4x8 (uint v) | Convert four 32-bit floating-point numbers (clamped within 0..1 range) into 8-bit and pack them into a 32-bit unsigned integer and vice-versa. |
uint packSnorm4x8 (vec4 v) vec4 unpackSnorm4x8 (uint v) | Convert four 32-bit floating-point numbers (clamped within -1..1 range) into 8-bit and pack them into a 32-bit unsigned integer and vice-versa. |
ivec_type bitfieldExtract (ivec_type value, int offset, int bits) uvec_type bitfieldExtract (uvec_type value, int offset, int bits) | Extracts a range of bits from an integer. |
ivec_type bitfieldInsert (ivec_type base, ivec_type insert, int offset, int bits) uvec_type bitfieldInsert (uvec_type base, uvec_type insert, int offset, int bits) | Insert a range of bits into an integer. |
ivec_type bitfieldReverse (ivec_type value) uvec_type bitfieldReverse (uvec_type value) | Reverse the order of bits in an integer. |
ivec_type bitCount (ivec_type value) uvec_type bitCount (uvec_type value) | Counts the number of 1 bits in an integer. |
ivec_type findLSB (ivec_type value) uvec_type findLSB (uvec_type value) | Find the index of the least significant bit set to 1 in an integer. |
ivec_type findMSB (ivec_type value) uvec_type findMSB (uvec_type value) | Find the index of the most significant bit set to 1 in an integer. |
void imulExtended (ivec_type x, ivec_type y, out ivec_type msb, out ivec_type lsb) void umulExtended (uvec_type x, uvec_type y, out uvec_type msb, out uvec_type lsb) | Multiplies two 32-bit numbers and produce a 64-bit result. |
uvec_type uaddCarry (uvec_type x, uvec_type y, out uvec_type carry) | Adds two unsigned integers and generates carry. |
uvec_type usubBorrow (uvec_type x, uvec_type y, out uvec_type borrow) | Subtracts two unsigned integers and generates borrow. |
vec_type ldexp (vec_type x, out ivec_type exp) | Assemble a floating-point number from a value and exponent. If this product is too large to be represented in the floating-point type the result is undefined. |
vec_type frexp (vec_type x, out ivec_type exp) | Splits a floating-point number( For |
© 版权所有 2014-present Juan Linietsky, Ariel Manzur and the Godot community (CC BY 3.0). Revision b1c660f7
.
Built with Sphinx using a theme provided by Read the Docs.