Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Spatial 着色器
空间着色器(Spatial shaders)用于对 3D 物体进行着色。它们是 Godot 提供的最复杂的一类着色器。空间着色器具有高度的可配置性,拥有不同的渲染模式和多样的渲染选项(例如次表面散射、透光、环境光遮蔽、边缘光等)。开发者可以选择性地编写顶点、片段和光照处理函数,来控制物体的具体绘制方式。
渲染模式
渲染模式的可视示例见《标准 3D 材质与 ORM 3D 材质》。
渲染模式 |
描述 |
|---|---|
blend_mix |
混合混合模式(Alpha 为透明度),默认。 |
blend_add |
添加混合模式。 |
blend_sub |
减法混合模式。 |
blend_mul |
乘法混合模式。 |
blend_premul_alpha |
预乘 Alpha 混合模式(完全透明时采用相加混合,完全不透明时采用常规混合)。 |
depth_draw_opaque |
仅绘制不透明几何体的深度(不透明)。 |
depth_draw_always |
始终绘制深度(不透明和透明)。 |
depth_draw_never |
不绘制深度。 |
depth_prepass_alpha |
对透明几何体进行不透明的深度预渲染。 |
depth_test_disabled |
禁用深度测试。 |
默认深度测试 |
深度测试会丢弃那些位于其他像素后方的像素。而且,仅在 Forward+(正向+)渲染模式下,如果像素与另一个像素处于完全相同的深度,它也会被丢弃。 |
反向深度测试 |
如果当前像素位于其他像素的前方,深度测试就会将其丢弃。这种模式对制作模板(stencil)特效非常有用。 |
sss_mode_skin |
适用于皮肤的次表面散射模式(会针对人类皮肤优化视觉效果,比如增强红色通道)。 |
cull_back |
剔除背面(默认)。 |
cull_front |
剔除正面。 |
cull_disabled |
禁用剔除(双面)。 |
unshaded |
结果只使用反照率。材质中不会发生照明/阴影,渲染更快。 |
wireframe |
几何体使用线条进行绘制(这对故障排查非常有用)。当使用兼容渲染器(Compatibility renderer)时,你必须在网格(mesh)加载 之前 调用 |
debug_shadow_splits |
绘制方向阴影时为不同的拆分使用不同的颜色(常用于排查故障)。 |
diffuse_burley |
漫反射使用 Burley(迪士尼 PBS)(默认值)。 |
diffuse_lambert |
漫反射使用 Lambert 着色。 |
diffuse_lambert_wrap |
漫反射使用 Lambert 环绕着色(受粗糙度影响)。 |
diffuse_toon |
漫反射使用卡通着色。 |
specular_schlick_ggx |
直接光照镜面反射高光使用 Schlick-GGX(默认)。 |
specular_toon |
直接光照镜面反射高光使用 Toon。 |
specular_disabled |
禁用直接光照镜面反射高光。不影响反射光(请改用 |
skip_vertex_transform |
|
world_vertex_coords |
|
ensure_correct_normals |
当网格应用了非均匀缩放时使用 (注意:目前尚未实现) 。 |
shadows_disabled |
禁用着色器中的阴影计算。该着色器将不会接收阴影,但仍然可以投射阴影。 |
ambient_light_disabled |
禁用环境光和辐射度图的收益. |
shadow_to_opacity |
光照会改变 alpha 值,阴影部分是不透明的,而没有阴影的地方是透明的。对于 AR 中将阴影堆叠到同一个相机流很有用。 |
vertex_lighting |
使用基于顶点的光照,而不是逐像素光照。 |
particle_trails |
当应用于粒子几何体时,启用拖尾效果。 |
alpha_to_coverage |
Alpha 抗锯齿模式,详见此处。 |
alpha_to_coverage_and_one |
Alpha 抗锯齿模式,详见此处。 |
fog_disabled |
禁用接收基于深度的雾效或体积雾。这对于像粒子特效这类使用 |
模板模式
备注
模板(Stencil)支持目前仍处于实验阶段,请自行承担使用风险。我们会尽可能避免破坏兼容性,但如果在 API 中发现了重大缺陷,它可能会在下一个次要版本中发生变动。
模板操作(Stencil operations)是一系列允许以硬件加速的方式向高效缓冲区进行写入的操作。它通常被用来对场景的某些部分进行遮罩(Masking)处理,决定哪些该显示,哪些该隐藏。
一些最广为人知的用途包括:
轮廓描边(Outlines):将需要描边的网格内部区域遮罩掉,以避免物体内部也出现描边。
X光透视(X-Ray):让网格模型能够显示在其他物体的后方。
传送门(Portals):通过遮罩物体,来绘制那些在正常情况下“不可能存在”的(非欧几里得)几何结构。
备注
你只能在透明渲染通道(transparent pass)中读取模板缓冲区。任何尝试在不透明渲染通道(opaque pass)中读取的操作都会失败,因为目前还不支持这种行为。
需要注意的是,对于合成器特效(compositor effects),主渲染器的模板缓冲区是无法被复制到自定义纹理中的。
模板模式 |
描述 |
|---|---|
读 |
从模板缓冲区中读取数据。 |
写 |
将参考值写入模板缓冲区。 |
write_if_depth_fail |
如果深度测试失败,则将参考值写入模板缓冲区。 |
始终通过比较 |
始终通过模板测试。 |
compare_equal |
如果参考值(reference value)与模板缓冲区中的值相等,则通过模板测试。 |
compare_not_equal |
如果参考值不等于模板缓冲区的值,则通过模板测试。 |
小于时通过比较 |
如果参考值小于模板缓冲区的值,则通过模板测试。 |
compare_less_or_equal |
如果参考值小于或等于模板缓冲区的值,则通过模板测试。 |
大于时通过比较 |
如果参考值大于模板缓冲区的值,则通过模板测试。 |
大于或等于时通过比较 |
如果参考值大于或等于模板缓冲区的值,则通过模板测试。 |
内置
标记为 in (输入)的值是只读的。标记为 out (输出)的值可以被写入(赋值),但它们不一定包含有意义的初始值。标记为 inout (输入输出)的值会提供一个合理的默认值,并且可以被选择性地写入。采样器(Samplers)不能被写入,所以没有进行任何标记。
并非所有的内置变量在所有处理函数中都是可用的。如果你想从 fragment() 函数中访问顶点的内置变量,可以使用插值变量。同样的道理也适用于从 light() 函数中访问内置变量。
全局内置变量
全局的内置在所有地方均可用,包括自定义函数中。
内置 |
描述 |
|---|---|
in float TIME |
自引擎启动以来的全局时间,以秒为单位。它每经过 |
in float PI |
常量 |
in float TAU |
常量 |
in float E |
常量 |
in bool OUTPUT_IS_SRGB |
输出使用 sRGB 色彩空间时为 |
in float CLIP_SPACE_FAR |
裁剪空间的远平面 |
在布尔值 IS_MULTIVIEW 中 |
当输出为立体(XR)时返回 |
在布尔值 IN_SHADOW_PASS 中 |
当着色器正在阴影贴图(shadow mapping)渲染通道中进行渲染时,返回 |
顶点内置
顶点数据( VERTEX 、 NORMAL 、 TANGENT 和 BITANGENT )是以模型空间(也称为局部空间)的形式呈现的。如果没有对它们进行写入(修改)操作,这些数值将保持原样不做改动,随后会被转换到视图空间,以便在 fragment() (片段)函数中使用。
它们可以选择性地以世界空间的形式呈现,只需使用 world_vertex_coords 渲染模式即可。
用户可以禁用内置的modelview变换(以后仍会发生投影), 并通过以下代码手动完成:
shader_type spatial;
render_mode skip_vertex_transform;
void vertex() {
VERTEX = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
BINORMAL = normalize((MODELVIEW_MATRIX * vec4(BINORMAL, 0.0)).xyz);
TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz);
}
如果没有被修改,其他的内置变量(比如 UV 、 UV2 和 COLOR 等)也会直接传递给 fragment() (片段)函数。
用户可以通过内置变量 POSITION 来重写(覆盖)模型的视图和投影变换。只要在着色器的任何地方对 POSITION 进行了写入操作,它就一定会被采用。因此,用户就必须自己负责确保 POSITION 始终拥有一个可接受的有效值。当使用了 POSITION 时, VERTEX 的值会被忽略,并且引擎默认的投影过程也不会发生。不过,最终传递给片段着色器(fragment shader)的顶点值,依然来自于 VERTEX 。
对于实例化(Instancing), INSTANCE_CUSTOM 变量包含了实例的自定义数据。当使用粒子系统时,这些信息通常是:
x:旋转角度,单位为弧度。
y:生命周期的阶段(
0.0到1.0)。z:动画帧。
这让你能轻松地基于默认粒子材质,将 Shader(着色器)适配到粒子系统上。在编写自定义粒子 Shader 时,你可以随心所欲地利用这个值。
内置 |
描述 |
|---|---|
in vec2 VIEWPORT_SIZE |
视口大小(单位为像素)。 |
in mat4 VIEW_MATRIX |
世界空间到视图空间变换。 |
in mat4 INV_VIEW_MATRIX |
视图空间到世界空间的变换。 |
in mat4 MAIN_CAM_INV_VIEW_MATRIX |
用于绘制当前视口的摄像机,从视图空间到世界空间的变换。 |
in mat4 INV_PROJECTION_MATRIX |
裁剪空间到视图空间的变换。 |
in vec3 NODE_POSITION_WORLD |
节点的位置,使用世界空间。 |
in vec3 NODE_POSITION_VIEW |
节点的位置,使用视图空间。 |
in vec3 CAMERA_POSITION_WORLD |
摄像机在世界空间(world space)中的位置。当处于多视图(multiview)或立体(stereo)渲染模式时,它代表的是双眼之间的中心点。 |
in vec3 CAMERA_DIRECTION_WORLD |
相机的方向,使用世界空间。 |
in uint CAMERA_VISIBLE_LAYERS |
剔除当前渲染阶段中相机不渲染的图层。 |
in int INSTANCE_ID |
实例化的实例 ID。 |
in vec4 INSTANCE_CUSTOM |
实例自定义数据(主要用于粒子)。 |
in int VIEW_INDEX |
我们正在渲染的视图。对于单视图(非多视图)或左眼视图,使用 |
in int VIEW_MONO_LEFT |
单视图或左眼视图的常量,恒为 |
in int VIEW_RIGHT |
右眼视图常量,恒为 |
in vec3 EYE_OFFSET |
当前正在渲染的(单只)眼睛在视图空间下的位置偏移量。仅适用于多视图(Multiview)渲染。 |
inout vec3 VERTEX |
模型空间中的顶点位置。如果使用了 |
in int VERTEX_ID |
顶点缓冲区中当前顶点的索引。 |
inout vec3 NORMAL |
模型空间中的法线。如果使用了 |
inout vec3 TANGENT |
模型空间中的切线。如果使用了 |
inout vec3 BINORMAL |
模型空间中的副法线。如果使用了 |
out vec4 POSITION |
如果在任何分支中被写入(赋值),它将覆盖裁剪空间中的最终顶点位置。 |
inout vec2 UV |
UV主通道. |
inout vec2 UV2 |
UV2辅助通道. |
inout vec4 COLOR |
来自顶点的颜色。每个通道的值限制在 |
out float ROUGHNESS |
顶点照明的粗糙度. |
inout float POINT_SIZE |
点渲染的点大小. |
inout mat4 MODELVIEW_MATRIX |
模型/局部空间到视图空间的变换(如果可能的话,请优先使用这个)。 |
inout mat3 MODELVIEW_NORMAL_MATRIX |
|
in mat4 MODEL_MATRIX |
模型/局部空间到世界空间的变换。 |
in mat3 MODEL_NORMAL_MATRIX |
|
inout mat4 PROJECTION_MATRIX |
视图空间向裁剪空间变换. |
in uvec4 BONE_INDICES |
|
in vec4 BONE_WEIGHTS |
|
in vec4 CUSTOM0 |
来自顶点图元的自定义值。当使用额外的 UV 贴图时, |
in vec4 CUSTOM1 |
来自顶点图元的自定义值。当使用额外的 UV 贴图时, |
in vec4 CUSTOM2 |
来自顶点图元的自定义值。当使用额外的 UV 贴图时, |
in vec4 CUSTOM3 |
来自顶点图元的自定义值。 |
out float Z_CLIP_SCALE |
如果在任何分支中对其进行了写入(赋值),它会将顶点向相机方向进行缩放,以避免穿模到墙壁等物体里。当写入该值时,光照和阴影依然能正常工作,但如果缩放比例设置得过低,屏幕空间特效(如 SSAO 环境光遮蔽和 SSR 屏幕空间反射)可能会出现异常。尽量让该值保持在接近 |
备注
MODELVIEW_MATRIX 结合了 MODEL_MATRIX (模型矩阵)和 VIEW_MATRIX (视图矩阵),在可能会出现浮点数精度问题的时候,使用它会更加稳妥。举个例子,如果物体距离世界原点非常远,当你分开使用 MODEL_MATRIX 和 VIEW_MATRIX 时,就可能会遇到浮点数精度的问题。
备注
INV_VIEW_MATRIX 是在当前渲染通道(pass)中用来渲染物体的矩阵;而 MAIN_CAM_INV_VIEW_MATRIX 则是场景中主摄像机的矩阵。在阴影渲染通道(shadow pass)中, INV_VIEW_MATRIX 的视图是基于一个位于光源位置处的摄像机来设定的。
片段内置
Godot片段处理器函数的默认用法是设置对象的材质属性, 并让内置渲染器处理最终的阴影. 但是, 你无需使用所有这些属性, 如果你不写入它们,Godot将优化掉相应的功能.
内置 |
描述 |
|---|---|
in vec2 VIEWPORT_SIZE |
视口大小(单位为像素)。 |
in vec4 FRAGCOORD |
屏幕空间中像素中心的坐标。其中 |
in bool FRONT_FACING |
如果当前的面展示的是正面则为 |
in vec3 VIEW |
片段位置到相机位置(在视图空间中)的归一化向量,该向量对于透视相机和正交相机而言是相同的。 |
in vec2 UV |
来自 |
in vec2 UV2 |
来自 |
in vec4 COLOR |
来自 |
in vec2 POINT_COORD |
使用 |
in mat4 MODEL_MATRIX |
模型/局部空间到世界空间的变换。 |
in mat3 MODEL_NORMAL_MATRIX |
用于法线的 模型/局部空间 到 世界空间 的变换矩阵。默认情况下,它和 |
in mat4 VIEW_MATRIX |
世界空间到视图空间变换。 |
in mat4 INV_VIEW_MATRIX |
视图空间到世界空间的变换。 |
in mat4 PROJECTION_MATRIX |
视图空间向裁剪空间变换. |
in mat4 INV_PROJECTION_MATRIX |
裁剪空间到视图空间的变换。 |
in vec3 NODE_POSITION_WORLD |
节点的位置,使用世界空间。 |
in vec3 NODE_POSITION_VIEW |
节点的位置,使用视图空间。 |
in vec3 CAMERA_POSITION_WORLD |
摄像机在世界空间(world space)中的位置。当处于多视图(multiview)或立体(stereo)渲染模式时,它代表的是双眼之间的中心点。 |
in vec3 CAMERA_DIRECTION_WORLD |
相机的方向,使用世界空间。 |
in uint CAMERA_VISIBLE_LAYERS |
剔除当前渲染阶段中相机不渲染的图层。 |
in vec3 VERTEX |
片段(即像素)在视图空间中的位置。它是 |
inout vec3 LIGHT_VERTEX |
一个可写的 |
in int VIEW_INDEX |
当前正在渲染的视图。用于在多视图(multiview)或立体(stereo)渲染中区分不同的视图。 |
in int VIEW_MONO_LEFT |
单视图或左眼视图的常量,恒为 |
in int VIEW_RIGHT |
右眼视图常量,恒为 |
in vec3 EYE_OFFSET |
当前正在渲染的(单只)眼睛在视图空间下的位置偏移量。仅适用于多视图(Multiview)渲染。 |
sampler2D SCREEN_TEXTURE |
在 Godot 4 中移除。请改用 |
in vec2 SCREEN_UV |
当前像素的屏幕 UV 坐标。 |
sampler2D DEPTH_TEXTURE |
在 Godot 4 中移除。请改用 |
out float DEPTH |
自定义深度值(取值范围 |
inout vec3 NORMAL |
源自 |
inout vec3 TANGENT |
源自 |
inout vec3 BINORMAL |
源自 |
out vec3 NORMAL_MAP |
如果你是从纹理中读取法线,而不是直接使用 |
out float NORMAL_MAP_DEPTH |
|
输出 vec3 NORMAL_MAP |
在这里(切线空间)设置弯曲法线贴图,以启用 bent normals (弯曲法线)功能。这主要用于改善高光遮蔽(specular occlusion)的效果,并且需要你专门制作一张弯曲法线贴图。蓝色通道会被忽略,因为它会在引擎内部被重新计算出来。这种做法可以让使用了 RGTC 压缩的弯曲法线贴图正常工作。 |
out vec3 ALBEDO |
反照率(默认为白色)。基础颜色。 |
out float ALPHA |
Alpha(取值范围 |
out float ALPHA_SCISSOR_THRESHOLD |
如果在任何分支中对其进行了写入(赋值),透明度(Alpha)低于特定数值的像素将会被丢弃。 |
out float ALPHA_HASH_SCALE |
在使用 Alpha Hash 透明模式时的 Alpha 哈希缩放值。默认值为 |
out float ALPHA_ANTIALIASING_EDGE |
启用 Alpha 覆盖抗锯齿的阈值下限。默认值为 |
out vec2 ALPHA_TEXTURE_COORDINATE |
用于 Alpha 覆盖抗锯齿(alpha-to-coverage antialiasing)的纹理坐标。需要启用 |
输出浮点型变量 PREMUL_ALPHA_FACTOR (预乘 Alpha 因子) |
预乘 Alpha 因子。仅在使用了 |
out float METALLIC |
金属度(范围为 |
out float SPECULAR |
高光/镜面反射(修改此值在物理上并不准确)。默认值为 |
out float ROUGHNESS |
粗糙度(范围为 |
out float RIM |
边缘光强度(取值范围为 |
out float RIM_TINT |
边缘光色调,取值范围从 |
out float CLEARCOAT |
在现有高光之上,额外叠加的一小块高光光斑。如果使用,Godot 将计算clearcoat层。 |
out float CLEARCOAT_GLOSS |
clearcoat的光泽度。如果使用了该参数,Godot 就会计算clearcoat效果。 |
out float ANISOTROPY |
用于根据切线空间扭曲镜面反射斑点。 |
out vec2 ANISOTROPY_FLOW |
失真方向, 与流程图一起使用. |
out float SSS_STRENGTH |
次表面散射的强度。如果使用了该参数,次表面散射效果就会被应用到物体上。 |
out vec4 SSS_TRANSMITTANCE_COLOR |
次表面散射透射的颜色。如果使用了该参数,次表面散射透射效果就会被应用到物体上。 |
out float SSS_TRANSMITTANCE_DEPTH |
次表面散射透射的深度。数值越高,该效果就能穿透到物体的更深处。 |
out float SSS_TRANSMITTANCE_BOOST |
如果该值设置得高于 |
inout vec3 BACKLIGHT |
背光的颜色(其作用类似于直射光,但即便物体表面的法线稍微背对光源,也能接收到这种光照)。如果使用了该参数,背光效果就会被应用到物体上。它可以被用作一种更节省性能的次表面散射(Subsurface Scattering)近似模拟。 |
out float AO |
环境光遮蔽(Ambient Occlusion)的强度。配合预烘焙的 AO 贴图使用。 |
out float AO_LIGHT_AFFECT |
环境光遮蔽(Ambient Occlusion)对直射光的影响程度(取值范围为 |
out vec3 EMISSION |
自发光颜色(可以超过 |
out vec4 FOG |
如果在任何分支中对其进行了写入(赋值),最终的像素颜色将会根据 |
out vec4 RADIANCE |
如果在任何分支中对其进行了写入(赋值),环境贴图的光照强度(radiance)将会根据 |
out vec4 IRRADIANCE |
如果在任何分支中对其进行了写入(赋值),环境贴图的辐照度(irradiance)将会根据 |
备注
因为写入 ALPHA 而经过透明管线的着色器可能受到透明排序问题的影响。更多信息及解决方法请阅读3D 渲染限制页面的透明排序章节。
内置灯光
编写光照处理函数是完全可选的。你可以通过使用 unshaded (无光照)渲染模式来跳过 light() 函数。如果没有编写任何光照函数,Godot 将会根据你在 fragment() 函数中设置的材质属性,自动为你计算光照(具体计算方式受渲染模式影响)。
light() 函数会在每一个像素上,针对每一盏灯各调用一次。它是在一个针对每种光源类型的循环中被调用的。
下面是一个使用兰伯特(Lambertian)光照模型的自定义 light() 函数示例:
void light() {
if (LIGHT_IS_AREA) {
// Area light GGX shading.
DIFFUSE_LIGHT += LIGHT_AREA_DIFFUSE_MULTIPLIER * ATTENUATION * LIGHT_COLOR;
SPECULAR_LIGHT += LIGHT_AREA_SPECULAR_MULTIPLIER * ATTENUATION * LIGHT_COLOR * SPECULAR_AMOUNT;
} else {
// Used for all other light types (directional, omni, spot).
DIFFUSE_LIGHT += clamp(dot(NORMAL, LIGHT), 0.0, 1.0) * ATTENUATION * LIGHT_COLOR / PI;
}
}
如果你想把这些光照加在一起,请使用 += 运算符将光线添加到 DIFFUSE_LIGHT 函数中,不要覆盖它。
警告
如果启用了 vertex_lighting (顶点光照)渲染模式,或者在项目设置中开启了 Rendering > Quality > Shading > Force Vertex Shading ,那么 light() 函数将不会被执行。(在移动平台上,该选项默认是开启的。)
内置 |
描述 |
|---|---|
in vec2 VIEWPORT_SIZE |
视口大小(单位为像素)。 |
in vec4 FRAGCOORD |
屏幕空间中像素中心的坐标。其中 |
in mat4 MODEL_MATRIX |
模型/局部空间到世界空间的变换。 |
in mat4 INV_VIEW_MATRIX |
视图空间到世界空间的变换。 |
in mat4 VIEW_MATRIX |
世界空间到视图空间变换。 |
in mat4 PROJECTION_MATRIX |
视图空间向裁剪空间变换. |
in mat4 INV_PROJECTION_MATRIX |
裁剪空间到视图空间的变换。 |
in vec3 NORMAL |
法向量, 在视图空间中. |
in vec2 SCREEN_UV |
当前像素的屏幕 UV 坐标。 |
in vec2 UV |
来自 |
in vec2 UV2 |
来自 |
in vec3 VIEW |
视图向量, 在视图空间中. |
in vec3 LIGHT |
光照向量,处于观察空间(View Space)中。 |
in vec3 LIGHT_COLOR |
由 Light color 乘以 light energy 再乘以 |
in float SPECULAR_AMOUNT |
对于 OmniLight3D 和 SpotLight3D ,数值为 |
in bool LIGHT_IS_DIRECTIONAL |
如果当前的渲染通道(pass)属于 DirectionalLight3D,则返回 |
in float ATTENUATION |
基于距离或阴影的衰减。 |
in vec3 ALBEDO |
基础反照率。 |
in vec3 BACKLIGHT |
|
in float METALLIC |
Metallic(金属度)。 |
in float ROUGHNESS |
粗糙度. |
out vec3 DIFFUSE_LIGHT |
漫射光效果. |
out vec3 SPECULAR_LIGHT |
镜面反射光效果。 |
out float ALPHA |
Alpha(取值范围 |
备注
因为写入 ALPHA 而经过透明管线的着色器可能受到透明排序问题的影响。更多信息及解决方法请阅读3D 渲染限制页面的透明排序章节。
透明材质无法投射阴影,也不会出现在 hint_screen_texture (屏幕纹理提示)和 hint_depth_texture (深度纹理提示)这两种 uniform(统一变量)中。这进而导致透明材质无法出现在屏幕空间的反射或折射效果中。此外,透明材质上也看不到 SDFGI (有向距离场全局光照)产生的锐利反射(只能看到模糊/粗糙的反射效果)。