Q&A——资源管理(二)

来源:互联网 发布:网络歌曲2015伤感情歌 编辑:程序博客网 时间:2024/05/23 00:10

资源管理

Q1:Prefab中的GameObject的tag设置为EditorOnly仍然会被打进Resoures包吗?有其它EditorOnly方案吗?

EditorOnly理论上只对场景中的 GameObject起效。因此 Project 目录中的 Prefab 打上 EditorOnly 后,放在 Resources 目录下依然会被打进游戏包中。但只要将其放在 Resources 目录以外,则其就会因为没有场景中的物件引用而被排除在外。

资源管理

Q2:打包时候AssetBundle的md5总变化(被打包的东西没变),请问能怎么解决?有说法是加上DeterministicAssetBundle就可以,但是我尝试后发现md5依然变化。

该方法确实并不受用。对于Unity 4.x版本的AssetBundle文件,其md5值在某些情况下确实会前后不一致(哪怕是完全一样的内容进行打包)。对于该系列版本,仅能建议开发团队建立配置文件来对AssetBundle进行管理。

而对于Unity 5.x版本,则可以在打包时开启 AppendHashToAssetBundleName 选项,这样Unity引擎会在每个AssetBundle文件后生成一个唯一的HashID(显示地放在文件名后),开发团队可以通过该ID来判断对应的AssetBundle文件是否发生改变。

资源管理

Q3:请问内置的shader怎么打包?我用到了内置材质球,不只是Shader,这时候在Profiler中看到加载的结果中会出现多份,如下图所示:
UWA Tech Doc

通常有两种方式对内置的Shader进行打包:

  1. 将其添加到Graphics Settings中的Always Included Shaders 中,此时添加后的内置Shader就不会被打入AssetBundle包中;
  2. 在http://unity3d.com/cn/get-unity/download/archive下载内置的 Shader,将其导入项目,并替换成非内置的材质球,从而可以直接通过脚本来控制其打包的方式。

资源管理

Q4:用Resources.UnloadAsset 释放未Instance的Object 会出现这样的错误 :Unload Assets may only be used on individual assets and can not be used on GameObject's/Components or AssetBundles.请问该如何解决?

Resources.UnloadAsset仅能释放非GameObject和Component的资源,比如Texture、Mesh等真正的资源。对于由Prefab加载出来的Object或Component,则不能通过该函数来进行释放。


资源管理

Q5:我现在动态加载StreamingAssets下的贴图,代码如下:
UWA Tech Doc
我发现这种方式内存消耗很大,一张512 x 512的贴图占用了2MB,看官方的解析是内存和显存各需一份。想了解下动态加载贴图有什么推荐的方式吗?

一般来说,我们比较建议通过AssetBundle来动态加载资源,而非通过bytes流来进行加载。如果你的项目正在使用这种方式来加载纹理,我们建议从策略上考虑将其更改。在我们目前来看,通过bytes流来生成资源,绝大部分原因是想对其进行加密,从而让资源难于破解。但其实这种加密方式用处不大,因为据我们所知,现在有很多工具可以直接通过底层显卡层来直接查看各种纹理、Mesh资源,比如Mali Graphics Debugger、Qualcomn Profiler等。因此,如果是从加密的角度来通过bytes流生成资源,那么我们建议通过AssetBundle这种直接的方式进行加载。

资源管理

Q6:我用的是Resource的加载方式,并且已经预加载好了材质所在的Prefab ,但是为什么在第一次显示材质的时候还要Load这个材质?

通过 Resources 加载和通过 AssetBundle 加载是有所区别的。Resources.Load 和 Instantiate 操作都不会立刻加载其依赖的材质,因此在loadPrefab = Resources.Load之后,其依赖的材质(包括相关的 Shader 和纹理)实际并没有被加载到内存中,在实例化后也是一样,直到某个 Camera 需要对其进行渲染时(调用了 Material.SetPastFast),才发现该材质还没进内存,此时才开始进行加载。

因此,在使用 Resources 加载的情况下,如果希望提前加载该 Material 以及相关的 Shader 和纹理,可以尝试通过调用 Resources.Load 直接加载该材质和纹理,并通过 Shader.Find 来加载 Shader。也可以尝试通过 Player Settings 中的 Preload Shaders(配合 Graphics Settings 下的 Preloaded Shaders) 和 Preloaded Assets 来批量预加载。


资源管理

Q7:我们的游戏使用 Spine 插件,因为要用到裁切动画,所以修改了Shader,但在使用的时候出现异常: Shader wants normals, but the mesh Skeleton Mesh doesn't have them,可能是什么原因?

开发团队需要注意:Surface Shader在生成代码中默认会处理normal(即 Spine/Skeleton 实际上是需要 normal 的),而对应的Mesh并没有包含normal,所以在预览窗口里渲染的时候会检查 Mesh 是否包含 normal 信息,没有的话会报这个错误。

开发团队可以尝试编写一个Vertex & Fragment Shader 从而避免处理normal,也可以尝试创建带normal的Mesh,来避免该问题。


资源管理

Q8:我在第一次执行GameObject.Instantiate一些资源的时候会卡(当时加载当时就实例的情况),有的复杂资源甚至在第一次GameObject.Instantiate的时候会卡70多毫秒,造成明显的卡顿,请问有什么好的解决方案吗?

Instantiate的卡顿与三部分开销相关:相关资源加载、脚本组件的序列化和构造函数的执行,并且绝大部分原因均是相关资源加载导致。所以,我们的建议如下:

1、通过 Profiler 查看 Instantiate 具体的CPU分配情况;
2、如果是资源加载导致的性能瓶颈,则一方面通过简化资源来缓解CPU耗时压力,另一方面通过 AssetBundle 依赖关系打包将资源预先加载,即将此处 Instantiate 的总体耗时拆分,平摊到之前帧进行执行(比如切换场景处等),从而让 Instantiate 实例化操作的局部耗时更加平滑;
3、如果是脚本组件序列化导致的性能瓶颈,则可尝试减少脚本中的序列化信息;
4、如果是构造函数的执行导致的性能瓶颈,一般只能在策略上进行规避,比如降低 Instantiate 的调用频率等。

针对资源加载部分,我们近期正以专题的形式连载中,后续会对其Instantiate实例化的调用进行更为详细的分析,敬请期待。


资源管理

Q9:同一个纹理,有多个Prefab生成的实例,会有多份这个纹理的copy吗?

该问题需要查看 Prefab 的具体加载方式。如果仅是通过 Resources.Load 进行加载,那么纹理是不会存在多份的,但如果是通过AssetBundle加载,每个 Prefab 均为一个 AssetBundle 且纹理没有进行依赖关系打包的话,那么纹理资源确实会在内存中存在多份。如果你发现了内存中存在多份相同纹理,且是通过 AssetBundle 文件来加载资源的,则建议将 AssetBundle 上传到UWA网站(www.uwa4d.com)中,其资源检测工具能协助开发团队高效检测并定位AssetBundle中的冗余资源。

资源管理

Q10:我项目的UnityShaderCache目录下有300个文件(如下),且不是一次生成, 而是随着游戏进行而产生的。

Application.persistentDataPath/cache/UnityShaderCache

为了在游戏第一次进行时把所有Shader都编译来减少卡顿,我把用到的Shader加入到 Always Included Shaders中, 并在游戏开始时调用了 Shader.WarmupAllShaders,也尝试把Shader打个包一起加载出来 ,然后Shader.WarmupAllShaders,但是效果并不理想。有什么好的解决方案吗?
另一个困惑:已加到 Always Included Shaders 中的。 还需要再加载一次么?

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

原创粉丝点击