AssetBundle系列——场景资源之解包(二)
本篇接着上一篇继续和大家分享场景资源这一主题,主要包括两个方面:
(1)加载场景
场景异步加载的代码比较简单,如下所示:
private IEnumerator LoadLevelCoroutine()
{
string url = "ftp://127.0.0.1/TestScene.unity3d";
int verNum = ; 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", -);
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 = ;
// 记录每个加载线程的进度,只有每个线程都加在结束了,场景加载才算完成
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 = ; 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 = ;
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产生。
AssetBundle系列——场景资源之解包(二)的更多相关文章
- AssetBundle系列——场景资源之打包(一)
本篇讲解的是3D游戏的场景资源打包方式,首先简单的分析一下场景中所包含的资源的类型. 场景资源一般包含:地表模型(或者是Unity Terrain),非实例化物体(摄像机.空气墙.光源.各种逻辑物体之 ...
- AssetBundle系列——游戏资源打包(二)
本篇接着上一篇.上篇中说到的4步的代码分别如下所示: (1)将资源打包成assetbundle,并放到自定目录下 using UnityEditor; using UnityEngine; using ...
- (转)AssetBundle系列——游戏资源打包(二)
转自:http://www.cnblogs.com/sifenkesi/p/3557290.html 本篇接着上一篇.上篇中说到的4步的代码分别如下所示: (1)将资源打包成assetbundle,并 ...
- AssetBundle系列——共享资源打包/依赖资源打包
有人在之前的博客中问我有关共享资源打包的代码,其实这一块很简单,就两个函数: BuildPipeline.PushAssetDependencies():依赖资源压栈: BuildPipeline.P ...
- AssetBundle系列——游戏资源打包(一)
将本地资源打包,然后放到资源服务器上供游戏客户端下载或更新.服务器上包含以下资源列表:(1)游戏内容资源assetbundle(2)资源维护列表,包含每个资源的名字(完整路径名)和对应的版本号[资源名 ...
- [Unity Asset]AssetBundle系列——游戏资源打包
转载:http://www.cnblogs.com/sifenkesi/p/3557231.html 将本地资源打包,然后放到资源服务器上供游戏客户端下载或更新.服务器上包含以下资源列表:(1)游戏内 ...
- (转)AssetBundle系列——共享资源打包/依赖资源打包
有人在之前的博客中问我有关共享资源打包的代码,其实这一块很简单,就两个函数: BuildPipeline.PushAssetDependencies():依赖资源压栈: BuildPipeline.P ...
- (转)AssetBundle系列——游戏资源打包(一)
转自:http://www.cnblogs.com/sifenkesi/p/3557231.html 将本地资源打包,然后放到资源服务器上供游戏客户端下载或更新.服务器上包含以下资源列表:(1)游戏内 ...
- 从零系列--开发npm包(二)
一.利用shell简化组合命令 set -e CVERSION=$(git tag | ) echo "current version:$CVERSION" echo " ...
随机推荐
- javaweb学习总结(二十一)——JavaWeb的两种开发模式
SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...
- Linux Buffers和Cached的区别(转)
在linux下使用free命令查看内存使用情况,有buffers和cached两项,以下是它们的区别: buffers是为块设备设计的缓冲.比如磁盘读写,把分散的写操作集中进行,减少磁盘I/O,从而提 ...
- Code Consultation
Need help architecting or coding your application? You can get technical help with building applicat ...
- mysql-5.7.15-winx64免安装版配置
1.拷到硬盘根目录下; 2.在 bin 平行目录下新建 data 文件夹: 3. 修改 my-default.ini 文件,添加 basedir = C:\mysql-5.7.15-winx64d ...
- [aaronyang]WPF4.5 - AyTabControlBase样式分享,绝对好看
样式代码如下: 对于博客园将文章移除首页的做法:我就迁移了.文章已经迁移:http://www.ayjs.net/post/75.html 由于例子比较简单,你只要指定Style即可,难点,透明区域的 ...
- Metaweblog在Android上使用
同步发表于http://avenwu.net/2015/02/04/metaweblog metaweblog是一个博客接口协议,目前主流的博客平台均支持该协议,比如博客园,CSDN,WordPres ...
- 【转】Log4net用法
Log4net用法 http://www.cnblogs.com/hfliyi/archive/2012/05/20/2510783.html
- windows7系统下如何安装windows xp系统(无法识别硬盘,删除隐藏分区)
一.硬盘模式的设置 要设置好硬盘模式,否则安装操作系统的时候,根本就不识别硬盘,自然无法安装操作系统了.此步骤主要是解决无法识别硬盘的问题. 首先,进入BIOS当中,一般在advanced当中,有一个 ...
- Gamma校正与线性工作流
1 Gamma校正是什么?8位亮度值x(0-1)经过x^0.45的一个提亮过程. 2 为什么需要Gamma校正 人的眼睛是以非线性方式感知亮度,在自然界中,人感觉到的一半亮度其实只有全部能量的0.2, ...
- Cubieboard2裸机开发之(四)定时器操作
前言 在Cubieboard2裸机开发之(三)里用到了一个延时函数delay,它的延时时间是不精确的,因此为了能够精确延时,就需要定时器的配合.定时器可以精确延时的一个重要原因是它的计时时钟(或者说频 ...