Up to date

This page is up to date for Godot 4.3. If you still find outdated information, please open an issue.

カスタムポストプロセッシング

はじめに

Godotは、ブルーム、DOF、SSAOを含む多くのポストプロセッシング効果をすぐに利用できます。これらについては 環境とポストプロセッシング で説明されています。でも時々、独自のカスタム効果を作成したい場合もあります。この記事では独自のカスタムエフェクトを作成する方法について説明します。

カスタムのポストプロセッシングシェーダーを実装する最も簡単な方法は、Godotの組み込み機能を使用して画面テクスチャから読み取ることです。これに慣れていない場合は、最初に Screen Reading Shaders Tutorial を読む必要があります。

シングルパス・ポストプロセッシング

ポストプロセッシングエフェクトは、Godotがフレームをレンダリングした後に適用されるシェーダーです。シェーダーをフレームに適用するには CanvasLayer を作成し、それに ColorRect を与えます。新しく作成した ColorRect に新しい Shadermaterial を割り当て、 ColorRect のレイアウトを "Full Rect" に設定します。

シーンツリーは次のようになります。

../../_images/post_tree1.png

注釈

もう1つのより効率的な方法は、 BackBufferCopy を使用して画面の領域をバッファにコピーし、 hint_screen_texture を使用して sampler2D を介してシェーダー内でそれにアクセスすることです。

注釈

この記事の執筆時点では、Godotは複数のバッファへの同時レンダリングをサポートしていません。ポストプロセッシングシェーダーは、Godotによって公開されていない他のレンダー パスやバッファ (深度や法線、ラフネスなど) にアクセスできません。 Godotによってサンプラーとして公開されるレンダリングされたフレームとバッファーにのみアクセスできます。

このデモでは、羊の画像の スプライト を使用します。

../../_images/post_example1.png

新しい ShaderColorRectShaderMaterial に割り当てます。 hint_screen_texture が付いた sampler2D とビルトインの SCREEN_UV を使用してフレームのテクスチャにアクセスできます。

次のコードをシェーダーにコピーします。以下のコードは、arlez80 による六角形化シェーダーです,

shader_type canvas_item;

uniform vec2 size = vec2(32.0, 28.0);
// If you intend to read from mipmaps with `textureLod()` LOD values greater than `0.0`,
// use `filter_nearest_mipmap` instead. This shader doesn't require it.
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

void fragment() {
        vec2 norm_size = size * SCREEN_PIXEL_SIZE;
        bool half = mod(SCREEN_UV.y / 2.0, norm_size.y) / norm_size.y < 0.5;
        vec2 uv = SCREEN_UV + vec2(norm_size.x * 0.5 * float(half), 0.0);
        vec2 center_uv = floor(uv / norm_size) * norm_size;
        vec2 norm_uv = mod(uv, norm_size) / norm_size;
        center_uv += mix(vec2(0.0, 0.0),
                         mix(mix(vec2(norm_size.x, -norm_size.y),
                                 vec2(0.0, -norm_size.y),
                                 float(norm_uv.x < 0.5)),
                             mix(vec2(0.0, -norm_size.y),
                                 vec2(-norm_size.x, -norm_size.y),
                                 float(norm_uv.x < 0.5)),
                             float(half)),
                         float(norm_uv.y < 0.3333333) * float(norm_uv.y / 0.3333333 < (abs(norm_uv.x - 0.5) * 2.0)));

        COLOR = textureLod(screen_texture, center_uv, 0.0);
}

羊の画像は次のようになります。

../../_images/post_example2.png

マルチパス・ポストプロセッシング

ブラーなどのポストプロセッシングエフェクトの中には、リソースを大量に消費するものがあります。ただし複数のパスに分割するとより速く実行できます。マルチパスのマテリアルでは、各パスが前のパスの結果を入力として受け取り、それを処理します。

マルチパスのポストプロセッシングシェーダーを生成するには、 CanvasLayer ノードと ColorRect ノードをスタックします。上の例では CanvasLayer オブジェクトを使用して、下のレイヤ上のフレームを使用してシェーダをレンダリングします。ノード構造を除けば、手順はシングルパス・ポストプロセッシングシェーダーの場合と同じです。

シーンツリーは次のようになります。

../../_images/post_tree2.png

例として、次のコードを各 ColorRect ノードにアタッチすることで、全画面のガウスブラーエフェクトを作成できます。シェーダーを適用する順序は、シーン ツリー内の CanvasLayer の位置によって異なります。高いほど早く適用されることを意味します。このブラーシェーダの場合、順序は重要ではありません。

shader_type canvas_item;

uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

// Blurs the screen in the X-direction.
void fragment() {
    vec3 col = texture(screen_texture, SCREEN_UV).xyz * 0.16;
    col += texture(screen_texture, SCREEN_UV + vec2(SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(-SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(2.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(2.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(3.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(3.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(4.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.05;
    col += texture(screen_texture, SCREEN_UV + vec2(4.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.05;
    COLOR.xyz = col;
}
shader_type canvas_item;

uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

// Blurs the screen in the Y-direction.
void fragment() {
    vec3 col = texture(screen_texture, SCREEN_UV).xyz * 0.16;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, SCREEN_PIXEL_SIZE.y)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, -SCREEN_PIXEL_SIZE.y)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 2.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 2.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 3.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 3.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 4.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.05;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 4.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.05;
    COLOR.xyz = col;
}

上記のコードを使用すると、次のような全画面ブラーエフェクトが得られます。

../../_images/post_example3.png