Unity AB パッケージ本体サイズの最適化

1 モデルテクスチャマップの最適化

プロジェクト AB では、キャラクターの数が多いため、キャラクター モデルの AB サイズも比較的大きくなりますが、キャラクター モデルは頂点と三角形の数を制御する必要がある一方で、モデル テクスチャ リソースの最適化です。アートをリソースとして使用する場合、品質を追求するため、モデル テクスチャは非常に大きくなることがよくあります。現在のプロジェクトを例に挙げます。アートで使用されるモデル テクスチャはすべて 4096*4096 です。 Unity さん、これはやってはいけません。ローエンド マシンに 4096 を許可しました。私はまだ鳥と遊んでいます。そのため、テクスチャの最大サイズは 2048 に制限されています。
元のリソース形式は次のとおりです。モデルには、この形式の 3 つのマップ、つまり UV マップ、法線マップ、およびグレースケール マップが含まれています。型付き AB リソースは 5.7M です。
ここに画像の説明を挿入
ここに画像の説明を挿入
私たちのプロジェクトが RPG ターンベース ゲームであることを考慮すると、戦闘シーンには複数のキャラクターのみが存在し、カメラからの距離は大きく変化しないため、MipMap を削除することをお勧めします。次に、パッケージ AB、リソース サイズは 4.1M です。
次に扱うのはテクスチャ圧縮です. ここでは主に Android をテストしました. テクスチャには透明なチャネルがないため、UV テクスチャとグレースケール テクスチャは RGBCrunchedETC 形式を採用し、通常のテクスチャは RGBCompressETC4bit 方式を採用します. AB リソースサイズは 2M です。
法線マップも RGBCrunchedETC 方式に従って圧縮される場合、AB リソースのサイズは、表示効果に応じて 1.4M まで削減できます。
最大サイズの設定もあります。モデルの表示効果に応じて分類制御を実行するのが最適です。

2TimeLineリソースの最適化

戦闘スキルをプロジェクト化します。TimeLine を使用して作成します。今日 TimeLine リソースをチェックしました。TimeLine プレハブ リソースは 100 万を超えており、そのうちのいくつかは 200 万に達しています。なんてことだ、アート仲間の皆さん、私が TimeLine に何をしたのでしょう、そこで、AssetBundleBorswer ツールを使用して、No. 00003 キャラクターの究極の動きの TimeLine AB リソースを分析しました。他のキャラクターのアニメーションやタイムラインのリソースが大量にあるのはなぜですか。
ここに画像の説明を挿入
そこで Unity エディターで元のリソースを確認してみました
ここに画像の説明を挿入
ここに画像の説明を挿入
が、何も問題はないようでした。この乱雑なリソースはどこから来たのでしょうか? AB は参照関係があると考えているため、問題があるはずです。検証はメタファイルで実行されます。m_SceneBindings 属性の下に参照されているリソースが大量にあるのを見て、私は言葉を失いました。
ここに画像の説明を挿入
次に、Unity に戻り、デバッグ モードをオンにし、リソースを再検査します。若すぎること、邪悪な人間の心を理解していないこと、そして騙されそうになったことを責めてください。これらの 106 のリソース参照、型付けされた AB は小さくてもよいでしょうか、 おい!
ここに画像の説明を挿入
実際に必要なリソースは、デバッグ モードをオフにしたときに表示される 3 つのリソースだけです。どうすればよいですか
ここに画像の説明を挿入
? コード ファーマーなので、レンガを移動する精神を使用しましょう、Du Niang Du Niang、レンガを移動したい、そしてDu Niangが私にリンクをくれました
https://zhuanlan.zhihu.com/p/396526134
それは本当に仲間です、私たちを助けてくれたホストに感謝します、そしてコピー&ペーストすると、修正ツールの準備が整います

    [MenuItem("Assets/CleanUpPlayableBind")]
    private static void CleanUpPlayableBind()
    {
        GameObject gob = Selection.activeGameObject as GameObject;
        if (gob != null) {
            var playable = gob.GetComponent<PlayableDirector>();
            CleanUpBind(playable);
        }
    }

    public static void CleanUpBind(PlayableDirector playable)
    {
        if (playable == null) return;
        Dictionary<UnityEngine.Object, UnityEngine.Object> bindings = new Dictionary<UnityEngine.Object, UnityEngine.Object>();
        foreach (var pb in playable.playableAsset.outputs)
        {
            var key = pb.sourceObject;
            var value = playable.GetGenericBinding(key);
            if (!bindings.ContainsKey(key) && key != null)
            {
                bindings.Add(key, value);
            }
        }

        var dirSO = new UnityEditor.SerializedObject(playable);
        var sceneBindings = dirSO.FindProperty("m_SceneBindings");
        for (var i = sceneBindings.arraySize - 1; i >= 0; i--)
        {
            var binding = sceneBindings.GetArrayElementAtIndex(i);
            var key = binding.FindPropertyRelative("key");
            if (key.objectReferenceValue == null || !bindings.ContainsKey(key.objectReferenceValue))
                sceneBindings.DeleteArrayElementAtIndex(i);
        }
        dirSO.ApplyModifiedProperties();
    }

