Unity 优化包体大小

总结项目优化中两个对包体大小优化比较大的点:

  1. 动画文件
  2. 模型默认材质球

一. 动画文件

对于3d项目模型的动作文件占资源大小还是有蛮大的一部分,所以想在不影响美术要求的情况下能不能对动作文件进行优化,在UWA上还真的发现有前辈已经总结了优化的方法(链接就是),总结来说就是两点:1.压缩浮点数精度  2.去除scale曲线。对比前后.anim文件效果如下:

对于.anim原始文件的大小还是优化很明显的,打bundle后包体大小跟内存大小也相应的减小。

二.模型默认材质球

要优化包体大小,就要清楚知道包里到底有哪些资源,资源在打成bundle后到底有没有冗余,通过 AssetStudio可以查看包里具体的资源, 打开我们打好的bundle所在文件夹,根据Filter Type选项过滤只留Shader类型资源并大小排序,不看不知道,一看吓一跳,内置Standard shader冗余了有两百多个,按每个701900b算总共占据了100M多包体大小,这是非常可怕的。

那么这些Standard shader到底是在哪些bundle包里?为什么会被打进包里?选中资源右键 Show original file 可以看其所在的bundle,通过分析bundle manifest文件得知原来这些Standard shader是模型资源外部导进工程的时候系统赋予了默认材质球,

即使后面做模型预制体的时候使用了美术其它的材质球,这个Standard shader还是会被引用打进bundle。那能不能哪里可以设置让Standard shader只打进一个包里或者说怎样处理不冗余,GraphicsSetting-> always included shader 倒是可以设置,这边设置的shader意思是该shader不会被打进引用它的bundle里,而是会在出包的时候直接当作依赖资源放进游戏包里。我们在GraphicsSetting-> always included shader设置了Standard shader重新打包看下效果:

如意料中的Standard shader全部没了,对比bundle文件夹的大小,少了差不多100M,这总bundle资源大小减的有点多。

不要高兴的太早,我们只是减少了bundle的大小,重新打个apk包你会发现编译的时间好长,而且打的apk包比之前反而大了很多,What?又出了什么鬼问题?查资料发现是由于 GraphicsSetting-> always included shader  设置了内置Standard shader,而Standard shader是有成千上万的变体,被加到always include 的shader会将shader的所有变体打包到游戏,所以在GraphicsSetting-> always included shader  设置内置Standard shader这个方法是行不通的。

那如何处理呢?通常我们模型很少会用Standard shader的材质球,而是用美术给的实际满足效果的shader材质球,所以还有一个办法是去掉模型对默认材质球的依赖,那其实只要在模型导入的时候把模型Renderer引用的材质球置为空就行了,代码如下:

using UnityEngine;
using System.Collections.Generic;
using UnityEditor;

public class DeletFbxDefaultMat
{
    private static Dictionary<string, GameObject> fbxs = new Dictionary<string, GameObject>();
    public static bool reimportModle = false;

    [MenuItem("Assets/删除模型默认材质球")]
    public static void DelFbxDefaultMat()
    {
        string[] guids = null;
        List<string> path = new List<string>();
        fbxs.Clear();

        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(object), SelectionMode.Assets);
        if (objs.Length > 0)
        {
            for (int i = 0; i < objs.Length; i++)
            {
                if (objs[i].GetType() == typeof(GameObject))
                {
                    string assetPath = AssetDatabase.GetAssetPath(objs[i]);
                    GetModel(assetPath);
                }
                else
                {
                    path.Add(AssetDatabase.GetAssetPath(objs[i]));
                }
            }

            if (path.Count > 0)
            {
                guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(GameObject).ToString().Replace("UnityEngine.", "")), path.ToArray());
            }
            else
            {
                guids = new string[] { };
            }
        }

        for (int i = 0; i < guids.Length; i++)
        {
            string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
            GetModel(assetPath);
        }

        Debug.Log("模型数量:" + fbxs.Count);
        StartDelete();
    }

    static void GetModel(string path)
    {
        string pathLower = path.ToLower();
        if (pathLower.EndsWith(".fbx") || pathLower.EndsWith(".3ds") || pathLower.EndsWith(".obj"))
        {
            GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
            if (go != null)
            {
                fbxs.Add(path, go);
            }
        }
    }

    static void StartDelete()
    {
        reimportModle = true;
        int n = 0;
        foreach (var item in fbxs)
        {
            UpdateProgress(++n, fbxs.Count, item.Key);
            AssetDatabase.ImportAsset(item.Key);
        }

        reimportModle = false;
        EditorUtility.ClearProgressBar();
        AssetDatabase.Refresh();

        Debug.Log("delete default mat over---");
    }

    static void UpdateProgress(int progress, int progressMax, string desc)
    {
        string title = "Processing...[" + progress + " - " + progressMax + "]";
        float value = (float)progress / (float)progressMax;
        EditorUtility.DisplayProgressBar(title, desc, value);
    }
}

public class ModelMatTool : AssetPostprocessor
{
    private void OnPostprocessModel(GameObject model)
    {
        if (null == model || !DeletFbxDefaultMat.reimportModle) return;

        Renderer[] renders = model.GetComponentsInChildren<Renderer>();
        if (null == renders) return;
        foreach (Renderer render in renders)
        {
            render.sharedMaterials = new Material[render.sharedMaterials.Length];
        }
    }
}

处理后效果如下:

发现没,模型默认的材质球没了,模型这时候是粉色的,不过没关系我们要的只是模型的mesh而已,我们做预制体的时候只要把美术用的材质球赋予给它就行了,重新打包包体总体减少了90M左右,效果还是可以的。这边有几个点需要注意的:

  1. 模型设置的Import Materials不要打勾
  2. 上面代码处理的是本地工程Library/metadata里的数据,所以出包的时候要在打包工程上处理。
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值