【Godot】Fragment Shaderの基礎と最初の一歩 - 色変更とエフェクトの実現

作成: 2025-12-08

Godot EngineにおけるFragment Shaderの基本的な役割と、それを使って色変更や簡単な視覚エフェクトを実現する方法を、初心者向けに分かりやすく解説します。

導入:なぜシェーダーを学ぶべきか

Godot Engineでゲーム開発を進める上で、 シェーダー は避けて通れない強力なツールです。シェーダーとは、グラフィックス処理ユニット(GPU)上で実行される小さなプログラムのことで、オブジェクトの見た目、色、光の反射、そして画面全体のエフェクトをピクセル単位で制御します。

なぜシェーダーが重要なのでしょうか?それは、 視覚的な魅力を飛躍的に向上させる と同時に、 高いパフォーマンス を実現できるからです。CPUで複雑な計算を行う代わりに、GPUの並列処理能力を最大限に活用することで、炎、水、カスタムライティング、ユニークな画面トランジションなど、GDScriptだけでは実現が難しい、あるいは重くなりがちな表現を軽快に実現できます。

本記事では、シェーダーの中でも特に視覚的な表現を担う Fragment Shader(フラグメントシェーダー) に焦点を当て、その基礎知識から、色変更や簡単なエフェクトを作成する最初の一歩を、具体的なコード例とともに解説します。

Godotシェーダーの基本構造

Godot Engineのシェーダーは、[GLSL ES 3.0][1]に似た独自のシェーディング言語を使用します。シェーダーファイル(.gdshader)を作成する際、まずそのシェーダーが何に適用されるかを定義する必要があります。

shader_type canvas_item; // 2Dオブジェクトに適用
// shader_type spatial; // 3Dオブジェクトに適用

canvas_itemは2DスプライトやUI要素に、spatialは3Dメッシュに適用されます。

Godotシェーダーは、主に以下の3つの関数(エントリーポイント)で構成されています。

関数名役割実行タイミング
vertexオブジェクトの頂点(位置)を操作します。変形、波打ち、回転などに使用されます。頂点ごとに1回
fragmentピクセル(フラグメント)の色を計算します。 テクスチャのサンプリング、色調整、エフェクトの核となります。ピクセルごとに1回
lightオブジェクトに当たる光の影響を計算します。カスタムライティングの実現に使用されます。光源とピクセルの組み合わせごとに1回

本記事の主役であるfragment関数は、画面上の すべてのピクセル に対して実行され、そのピクセルの最終的な色を決定する役割を担います。

Fragment Shaderの役割と基本

Fragment Shaderの基本構造は非常にシンプルです。

shader_type canvas_item;

void fragment() {
    // ここにピクセルごとの色計算ロジックを記述
}

このfragment関数内で、私たちは主に2つの重要な組み込み変数を使って作業します。

  1. UV (vec2): 現在処理しているピクセルのテクスチャ座標(UV座標)です。値は通常、左上(0.0, 0.0)から右下(1.0, 1.0)の範囲に正規化されています。
  2. COLOR (vec4): Fragment Shaderの 最終的な出力色 を格納する変数です。この変数に値を代入することで、ピクセルの色を決定します。

COLORvec4型で、(R, G, B, A)の4つの浮動小数点数(0.0から1.0の範囲)で構成されます。

実践1: Fragment Shaderで色を変更する

最も基本的なFragment Shaderの使い方は、オブジェクト全体の色を単色に変更することです。

コード例:単色への変更

shader_type canvas_item;

void fragment() {
    // COLOR変数に直接、新しい色を代入します。
    // vec4(R, G, B, A) の形式で、各成分は0.0から1.0の範囲です。
    // 例:鮮やかなマゼンタ(赤と青の最大値、緑はゼロ、不透明度1.0)
    COLOR = vec4(1.0, 0.0, 1.0, 1.0); // マゼンタ
}

このシェーダーをスプライトに適用すると、スプライトのテクスチャに関係なく、全体がマゼンタ色に塗りつぶされます。

コード例:テクスチャの色を反転させる

既存のテクスチャの色を活かしつつ、それを操作したい場合は、texture()関数を使って現在のテクスチャの色を取得し、それを基に計算を行います。

shader_type canvas_item;

void fragment() {
    // 1. 現在のUV座標にあるテクスチャの色を取得します。
    vec4 texture_color = texture(TEXTURE, UV);

    // 2. 色を反転させます。(1.0から元の色を引く)
    // アルファ値(透明度)はそのまま維持します。
    vec3 inverted_rgb = vec3(1.0) - texture_color.rgb;

    // 3. 最終的な出力色COLORに設定します。
    COLOR = vec4(inverted_rgb, texture_color.a);
}

このように、Fragment Shaderはピクセルごとにテクスチャの色を読み取り、計算を施し、新しい色を書き出すという処理を高速に行います。

実践2: UV座標と時間を使ったエフェクト

Fragment Shaderの真価は、 UV 座標や組み込みの TIME 変数といった入力値を使って、動的なエフェクトを作成できる点にあります。

コード例:シンプルなグラデーション

UV座標のx成分(横方向)を使って、左から右へ黒から白へのグラデーションを作成してみましょう。

shader_type canvas_item;

void fragment() {
    // UV.xは左端で0.0、右端で1.0の値を取ります。
    float gradient = UV.x;

    // この値をR, G, Bの各成分に設定します。
    // 例:グレースケールのグラデーション
    COLOR = vec4(gradient, gradient, gradient, 1.0);
}

コード例:UV座標を使った円形マスク

UV 座標の中心からの距離を利用して、円形のマスクエフェクトを作成してみましょう。これは、スポットライトや爆発の波紋など、様々なエフェクトの基礎となります。