終わり!ちなみに、TimeLine で使用されるアニメーション リソースについては、浮動小数点精度値とスケール チャネルを圧縮することを忘れないでください。通常、このような高精度は使用しません。AB は、冗長部分を除いて、以前は比較的大きかったです。リソースがあるため、アニメーション圧縮はありません。最終的に、AB リソースは私によって 1.6M から 132k に減りました、ナイス。
ここに画像の説明を挿入
ここに画像の説明を挿入

アニメーションの最適化

コアコード

    [MenuItem("Assets/AnimationClipChange/Directory/降低精度并删除Scale通道")]
    private static void ChangeAnimFloatAndScaleDirectory()
    {
        Object gob = Selection.activeObject;
        string path = AssetDatabase.GetAssetPath(gob);
        if (Directory.Exists(path))
        {
            string[] udids = AssetDatabase.FindAssets("t:AnimationClip", new string[] { path });
            int index = 0;
            foreach (var item in udids)
            {
                string itemPath = AssetDatabase.GUIDToAssetPath(item);
                EditorUtility.DisplayProgressBar("执行中..." + path, itemPath, (float)index / udids.Length);

                AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(itemPath);
                optmizeAnimationFloatAndScale(clip);
                index++;
            }
            EditorUtility.ClearProgressBar();
            Debug.LogColor("AnimationClip change float finish!");
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        else
        {
            Debug.LogError("select target is not a directory:" + path);
        }

    }


    static void optmizeAnimationFloatAndScale(AnimationClip targetAnimClip)
    {
        optmizeAnimationScaleCurve(targetAnimClip);
        optmizeAnimationFloat(targetAnimClip);
        Resources.UnloadUnusedAssets();
        
    }


    /// <summary>
    /// 优化浮点数精度
    /// </summary>
    static AnimationClip optmizeAnimationFloat(AnimationClip clip)
    {
        //浮点数精度压缩到f3
        AnimationClipCurveData[] curves = null;
        curves = AnimationUtility.GetAllCurves(clip);
        Keyframe key;
        Keyframe[] keyFrames;
        for (int ii = 0; ii < curves.Length; ++ii)
        {
            AnimationClipCurveData curveDate = curves[ii];
            if (curveDate.curve == null || curveDate.curve.keys == null)
            {
                //Debug.LogWarning(string.Format("AnimationClipCurveData {0} don't have curve; Animation name {1} ", curveDate, animationPath));
                continue;
            }
            keyFrames = curveDate.curve.keys;
            for (int i = 0; i < keyFrames.Length; i++)
            {
                key = keyFrames[i];
                key.value = float.Parse(key.value.ToString("f3"));
                key.inTangent = float.Parse(key.inTangent.ToString("f3"));
                key.outTangent = float.Parse(key.outTangent.ToString("f3"));
                keyFrames[i] = key;
            }
            curveDate.curve.keys = keyFrames;
            clip.SetCurve(curveDate.path, curveDate.type, curveDate.propertyName, curveDate.curve);
        }

        return clip;
    }

    /// <summary>
    /// 优化scale曲线
    /// </summary>
    static AnimationClip optmizeAnimationScaleCurve(AnimationClip clip)
    {
        //去除scale曲线
        foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(clip))
        {
            string name = theCurveBinding.propertyName.ToLower();
            if (name.Contains("scale"))
            {
                AnimationUtility.SetEditorCurve(clip, theCurveBinding, null);
            }
        }

        return clip;
    }

おすすめ

転載: blog.csdn.net/u011484013/article/details/119839565