技术分享连载(七十五)

简介:

资源管理

Q1:我们开发的是独立游戏,游戏本身资源不是很多,也不考虑会更新资源,就把资源都放到Resource下。基于上述背景,我想问下游戏启动时间会和这些资源的数量有关吗?这些资源会不会占用内存?还是说要Load出来并实例化之后才会算进内存里面?放在Resource下面的对象和在脚本里面直接引用有区别么?听说Unity 5.6之后的版本中Resources.load的速度慢了很多,我是否需要考虑把资源全部打包成AssetBundle来加载更好呢?相对资源打包成AssetBundle加载快也方便更新,那Resource加载有什么优势?

就题主的问题,回答如下:
(1)Resource文件下,如果资源过多,确实会影响游戏的启动时间;
(2)Resource文件夹下的资源本身不会在启动后加载到内存中,资源是在Resources.Load后被加载进内存的。但是需要指出的是,引擎启动时会创建一个Resource索引表,Resource文件夹下文件越多,其索引表也就越大,这个是会占用内存的;
(3)目前确实有不少团队反馈这个问题,具体内容可以查看这里:
https://answer.uwa4d.com/question/596dd374848e993475a664e5
(4)关于以上两种加载方式的选择,我们建议使用AssetBundle,这也是Unity Best Practice中的建议: Don’t Use Resource.

补充一点我个人的看法, 欢迎拍砖:
Resource和AssetBundle是两套不同倾向的资源管理策略,各自有适用的应用环境。Resource可以看成一个默认加载的巨大AssetBundle,优点在于使用方便,不需要应用层维护资源依赖关系,缺点在于对更新不友好(后文会详细解释),内存敏感的场景下不便于细粒度控制资源的内存占用生命周期,此外还会影响游戏初始化速度。

AssetBundle可以提供更细粒度的资源控制策略,而且对于资源更新友好,但是缺点是管理麻烦,应用层需要维护依赖关系以及管理生命周期,稍不注意就容易出现资源泄露等问题。

Resources和AssetBundle之间有一条天然的鸿沟,那就是AssetBundle无法依赖到Resource里的资源,反之亦然。那么就带来一个问题,如果Resources里一个资源a需要更新,除了更新这个资源a外,还需要更新依赖这个资源的资源b、c、d、e等,还要更新资源a依赖的资源x、y、z等,进而b、c、d、e、x、y和z所依赖的、以及被依赖的资源都需要更新,牵一发而动全身,简直是更新的噩梦。

对于资源更新频繁的网游,尽可能首选AssetBundle,Resource下可以放一些无需更新且启动时就需要的资源,譬如登陆场景的Loading图等,游戏启动的逻辑简洁不易出错;对于无资源更新的单机游戏,也需要尽可能控制Resources下的资源量,避免过长的游戏启动时间。

Unity 5.5及之后的版本,若发现Resources.Load慢了很多,不妨试试Resources.LoadAsync,说不定会颠覆大家的先入为主的“同步加载快于异步加载”的认识。类似地,AssetBundle.LoadAsset/LoadAssetAsync也可能存在同样的问题。

感谢UWA问答社区的胡阿毛提供了以上回答。

如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/598b1a22fb389f61434c5d4c


资源管理

Q2:如下图,不理解ScriptMapper具体是什么,为什么会引用StandardShader,有什么办法可以彻底把StandardShader从内存里移除呢?
请输入图片描述

这说明是有代码在索引这个Shader。建议题主尝试以下方法来定位Standard Shader的具体引用:

在游戏运行时遍历所有的GameObject或者Material,然后获取其所使用的Shader信息,查找跟“Standard”名称相对应的Shader,然后就可以定位它是出自哪个Material或GameObject。

上述方法应该适用于大部分情况,但无法适用于以下情况:

  • Shader被加载后直接被缓存在代码脚本中;
  • Shader是通过AssetBundle.LoadAll加载的;
  • Shader通过Preload Shader加载的。

