webgl-shader-constraints について
ブラウザー向けに Unity を開発する人のためのリファレンススキルです。WebGL 1.0 と 2.0 の制約や回避策、シェーダーバリアント削減などの最適化を扱います。
主な機能
- 01WebGL 1.0 と 2.0 の制約
- 02ループと配列インデックスの回避策
- 03シェーダーバリアントの削減
- 04テクスチャとメモリの指針
- 05WebGL のパフォーマンス指針
活用シーン
- 01ブラウザービルドだけで失敗するシェーダーの調査
- 02シェーダービルド容量と初回コンパイル時間の削減
- 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 ビルドでのみシェーダーエラーが発生したという報告があった場合や、シェーダーに関連するビルドサイズの問題を扱う場合も、このスキルを使用します。
基本ルール
-
WebGL 1.0(OpenGL ES 2.0)では動的な配列インデックス指定が禁止されています。 配列のインデックスには、定数またはループカウンター変数のみを使用できます。WebGL 1.0 でシェーダーエラーが発生する最大の原因です。
-
WebGL 1.0 で使用できるのはカウント付きの
forループのみです。whileループやdo-whileループは使用できません。ループカウンターの初期化、比較、インクリメントは、for文内で行う必要があります。ループの上限は定数式でなければなりません。 -
WebGL 2.0(OpenGL ES 3.0)ではループとインデックス指定の制約がなくなりますが、精度修飾子が必須になります。 すべての変数には明示的な精度(
highp、mediump、lowp)を指定するか、デフォルトの精度宣言を使用する必要があります。 -
WebGL がサポートするのはベイク済み GI と非方向性ライトマップのみです。 リアルタイム GI、方向性ライトマップ、L2 球面調和関数を使用したライトプローブは使用できません。
-
WebGL ビルドでは Standard Shader を使用しないでください。 数百ものバリアントがコンパイルされ、ビルドサイズが 50MB 以上増えることがあります。最小限のキーワードを使用した Simple Lit、Unlit、またはカスタムシェーダーを使用してください。
-
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 のパフォーマンスに関するヒント
-
シェーダーのコンパイル中はメインスレッドがブロックされます。 ネイティブビルドとは異なり、WebGL はシェーダーを同期的にコンパイルします。シェーダーが多いと、初回ロード時に長時間フリーズします。バリアント数を最小限にしてください。
-
Web 向けには Built-in ではなく URP を使用します。 適切に設定した URP は、ビルドサイズが小さく、シェーダーバリアントも少なくなります。
-
テクスチャ圧縮は重要です。 WebGL 2.0 では ASTC(推奨)または ETC2 を使用します。DXT/BC 形式が動作するのはデスクトップブラウザーのみです。
-
メモリには厳しい制限があります。 WebGL はブラウザーのメモリーサンドボックス内で実行されます。シェーダーバリアントのコレクションが大きいと、OOM クラッシュが発生することがあります。
-
モバイルブラウザーでテストしてください。 iOS Safari の WebGL パフォーマンスはデスクトップ版 Chrome より大幅に劣ります。デスクトップ版 Chrome では動作する多くのエフェクトが、モバイル版 Safari では動作しない、またはカクつくことがあります。
WEBGPU(将来)
Unity 6 では WebGPU の実験的なサポートが提供されています。利用可能になると、WebGPU によって多くの WebGL の制約がなくなり、コンピュートシェーダー、ストレージバッファー、より優れたスレッド処理が可能になります。ただし、2025 年時点では、ブラウザーゲームの本番環境向けターゲットは引き続き WebGL 2.0 です。WebGL 2.0 をターゲットにシェーダーを作成し、WebGPU は段階的な機能強化として導入する計画を立ててください。
参考資料
- Unity WebGL Graphics — https://docs.unity3d.com/530/Documentation/Manual/webgl-graphics.html
- Unity 6 WebGL2 ドキュメント — https://docs.unity3d.com/6000.3/Documentation/Manual/WebGL2.html
- Unity Web Graphics API の概要 — https://docs.unity3d.com/6000.3/Documentation/Manual/web-graphics-apis-intro.html
- Unity Web の最適化:グラフィックス — https://docs.unity3d.com/2022.3/Documentation/Manual/web-optimization-graphics.html
- Unity:Web ビルドのプロファイリングと最適化 — https://unity.com/how-to/profile-optimize-web-build
- Unity Web:未使用のリソースを削除 — https://docs.unity3d.com/2022.3/Documentation/Manual/web-optimization-remove-resources.html
- WebGL2 Fundamentals:新機能 — https://webgl2fundamentals.org/webgl/lessons/webgl2-whats-new.html
- Radiator Blog:2023 年版 WebGL のヒント — https://www.blog.radiator.debacle.us/2023/01/unity-webgl-tips-advice-in-2023.html
- Backtrace:WebGL のメモリ問題 — https://backtrace.io/blog/memory-and-performance-issues-in-unity-webgl-builds
- Playgama:2025 年版 Unity WebGL — https://playgama.com/blog/general/unity-for-browser-games-boost-performance-and-engagement-effortlessly/
- JohannesDeml:WebGL 読み込みテスト(700 件以上のビルド) — https://github.com/JohannesDeml/UnityWebGL-LoadingTest
- CrazyGames:Unity 最適化パッケージ — https://github.com/CrazyGamesCom/unity-optimizations-package