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

はじめに

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

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

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

Post-processing effects are shaders applied to a frame after Godot has rendered it. To apply a shader to a frame, create a CanvasLayer, and give it a ColorRect. Assign a new ShaderMaterial to the newly created ColorRect, and set the ColorRect's anchor preset to Full Rect:

Setting the anchor preset to Full Rect on the ColorRect node

Setting the anchor preset to Full Rect on the ColorRect node

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

../../_images/post_tree1.png

注釈

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

注釈

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

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

../../_images/post_example1.png

Assign a new Shader to the ColorRect's ShaderMaterial. You can access the frame's texture and UV with a sampler2D using hint_screen_texture and the built-in SCREEN_UV uniforms.

次のコードをシェーダーにコピーします。以下のコードは、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 less_than_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(less_than_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(less_than_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