UnityでのAndroidビルドファイルのサイズの縮小

ビルドサイズは、モバイルアプリケーションの重要な機能です。 アプリケーションの重量が大きい場合、クリーニング時に最初に削除されます。 また、サイズを小さくすると、起動、インストール、ダウンロードを高速化できます。



Unityの空のプロジェクトでさえ、非常に重くなります。 Unity 2017.1のデフォルト設定の空のAndroidプロジェクトの重量は21,637 KBです。 ただし、コンパイル用のプラットフォーム(それぞれARMv7およびx86)を指定することにより、11952 \ 12412 KBに非常に簡単に削減できます。



これと同様に、Graphic APIを選択することで、重量をもう少し減らすことができます。 Auto Graphics APIの代わりにOpenGLES2を選択した場合、さらに236 KB(11952の代わりに11716)を保存できます。 利点はごくわずかであり、パフォーマンスが低下する可能性があるため、これはお勧めしません。



それでは、プロジェクトの内容について話しましょう。 スプライトがたくさんある2Dゲームを考えてみましょう。

多くのスプライトが1つ以上の軸に沿って対称になる可能性があります。



この場合に自動圧縮があるかどうかを確認しましょう。たとえば、1つのテクスチャ(このテクスチャなど)を設定したSprite Rendererでシーンをコンパイルします。







ARMv7ビルドは11952 KBから12046 KBに増加し、空のビルドからのゲインは94 KBです。



次に、テクスチャの半分を準備します。







2つのスプライトレンダラーを同じ位置に配置し、右にミラーリングのフリップXを設定し、スプライトインポート設定でピボット右を指定してミラーの半分を揃えます。 以前と同じ円にする必要があります。 コンパイルして、サイズを見てください:12000 KB、つまり、増加はほぼ2倍少ない(94に対して48 KB)。 特別な圧縮がある場合、デフォルトでは非効率的です。



原則として、必要なテクスチャをすべてミラーリングしようとすることはできますが、より大きなプロジェクトの一部としてはあまり便利ではありません。オブジェクトごとに半分を彫刻する必要があります。 この問題は、水平イメージミラーリング用の独自のシェーダーを作成することで解決できます。



Sprite Rendererの標準Unityシェーダーを見つけます。



