项目中策划数据的存储和读取

项目中策划数据的存储和读取

这是第143篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)

本期目录:

  • 项目中策划数据的存储和读取
  • ASTC纹理的应用性
  • Android上关于Lightmap宏失效
  • 如何修改模型的UV信息
  • AssetBundle资源加载和卸载

配置文件

Q:因为项目中策划数据是生成二进制文件,最近发现在获取String值的时候消耗了大量的Mono堆内存(byte[] to string)。我尝试把所有的Excel数据转成ScriptableObject对象再打到AssetBundle中发现AssetBundle.LoadAsset()相比于byte[] to string申请Mono堆内存更大。请问大家项目中策划数据是如何存储和读取的,对于大量文本内容如何能尽量减小Mono内存的消耗?

A1:配置表二进制,ScriptableObject, CSV都是常用的方式,如果是Lua重度的游戏可能会直接把配置表转为Lua文件进行加载。加载配置表的时候Mono堆内存消耗大,一个可能是本身配置表数据量过大,再一个可能是同时加载的配置表过多,导致申请的Mono堆内存过大,而这个峰值上来了就降不下来了。
如果是本身配置表过大,检查下是否可以缩减一些冗余数据,再一个就是拆表,分步加载。另外就是注意在解析数据的过程中分配的内存,List,String等的复用来减少频繁分配内存。
感谢赵林@UWA问答社区提供了回答

A2:我们游戏用的是Lua文件来存储数据。确实会出现光数据就有60MB的内存。感觉还是使用一些db作为数据比较合适。用的时候去对应数据并缓存下来即可。而且一个玩家在玩的过程应该不会用到所有的数据,如果直接用Lua或其他文本文件,那就意味着只要用到其中一条,就把整个表都加进来了。
感谢halm@UWA问答社区提供了回答

A3:1) 不要将配置表打成AssetBundle包,这样不仅降低加载速度,也会产生大量的GC,毕竟有一次转化过程,而且增加了Mono内存;
2) 少用序列化文件;
3) 重点是我们要将配置表进行适时的加载,不要一次性加载,Streaming加载部分数据,降低读取整表需要的耗时和内存消耗。
感谢郑骁@UWA问答社区提供了回答

A4:看到这个问题,忍不住要给使用了很多年的开源策划数据导表神器tabtoy打个广告:
https://lab.uwa4d.com/lab/5c26dbc072745c25a8e40d04
具体特性如下:

  • 编写电子表格, 导出. 只需2步, 即可导出数据!
  • 跨平台运行, 无第三方依赖, 无需任何的vbs,vba,dll
  • 支持文件格式最多的导出器(Json, Lua, C#+二进制, protobuf text, Proto, golang)
  • 一次设置, 自动生成索引代码, 支持Lua, C#
  • 单元格字段列顺序随意调整, 自动检查错误, 精确报错位置
  • 强类型, 导出时自动类型检查, 提前暴露表格错误
  • 支持中文枚举值, 中文结构体字段, 编写,更直观
  • 支持同类型表拆分, 多人协作填表导出互不影响
  • 支持纵向填写字段作为配置, 将电子表格作为快速配置文件
  • 全中文导出提示,并支持多语言导出提示
  • 支持导出Tag匹配,导出需要的部分, 避免客户端混合服务器私密数据
  • 支持类型信息导出, 方便无反射的语言(例如C++)使用
  • 充分利用CPU多核进行导出, 是已知的现有导出器中速度最快的
    感谢张锐@UWA问答社区提供了回答

该问答来自UWA问答社区,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c1d028fcbf84301a9dd1f03


资源管理

Q:最近准备把iOS所有设备都选用ASTC这种压缩方式,可担心会伤及iOS的高端用户。但总不能对高低端设备用两套资源吧,小厂商受不起,且不知道它对高端机有什么帮助,不知道它对帧率和发热有改善吗?

A1:Texture,第一要从文件读到内存中,第二要从内存上传到显存中(逻辑上的显存,某些时候是显卡上独立的一块存储,某些时候是从内存中划分的一块,移动平台应该都是从内存划分一块),第三Shader里进行纹理采样的时候要从显存中读取Texture。
对比RGBA和ASTC,后者体积小了很多,所以"读文件/上传到显存"理论上都会更快,对实际用户体验影响有多大要看具体情况。
进行纹理采样的时候,通常会一次读目标纹素附近的若干个纹素到Cache,如果后续访问的是临近纹素,就可以直接从Cache里取,不需要再次访问显存,访问显存是很慢的操作,也是很耗电的操作(和访问Cache相比),数据传输会占用带宽,访问显存的带宽消耗比访问Cache大的多。
对于ASTC,压缩时按Block压,读取时也按Block读,还需要用专门的GPU硬件对Block进行解压,然后才能传给Shader。
对比RGBA32和ASTC,假设一次读取16byte数据,那么前者是16/4 = 4个纹素(每个纹素32bits),后者起码是16个纹素(每个纹素8bits),所以后续访问时ASTC的Cache命中会高很多,也就是整体上会大大的减少访问显存的次数。虽然ASTC需要解压,但是对设计过的压缩格式,解压的速度(ALU计算的速度)通常比数据传输的速度快很多(如同CPU的计算速度和内存的访问速度差距),所以解压开销换带宽是划算的,综合来看,ASTC比RGBA要快,要省电。同样,对用户体验到底能影响多少,也要看实际情况,我们反正是能压的都压,能压多高就压多高。对帧率是否有影响要看瓶颈是否在Texture带宽。
感谢gx@UWA问答社区提供了回答

1)项目组人多钱多等版号:做两套AssetBundle包,ipa自带ASTC版本,发现iPhone 5s以前的机型下载RGBA32+PVRTC版本的AssetBundle包;
2)项目组折腾不起,老板或者运营商一定要兼容99%的iOS设备,不可以有放弃,继续RGBA32+PVRTC;
3)项目组折腾不起,老板和运营商开化,愿意放弃iPhone 5s及以前的设备,果断ASTC。
感谢郑昊@UWA问答社区提供了回答

