模型资源打包与加载

前言

模型的打包与加载,比普通类型的资源要复杂一些,涉及到模型身上引用到的图片、材质球、fbx文件的处理。而材质球的打包也不是打包的本体,而是先将材质球转成json的形式进行打包,之后加载时,再解析json中的数据重新生成材质球。这样做的目的,一来可能是为了减小包体大小,或者便于处理依赖,也可以使材质球信息更方便查看和管理。

打包

初始资源

初始资源有四个,分别是materials, prefab,texture,fbx
初始资源

解析Material成json

打开debug模式,查看材质球,可以看到有三个属性。material

因此可以建立与材质球对应的类
材质球结构类如下:

// 材质球结构类
public class MatData
{

    public string shader = "";
    public List<Attritubute> attributes = new List<Attritubute>();
}

public class Attritubute
{
    public Tuple<string, MatShaderPropertyType, MatVector> attri;
    public Tuple<string, MatShaderPropertyType, MatTex> texAttri;
    public Tuple<string, MatShaderPropertyType, double> floatAttri;
}

public struct MatVector
{
    public double x;
    public double y;
    public double z;
    public double w;
    public void Set(double x,double y,double z , double w)
    {
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
    }
}

public struct MatTex
{
    public string texName;
    public string bundleDir;
    public double x;
    public double y;
    public double z;
    public double w;
    public byte[] data;
}

public enum MatShaderPropertyType
{
    Color,
    Vector,
    Float,
    Range,
    TexEnv,
}

再新建一个解析类,用将material转换成对应结构。
材质球解析类如下:

	//材质球解析类
    public static MatData MatToJson(Material mat)
    {
        MatData data = new MatData();
        Shader shader = mat.shader;
        data.shader = shader.name;
        int propertyCount = ShaderUtil.GetPropertyCount(shader);
        for (int i = 0; i < propertyCount; i++)
        {
            Attritubute attr = new Attritubute();
            string propertyName = ShaderUtil.GetPropertyName(shader, i);
            MatShaderPropertyType type = (MatShaderPropertyType) ShaderUtil.GetPropertyType(shader, i);
            switch (type)
            {
                case MatShaderPropertyType.Color:
                    Color color = mat.GetColor(propertyName);
                    attr.attri = new Tuple<string, MatShaderPropertyType, MatVector>(propertyName, type, new MatVector()
                    {
                        x = color.r, y = color.g, z = color.b, w = color.a
                    });
                    break;
                case MatShaderPropertyType.Float:
                case MatShaderPropertyType.Range:
                    double f = mat.GetFloat(propertyName);
                    attr.floatAttri = new Tuple<string, MatShaderPropertyType, double>(propertyName,type,f);
                    break;
                case MatShaderPropertyType.Vector:
                    Vector4 v4 = mat.GetVector(propertyName);
                    attr.attri = new Tuple<string, MatShaderPropertyType, MatVector>(propertyName,type,new MatVector()
                    {
                        x = v4.x,y= v4.y,z=v4.z,w = v4.w
                    });
                    break;
                case  MatShaderPropertyType.TexEnv:
                    Texture t2d = mat.GetTexture(propertyName);
                    string assetPath = AssetDatabase.GetAssetPath(t2d);
                    attr.texAttri = new Tuple<string, MatShaderPropertyType, MatTex>(propertyName,type,new MatTex()
                    {
                        texName = t2d.name,
                        bundleDir = assetPath
                    });
                    break;
            }
            data.attributes.Add(attr);
        }
        return data;
    }

将结构解析完成后,得到材质球信息类,再调用LitJson,传入信息类,得到json文本,如下:

    public static void DoMatAndPng(string rootName, string path)
    {
        string assetPath = TCommon.RemovePathPrefix(path);
        Material m = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
        
          //转换材质球为json
            MatData data = MatTool.MatToJson(m);
            string jsonData = JsonMapper.ToJson(data);
            StringBuilder sb = new StringBuilder();
            JsonWriter write = new JsonWriter(sb);
            JsonMapper.ToJson(data, write);
            int idx = path.LastIndexOf('\\');
            string paraPath = path.Substring(0, idx);
            paraPath = paraPath + "\\mat.json";
            File.WriteAllText(paraPath, sb.ToString());
        
    }

