mcpField
D
defold-shaders-editing

defold-shaders-editing

github.com/indiesoftby開発10449 回インストール27 週間前に更新
リポジトリ

defold-shaders-editing について

Defold の GLSL シェーダーファイルを作成・編集するスキルです。頂点・フラグメントプログラム、再利用可能なコード片、現代的な構文、マテリアルとの連携を扱います。

主な機能

  1. 01.vp、.fp、.glsl ファイルの編集
  2. 02現代的な GLSL 構文の指針
  3. 03シェーダーとマテリアルのデータ連携
  4. 04クロスコンパイルの制約を説明

活用シーン

  1. 01Defold の頂点・フラグメントシェーダー作成
  2. 02再利用可能な GLSL コード片の追加
  3. 03シェーダー変数とマテリアル設定の整合

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/indiesoftby/defold-agent-config --skill defold-shaders-editing

インストール後、Claude Code で/defold-shaders-editingを入力して読み込まれたか確認します。

詳細

Defold シェーダーの編集

Defold のシェーダーファイル(頂点プログラム(.vp)、フラグメントプログラム(.fp)、GLSL インクルードスニペット(.glsl))を作成および編集します。

使用する場面

このスキルでは、Defold のレンダリングパイプラインで使用する GLSL シェーダーファイルを扱います。.material ファイルは対象外です。そちらには defold-proto-file-editing スキルを使用してください(references/material.md を参照)。

シェーダーパイプラインと GLSL バージョン