A3:1024✖️1024分辨率,下图为占用内存大小,RGBA32效果最好,内存占用也最大,ASTC小效果又好,完爆ETC,对耗电和帧率有提升,但是很小,大部分发热还是CPU和GPU的计算压力。
3052(0).png
感谢郑骁@UWA问答社区提供了回答

A4:最近也在思考这个问题,如果用ASTC的话伤及iOS高端用户的问题。ASTC格式是目前iOS推荐使用的格式,应该说是在质量和包体内存加载效率等方面挺好的一个平衡的格式了。缺点就是不支持5s以及以前的机型,另外,毕竟是有损压缩,尤其是在半透的UI上,还是可以看出跟RGBA32质量的差距。
目前暂定的方案还是通过准备两份资源的方式,ipa自带ASTC,然后挑出比较明显的差别处,比如说半透UI,另外准备一份RGBA32的资源,只有高端iOS用户能看到。但是这份资源可以不要求用户强制下载,只是一个下载选项,下载的时机可以根据需要设定,可以是下载完后一个提示,但是可以取消。也可以内部有下载高清资源的选项等,当然也可以在wifi情况下在用户空闲时后台下载,当然设计的宗旨就是不影响用户体验的情况下给予玩家一个选择。
这套处理机制建立起来有个好处就是,如果需要适配的话随手也可以把5s以下的也解决了,给5s也准备一份资源下载。
感谢赵林@UWA问答社区提供了回答

该问答来自UWA问答社区,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c1cc1a54e577c207402d31d


Lightmap

Q:项目中有些场景使用了Lightmap,有些场景没使用Lightmap。Shader里面使用 LIGHTMAP_ON 开关去读取Lightmap发现在PC上加载的场景AssetBundlle资源是有Lightmap的,但是发布Android 在手机上Lightmap没读取到,应该是这个宏开关失效了 求解。

#ifdef LIGHTMAP_ON
half4 lm = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lmuv.xy);
lm.rgb = DecodeLightmap(lm);
#endif

A:修改Shader Sripping里的Lightmap Modes,不要让它是自动,如果是自动,它会根据你当前打开的场景,来设置打包AssetBundle,如果是空场景,Lightmap就全丢了。
感谢郑骁@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c243ef674f78a31e5338851


FBX

Q:修改模型的UV信息,用了AssetDatabase.SaveAssets()保存,但是重启Unity后还原了,请问怎么保存?打开FBX查看信息是导会到Max看还是什么?EditorUtility.SetDirty已经调用了。
请输入图片描述
请输入图片描述

