🛸

Godot: 指定した高さより上を描画しないシェーダー

に公開

はじめに

Godot Engine Advent Calendar 2025 参加しました。

過去の自分が知りたかった内容を書きました。 学び始めたばかりという予防線を張ります。

以下のようなUFOに吸い込む表現を作りたいとします。
穴より上にある物体が描画されないようにしたいですね。

実装

ここでは3Dモデルを特定の位置より上で描画しないようにします。
描画を消したいモデルに対して、shaderを設定し、textureをアタッチします。

shader_type spatial;

render_mode blend_mix, cull_back ;

uniform sampler2D albedo_texture: source_color;
uniform float threshold_height = 100.0;

varying float world_y;

void vertex() {
    world_y = (MODEL_MATRIX * vec4(VERTEX, 1.0)).y;
}

void fragment() {
    if (world_y > threshold_height) {
        discard;
    }

    ALBEDO = texture(albedo_texture, UV).rgb;
}

3DモデルのSurface Material OverrideにShaderとAlbedoを設定します。

scene Surface Material Override

shaderの理解

一個ずつ何してるかを見てみます。

shader_type spatial;

spatial: 3D rendering用なのでこれを指定します。

spatial for 3D rendering. [1]

render_mode blend_mix cull_back

blend_mix 通常のalpha blend
cull_back 背面を描画しない
(この二つはdefaultなので、省略しても同じ挙動になります [2])

uniform sampler2D albedo_texture: source_color;

uniform: shader外から渡される変数の宣言
sampler2D: 2D テクスチャ用の型
albedo_texture: 変数名
source_color: 色テクスチャとして扱う指定

uniform float threshold_height = 100.0;

この値より上を描画しないようにします。

varying float world_y;

Varying(可変)
Varyingは、頂点シェーダーからフラグメントシェーダーに渡すことができる変数の一種です。 [3]

vertex()

void vertex() {
    world_y = (MODEL_MATRIX * vec4(VERTEX, 1.0)).y;
}

各頂点の world座標系の y座標を計算して、 フラグメントシェーダーで使えるように渡しています。

  • MODEL_MATRIX ローカル空間からワールド空間への変換行列です。
  • vec4(VERTEX, 1.0) 頂点座標(3次元) に w = 1.0をつけてvec4の同次座標として扱い、行列計算できるようにします。[4]

fragment()

void fragment() {
    if (world_y > threshold_height) {
        discard;
    }

    ALBEDO = texture(albedo_texture, UV).rgb;
}

threshold_heightより大きければ、discardで、そのpixelの描画自体を行いません。
透明にするなら ALPHA = 0.0; でもよさそうです。

ALBEDO = texture(albedo_texture, UV).rgb;
UV はmeshの各頂点にあらかじめ設定されているtextureの座標です。
今描こうとしているpixelがtextureのどの位置に対応するか から、 設定したtextureから色を取得して表面色ALBEDOに設定します。

最後にthreshold_heightを動的に変えるようなscriptを書きます。
上のgifでは吸い込む物体の高さに連動させています。

_shader = _model.get_child(0).get_surface_override_material(0)
_shader.set_shader_parameter("threshold_height", height)

作りたかった経緯など

UFOでものを吸い込むゲームを作ってみたかったのですが、どうすればよいか分からず...。

とりあえず制作を進められそうなものができたので、ちょうど記事を書きました。
もっと良い方法がありそうです。 精進します。
ありがとうございました。

脚注
  1. Introduction to shaders — Godot Engine (stable) documentation in English ↩︎

  2. Spatial(3D)シェーダー — Godot Engine (4.x)の日本語のドキュメント ↩︎

  3. GLSLからGodotシェーダーへの変換 — Godot Engine (4.x)の日本語のドキュメント ↩︎

  4. CanvasItem(2D)シェーダー — Godot Engine (4.x)の日本語のドキュメント ↩︎

Discussion