mcpField
W
webgl-shader-constraints

webgl-shader-constraints

github.com/adevra開発1643 回インストール31 週間前に更新
リポジトリ

webgl-shader-constraints について

ブラウザー向けに Unity を開発する人のためのリファレンススキルです。WebGL 1.0 と 2.0 の制約や回避策、シェーダーバリアント削減などの最適化を扱います。

主な機能

  1. 01WebGL 1.0 と 2.0 の制約
  2. 02ループと配列インデックスの回避策
  3. 03シェーダーバリアントの削減
  4. 04テクスチャとメモリの指針
  5. 05WebGL のパフォーマンス指針

活用シーン

  1. 01ブラウザービルドだけで失敗するシェーダーの調査
  2. 02シェーダービルド容量と初回コンパイル時間の削減
  3. 03Unity シェーダーの WebGL 1.0 または 2.0 対応

インストール

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

$npx skills add https://github.com/adevra/unity-shader-agent-skills --skill webgl-shader-constraints

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

詳細

Unity の WebGL シェーダーの制約と回避策

トリガー

ユーザーが WebGL ブラウザー向けに Unity シェーダーを開発している場合に、このスキルを使用します。トリガーには、「WebGL」、「ブラウザーゲーム」、「Web ビルド」、「WebGL 1.0」、「WebGL 2.0」、「WebGPU」、「GLSL」、「OpenGL ES 2.0/3.0」、「Web でのシェーダーコンパイル」、「Web ビルドサイズ」、「Web 向けシェーダーバリアント」、「Always Included Shaders」、または Unity コンテンツのブラウザーへのデプロイに関する言及が含まれます。Web ビルドでのみシェーダーエラーが発生したという報告があった場合や、シェーダーに関連するビルドサイズの問題を扱う場合も、このスキルを使用します。


基本ルール

  1. WebGL 1.0(OpenGL ES 2.0)では動的な配列インデックス指定が禁止されています。 配列のインデックスには、定数またはループカウンター変数のみを使用できます。WebGL 1.0 でシェーダーエラーが発生する最大の原因です。

  2. WebGL 1.0 で使用できるのはカウント付きの for ループのみです。 while ループや do-while ループは使用できません。ループカウンターの初期化、比較、インクリメントは、for 文内で行う必要があります。ループの上限は定数式でなければなりません。

  3. WebGL 2.0(OpenGL ES 3.0)ではループとインデックス指定の制約がなくなりますが、精度修飾子が必須になります。 すべての変数には明示的な精度(highp、mediump、lowp)を指定するか、デフォルトの精度宣言を使用する必要があります。

  4. WebGL がサポートするのはベイク済み GI と非方向性ライトマップのみです。 リアルタイム GI、方向性ライトマップ、L2 球面調和関数を使用したライトプローブは使用できません。

  5. WebGL ビルドでは Standard Shader を使用しないでください。 数百ものバリアントがコンパイルされ、ビルドサイズが 50MB 以上増えることがあります。最小限のキーワードを使用した Simple Lit、Unlit、またはカスタムシェーダーを使用してください。

  6. Web 向けのシェーダーバリアントを積極的にストリップしてください。 バリアントごとにダウンロードサイズと初回のシェーダーコンパイル時間が増加し、ブラウザーのメインスレッドがブロックされます。


WebGL 1.0 と 2.0 の機能比較

機能WebGL 1.0(ES 2.0)WebGL 2.0(ES 3.0)
配列のインデックス指定定数/ループインデックスのみ動的なインデックス指定が可能
ループカウント付きの for のみすべてのループ形式
GPU インスタンシング不可可能
3D テクスチャ不可可能
テクスチャ配列不可可能
整数テクスチャ不可可能
texelFetch不可可能
ユニフォームバッファオブジェクト不可可能
頂点テクスチャユニット0 が保証される≥16 が保証される
MRT(マルチプルレンダーターゲット)不可可能
デファードレンダリング不可能可能(ただし高コスト)
方向性ライトマップ不可不可(Unity の制限)
精度修飾子任意必須

ループとインデックス指定の回避策(WebGL 1.0)

// FAILS on WebGL 1.0 — dynamic array indexing
half4 colors[4];
int index = someCalculation();
half4 result = colors[index]; // ERROR: non-constant index

// WORKAROUND — unroll with if/else
half4 result;
if (index == 0) result = colors[0];
else if (index == 1) result = colors[1];
else if (index == 2) result = colors[2];
else result = colors[3];

// FAILS on WebGL 1.0 — while loop
int i = 0;
while (i < count) { /* ... */ i++; } // ERROR

// WORKAROUND — counting for loop with constant bound
for (int i = 0; i < 16; i++) // 16 is a constant
{
    if (i >= count) break; // dynamic exit
    // ... loop body
}