shader_type canvas_item;

void fragment() {
    // 1. UV座標を中央(0.5, 0.5)が原点となるように変換します。
    vec2 centered_uv = UV - vec2(0.5);

    // 2. 原点からの距離を計算します。(length関数を使用)
    float distance = length(centered_uv);

    // 3. 距離に基づいてアルファ値(透明度)を決定します。
    // smoothstep関数を使って、0.3から0.4の距離で滑らかに透明になるようにします。
    float alpha = 1.0 - smoothstep(0.3, 0.4, distance);

    // 4. 元のテクスチャの色を取得します。
    vec4 texture_color = texture(TEXTURE, UV);

    // 5. 最終的な出力色に、計算したアルファ値を適用します。
    COLOR = vec4(texture_color.rgb, texture_color.a * alpha);
}

このコードにより、スプライトの中心から一定の距離(この例では0.4)を超えると、オブジェクトが徐々に透明になる円形のマスクが適用されます。 UV 座標を操作することで、ピクセル単位での複雑な形状制御が可能になることが分かります。

コード例:時間で変化する色のアニメーション

組み込みの TIME ユニフォーム(シェーダーが実行されてからの経過時間、秒単位)を使うと、簡単にアニメーションを実現できます。

shader_type canvas_item;

void fragment() {
    // sin関数を使って、TIMEを0.0から1.0の範囲で周期的に変化させます。
    // sin(x)は-1.0から1.0の範囲なので、(sin(x) * 0.5 + 0.5)で0.0から1.0に変換します。
    float r = sin(TIME * 2.0) * 0.5 + 0.5; // 赤成分を時間で変化
    float g = cos(TIME * 1.5) * 0.5 + 0.5; // 緑成分を時間で変化
    float b = 0.5; // 青成分は固定

    // 最終的な出力色を設定します。
    COLOR = vec4(r, g, b, 1.0);
}

このコードを適用すると、スプライトの色が時間とともに滑らかに変化し続ける、サイケデリックなエフェクトが実現します。 TIME を使うことで、 ノードの_process()関数を使わずに、GPU上でアニメーションが完結するため、非常に効率的です。

実践3: テクスチャのスクロールアニメーション

Fragment Shaderの最も実用的な応用例の一つが、テクスチャのスクロールです。水面や炎、ベルトコンベアなどの表現に不可欠です。

コード例:テクスチャの水平スクロール

UV 座標に TIME を加算することで、テクスチャを時間とともに移動させることができます。

shader_type canvas_item;

void fragment() {
    // 1. UV座標のx成分にTIMEをゆっくりと加算します。
    // 0.1はスクロール速度を調整するための係数です。
    vec2 scrolled_uv = UV + vec2(TIME * 0.1, 0.0);

    // 2. 新しいUV座標でテクスチャをサンプリングします。
    vec4 texture_color = texture(TEXTURE, scrolled_uv);

    // 3. 最終的な出力色を設定します。
    COLOR = texture_color;
}

このテクニックは、背景の星空を流したり、水が流れる様子を表現したりする際に非常に有効です。 UV 座標の操作は、Fragment Shaderの応用において最も重要な概念の一つです。

まとめ:Fragment Shaderの次なる一歩

本記事では、Godot EngineにおけるFragment Shaderの基本的な役割、構造、そして色変更や簡単なアニメーションを実現する方法を学びました。

Fragment Shaderは、ピクセルごとの色を計算する強力なツールであり、 UV 座標や TIME といった組み込み変数を活用することで、無限の視覚エフェクトを生み出すことができます。

本記事の要点:

  • シェーダーはGPUで実行され、高いパフォーマンスで視覚表現を制御します。
  • fragment 関数はピクセルごとの色を決定し、 COLOR 変数に出力します。
  • UV 座標はテクスチャ上の位置を示し、グラデーションや座標ベースのエフェクトに不可欠です。
  • TIME ユニフォームを使うことで、効率的な時間ベースのアニメーションが可能です。

この基礎をマスターしたら、次は外部から値を渡す ユニフォーム(Uniforms) を学び、GDScriptからシェーダーのパラメーターを制御する方法や、 vertex シェーダーを使ったオブジェクトの変形に挑戦してみましょう。Fragment Shaderの知識は、あなたのゲームのビジュアルを次のレベルへと引き上げる鍵となるはずです。

次のステップ:Uniformsでシェーダーを制御する

Fragment Shaderをより実践的に活用するためには、外部から値を渡す仕組みである Uniforms(ユニフォーム) の理解が不可欠です。Uniformsは、GDScriptなどのCPU側のコードからシェーダー内の変数に値を送るための「窓口」のようなものです。

例えば、エフェクトの強さ、色、アニメーションの速度などを、ゲームの実行中に動的に変更したい場合にUniformsを使用します。

Uniformsの宣言例

シェーダーファイルの先頭で、以下のようにUniformsを宣言します。

shader_type canvas_item;

// エフェクトの強さをGDScriptから設定できるようにする
uniform float effect_strength : hint_range(0.0, 1.0) = 0.5;

// エフェクトの色をGDScriptから設定できるようにする
uniform vec4 effect_color : hint_color = vec4(1.0, 0.0, 0.0, 1.0);

このように宣言された変数は、GDScriptからmaterial.set_shader_parameter("effect_strength", value)のようなメソッドを通じてアクセス・変更が可能になります。これにより、シェーダーは単なる静的な見た目の設定ではなく、ゲームロジックと連携した動的な表現ツールへと進化します。

Fragment Shaderの知識は、あなたのゲームのビジュアルを次のレベルへと引き上げる鍵となるはずです。