スプライト/デフォルト
Shader "Sprites/Default" { Properties { [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} _Color ("Tint", Color) = (1,1,1,1) [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0 } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" } Cull Off Lighting Off ZWrite Off Fog { Mode Off } Blend One OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile DUMMY PIXELSNAP_ON #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; half2 texcoord : TEXCOORD0; }; fixed4 _Color; v2f vert(appdata_t IN) { v2f OUT; OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex); OUT.texcoord = IN.texcoord; OUT.color = IN.color * _Color; #ifdef PIXELSNAP_ON OUT.vertex = UnityPixelSnap (OUT.vertex); #endif return OUT; } sampler2D _MainTex; fixed4 frag(v2f IN) : SV_Target { fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color; c.rgb *= ca; return c; } ENDCG } } }
      
      







まず、すべてが機能することを確認してください。 シェーダーを作成し、コードをコピーして、コード内の名前をSprites / Horizo​​ntalSymmetryに変更します。 次に、マテリアルを作成してシェーダーを選択する必要があります。 マテリアルをスプライトレンダラーに割り当ててみましょう。 前のように見えるはずです。



それでは、シェーダーを見てみましょう。 すべての魔法はここで起こります:



 fixed4 frag(v2f IN) : SV_Target { //tex2D      . //_MainTex -  , IN.texcoord -     0..1 fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color; // r,g,b    acrgb *= ca; return c; }
      
      





これは、指定されたポイントのピクセルの色を返す関数です。 ミキシングの位置、テクスチャ、色が与えられます。 fixed4を恐れないでください。これは、4つの浮動小数点を持つデータ型です:r、g、b、a。



最初の行では、テクスチャの色を取得し、その後、IN.colorの色を掛けます。 この色はシェーダーパラメーターであり、スプライトレンダラー/色で変更できます。



次に、色とアルファの乗算が行われます。 これは、透明度がアルファだけでなく、rgbの値にも依存するという事実によるものです。 色空間のより良い理解のために、あなたは実験することができます:



 fixed4 frag(v2f IN) : SV_Target { fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color; c.rgb=0.5; ca = 0.0; return c; }
      
      





透明な灰色のテクスチャが得られます。 rgb = 1およびa = 0の場合、不透明な白になり、rgb = 0およびa = 0の場合、完全に透明になり、rgb = 0およびa = 1に黒の不透明になります。



すべてがうまくいったら、水平ミラーリングを試してみましょう。 この関数を変更して、画像の前半でテクスチャ全体を配置し、後半で同じテクスチャをミラーリングするようにする必要があります。



この問題は真正面から解決できます。



 fixed4 frag(v2f IN) : SV_Target { //      fixed2 nIn = IN.texcoord; //    0...2 nIn.x = nIn.x*2; //   ,   1..0 if (nIn.r>1) nIn.r = 2-nIn. //    fixed4 c = tex2D(_MainTex, nIN.texcoord) * IN.color; // r,g,b    acrgb *= ca; return c; }
      
      





少し考えれば、決定をより短く、より美しく、より速くすることができます:



 fixed4 frag(v2f IN) : SV_Target { //   IN.texcoord.x = 1-abs(2*IN.texcoord.x-1); //     fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color; // r,g,b    acrgb *= ca; return c; }
      
      





演習として、垂直対称と二重対称のこの問題を解決することを読者に提案します。



スプライトがデフォルトで特定のパス(メッシュ)に沿って描画されるという事実に関連する透明度のアーティファクトがある場合があります。 次のように扱われます:スプライト/設定のインポート/メッシュタイプ=完全な長方形。



この方法は、理論的には、使用されるテクスチャのサイズを4倍減らすことができます。 スプライトの1/4でビルドがどのように動作するかを確認しましょう(二重対称シェーダーを使用)。 ビルドサイズ-11978 KB対12000(スプライトの半分)。 空のプロジェクトの重量は11952 KBだったことを思い出させてください。 つまり、再び、増加はほぼ半分になりました(最適化なしの元の円から3.6倍)。



ただし、これは制限ではありません。 私のゲームでは、放射状に対称な多数のワッシャーを使用しました。 これは、サークル全体を尋ねるにはストリップが1つだけあれば十分であることを意味します。 さらに、半分のストリップ(半径、直径ではない)。



テクスチャを準備します。





今ではシェーダー次第です。 私たちのタスクは、円を円から外すことです。



これを行うには、現在のポイントの中心からの距離を見つけ、その位置でテクスチャ座標を使用します(1-distance * 2、0)。 中心からの最大距離が1ではなく0.5になるため、2の乗算が発生します。テクスチャは左(円の端)から右(円の中心)に準備されるため、1から減算します。



実装例:



 fixed4 frag(v2f IN) : SV_Target { fixed2 nIn = IN.texcoord; nIn.x = nIn.x-0.5; nIn.y = nIn.y-0.5; float dist = sqrt(nIn.x*nIn.x+nIn.y*nIn.y); IN.texcoord.x = 1-dist*2; fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color; c.rgb *= ca; return c; }
      
      





注:ルートはここで計算されるため、シェーダーの動作は完全な円形の画像よりも遅くなります。



マテリアルを作成し、Sprite Rendererに配置し、Sprite =ラインを配置します。 画像は非常に狭いため、スプライトを引き伸ばす必要があります(値をTrasnform.Scale.yに設定します)。 元の円\楕円を取得する必要があります。



新しいシェーダーとストリップの円でビルドサイズを確認してみましょう。11957KBでした。 つまり、空のプロジェクトからのゲインはわずか5 KBであり、これにはシェーダーのサイズが含まれます。



その結果、場合によってはビルドサイズを大幅に削減できる便利なツールが手に入りました。 Androidだけでなく、シェーダーをサポートするプラットフォームにも適しています。



All Articles