zoukankan      html  css  js  c++  java
  • AssetBundle系列——场景资源之解包(二)

    本篇接着上一篇继续和大家分享场景资源这一主题,主要包括两个方面:

    (1)加载场景

    场景异步加载的代码比较简单,如下所示:

        private IEnumerator LoadLevelCoroutine()
        {
            string url = "ftp://127.0.0.1/TestScene.unity3d";
            int verNum = 1;
    
            WWW wwwForScene = WWW.LoadFromCacheOrDownload(url, verNum);
            while (wwwForScene.isDone == false)
                yield return null;
    
            AssetBundle bundle = wwwForScene.assetBundle;
            yield return Application.LoadLevelAsync("TestScene");
            wwwForScene.assetBundle.Unload(false);
        }

    (2)加载场景物件

    主要包含以下细分步骤:

    a、下载并解析场景配表,得到场景物件信息。场景物件的数据结构如下所示:

    public class XmlSceneGameobjectProp
    {
        // Mesh信息
        public class MeshInfo
        {
            public string name;
            public string shader;
    
            public bool hasColor = false;
            public Vector4 color;
    
            public bool isStatic = true;
            public int lightmapIndex;
            public Vector4 lightmapTilingOffset;
        }
    
        public string name;
        public string group;
        // Transform信息
        public float posX, posY, posZ;
        public float rotX, rotY, rotZ;
        public float scaleX, scaleY, scaleZ;
        // Mesh列表,一个模型可以包含多个MeshRenderer
        public List<MeshInfo> LstMesh = new List<MeshInfo>();
    }

    xml解析的主体代码如下所示:

     private void ParseChildNode(XmlElement xmlGroup, XmlElement xmlChild)
        {
            SceneGameobjectProp newChild = new SceneGameobjectProp();
            newChild.group = xmlGroup.GetAttribute("name");
            newChild.name = xmlChild.GetAttribute("name");
            // 注册资源名字
            if (lstRes.Contains(newChild.name) == false)
            {
                lstRes.Add(newChild.name);
            }
    
            // Tranform节点
            XmlNode xmlTransform = xmlChild.SelectSingleNode("Transform");
            // MeshRenderer节点
            XmlNode xmlMeshRenderer = xmlChild.SelectSingleNode("MeshRenderer");
    
            if (xmlTransform != null && xmlTransform is XmlElement)
            {
                CXmlRead goReader = new CXmlRead(xmlTransform as XmlElement);
                newChild.posX = goReader.Float("posX", 0f);
                newChild.posY = goReader.Float("posY", 0f);
                newChild.posZ = goReader.Float("posZ", 0f);
                newChild.rotX = goReader.Float("rotX", 0f);
                newChild.rotY = goReader.Float("rotY", 0f);
                newChild.rotZ = goReader.Float("rotZ", 0f);
                newChild.scaleX = goReader.Float("scaleX", 1f);
                newChild.scaleY = goReader.Float("scaleY", 1f);
                newChild.scaleZ = goReader.Float("scaleZ", 1f);
            }
    
            if (xmlMeshRenderer != null && xmlMeshRenderer is XmlElement)
            {
                foreach (XmlNode node in xmlMeshRenderer.ChildNodes)
                {
                    if ((node is XmlElement) == false)
                        continue;
    
                    SceneGameobjectProp.MeshInfo mesh = new SceneGameobjectProp.MeshInfo();
                    mesh.name = (node as XmlElement).GetAttribute("Mesh");
                    mesh.shader = (node as XmlElement).GetAttribute("Shader");
                    XmlNode xmlLightmap = node.SelectSingleNode("Lightmap");
                    if (xmlLightmap != null && xmlLightmap is XmlElement)
                    {
                        CXmlRead reader = new CXmlRead(xmlLightmap as XmlElement);
                        mesh.isStatic = reader.Bool("IsStatic", true);
                        mesh.lightmapIndex = reader.Int("LightmapIndex", -1);
                        mesh.lightmapTilingOffset = new Vector4(reader.Float("OffsetX", 0f), reader.Float("OffsetY", 0f), reader.Float("OffsetZ", 0f), reader.Float("OffsetW", 0f));
                    }
                    XmlNode xmlColor = node.SelectSingleNode("Color");
                    if (xmlColor != null && xmlColor is XmlElement)
                    {
                        CXmlRead reader = new CXmlRead(xmlColor as XmlElement);
                        mesh.hasColor = reader.Bool("hasColor", false);
                        mesh.color = new Vector4(reader.Float("r", 0f), reader.Float("g", 0f), reader.Float("b", 0f), reader.Float("a", 0f));
                    }
                    newChild.LstMesh.Add(mesh);
                }
            }
    
            lstGameObjectProp.Add(newChild);
        }

    b、加载场景物件asset

    同时开启多个Coroutine进行WWW的LoadFromCacheOrDownload操作,经测试开启的WWW线程越多,速度会越快,但是需要考虑实际的机器或平台的承载能力。

    注意,我这儿的WWW操作是直接从缓存里面载入内存,而不是从网上下载。所有更新的游戏物件,可以在游戏开始的时候一次从网上Download到Cache,这样,在游戏过程中就不需要从网上Download资源了,wifi下载3G玩,爽歪歪~

    如果一定要在此处从网上Download资源的话,线程数最好设为5个,很多平台有自己的限制,比如有的网页浏览器只能同时开6个等等......

        // 同时开启的Coroutine的数目
        private const int ThreadNum = 100;
        // 记录每个加载线程的进度,只有每个线程都加在结束了,场景加载才算完成
        private int[] arrThreadProggress = new int[ThreadNum];
    
        // 加载完成后的回掉
        public delegate void LoadFinishDelegate();
        public LoadFinishDelegate OnLoadFinish = null;
      
        // 需要下载的资源列表
        private List<string> lstRes = new List<string>();
        // 是否加载完毕的标记
        private bool hasFinished = false;
    
        private void LoadAsset()
        {for (int i = 0; i < ThreadNum; ++i)
            {
                CoroutineProvider.Instance().StartCoroutine(LoadAssetCoroutine(i));
            }
        }
    
        private IEnumerator LoadAssetCoroutine(int threadIndex)
        {
            while (arrThreadProggress[threadIndex] < lstRes.Count)
            {
                // 载入资源
                string name = lstRes[arrThreadProggress[threadIndex]];
                GameApp.GetResourceManager().LoadAsync(GlobalSetting.SceneAssetPath + name, typeof(GameObject));
                while (GameApp.GetResourceManager().IsResLoaded(GlobalSetting.SceneAssetPath + name) == false)
                {
                    yield return null;
                }
                arrThreadProggress[threadIndex] += ThreadNum;
            }
            // 线程资源下载完毕,进行加载回掉
            if (IsLoadFinished() && hasFinished == false)
            {
                hasFinished = true;if (OnLoadFinish != null)
                {
                    OnLoadFinish();
                }
            }
        }

    上面的黑体标出的代码是是实际的加载代码,具体实现已经在帖子“AssetBundle系列——资源的加载、简易的资源管理器”中讲解过了,此处不再赘述。

    c、实例化场景物件

      // 实例化
        GameObject goIns = GameObject.Instantiate(asset) as GameObject;
        goIns.name = goProp.name;
    
        // 设置父节点
        GameObject goGroup = null;
        dicGroupGameobject.TryGetValue(goProp.group, out goGroup);
        if (goGroup != null)
            goIns.transform.parent = goGroup.transform;
        else
            goIns.transform.parent = goRoot.transform;
    
        // 设置Transform
        goIns.transform.position = new Vector3(goProp.posX, goProp.posY, goProp.posZ);
        goIns.transform.eulerAngles = new Vector3(goProp.rotX, goProp.rotY, goProp.rotZ);
        goIns.transform.localScale = new Vector3(goProp.scaleX, goProp.scaleY, goProp.scaleZ);
    
        // 设置Shader、Lightmap
        int index = 0;
        int meshCount = goProp.LstMesh.Count;
        foreach (MeshRenderer mr in goIns.gameObject.GetComponentsInChildren<MeshRenderer>(true))
        {
            if (mr.sharedMaterial != null)
            {
                if (index < meshCount)
                {
                    SceneGameobjectProp.MeshInfo meshProp = goProp.LstMesh[index];
                    mr.sharedMaterial.shader = Shader.Find(meshProp.shader);
                    if (meshProp.hasColor)
                        mr.sharedMaterial.color = meshProp.color;
                    bool isStatic = meshProp.isStatic;
                    mr.gameObject.isStatic = isStatic;
                    if (isStatic)
                    {
                        mr.lightmapIndex = meshProp.lightmapIndex;
                        mr.lightmapTilingOffset = meshProp.lightmapTilingOffset;
                    }
                }
                index++;
            }
        }

       本帖主要是关于assetbundle的处理方法,关于物体材质的实例化逻辑,有很多种做法,我这只是提供了其中一种做法。其中有一点需要注意的,就是material和sharedMaterial的区别,上面实例化中的代码,我用的是sharedMaterial来设置,使用material是有问题的,因为每一次对material的赋值会导致生成一个materil的instance产生。

  • 相关阅读:
    微信支付系列(2)——jsapi支付源码解析
    微信支付系列(1)
    java创建文件和目录
    在线文档预览方案-office web apps
    必要的思考
    做WEB开发的时候,前端与后端我们应该要注意哪些细节,哪些容易出现的漏洞?
    使用MVVM框架时,如何处理在页面动态渲染完之后需要发生的事件呢?
    系统间通信(10)——RPC的基本概念
    系统间通信(9)——通信管理与RMI 下篇
    系统间通信(8)——通信管理与RMI 上篇
  • 原文地址:https://www.cnblogs.com/sifenkesi/p/3598569.html
Copyright © 2011-2022 走看看