Optimización del tamaño del cuerpo del paquete Unity AB

1 Optimización del mapa de texturas del modelo

En el proyecto AB, hay muchos personajes, por lo que el tamaño AB del modelo de personaje también es relativamente grande. Por un lado, el modelo de personaje debe controlar la cantidad de vértices y triángulos, y por otro lado, es la optimización de los recursos de textura del modelo. Cuando se utiliza el arte como recurso, para buscar la calidad, las texturas del modelo a menudo se hacen muy grandes. Tomemos nuestro proyecto actual como ejemplo. Las texturas del modelo utilizadas en el arte son todas 4096 * 4096. En Unity, no debes hacer esto. 4096 dejas que la máquina de gama baja siga jugando con un pájaro, por lo que el tamaño máximo de la textura está limitado a 2048.
El formato de recurso original es el siguiente. Un modelo contiene 3 mapas en este formato, a saber, mapa uv, mapa normal y un mapa en escala de grises. El recurso AB escrito es 5.7M.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Teniendo en cuenta que nuestro proyecto es un juego de rol por turnos, solo habrá varios personajes en la escena de la batalla y la distancia de la cámara no cambiará significativamente, por lo que se recomienda eliminar MipMap. Luego paquete AB, el tamaño del recurso es 4.1M.
Lo siguiente a tratar es la compresión de texturas. Probé principalmente Android aquí. Dado que las texturas no tienen un canal transparente, la textura UV y la textura en escala de grises adoptan el formato RGBCrunchedETC, y la textura normal adopta el método RGBCompressETC4bit. El recurso AB el tamaño es 2M
Si el mapa normal también se comprime de acuerdo con el método RGBCrunchedETC, el tamaño del recurso AB se puede reducir a 1,4M, lo que depende del efecto de visualización.
También está la configuración de Max Size, lo mejor es realizar un control de clasificación de acuerdo con el efecto de visualización del modelo.

2Optimización de recursos TimeLine

Habilidades de combate del proyecto, usamos TimeLine para hacerlo. Revisé los recursos de TimeLine hoy. Un recurso prefabricado de TimeLine ha llegado a más de 1M, y algunos de ellos son 2M. Dios mío, todos ustedes, amigos del arte. ¿Qué le hice a TimeLine? así que usé la herramienta AssetBundleBorswer para analizar los recursos de TimeLine AB del último movimiento del personaje No. 00003. ¿Por qué hay un montón de recursos de animación y línea de tiempo de otros personajes?
inserte la descripción de la imagen aquí
Luego eché un vistazo a los recursos originales en el editor de Unity
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
, y parecía que no había nada de malo en ello. ¿De dónde vino este recurso desordenado? Dado que AB cree que tienen una relación de referencia, debe haber un problema. El la verificación se está llevando a cabo en el metaarchivo. Esta vez no me decepcionó. Vi este montón de recursos referenciados bajo el atributo m_SceneBindings, y me quedé sin palabras.
inserte la descripción de la imagen aquí
Luego regrese a la unidad, active el modo de depuración, vuelva a examinar los recursos, cúlpeme por ser demasiado joven, no entender el siniestro corazón humano y casi ser engañado por usted, estas 106 referencias de recursos, ¿puede el AB escrito ser pequeño? , ¡ey!
inserte la descripción de la imagen aquí
Los recursos que realmente necesito son solo los tres recursos que se muestran cuando el modo de depuración está desactivado. ¿Qué
inserte la descripción de la imagen aquí
debo hacer? Como soy un agricultor de código, usemos el espíritu de mover ladrillos, Du Niang Du Niang, quiero mover ladrillos, y luego Du Niang me dio un enlace
https://zhuanlan.zhihu.com/p/396526134
Realmente es un compañero, gracias al anfitrión por ayudarnos, y luego copie y pegue, una herramienta de modificación está lista

    [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();
    }

¡Hecho! Por cierto, para los recursos de animación utilizados por TimeLine, recuerde comprimir sus valores de precisión de coma flotante y canales de escala. Por lo general, no usamos una precisión tan alta. El AB era relativamente grande antes, excepto por el redundante recursos, no hay compresión de animación. Al final, Niza reduje el recurso AB de 1,6 millones a 132k.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Optimización de animación

código central

    [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;
    }

Supongo que te gusta

Origin blog.csdn.net/u011484013/article/details/119839565
Recomendado
Clasificación