A1:最优的方式应该是在导入时OnPostProcessModel进行UV修改,创建同名的Mesh Asset然后使用这个提取出来的Mesh也是可以的,但是用提取出的Mesh有个问题就是切断了跟FBX的联系,如果外部工具进行FBX进行了修改,就需要导入重新提取。还有就是你想设置FBX的一些导入属性的时候就得设置后重新提取,这是不方便的地方。
感谢赵林@UWA问答社区提供了回答

A2:简单做法就是先把Mesh从FBX里面克隆一份出来再修改,FBX里面的是只读的。因为FBX是只读的,不能覆盖,所以你就一直用提取出来的Mesh好了。
感谢张迪@UWA问答社区提供了回答

该问答来自UWA问答社区,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c234b30d832ca31ea08a6bf


资源管理

Q:目前项目所有的资源都是使用AssetBundle的,我有以下几个问题:
1)目前所有的资源根据依赖信息,加载自己以及其他的AssetBundle并且它们都被缓存下来,目前都没有被销毁。这样会导致内存越来越大吧?
2)虽然所有的AssetBundle都应该被Unload,但是如果这个主观判断并去卸载肯定不合适吧。那有什么策略可以较好的管理呢?如果资源和AssetBundle包之间使用引用计数来管理,那是不是意味着所有加载的地方都要管理卸载了?个人感觉不太合适,因为如果项目庞大,那么加载的地方太多了。
3)如果使用Unload(false)来管理,那岂不是意味着我一份资源在内存中会存在大量的重复。不知道是不是加载AssetBundle太多了,直接导致了切换场景的时候Resources.UnloadUnusedAssets();的效率明显下降了。
4)我的图片虽然设置了Packingtag,但是它是被Shader使用的,所以有可能最终导致它没法打成图集吗?

A1:都缓存肯定内存会越来越大的,所以需要有合适的释放策略。unload(false)切断了AssetBundle与里面Asset的关系,如果再次加载,而之前的没有释放,会出现资源重复的情况。还是需要自己来进行管理,加载的地方是多,但是可以统一管理,统一的加载卸载接口,包括自己做引用计数管理,可以自己制定卸载策略,比如说切换场景的时候做一次比较彻底的清理,核心战斗中尽量不做资源清理,其他根据具体情况做缓存排序,指定释放策略。
最后一个问题没做过测试,如果是自己的Shader,如果可以打成图集,就需要自己处理UV才能显示正确。
感谢赵林@UWA问答社区提供了回答

A2:1)内存会一直增长,头文件+资源主体
2)引用计数是主要手段,大项目更需要引用计数,加载资源的地方和时机太多,统一接口达到统一管理的目的。
3)出现多份资源的情况是:加载AssetBundle中的资源并实例化之后,unload(false)资源,然后又重新加载了AssetBundle并实例化了资源,这种问题一般在依赖的资源中问题较多,例如Shader,Material等,非主动请求加载的资源。
4)卸载时机:
轮询卸载:在非加载时段,进行轮询,做好卸载队列,分帧卸载,防止卡顿
销毁卸载:在某UI或实体销毁时,并在引用计数为0的情况下,X秒后主动请求遍历卸载。
感谢郑骁@UWA问答社区提供了回答

该问答来自UWA问答社区,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c1fc2c7d832ca31ea08a63a

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

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:793972859(原群已满员)

封面图来源:FPS Sample开源库测评

  • 汪振 发表在 1月5日 回复

    关于iOS的Texture压缩格式, 看了许多文章, 发现还停留在纠结PVRTC格式上, 我想说新版, 从Unity2017就看开始支持IOS端的ETC2格式的压缩了, 这样安卓和iOS都可以使用统一的压缩格式, 打包出来的AB文件几乎都差不多大小, 并且ETC2格式支持只需要长宽4的倍数的图片即可, 这样, 对于那些大量使用大背景图的工程, 在IOS端使用ETC2能节省大量的空间! 并且如果还想更小的压缩大小, 压缩格式还可以选择Crunched ETC或Crunched ETC2, 压缩大小还能再更小!! 如果项目还停留在5.x的unity版本, 光凭这个iOS端支持ETC的压缩格式, 就值得升级到Unity2017版本, 现在最新的2017长期支持版本, 已经非常稳定! 强烈一步到位升级到2017.4.x版本!