texture-packing-variant-stripping について
モバイルや Web ビルドのテクスチャとシェーダーバリアントを管理する Unity 開発者向けの最適化リファレンスです。チャンネルパッキングと、キーワードやバリアントを削減する方法を解説します。
主な機能
- 01RGBA テクスチャのチャンネルパッキング
- 02URP マスクマップの規約
- 03shader_feature と multi_compile の指針
- 04URP 機能とキーワードの削減
- 05モバイルと Web 向けテクスチャ圧縮
活用シーン
- 01グレースケールマップをまとめてテクスチャサンプルを削減
- 02シェーダーバリアントとビルド容量の削減
- 03モバイル向けパック済みテクスチャの圧縮形式選び
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ adevra/ unity-shader-agent-skills --skill texture-packing-variant-strippingインストール後、Claude Code で/texture-packing-variant-strippingを入力して読み込まれたか確認します。
詳細
Unity モバイル向けのテクスチャパッキングとシェーダーバリアントのストリッピング
トリガー
Unity でテクスチャの最適化、チャンネルパッキング、シェーダーバリアントの肥大化、ビルドサイズ、シェーダーのコンパイル時間、シェーダーキーワードの管理を行う場合に、このスキルを使用してください。トリガーとなる語句には、「チャンネルパッキング」、「テクスチャパッキング」、「マスクマップ」、「MODS マップ」、「RMA」、「シェーダーバリアント」、「バリアントのストリッピング」、「multi_compile」、「shader_feature」、「ビルドサイズ」、「シェーダーキーワード」、「Always Included Shaders」、「IPreprocessShaders」、またはシェーダーのコンパイルが遅い、ビルドサイズが大きいという問題の報告などがあります。
テクスチャチャンネルのパッキング
チャンネルパッキングでは、複数のグレースケールマップを単一の RGBA テクスチャに格納します。これにより、モバイルにおける主なボトルネックであるテクスチャサンプル数とメモリ帯域幅の両方を削減できます。
標準的な URP パッキング規約
Mask Map (single RGBA texture):
R = Metallic
G = Occlusion (AO)
B = Detail mask (or custom)
A = Smoothness
ベストプラクティス
-
視覚的に最も重要なマスクを Green チャンネルに配置します。 人間の視覚は緑に最も敏感であり、ほとんどのテクスチャ圧縮形式(ETC2、ASTC、DXT)では、Green により多くのビットが割り当てられます。
-
関連するデータを一緒にパッキングします。 Metallic と Smoothness を常に一緒にサンプリングする場合は、同じテクスチャに配置します。
-
パッキングしたマスクテクスチャには、リニア色空間(sRGB ではない)を使用します。 Unity では、色以外のデータ(roughness、AO、metallic、height)のテクスチャインポート設定で「sRGB」のチェックを外します。
-
1 回のテクスチャサンプルで 4 回分を置き換えられます。 次のようにする代わりに:
// BAD — 4 texture samples half metallic = SAMPLE_TEXTURE2D(_MetallicMap, sampler_MetallicMap, uv).r; half ao = SAMPLE_TEXTURE2D(_AOMap, sampler_AOMap, uv).r; half detail = SAMPLE_TEXTURE2D(_DetailMask, sampler_DetailMask, uv).r; half smooth = SAMPLE_TEXTURE2D(_SmoothnessMap, sampler_SmoothnessMap, uv).r;次のようにします:
// GOOD — 1 texture sample half4 masks = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, uv); half metallic = masks.r; half ao = masks.g; half detail = masks.b; half smooth = masks.a;
応用:テレインのパッキング
Unity の Shader Graph 17.4 のテレインサンプルでは、4 レイヤーのテレインに対して、テクスチャサンプル数を12 回から 5 回に削減する高度なパッキングが紹介されています。
- CNS パッキング:Color(RGB)+ Normal(RG → B を再構築)+ Smoothness を 1 セットに格納
- CHNOSArray:Color、Height、Normal、Occlusion、Smoothness をパッキングしたテクスチャ配列
HLSL チャンネルパッキングヘルパー
// Pack 4 grayscale values into RGBA
half4 PackChannels(half metallic, half ao, half detail, half smoothness)
{
return half4(metallic, ao, detail, smoothness);
}
// Reconstruct normal Z from XY (for normal map packing)
half3 UnpackNormalRG(half2 normalRG)
{
half3 n;
n.xy = normalRG * 2.0h - 1.0h;
n.z = sqrt(1.0h - saturate(dot(n.xy, n.xy)));
return n;
}
シェーダーバリアントの管理
バリアント爆発の問題
各 multi_compile キーワードによって、バリアント数は乗算的に2 倍になります。
#pragma multi_compile _ _A → 2 variants
#pragma multi_compile _ _A _B → 3 variants
#pragma multi_compile _ _A
#pragma multi_compile _ _B → 2 × 2 = 4 variants
#pragma multi_compile _ _A
#pragma multi_compile _ _B
#pragma multi_compile _ _C → 2 × 2 × 2 = 8 variants
URP に組み込まれているキーワード(影、フォグ、追加ライトなど)を含めると、単一のシェーダーで数千ものバリアントが生成されることがあります。
影響
- ビルド時間:複雑なシェーダーでは 20 分以上
- ビルドサイズ:シェーダーデータが 100MB 以上(WebGL では深刻な問題)
- ランタイムメモリ:バリアント切り替えによってドローコールが 20~40% 増加
- WebGL:シェーダーのコンパイルがメインスレッドをブロックするため、バリアントが多いほどフリーズ時間が長くなります
shader_feature と multi_compile の比較
shader_feature | multi_compile | |
|---|---|---|
| コンパイル対象 | ビルド内のマテリアルで使用されるバリアントのみ | すべての組み合わせ |
| 用途 | マテリアル固有の切り替え | グローバル状態(フォグ、シャドウ) |
| 未使用のバリアント | 自動的にストリッピングされます | 使用されていなくても含まれます |
| ローカル版 | shader_feature_local(最大 64) | multi_compile_local(最大 64) |
| グローバル版 | shader_feature(最大 256) | multi_compile(最大 256) |
ルール:制御可能なもの(マテリアルの切り替え、機能フラグ)にはすべて shader_feature を使用します。multi_compile は、Unity がグローバルに制御するもの(フォグ、ライトマップ、インスタンシング)にのみ使用してください。
推奨される URP キーワードのストリッピング
機能を使用していない場合は、次のキーワードをストリッピングしてください。
// In an IPreprocessShaders implementation:
static readonly ShaderKeyword[] STRIP_KEYWORDS = new[]
{
new ShaderKeyword("_ADDITIONAL_LIGHTS"), // If using main light only
new ShaderKeyword("_ADDITIONAL_LIGHT_SHADOWS"), // If no additional light shadows
new ShaderKeyword("_SHADOWS_SOFT"), // If using hard shadows only
new ShaderKeyword("_MIXED_LIGHTING_SUBTRACTIVE"), // If not using mixed lighting
new ShaderKeyword("_SCREEN_SPACE_OCCLUSION"), // If not using SSAO
new ShaderKeyword("LIGHTMAP_SHADOW_MIXING"), // If not mixing lightmaps + realtime
new ShaderKeyword("_LIGHT_LAYERS"), // If not using light layers
new ShaderKeyword("_REFLECTION_PROBE_BLENDING"), // If not blending reflection probes
new ShaderKeyword("_REFLECTION_PROBE_BOX_PROJECTION"), // If not using box projection
};
URP アセットの機能のストリッピング
URP アセットの設定で未使用の機能を無効にし、それらのバリアントがコンパイルされないようにします。
- Additional Lights → オフ(ディレクショナルライトのみを使用する場合)
- Shadows → カスケード数を減らし、ソフトシャドウを無効にする
- Post-Processing → 使用しない場合は無効にする
- HDR → 必要ない場合は無効にする
- Environment Reflections → ベイク済みの反射を使用する場合は無効にする
プラットフォーム条件付きコンパイル
// Include features only on platforms that can handle them
#if defined(SHADER_API_MOBILE) || defined(SHADER_API_GLES) || defined(SHADER_API_GLES3)
// Mobile/WebGL: simplified path
#define MOBILE_SHADER 1
#else
// Desktop: full features
#define MOBILE_SHADER 0
#endif
half4 frag(Varyings i) : SV_Target
{
half4 color = SampleAlbedo(i.uv);
#if !MOBILE_SHADER
// Desktop-only: normal mapping, specular, etc.
color.rgb += SampleNormalAndLight(i);
#endif
return color;
}
モバイル/Web向けテクスチャ圧縮
| 形式 | プラットフォーム | ビット/ピクセル | 品質 | 備考 |
|---|---|---|---|---|
| ASTC 4×4 | Android (ES 3.0+), iOS | 8 | 最良 | すべてのモバイル向けに推奨 |
| ASTC 6×6 | Android (ES 3.0+), iOS | 3.56 | 良好 | 重要度の低いテクスチャに使用 |
| ASTC 8×8 | Android (ES 3.0+), iOS | 2 | 許容範囲 | 背景や遠景のテクスチャ |
| ETC2 | Android (ES 3.0+), WebGL 2.0 | 4-8 | 良好 | WebGL 2.0のデフォルト |
| ETC1 | Android (ES 2.0) | 4 | 可 | アルファチャンネル非対応 |
| PVRTC | iOS (older) | 2-4 | ばらつきあり | レガシー形式。ASTCを推奨 |
チャンネルパックテクスチャの場合:リニアカラースペースでASTC 4×4またはETC2を使用してください。マスクマップにはPVRTCを使用しないでください。ブロック圧縮により、マスクの境界が鋭い部分に目立つアーティファクトが生じます。
最適化チェックリスト
- すべてのグレースケールマップを、共有テクスチャのRGBAチャンネルにパック済み
- パックしたテクスチャをLinear(sRGBではなく)としてインポート済み
- 最も重要なマスクデータにGreenチャンネルを使用
- マテリアルトグルには
multi_compileではなくshader_featureを使用 - 可能な場合はローカルキーワードを使用(
shader_feature_local) - URP Assetで未使用のURP機能を無効化
- Always Included Shadersリストを整理(Project Settings > Graphics)
- 未使用キーワード向けのIPreprocessShadersストリッピングスクリプトを追加
- ビルドログでバリアント数を確認(「Compiled N shader variants」を確認)
- すべてのモバイルテクスチャにASTCまたはETC2圧縮を使用
- Standard Shaderをプロジェクトから削除(Simple Litまたはカスタムシェーダーを使用)
参考資料
- Unity 6 URPのチャンネルパックテクスチャ — https://docs.unity3d.com/6000.3/Documentation/Manual/urp/shaders-in-universalrp-channel-packed-texture.html
- Unity Learn:モバイル向けテクスチャチャンネルパッキング — https://learn.unity.com/course/3d-art-optimization-for-mobile-gaming-5474/
- Shader Graph 17.4:Terrain Packing — https://docs.unity3d.com/Packages/[email protected]/manual/Shader-Graph-Sample-Terrain-Packing.html
- Polycount Wiki:チャンネルパッキング — http://wiki.polycount.com/wiki/ChannelPacking
- Unity 6:シェーダーバリアントのストリッピング — https://docs.unity3d.com/6000.3/Documentation/Manual/shader-variant-stripping.html
- Unity Blog:スクリプタブルシェーダーバリアントのストリッピング — https://unity.com/blog/engine-platform/stripping-scriptable-shader-variants
- Unity Blog:シェーダーバリアント最適化のヒント — https://unity.com/blog/engine-platform/shader-variants-optimization-troubleshooting-tips
- Unity Manual:shader_featureとmulti_compileの比較 — https://docs.unity3d.com/2020.2/Documentation/Manual/SL-MultipleProgramVariants.html
- TheGamedev.Guru:シェーダーバリアントのストリッピング — https://thegamedev.guru/unity-cpu-performance/shader-variants-stripping/
- Unity Web:未使用リソースの削除 — https://docs.unity3d.com/2022.3/Documentation/Manual/web-optimization-remove-resources.html
- Unity Learn:グラフィックスの最適化 — https://learn.unity.com/tutorial/optimizing-graphics-in-unity