打包json与png

再对其进行打包即可。
同时也可以拿到材质球上的texture,再对texture进行打包。代码如下:

        //对mat_json文件标记ab
        AssetImporter importer = AssetImporter.GetAtPath(TCommon.RemovePathPrefix(paraPath));
        importer.assetBundleName = $"{rootName}_mat";
        importer.assetBundleVariant = TCommon.ABSUFFIX;
        //对png标记
        AssetImporter importerTex = AssetImporter.GetAtPath(data.attributes[0].texAttri.Item3.bundleDir);
        importerTex.assetBundleName = $"{rootName}_png";
        importerTex.assetBundleVariant = TCommon.ABSUFFIX;

打包fbx预制体

处理fbx模型文件,模型文件并不直接打包,可新建预制体,进行实例化后,对prefab进行打包。这样可以间接剔除掉除fbx外的其他资源被打包。不会导致冗余。

    public static void DoFbx(string rootName, string fbxPath)
    {
        GameObject fbxGo = AssetDatabase.LoadAssetAtPath<GameObject>(TCommon.RemovePathPrefix(fbxPath));
        GameObject instanGo = GameObject.Instantiate(fbxGo);
        string prefabPath = fbxPath.Substring(0, fbxPath.LastIndexOf('\\'));
        prefabPath = $"{prefabPath}\\{rootName}.prefab";
        prefabPath = prefabPath.Replace("\\", "/");
        Object newPrefab = PrefabUtility.CreateEmptyPrefab(TCommon.RemovePathPrefix(prefabPath));
        GameObject finalPrefab = PrefabUtility.ReplacePrefab(instanGo, newPrefab);
        string finalPath = AssetDatabase.GetAssetPath(finalPrefab);
        AssetImporter importer = AssetImporter.GetAtPath(finalPath);
        importer.assetBundleName = $"{rootName}_base";
        importer.assetBundleVariant = TCommon.ABSUFFIX;
    }

加载

模型加载的思路:从assetbundle中加载出fbx所在的prefab、json、png。
通过json解析,组装出材质球。材质球赋值png和对应的shader,prefab上的meshRenderer组件再赋值材质球。代码如下:

    public GameObject LoadModel(string modelName)
    {
        //加载图片
        string pngPath = $"{Application.streamingAssetsPath}/model/{modelName}_png{TCommon.ABSUFFIX_AFTER}";
        string fbxPath = $"{Application.streamingAssetsPath}/model/{modelName}_base{TCommon.ABSUFFIX_AFTER}";
        AssetBundle ab_png = AssetBundle.LoadFromFile(TCommon.RemovePathPrefix(pngPath));
        Texture2D png = ab_png.LoadAsset<Texture2D>("city02_beauty");
        
        //加载材质球json
        string jsonPath = $"{Application.streamingAssetsPath}/model/{modelName}_mat{TCommon.ABSUFFIX_AFTER}";
        AssetBundle ab_json = AssetBundle.LoadFromFile(jsonPath);
        TextAsset textAsset = ab_json.LoadAsset<TextAsset>("mat");
        MatData matData = new MatData();
        matData = JsonMapper.ToObject<MatData>(textAsset.text);
        Shader shader = new Shader();
        
        shader = Shader.Find(matData.shader);
        Material mat = new Material( shader);
        mat.mainTexture = png;
        Debug.Log("aa:"+matData.shader);

        //加载fbx
        AssetBundle fbx_ab = AssetBundle.LoadFromFile(TCommon.RemovePathPrefix(fbxPath));
        GameObject prefab = fbx_ab.LoadAsset<GameObject>(modelName);
        GameObject model = GameObject.Instantiate(prefab);
        MeshRenderer render = model.GetComponent<MeshRenderer>();
        render.material = mat;
        return model;

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值