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.

天空着色器

天空着色器是一种特殊的着色器,主要用于绘制天空背景,以及更新用于图像光照(IBL)的辐射立方体贴图。天空着色器只包含一个处理函数,即 sky() 函数。

用到天空着色器的地方有三个。

  • 首先是在你选择使用 Sky 作为场景的背景时,会使用天空着色器来绘制天空。

  • 其次是在使用 Sky 作为环境光颜色或反射时,会使用天空着色器来更新辐射率立方体贴图。

  • 最后是会使用天空着色器来绘制低分辨率的子阶段,可以用在高分辨率背景或立方体贴图阶段。

综上,一帧之内最多可能调用六次天空着色器,不过实际操作中很难达到那么多次,因为辐射率立方体贴图并不需要每帧都更新,并且也不是所有的子阶段都会用到。你可以根据调用的时机改变着色器的行为,检查布尔值 AT_*_PASS 即可。例如:

shader_type sky;

void sky() {
    if (AT_CUBEMAP_PASS) {
        // Sets the radiance cubemap to a nice shade of blue instead of doing
        // expensive sky calculations
        COLOR = vec3(0.2, 0.6, 1.0);
    } else {
        // Do expensive sky calculations for background sky only
        COLOR = get_sky_color(EYEDIR);
    }
}

使用天空着色器绘制背景时,屏幕上所有未被遮挡的片段都会执行该着色器。不过对于背景的子阶段而言,子阶段中的每个像素都会执行该着色器。

使用天空着色器更新辐射率立方体贴图时,立方体贴图中的每个像素都会执行该天空着色器。换句话说,只有在辐射率立方体贴图需要更新时才会执行该着色器。着色器参数发生改变后就需要更新辐射率立方体贴图。例如着色器中用到了 TIME 的话,那么辐射率立方体贴图就会需要每一帧都更新。下列更改会强制进行辐射率立方体贴图的更新:

  • 用到 TIME

  • 用到 POSITION 并且相机位置发生了改变。

  • 用到 LIGHTX_* 属性并且 DirectionalLight3D 发生了改变。

  • 着色器中的任意 uniform 发生了改变。

  • 屏幕大小发生了变化并且用到了子阶段。

尽量避免毫无必要地更新辐射立方体贴图。如果你确实需要每帧都更新这张辐射立方体贴图,请务必确保你的 Sky process mode 被设置成了 PROCESS_MODE_REALTIME

请注意, process mode 只会影响辐射立方体贴图的渲染。而可见的天空始终是通过为每个像素调用片段着色器来渲染的。如果片段着色器非常复杂,这就会产生很高的渲染开销。如果天空是静态的(满足上述列出的条件)或者变化很慢,那么每一帧都去运行完整的片段着色器其实是没有必要的。我们可以通过将整个天空渲染到辐射立方体贴图中,然后在渲染可见天空时直接读取这张贴图来避免这种开销。对于一个完全静态的天空来说,这意味着它只需要被渲染一次就行了。

下面的代码会将完整的天空渲染到辐射立方体贴图(radiance cubemap)中,并在显示可见天空时读取这张立方体贴图。

shader_type sky;

void sky() {
    if (AT_CUBEMAP_PASS) {
        vec3 dir = EYEDIR;

        vec4 col = vec4(0.0);

        // Complex color calculation

        COLOR = col.xyz;
        ALPHA = 1.0;
    } else {
        COLOR = texture(RADIANCE, EYEDIR).rgb;
    }
}

这样一来,复杂的计算就只会发生在立方体贴图(cubemap)通道中。你可以通过设置天空的 process moderadiance size 来进行优化,从而在性能和视觉保真度之间取得理想的平衡。

渲染模式

子通道(Subpasses)允许你以较低的分辨率来执行一些开销较大的计算,从而加快着色器的运行速度。例如,下面的代码会让云层的渲染分辨率低于天空其他部分的分辨率。

shader_type sky;
render_mode use_half_res_pass;

