UWA

每天一点UWA:第五周

Posted by 蔡华的博客 on August 27, 2017

AssetBundle

shader加载

  • 首先 Shader. WarmupAllShaders 并不影响 Shader 的加载,因为该函数的作用是将所有已加载的 Shader 都做一次快速渲染(渲染单个像素,GPU 在首次使用某一个 Shader 时会有额外开销,Warm 相当于是将这部分开销提前)。
  • 可以通过AssetBundle.LoadAll等接口预加载 AssetBundle 中的 Shader。而对于 Always Included Shaders 中的 Shader 则可以通过 Shader. Find 来预加载。

StreamingAssetPath 和 PersistantDataPath直接load非AssetBundle资源?

  • 可以但是只能用WWW这样的有限的API.
  • 如果load MP3、JPG这样的非内部资源格式效率低,尤其是JPG还要软解码,效率更低。
  • 还是推荐AssetBundle。

在Unity 5.x 的打包机制下确实无法手动为 FBX 下的 Mesh 或 AnimationClip 单独资源设置 AssetBundle Name。

如果Animator是直接引用了FBX里的动画文件,而不是复制了FBX的动画文件出来再引用,那么打包的时候不会把FBX打进AssetBundle。

Resources.UnloadUnusedAssets同样可以卸载由AssetBundle.Load加载的资源,只是前提是其对应的AssetBundle已经调用Unload(false),且并没有被引用。

总结一下AssetBundle的加载和卸载

加载

  • AssetBundle的各种创建函数可以从本地文件(LoadFromXXX)或者内存中将AssetBundle加载到一块内存区域(use from memory or unitywebrequest)或者只是建立一个序列化引用(use loadformfile)。
  • AssetBundle的各种load函数会将真正的asset从AssetBundle中加载出来到内存中。
  • instantiate函数创建GameObject实例

卸载

  • AssetBundle的实例函数unload(false)会卸载内存中的AssetBundle(虽然函数的说明中是Unloads all assets in the bundle.),参数是true的话删除AssetBundle和用它创建的asset。
  • 上面的函数针对的单个AssetBundle,而UnloadAllAssetBundles这个静态函数就是针对所有当前已经load的AssetBundle了。
  • 对于一个具体的asset可以使用Resources.UnloadAsset来卸载,或者使用Resources.UnloadUnusedAssets将多有没有引用的asset卸载。前提就是调用过AssetBundle的Unload(不论参数是false还是true)。

Build

Optimize Mesh Data选项

  • build时我们在player setting里面有这个选项,它只针对Build Player或者Bundle 时才生效的,所以提前做的AssetBundle是无效的。
  • 模型导入时也有个Optimize Mesh选项,是调整面片排序的,和build时的是两回事。

UI

UGUI做的一个界面中有一个背景图片,关闭销毁这个界面后调用 Resources.UnloadUnusedAssets,图片还在内存中

  • 在使用 Resources.Load 加载 UI 界面的情况下,即使“关闭销毁这个界面”后,Resources.UnloadUnusedAssets 确实还是无法卸载对应的图集的。因为此时该图集依然被 Resources.Load 加载出来的 Prefab 引用。
  • 建议是手动调用 Resources.UnloadAssets 来手动释放图集(可以通过 Sprite.texture 来找到对应的图集),在重新实例化该 UI 界面时,图集也会自动进行 Reload 的。

模型

MeshBaker 烘焙的Mesh可以保存到Prefab中,但是不能像FBX一样,设置Model导入设置中的Generate Lightmap UVs 等信息,请问有没有大招可以处理此情况?

  • 首先从理论上说,一个 Mesh 只能有一个 LightmapIndex 和 LightmapOffset 属性,这就决定了 Mesh 的合并必须在 Lightmap 的烘焙之前。
  • 做Mesh合并时,需要注意到UV2对于一个Mesh而言,其所有三角面的UV区域都必须是互不重叠的,所以不能简单直接地合并。 考虑到合并前每一个Mesh的UV2区域都应该是在[0,1]x[0,1]的区间中,在合并时可以给每一个UV2区域做一个缩小和平移,从而可以把每个区间在互不重叠的情况下,放到同一个[0,1]x[0,1]的区间中。 在UV2也正确拼合后,重新进行Lightmap的烘焙即可得到正确的效果。

关于静态batch

  • 勾选Static的GameObject下的Mesh都会被合入CombineMesh(无论什么材质),且每个Mesh都作为SubMesh存在。
  • 在Unity 5.3之前,对于渲染顺序相邻且材质相同的SubMesh则会动态将其索引数组拼合,从而合成一个Draw Call。
  • 而Unity 5.3之后(还是在同材质,渲染顺序相邻的前提下)则不再拼合索引数组,因为在不切换材质时产生多个Draw Call的开销并不大,而这多个Draw Call会被统计为一个Batch。

如何删除StaticBatchingUtility.Combine会产生Combined Mesh的内存

  • 通过某个使用了该Combined Mesh的MeshFilter来获取其引用(MeshFilter.sharedMesh),然后通过Destroy接口来将其卸载。因为Combined Mesh不属于真正的Assets(在Deep Memory中不属于Assets下,而是在Scene Memory下),所以不能用Resources.UnloadAsset来卸载。

内存

AssetBundle内存占用问题

  • 在webStream仍旧存在时(似乎是5.4之前),一个AssetBundle(1mb)解压到websream后如果是2mb,那么这个AssetBundle最终所占的内存就是2mb,因为webstream中已经包含了AssetBundle。

AssetBundle资源卸载

AssetBundle加载好以后立刻通过Instantiate实例化一个对象,然后通过Resources.UnloadAsset和Resources.UnloadUnusedAssets来进行卸载,如果无法卸载,则该资源一定被缓存了。