技术分享连载(六十)

原文链接:https://blog.uwa4d.com/archives/TechSharing_60.html

我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。
UWA QQ群:465082844
UWA 问答社区:answer.uwa4d.com


资源管理

Q1:对于WWW.LoadFromCacheOrDownload(System.String url, Int32 version)这个接口的第二个参数,我知道是做缓存资源的更新用的。我们之前在Editor模式下作了一个测试:用该函数加载一个资源,Version参数设置为1,会发现在缓存目录下生成了一个对应该资源的缓存目录,这很正常。然后我们再次用这个接口加载这个资源,Version参数设置为2,现会发在缓存目录下生成一个新的对应该资源的缓存目录,并没有覆盖旧的目录。这个情况在移动平台上是否也是这样的?

是的,在移动平台上,通过LoadFromCacheOrDownload加载的AssetBundle,其Version版本号变化时,新的解压Data是不会覆盖旧的解压Data的。清除旧的解压Data主要有三种方式:

  1. 设置缓存的过期日期,默认情况下是150天;
  2. 调用Caching.CleanCache来全部清空缓存;
  3. 当本地Cache已满时,Unity会从最早的AssetBundle来进行自动清理。

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


资源管理

Q2:我听说WWW.LoadFromCacheOrDownload(System.String url, Int32 version)这个接口加载资源,如果是Unity 4.x的版本,会有500个资源的数量限制,如果超过这个限制,Unity会删除之前缓存的每个资源,是这样吗?那在Unity 5.x 版本上是否还存在这样的问题呢?

在Unity 4.x的版本中,如果通过LoadFromCacheOrDownload来加载AssetBundle,那么有两种情况需要考虑:

  1. 内存中加载的AssetBundle数量。在iOS平台上,通过该接口加载、同时存在于内存中的AssetBundle数量确实是有限的,接近300个,这是由于iOS上文件句柄数的限制导致。而该限制在Unity 5.0以后则被完善了,因为Unity 5引入了虚拟文件系统,所以不再有这个限制;在Android平台上,则没有这个限制,或者说数量限制值非常大,基本可以忽略。

  2. 本地Cache中缓存的AsseBundle数量。无论是iOS、Android还是PC版本,都没有500的数量限制,而是有一个硬盘占用大小限制。具体来说,在WebPlayer平台上,有50MB的缓存限制,而在其他平台上,则是4GB的缓存限制。所以只要硬盘占用大小不超过限定值即可。

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


资源管理

Q3:我阅读了UWA的你应该知道的AssetBundle管理机制一文,想对其中“每次加载都涉及到解压操作”的理解进行确认:对于new WWW实际是解压到WebStream。而如果是用的LoadFromCacheOrDownload,那么资源是在磁盘,所以在调用www.assetbundle时才做解压。那么有个问题,如果使用直接获取AssetBundle的那些API,解压过程是怎样的呢?CreateFromFile是在调用assetbundle.load的时候从磁盘解压,CreateFromMemory是直接解压到WebStream?

另外,对于WebStream来说,同一个WWW对象多次调用www.assetbundle方法时,得到了栈上的多个变量,但是这些变量都指向同一个WebStream中的对象吗?

对于第一个问题,AssetBundle的解压均发生在加载API的调用处,而不发生在www.assetbundle时,即无论是New WWW、LoadFromCacheOrDownload、LoadFromFile还是LoadFromMemory,其AssetBundle的解压均在上述API调用处。在Unity 5.3版本之前,Create/LoadFromMemory是直接解压到WebStream中,而在5.3后,则已经不存在WebStream这一说法了。具体可以查看官方文档:https://docs.unity3d.com/Manual/AssetBundleCompression.html

对于第二个问题,同一个WWW对象,多次调用www.assetbundle时并不出现WebStream的Clone操作,即这些变量均指向同一WebStream对象。


动画模块

Q4:我们在内存优化时发现一个问题,编辑器版本 Unity 5.3.4p6,使用UGUI,场景A中一个Text控件使用自定义字体资源,然后把该控件Text属性勾选为空(disable),再Load一个空场景,看场景A卸载后在内存中的残留,发现有一份引用是 ManagedStaticRefrences()的 Font 内存。如果不是把Text属性disable,则场景A卸载后内存里不会再残留被引用的Font内存,请问可能是什么原因造成的呢?相关例子已经提交给UWA。

UWA对于该例子进行了检测,的确能够在 Editor 复现。查了下 UGUI 代码,能对 Font 产生引用的,主要是这个函数 FontUpdateTracker.TrackText(Text),其中会把 t.font 引用起来;而对应的解引用的函数为 FontUpdateTracker.UntrackText。因此,如果出现了两者的调用不匹配,就有可能造成 font 的 ManagedStaticRefrences 引用。

进一步查看后,可以看到在定义了 UNITY_EDITOR 宏时,UI 元素会增加一个名为 OnValidate 的函数,Text 组件则在其中进行了 TrackText 的操作。
而最关键的是,该函数在 Text 组件以“未**”的状态被实例化时同样会被触发,同时,如果这样的 Text 组件在后续没有被**过就被销毁,其 OnDestroy 和 OnDisable 函数是不会被调用的,参见文档中的这句话:OnDestroy will only be called on game objects that have previously been active.
而 OnDisable 中才会调用 Untrack 解引用,所以造成了不匹配,导致了 font 的 ManagedStaticRefrences。
但是,OnValidate 函数只在 Editor 上才有,真机上不会发生上面说到的不匹配的情况。所以建议研发团队先在真机上测试下是否还有这种情况,如果确实没有,那么就忽略该问题即可。

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


图形渲染

Q5:我想了解如何使用顶点色Mask控制明暗关系,才能达到类似崩坏琪亚娜效果?

贴一个之前Guilty Gear Xrd (http://qiankanglai.me/2015/10/09/ggx-part1)的例子,参考了 【翻译】西川善司「实验做出的游戏图形」「GUILTY GEAR Xrd -SIGN-」中实现的「纯卡通动画的实时3D图形」的秘密—前篇(1)(http://www.cnblogs.com/TracePlus/p/4205798.html) 中的做法:

研发团队可以在顶点色里刷入明暗信息,如下图:
请输入图片描述

原来的效果如下:
请输入图片描述
接下来把顶点色的明暗乘上去(或者用其他的运算,主要就是用来控制亮度)
请输入图片描述
注意左臂腋窝部分…阴影部分变大了。至于具体的控制方法,个人认为一般点乘居多,美术只要控制好顶点色输入的亮度就行。

感谢来自 UWA 问答社区的钱康来提供回答:
https://answer.uwa4d.com/question/58e5ffe180ca640f2736fc94
如您对该问题仍有疑问,可以转至社区进行进一步交流。


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站(answer.uwa4d.com)上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com 官方技术QQ群:465082844(非水群,仅限技术交流)