Defold は 2 つのシェーダーパイプラインに対応しています。

  1. レガシーパイプライン — OpenGL ES 2.0 互換の GLSL(#version ディレクティブなし)で記述されたシェーダーです。Defold 1.9.2 以降は非推奨です。
  2. モダンパイプライン — SPIR-V 互換の GLSL(#version 140 以上)で記述されたシェーダーです。現在の標準です。

シェーダーは必ず、ファイルの先頭に #version 140(OpenGL 3.1)を指定して記述してください。 このディレクティブにより、ビルドプロセスでモダンパイプラインが選択されます。#version が見つからない場合、Defold はレガシーパイプラインにフォールバックします。

#version 140
クロスコンパイルとプラットフォームのターゲット

Defold は、1 つの GLSL ソースから複数のグラフィックス API 向けにシェーダーをコンパイルします。

  • OpenGL 3.x / 4.x(デスクトップ:Windows、macOS、Linux)
  • OpenGL ES 2.0 / 3.0(モバイル:Android、iOS)
  • WebGL 1.0 / 2.0(HTML5)
  • SPIR-V(Android、デスクトップでの Vulkan)
  • Metal(iOS、macOS — SPIR-V クロスコンパイル経由)

このようにクロスコンパイルするため、すべての GLSL 機能がどの環境でも利用できるわけではありません。一部の関数(例:dFdx、dFdy、fwidth)は ES 2.0 / WebGL 1.0 のターゲットでは拡張機能が必要ですが、ES 3.0 以降 / デスクトップ GL では組み込み機能です。条件付き機能には #extension とプリプロセッサーガードを使用してください。

#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif

#if !defined(GL_ES) || __VERSION__ >= 300 || defined(GL_OES_standard_derivatives)
    // Use derivative functions
#else
    // Provide fallback
#endif

留意すべき主な制限事項:

  • 境界が変数で決まる動的ループは、ES 2.0 / WebGL 1.0 では動作しない場合があります
  • ES 2.0 では整数演算に制限があります
  • sampler2DArray には ES 3.0 以降 / WebGL 2.0 以降が必要です
  • ストレージバッファーとコンピュートシェーダーには Vulkan / Metal が必要です

ファイルの種類

頂点プログラム(.vp)

頂点ごとに 1 回実行されます。頂点の位置をモデル/ワールド空間からスクリーン空間に変換します。gl_Position を出力し、out 変数を介してフラグメントシェーダーにデータを渡します。

フラグメントプログラム(.fp)

フラグメント(ピクセル)ごとに 1 回実行されます。最終的な色を計算します。ユーザー定義の out vec4 変数に出力します(#version 140 では非推奨の gl_FragColor は使用しません)。

GLSL インクルードスニペット(.glsl)

.vp または .fp ファイルから #include で読み込む、再利用可能な GLSL コードです。単独では実行されません。二重インクルードを防ぐため、ヘッダーガードを使用してください。

モダン GLSL の構文ルール(#version 140)

Attributes → in

頂点シェーダーでは、attribute の代わりに in を使用します。

in highp vec4 position;
in mediump vec2 texcoord0;

フラグメントシェーダーには頂点属性はありません。

Varyings → out / in

頂点シェーダーでは、varying の代わりに out を使用します。フラグメントシェーダーでは in を使用します。

// vertex shader
out mediump vec2 var_texcoord0;

// fragment shader
in mediump vec2 var_texcoord0;
フラグメント出力 → out vec4

非推奨の gl_FragColor の代わりに、宣言した out 変数を使用します。

out vec4 out_fragColor;

void main()
{
    out_fragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
Uniform ブロック

不透明型ではない uniform(行列、ベクトル、浮動小数点数)は、uniform ブロックに配置する必要があります。頂点シェーダーには vs_uniforms、フラグメントシェーダーには fs_uniforms を使用してください(慣例によるものです)。

uniform vs_uniforms
{
    highp mat4 view_proj;
};

不透明型の uniform(サンプラー、イメージ)は、単独のままにします。

uniform mediump sampler2D texture_sampler;

uniform ブロックのメンバーには、ブロック名を付けずに名前で直接アクセスします。

gl_Position = view_proj * vec4(position.xyz, 1.0);
テクスチャサンプリング → texture()

非推奨の texture2D() / texture2DArray() の代わりに texture() を使用します。

vec4 color = texture(texture_sampler, var_texcoord0.xy);
精度修飾子

#version 140 では明示的な精度(lowp、mediump、highp)は任意です。パイプラインが、精度指定を必要とするプラットフォーム向けに自動設定します。ただし、明確にするため、またはプロジェクト内の既存コードのスタイルに合わせるために使用してもかまいません。周囲のファイルの規約に従ってください。

エディター固有のコード(EDITOR define)

Defold Editor のビューポートでシェーダーがレンダリングされるとき、プリプロセッサー define EDITOR を使用できます。#ifdef EDITOR を使って、エディターとゲームで動作を変えるコードを記述します。

#ifdef EDITOR
    // Simplified rendering for editor preview
    out_fragColor = texture(texture_sampler, var_texcoord0.xy);
#else
    // Full rendering with effects for the game
    out_fragColor = apply_effects(texture(texture_sampler, var_texcoord0.xy));
#endif

一般的な用途:

  • パフォーマンス向上のため、エディターでは負荷の高いエフェクト(RGSS、ポストプロセッシング)を無効にする
  • プレビューが適切に表示されないマテリアルに、デバッグ用またはフォールバック用のビジュアルを表示する
  • 実行時のみのデータに依存する機能(例:スキニング)をスキップする

スニペットのインクルード(#include)

シェーダーファイルでは、プロジェクト相対パスまたはファイル相対パスを指定して、#include で .glsl スニペットをインクルードできます。

// Absolute (project-relative) path
#include "/main/my-snippet.glsl"

// Relative to current file
#include "my-snippet.glsl"
#include "../shared/utils.glsl"

ルール:

  • インクルードできるのは .glsl ファイルのみです
  • パスはプロジェクト内(またはライブラリー依存関係内)である必要があります
  • 絶対パスは / で始まります
  • #include を文の途中で使用することはできません
ヘッダーガード

二重インクルードを防ぐため、.glsl スニペットではヘッダーガードを使用します。

#ifndef MY_SNIPPET_GLSL
#define MY_SNIPPET_GLSL

// ... snippet code ...

#endif // MY_SNIPPET_GLSL

マテリアルとの関係

シェーダーとマテリアル(.material)は密接に連携しています。マテリアルファイルは、シェーダーが受け取るデータを定義します。マテリアルファイルを編集する場合は、defold-proto-file-editing スキルを使用してください(参照:references/material.md)。

定数(ユニフォーム)

マテリアルの vertex_constants / fragment_constants で宣言された定数は、シェーダー内のユニフォーム変数になります。ユニフォームブロック内に配置してください。

マテリアルの定数型シェーダーのユニフォーム型説明
CONSTANT_TYPE_VIEWPROJmat4ビュー行列 × プロジェクション行列を結合した行列
CONSTANT_TYPE_WORLDmat4ワールド変換行列
CONSTANT_TYPE_VIEWmat4ビュー(カメラ)行列
CONSTANT_TYPE_PROJECTIONmat4プロジェクション行列
CONSTANT_TYPE_WORLDVIEWmat4ワールド行列 × ビュー行列
CONSTANT_TYPE_WORLDVIEWPROJmat4ワールド行列 × ビュー行列 × プロジェクション行列
CONSTANT_TYPE_NORMALmat4法線行列 — transpose(inverse(view * world))。ワールド空間ではなく、ビュー空間の法線を生成します。
CONSTANT_TYPE_USERvec4カスタムデータ。go.set() / go.animate() で変更可能
CONSTANT_TYPE_USER_MATRIX4mat4カスタム行列データ。go.set() で変更可能

マテリアルの name は、ユニフォームブロック内の変数名と一致している必要があります。

サンプラー

マテリアルの samplers セクションで宣言されたサンプラーは、sampler2D ユニフォームになります。マテリアルのサンプラー name は、シェーダーのユニフォーム名と一致している必要があります。

uniform mediump sampler2D texture_sampler;  // Matches samplers { name: "texture_sampler" ... }

スプライト、タイルマップ、GUI、パーティクルでは、最初の sampler2D がコンポーネントの画像に自動的にバインドされます。

頂点属性

マテリアルの attributes セクションで宣言された属性(またはエンジンが提供するデフォルト属性)は、頂点シェーダー内の in 変数になります。

コンポーネントの種類ごとのデフォルト属性:

コンポーネント属性
スプライトposition、texcoord0
タイルマップposition、texcoord0
GUI ノードposition、texcoord0、color
ParticleFXposition、texcoord0、color
モデルposition、texcoord0、normal
フォントposition、texcoord0、face_color、outline_color、shadow_color
頂点空間

マテリアルの vertex_space 設定は、位置データがどのように渡されるかに影響します。

  • VERTEX_SPACE_WORLD(デフォルト)— 位置はワールド空間に事前変換されています。2D コンポーネント(スプライト、タイルマップ)で使用します。view_proj(または CONSTANT_TYPE_VIEWPROJ)を使って、スクリーン空間へ直接変換します。
  • VERTEX_SPACE_LOCAL — 位置はローカル/オブジェクト空間にあります。3D モデルで使用します。シェーダー内で world → view → projection を通して変換する必要があります。
インスタンシング

インスタンス化レンダリング(Model コンポーネント)では、mtx_world と mtx_normal をユニフォームではなく in 属性として宣言します。

in mediump mat4 mtx_world;
in mediump mat4 mtx_normal;

マテリアルには vertex_space: VERTEX_SPACE_LOCAL を設定する必要があります。これらの属性は、インスタンスごとのステップ関数用に自動的に設定されます。

法線行列(mtx_normal)— ビュー空間とワールド空間

組み込みの CONSTANT_TYPE_NORMAL は、CPU 上で transpose(inverse(view * world)) を計算します。これにより、法線はワールド空間ではなくビュー空間(カメラ空間)で得られます。

ビュー空間の法線で問題ない場合:

  • すべてのライティング計算をビュー空間で行う場合
  • カメラ位置が暗黙的に原点 (0,0,0) にある場合(スペキュラー計算が簡単になります)

ワールド空間の法線が必要な場合:

  • キューブマップ反射、環境マッピング
  • ワールド空間でのライティング、ワールド空間のエフェクト

ワールド空間の法線を得るには、随伴行列のトリックを使って頂点シェーダー内で mtx_world から法線行列を計算します(完全な inverse() より低コストです。余因子展開の代わりに外積を 3 回計算します)。

// transpose(adjugate(M)) for upper-left 3x3 of mat4.
// Equivalent to transpose(inverse(M)) up to a uniform scale factor,
// which is eliminated by normalize().
mat3 adjoint(mat4 m)
{
    return mat3(
        cross(m[1].xyz, m[2].xyz),
        cross(m[2].xyz, m[0].xyz),
        cross(m[0].xyz, m[1].xyz)
    );
}

頂点シェーダーでの使用方法:

var_world_normal = normalize(adjoint(mtx_world) * normal.xyz);
目的方法
ビュー空間の法線組み込みの mtx_normal(CONSTANT_TYPE_NORMAL)を使用
ワールド空間の法線シェーダー内で normalize(adjoint(mtx_world) * normal.xyz) を計算

重要なルール: 座標空間を混在させないでください。ライトの方向がワールド空間にある場合、法線もワールド空間にする必要があります。

標準的な例

組み込み参照シェーダー

標準的なシェーダーの参考として .deps/builtins/materials/ を使用します。

  • sprite.vp / sprite.fp — 2D スプライト(ワールド空間、view_proj、tint)
  • model.vp / model.fp — ライティングを含む 3D モデル(ローカル空間、mtx_worldview、mtx_normal、light)
  • model_instanced.vp — インスタンシングを使用する 3D モデル(mtx_world、mtx_normal を in 属性として使用)
  • gui.vp / gui.fp — GUI ノード(ワールド空間、color 属性、乗算済みアルファ)
  • particlefx.vp / particlefx.fp — パーティクルエフェクト
  • tile_map.vp / tile_map.fp — タイルマップ
  • skinning.glsl — スケルタルアニメーション用インクルード(フォールバックに #ifdef EDITOR を使用)
GLSL インクルードのスニペット(ヘッダーガードと拡張機能を含む)
#ifndef MY_UTILS_GLSL
#define MY_UTILS_GLSL

#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif

// Utility function available on platforms that support derivatives
#if !defined(GL_ES) || __VERSION__ >= 300 || defined(GL_OES_standard_derivatives)
mediump float edge_smoothing(mediump float dist)
{
    return smoothstep(0.0, fwidth(dist), dist);
}
#else
mediump float edge_smoothing(mediump float dist)
{
    return step(0.0, dist);
}
#endif

#endif // MY_UTILS_GLSL

ワークフロー

新しいシェーダーペア(.vp + .fp)の作成
  1. コンポーネントの種類(スプライト、モデル、GUI など)を確認し、使用する属性と頂点空間を把握します。
  2. 対応する .material ファイルを確認する(または作成を計画する)ことで、シェーダーが受け取る定数、サンプラー、属性を把握します。マテリアルの編集には defold-proto-file-editing スキルを使用します。
  3. 両方のファイルの先頭に #version 140 を記述します。
  4. .vp では、in 属性、out バリアリング、定数を含むユニフォームブロックを宣言し、gl_Position を計算します。
  5. .fp では、in バリアリング、色出力用の out vec4、サンプラー、ユニフォームブロックを宣言し、出力色を計算します。
  6. ユニフォーム名がマテリアルの定数名と完全に一致することを確認します。
  7. サンプラー名がマテリアルのサンプラー名と完全に一致することを確認します。
GLSL インクルードのスニペットの作成
  1. .glsl ファイルを作成します。
  2. ヘッダーガード(#ifndef / #define / #endif)を追加します。
  3. すべてのターゲットで利用できるわけではない機能を使う場合は、プリプロセッサーガードとともに #extension ディレクティブを追加します。
  4. 再利用可能な関数または定数を記述します。
既存のシェーダーの編集
  1. 現在のシェーダーファイルと対応する .material ファイルを読みます。
  2. 要求された部分のみを変更します。
  3. 既存のコードスタイル(精度修飾子、命名、空白)を維持します。
  4. 新しいユニフォームはすべてマテリアルファイルにも追加します(defold-proto-file-editing スキルを使用)。
  5. 削除したユニフォームはマテリアルファイルからも削除します。

コメント