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.

着色器简介

本页面会讲解什么是着色器,会为你综述其在 Godot 中的使用方法。引擎中着色语言的详细参考见 着色语言

着色器(Shader)是一种在图形处理单元(GPU)上运行的特殊程序。他们最初使用来为 3D 场景着色的,不过现在能做的事情就更多了。你可以用它们来控制引擎在屏幕上绘制几何体以及像素的方式,可以用来实现各种特效。

类似 Godot 的现代渲染引擎都会用着色器来执行所有绘制操作:图形卡可以并行执行成千上万条指令,可以达到惊人的渲染速度。

因为天生就是并行的,所以着色器处理信息的方式与普通的程序有所不同。着色器代码是单独针对顶点或像素执行的。你也无法在帧与帧之间存储数据。因此,使用着色器时,你需要使用与其他编程语言不同的编码和思考方式。

假设你想要把纹理中的所有像素点都设置成某个给定的颜色。使用 GDScript,你的代码会用 for 循环:

for x in range(width):
  for y in range(height):
    set_color(x, y, some_color)

在着色器中,你的代码已经是循环的一部分了,所以对应的代码应该类似这样。

void fragment() {
  COLOR = some_color;
}

备注

图形卡会为需要绘制的每一个像素调用若干次 fragment() 函数。后面会详细说明。

Godot 中的着色器

Godot 所提供的着色语言是基于流行的 OpenGL 着色语言(GLSL)的简化。引擎会为你处理一些底层的初始化工作,让编写复杂着色器更为简单。

In Godot, shaders are made up of main functions called "processor functions". Processor functions are the entry point for your shader into the program. There are seven different processor functions.

  1. The vertex() function runs over all the vertices in the mesh and sets their positions and some other per-vertex variables. Used in canvas_item shaders and spatial shaders.

  2. The fragment() function runs for every pixel covered by the mesh. It uses values output by the vertex() function, interpolated between the vertices. Used in canvas_item shaders and spatial shaders.

  3. The light() function runs for every pixel and for every light. It takes variables from the fragment() function and from its previous runs. Used in canvas_item shaders and spatial shaders.

  4. The start() function runs for every particle in a particle system once when the particle is first spawned. Used in particles shaders.

  5. The process() function runs for every particle in a particle system for each frame. Used in particles shaders.

  6. The sky() function runs for every pixel in the radiance cubemap when the radiance cubemap needs to be updated, and for every pixel on the current screen. Used in sky shaders.

  7. The fog() function runs for every froxel in the volumetric fog froxel buffer that intersects with the FogVolume. Used by fog shaders.

警告

如果启用了 vertex_lighting 渲染模式,或者在项目设置中启用了 Rendering > Quality > Shading > Force Vertex Shading(渲染 > 质量 > 着色 > 强制顶点着色),则不会运行 light() 函数。在移动平台上默认启用。

备注

Godot also exposes an API for users to write totally custom GLSL shaders. For more information see Using compute shaders.

着色器类型

Instead of supplying a general-purpose configuration for all uses (2D, 3D, particles, sky, fog), you must specify the type of shader you're writing. Different types support different render modes, built-in variables, and processing functions.

在 Godot 中,所有的着色器都需要在第一行指定它们的类型,类似这样:

shader_type spatial;

有以下类型可用:

渲染模式

可以在着色器的第二行,也就是在着色器类型之后,指定渲染模式,类似这样:

shader_type spatial;
render_mode unshaded, cull_disabled;

渲染模式会修改 Godot 应用着色器的方式。例如,unshaded 模式会让引擎跳过内置的光线处理器函数。

每种着色器类型都有不同的渲染模式。每种着色器类型的完整渲染模式列表请参阅参考手册。

顶点处理器

spatialcanvas_item 着色器中,会为每一个顶点调用 vertex() 处理函数。在 particles 着色器中则会为每一个粒子调用一次。

你的世界中的几何体上,每一个顶点都有位置、颜色等属性。该函数会修改这些值,并将其传入片段函数。你也可以借助 varying 向片段着色器传递额外的数据。

默认情况下,Godot 会为你对顶点信息进行变换,这是将几何体投影到屏幕上所必须的。你可以使用渲染模式来自行变换数据;示例见 Spatial 着色器文档

片段处理器

The fragment() processing function is used to set up the Godot material parameters per pixel. This code runs on every visible pixel the object or primitive draws. It is only available in spatial, canvas_item, and sky shaders.

片段函数的标准用途是设置用于计算光照的材质属性。例如,你可以为 ROUGHNESSRIMTRNASMISSION 等设置值,告诉光照函数光照应该如何处理对应的片段。这样就可以控制复杂的着色管线,而不必让用户编写过多的代码。如果你不需要这一内置功能,那么你可以忽略它,自行编写光照处理函数,Godot 会将其优化掉。例如,如果你没有向 RIM 写入任何值,那么 Godot 就不会计算边缘光照。编译时,Godot 会检查是否使用了 RIM;如果没有,那么它就会把对应的代码删除。因此,你就不会在没有使用的效果上浪费算力。

光照处理器

light() 处理器也会在每一个像素上运行,并且同时还会在每一个影响该对象的灯光上运行。如果没有灯光影响该对象则不会运行。它会被用于 fragment() 处理器,一般会在 fragment() 函数中进行材质属性设置时执行。

light() 处理器在 2D 和 3D 中的工作方式不同;每种工作方式的详细描述请参阅它们对应的文档 CanvasItem 着色器 and Spatial 着色器