void sky() {
    if (AT_HALF_RES_PASS) {
        // Run cloud calculation for 1/4 of the pixels
        vec4 color = generate_clouds(EYEDIR);
        COLOR = color.rgb;
        ALPHA = color.a;
    } else {
        // At full resolution pass, blend sky and clouds together
        vec3 color = generate_sky(EYEDIR);
        COLOR = color + HALF_RES_COLOR.rgb * HALF_RES_COLOR.a;
    }
}

渲染模式

描述

use_half_res_pass

允许着色器对半分辨率阶段进行写入和访问。

use_quarter_res_pass

允许着色器对四分之一分辨率阶段进行写入和访问。

disable_fog

使用后,雾不会影响天空。

内置

标记为 in 的值是只读的。标记为 out 的值可以选择性写入,并且它们不一定包含有意义的初始值。采样器(Samplers)不能被写入,因此不做标记。

全局内置变量

全局内置变量在任何地方都可以使用,包括在自定义函数中。

LIGHTX 灯光有 4 个,可以通过 LIGHT0LIGHT1LIGHT2LIGHT3 访问。

内置

描述

in float TIME

自引擎启动以来的全局时间,以秒为单位。它每经过 3,600 秒就会重置循环一次(这个时长可以通过 rollover 设置来修改)。它受 time_scale (时间缩放/游戏速度)的影响,但不受暂停(pausing)的影响。如果你需要一个不受 time_scale 影响的 TIME 变量,可以添加你自己的 global shader uniform ,并在每一帧更新它。

in vec3 POSITION

相机的位置,使用世界空间。

samplerCube RADIANCE

辐射立方体贴图(Radiance cubemap)。只能在背景渲染通道(background pass)中读取。使用前请检查 !AT_CUBEMAP_PASS

in bool AT_HALF_RES_PASS

当正在渲染半分辨率通道时,该值为 true

in bool AT_QUARTER_RES_PASS

当正在渲染四分之一分辨率通道时,该值为 true

in bool AT_CUBEMAP_PASS

当正在渲染辐射立方体贴图(radiance cubemap)时,该值为 true

in bool LIGHTX_ENABLED

如果 LIGHTX (某个光源)在场景中是可见的,则返回 true 。如果返回 false ,那么该光源的其他属性可能包含的是无意义的垃圾数据。

in float LIGHTX_ENERGY

LIGHTX 的能量乘数。

in vec3 LIGHTX_DIRECTION

LIGHTX 面朝的方向。

in vec3 LIGHTX_COLOR

LIGHTX 的颜色。

in float LIGHTX_SIZE

天空中的 LIGHTX (通常指代太阳或月亮等光源)的视直径。以弧度为单位。作为参考,从地球上看太阳的视直径大约是 0.0087 弧度(0.5 度)。

in float PI

常量 PI (值为 3.141592 )。它是圆的周长与直径的比值,也是转半圈(180度)所包含的弧度数。

in float TAU

常量 TAU (值为 6.283185 )。它等同于 PI * 2 ,也就是一个完整圆周(整圈)所包含的弧度数。

in float E

常量 E (值为 2.718281 )。即欧拉数,自然对数的底数。

Sky 内置

内置

描述

in vec3 EYEDIR

当前像素的归一化方向。在制作程序化特效时,可以用它作为基础的方向参考。

in vec2 SCREEN_UV

当前像素的屏幕 UV 坐标。用于将纹理映射到整个屏幕上。

in vec2 SKY_COORDS

球面 UV 坐标。用于将全景纹理映射到天空上。

in vec4 HALF_RES_COLOR

来自半分辨率(half resolution)渲染通道的对应像素颜色值。使用线性滤波。

in vec4 QUARTER_RES_COLOR

来自四分之一分辨率(quarter resolution)渲染通道的对应像素颜色值。使用线性滤波。

out vec3 COLOR

输出颜色。

out float ALPHA

输出 alpha 值,仅能在子阶段中使用。

out vec4 FOG