ディザ抜きと呼ばれる手法を使うと半透明の表現ができます。
半透明といえばアルファブレンドですが、最近のゲームではアルファブレンドの代わりとしてディザ抜きがよく用いられています。
ディザ抜き
ディザ抜きはアルファブレンドに比べて若干ジャギジャギ感はありますが、次のメリットがあります。
- 描画コストが軽い(不透明レンダリングなので)
- 描画順を考えなくていい
- 重ねた時に破綻しない
- 内部のポリゴンが透けて見えない
Godotでディザ抜きをする
Godotでディザ抜きする方法を解説します。
BayerMatrix画像を用意する
ディザ抜きにはBayerMatrixというものを使用します。
0/16 | 8/16 | 2/16 | 10/16 |
12/16 | 4/16 | 14/16 | 6/16 |
3/16 | 11/16 | 1/16 | 9/16 |
15/16 | 7/16 | 13/16 | 5/16 |
このパラメータをグレイスケール化した4x4の小さな画像テクスチャを用意します。
テクスチャのインポート設定を次のように設定します。
- Compress ModeをLosslessにする
- FilterをOFFにする
ディザ抜きシェーダを書く
次にディザ抜きするシェーダを書きます。
- フラグメントシェーダでBayerMatrixテクスチャをFRAGCOORDで参照
- dither値とAlpha値と比較して抜く場合は
discard
構文でフラグメント処理を打ち切る
shader_type spatial; uniform sampler2D Texture; // モデルのテクスチャ uniform sampler2D Bayer; // 4x4のBayerMatrix画像 uniform float Alpha = 1.0; // アルファパラメータ (0.0~1.0) void fragment() { float dither = texture(Bayer, FRAGCOORD.xy * 0.25).r; if (dither >= Alpha) discard; ALBEDO = texture(Texture, UV).rgb; }
シェーダパラメータをスクリプトから設定する
AlphaパラメータをShaderMaterialに設定します。 (TextureとBayerは事前にセットしておきます。)
extends MeshInstance const DURATION = 1.0 var alpha = 0.0 var fade_mode = 0 func _process(delta): # スペースキーを押すとフェードアニメーションを開始 if Input.is_action_just_pressed("ui_accept"): if fade_mode == 0: if alpha < 0.5: fade_mode = 1 else: fade_mode = -1 if fade_mode < 0: alpha -= delta / DURATION if alpha <= 0.0: alpha = 0.0 fade_mode = 0 if fade_mode > 0: alpha += delta / DURATION if alpha >= 1.0: alpha = 1.0 fade_mode = 0 # ShaderMaterialに値をセット var mat = material_override as ShaderMaterial mat.set_shader_param("Alpha", alpha)