// FAILS on WebGL 1.0 — non-constant loop bound
for (int i = 0; i < _DynamicCount; i++) { } // ERROR

// WORKAROUND — constant max with early break
#define MAX_ITERATIONS 32
for (int i = 0; i < MAX_ITERATIONS; i++)
{
    if (i >= _DynamicCount) break;
    // ... loop body
}

Web 向けシェーダーバリアントのストリッピング

シェーダーバリアントは、WebGL のビルドサイズを増加させる最大の要因です。各バリアントは、ブラウザーでダウンロードしてコンパイルする必要があります。

ステップ 1: Always Included Shaders を削除する

Project Settings > Graphics > Always Included Shaders で、不要なものをすべて削除します。Standard Shader だけでも数百のバリアントが追加されます。

ステップ 2: multi_compile の代わりに shader_feature を使用する
// BAD for web — compiles ALL keyword combinations
#pragma multi_compile _ _FEATURE_A
#pragma multi_compile _ _FEATURE_B
// = 4 variants (2 × 2)

// GOOD for web — only compiles variants used by materials in build
#pragma shader_feature _ _FEATURE_A
#pragma shader_feature _ _FEATURE_B
// = only variants referenced by materials in scenes
ステップ 3: ローカルキーワードを使用する(シェーダーあたり最大 64 個)
// Global keywords (shared pool of 256, wasteful)
#pragma multi_compile _ _MY_KEYWORD

// Local keywords (per-shader pool of 64, efficient)
#pragma shader_feature_local _ _MY_KEYWORD
ステップ 4: Web 向けの条件付きコンパイル
// Strip expensive features on WebGL
#if !defined(SHADER_API_GLES) && !defined(SHADER_API_GLES3)
    // Desktop-only features here (SSR, complex lighting, etc.)
#endif

// Or target mobile/web specifically
#if defined(SHADER_API_MOBILE) || defined(SHADER_API_GLES) || defined(SHADER_API_GLES3)
    // Simplified mobile/web path
#else
    // Full desktop path
#endif
ステップ 5: IPreprocessShaders を使用したプログラムによるストリッピング
using UnityEditor.Build;
using UnityEditor.Rendering;
using System.Collections.Generic;

class WebGLShaderStripper : IPreprocessShaders
{
    public int callbackOrder => 0;
    
    public void OnProcessShader(Shader shader, ShaderSnippetData snippet, 
                                 IList<ShaderCompilerData> data)
    {
        for (int i = data.Count - 1; i >= 0; i--)
        {
            // Strip deferred variants (useless on WebGL)
            if (snippet.passType == PassType.Deferred)
            {
                data.RemoveAt(i);
                continue;
            }
            
            // Strip specific keywords
            var keywords = data[i].shaderKeywordSet;
            if (keywords.IsEnabled(new ShaderKeyword("_SHADOWS_SOFT")) ||
                keywords.IsEnabled(new ShaderKeyword("_ADDITIONAL_LIGHTS")))
            {
                data.RemoveAt(i);
            }
        }
    }
}

WebGL のパフォーマンスに関するヒント

  1. シェーダーのコンパイル中はメインスレッドがブロックされます。 ネイティブビルドとは異なり、WebGL はシェーダーを同期的にコンパイルします。シェーダーが多いと、初回ロード時に長時間フリーズします。バリアント数を最小限にしてください。

  2. Web 向けには Built-in ではなく URP を使用します。 適切に設定した URP は、ビルドサイズが小さく、シェーダーバリアントも少なくなります。

  3. テクスチャ圧縮は重要です。 WebGL 2.0 では ASTC(推奨)または ETC2 を使用します。DXT/BC 形式が動作するのはデスクトップブラウザーのみです。

  4. メモリには厳しい制限があります。 WebGL はブラウザーのメモリーサンドボックス内で実行されます。シェーダーバリアントのコレクションが大きいと、OOM クラッシュが発生することがあります。

  5. モバイルブラウザーでテストしてください。 iOS Safari の WebGL パフォーマンスはデスクトップ版 Chrome より大幅に劣ります。デスクトップ版 Chrome では動作する多くのエフェクトが、モバイル版 Safari では動作しない、またはカクつくことがあります。


WEBGPU(将来)

Unity 6 では WebGPU の実験的なサポートが提供されています。利用可能になると、WebGPU によって多くの WebGL の制約がなくなり、コンピュートシェーダー、ストレージバッファー、より優れたスレッド処理が可能になります。ただし、2025 年時点では、ブラウザーゲームの本番環境向けターゲットは引き続き WebGL 2.0 です。WebGL 2.0 をターゲットにシェーダーを作成し、WebGPU は段階的な機能強化として導入する計画を立ててください。


参考資料

コメント