此问答来自于UWA 问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/598acb48fb389f61434c5d4a


资源管理

Q3:Profiler里Assets和Scene Memory的区别是什么?比如Mesh这一项,在Scene Memory的Mesh中看到的只有2个合并的Mesh:CombinedMesh(root: scene),在Assets的Mesh里看到的有100多个,包括场景里的非合并Mesh,动态加载出来的角色Mesh等。并且Assets的Mesh中的某些点击后选择右边的Referenced By,在Hierarchy里会自动选中场景中的物体,怎么看也不像是单纯的模板,而是实例化出来的东西。
请输入图片描述
请输入图片描述

Resources.Load/Assetbundle.Load出来的ParticleSystem都是放Assets下的,可以认为是模板资源,并不在场景里。Instantiate出来的放在Scene Memory下,是出现在场景里的。所以两边都有是正常的。

在Unity里资源至少分为两类:一类是可以被引用的,比如Mesh、Texture,如果要渲染多个相同的Mesh,并不需要对Mesh实例化,只需要在场景里多创建几份MeshRenderer/MeshFilter去引用它即可。所以Assets下的Mesh不应该被认为是实例化出来的东西,这些Mesh仅仅是通过AsssetBundle.Load/Resources.Load加载出来的,只是被场景里的东西引用了;但SceneMemory下的Mesh通常是通过new Mesh或者Instantiate创建的,这部分可以说是实例化出来的了,另外像CombinedMesh是Unity自己创建的,也可以算是实例化的。

另一类是不可被引用的,通常是组件资源,比如ParticleSystem,如果要渲染多个相同的ParticleSystem,就需要实例化多份出来,ParticleSystem的模板在Assets下,而实例化出来的在SceneMemory下。

此问答来自于UWA 问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5989765c9ba6ca7742b05636


骨骼动画

Q4:开启GPUSkinning,有合并数量限制(骨骼数量),在此我有几个疑惑:
1)动态修改合并后的Mesh数据,比如顶点色,如何递交GPU呢?
2)SkinnedMeshRender并没有相关的函数去刷新?
如果前两个问题解决起来麻烦,那么对于SkinnedMeshRender组件,自定义类,去实现相同的功能是否可行,若可行,是否需要注意某些细节,以适应Unity引擎。

问题一,可以看下这篇文章,里面简单提到了把动画放进纹理的方法(第三部分),理论上没有骨骼限制了。具体实现可以看文中Github地址。

问题二,直接更新或者覆盖SkinnedMeshRenderer的SharedMesh即可,但可能会对性能有影响,如果大量使用是需要具体问题具体分析的。

此问答来自于UWA 问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5989530a315ce4f3357f3062


制作

Q5:我准备用如下代码,使得GameObject旋转到某一角度:
请输入图片描述
但发现,当PredefAngleX取某些值时(例如45),旋转后if语句总是True,导致无法进入else进行下一步。但此时不管是Inspector还是Debug.Log出来,Transform.localEulerAngles.x和PredefAngleX都显示为45。 然后PredefAngleX取另外一些值时又正常(旋转后if能变为False)。MoveTowards用在Transform.Position则总是正常的。这是为什么呢?

浮点数精度导致。 建议体质把if条件换成如下:
if (Mathf.Approximately(transform.localEulerAngles.x, predefAngleX)){…}

比较相差Epsilon的数值可以用以下方法:
Mathf.Approximately ( https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html )






原文出处:侑虎科技
本文作者:admin
转载请与作者联系,同时请务必标明文章原始出处和原文链接及本声明。

目录
相关文章
|
图形学 Android开发 分布式计算
|
缓存 测试技术 图形学
|
编解码 前端开发 图形学
|
Java Android开发 图形学
|
图形学 iOS开发 异构计算
|
iOS开发 图形学 Android开发
|
前端开发 图形学 数据可视化

热门文章

最新文章