我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。
资源管理
Q1:对于运行时动态加载的普通模型比如怪物,我们目前的打包策略是把它单独打一个AssetBundle包,通过AssetBundle加载并实例化的消耗。如下图所示,对于WWW、AssetBundle、GameObject,卸载方法分别为WWW.Dispose、assetBundle.Unload、Destroy/DestoyImmediat。但对于通过AssetBundle加载出来的Assets资源, 这块的资源用什么策略清理合适?
1)Resources.UnloadUnusedAssets,但该函数比较费时,一般只在切换场景时候使用;
2)assetBundle.Unload(true); 运行时Assetbundle在Instantiate prefab完成后也立即执行了unload(false),所以也不适用;
对实例化出来的GameObject在使用后即使执行了DestroyImmediate,模型引用的贴图还驻留在内存中,难道要遍历GameObject使用的Assets分别执行UnloadAsset么?
如果是仅加载Prefab,那么随Prefab一起加载进来的资源是不太方便被“优雅”地卸载的,即便是对应的GameObject被Destroy了,那么它对应的资源会变成“游离”状态(没有Refcount),只能等到手动调用Resources.UnloadUnusedAssets或场景切换时被引擎卸载。 所以,一般建议研发团队尝试通过依赖关系进行打包,将资源和Prefab进行分离,这样可以将加载资源和加载Prefab分开,从而可以通过“显式”地方式加载资源并将其进行储存,这样当你想精准释放资源时,则可以直接通过Resources.UnloadAsset来进行卸载。
该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59b0e87a6bf71eaf669e0c72
资源管理
Q2:现在项目里面有多个相似的Shader,由于代码相似而分散到多个Shader文件,所以不好维护管理,而且美术人员用起来也不方便,因此有想法使用“multi_compile”功能整合在一起。我的Unity版本是5.3.3,想问下使用“multi_compile”会不会有性能问题?有什么要注意的地方?
理论上性能没什么影响,因为本质上还是会产生多个版本的Shader,一种材质只会用到对应的一个版本。
注意点可以看官方文档,比较全面:https://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html。 主要是注意下组合数,避免生成的版本过多,另外也可以了解下 shader-feature,与multi-compile相似,但适用于某些特殊情况。
该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59ae14f82cc11cf02b784984
动画
Q3:平时研究动画系统的时候有几个不太明白的问题:
1.BlendTree(不论1D或者2D) 在采样的时候,如果BlendTree内的AnimationClip的长度不同,那么输出的动画长度是可变的。不同的BlendTree参数会导致不同的BlendTree输出的动画长度。问题是BlendTree最终输出的动画长度是如何计算出来的?采样AnimationClip的时候,对于动画的TimeScale做了什么调整? 图例:run是一个BlendTree2D,当它的参数Speed=300时,和Speed=900时的长度是不一样的。
2.Unity的BlendTree2D是如何根据两个动画参数确定该在哪几个AnimationClip中采样?这些AnimationClip各自的权重是多少? 图例:当Direction=-19,Speed=777的时候,黄箭头所指的动画实际上是由红箭头所指的4个动画混合而成的。那么混合权重分别是多少?
对于不同的Clip动画数据进行Blend时,Unity会把所有Clip的时间都归一化(展开为相同长度)后,再根据各个Clip的权重进行加权平均。Blend后的时间长度与各Clip的权重相关,时间更接近权重大的Clip的时间(近似时间长度的加权平均)。BlendTree参数值用来决定当前Blend各Clip的权重值,参数不同导致权重不同,因此时间也就不同。参数值如何决定哪些Clip进行Blend,其权重则跟不同Clip的参数threshhold相关。
2D时在参数空间中根据(x,y)的坐标位置对临近的Clips进行插值。不同2D Blend 类型使用的插值方法不同,而插值方法的实现也就决定了各Clip的权重。对于插值算法可以参考这里提供的pdf:
http://answers.unity3d.com/questions/1206428/how-weights-of-2d-blending-are-calculated.html
该问题来自UWA问答社区,感谢 Switch.N 提供了回答,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59b24f806a3c64fe76fc00ab
资源管理
Q4:LoadSubsAsync和LoadSubs加载SpriteData,我想请问一下: 如果先LoadTexture加载纹理再加载LoadSubs,或者LoadSubsAsync函数调用加载SpriteData,纹理是否会加载两次,以及性能如何呢? 按照我的理解,LoadSubsAsync或者LoadSubs,它自身有Texture属性,我断点调试可以看到SpriteData内的Texture会随着SpriteData加载而出来。
LoadSub和LoadSubAsync是会同时加载Texture的。 而先Load再LoadSub,并不会造成冗余问题,所以Load过Texture后,LoadSub的耗时就很小了。 但如果Texture里的Sprite是打了图集的,那么LoadSub的时候还是会有个图集加载的耗时。
该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59b14a656bf71eaf669e0c7f/
UI
Q5:对于UI网格更新和重建的两个情况,我有如下两个疑问想了解下:
1)我对于网格重建的理解是:如果UI的Mesh发生了变化,比如血条UI中血量变了可能导致Mesh变化,从而发生了重建。但网格更新是什么样一种情况呢?UWA Blog的原文中提到了“只在其中的UI元素发生变动(位置、颜色等)时才会进行”,这句话是否可以理解为颜色变化和位置的变化产生了网格更新?
2)是否即使UI没有变化,每帧中仍然是会产生Draw Call?这样想是因为每帧都要显示UI,而这个UI的数据即使有缓存可能也是让CPU省事了,但是GPU仍旧需要进行渲染的工作,从而CPU还是要调用Draw Call。如果是这样,那么其实UI的Mesh重建因为需要CPU进行计算所以开销比较大;而UI由于位置发生变化导致的Mesh更新,因为只是重新提交给GPU UI模型的世界坐标,因此消耗是比较小的;而UI由于颜色变化导致的Mesh更新,其实消耗就更小了,这里只是在提交渲染状态时改变颜色即可。不知道上面的理解是否正确。
更新指的是UI元素本身的某些属性发生变化,从而需要重新生成,或者更新顶点属性。比如颜色变了,在UGUI中颜色的变化是通过修改顶点色实现的,所以就需要更新UI元素对应的每个顶点的顶点色属性(可以认为就是修改下某个数组里的数值)。位置移动一般是不会造成顶点属性的变化的。所以总的来说,“网格更新”更新的是顶点属性。
UI元素和别的网格不同点在于,UI的网格是需要进行合并的,并且在UGUI中是以Canvas为单位的,在提交GPU之前,同一Canvas下的所有UI元素都会被合入一个Mesh中(但包含多个SubMesh)。所以位置的移动,顶点属性的变化,都会导致这个Mesh要重新合并,也就是网格重建。这也是为什么说要“动静分离”的原因,完全静态的Canvas是不需要重建的,但只要里面有一个UI元素在动,就会引起Canvas的重建。
最后建议题主看一下UWA博客中的直播,关于网格更新和重建讲得比较详细。https://blog.uwa4d.com/archives/1875.html
该问题来自UWA 社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/59af579c6a071c595e8994b2
领取专属 10元无门槛券
私享最新 技术干货