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でものを吸い込むゲームを作ってみたかったのですが、どうすればよいか分からず...。
とりあえず制作を進められそうなものができたので、ちょうど記事を書きました。
もっと良い方法がありそうです。 精進します。
ありがとうございました。


Discussion