内容简介:Unity3D 的大场景内存优化
我们公司的一个 MMORPG 项目最近在内存方面碰到了红线,昨天开会讨论了一下。我提出了一个改进方案,写篇 blog 记录一下。
问题是这样的。在当下的手机及平板硬件设备条件下,操作系统留给应用的可用内存并不多,大约只有 500M 左右。
和 PC 环境不同,手机上是交换分区的机制来对应一些临时突发性内存需求的。而手机必须保证一些系统服务(某些高优先级后台业务)的运行,所以在接电话、收取推送等等意外任务发生时,有可能多占用一些内存,导致操作系统杀掉前台任务让出资源。
根据实际测试,游戏想跑在当前主流高端手机上必须把自己的内存占用峰值控制在 400M 内存以下,350 M 会是一个合理的值,而这个值是远远低于 10 年前的 PC 游戏标准的。而我们的项目却是一个写实类型的 拥有大场景的 MMORPG 。
Unity3D 是在智能手机普及以前设计的,远没有料到会被广泛用于手机游戏的制作。它在设计之初并没有为低内存环境考虑。内存使用太粗犷,是在使用 Unity 开发 MMORPG 项目时最被吐槽的一点。
为手机游戏定制游戏引擎,最特别的,和 PC 游戏不同的两点就是内存必须严格控制、能耗必须严格控制。比如在我们开发的 ejoy2d 中,会为资源数据中的项目引用定制短指针,即资源内部的相互引用使用 32bit 偏移量来代替 64bit 指针,每个指针节省出 4 字节内存;变换矩阵使用 6 个 32bit 的定点数,资源中相同矩阵共享一份数据;资源数据尽量连续存放,避免小数据块太多造成内存碎片浪费内存等等。这些显然是 Unity 没花精力去做的。在 PC 上,省下几M 几十M 内存微不足道,但在手机上很可能就是生死之间。
ps. 能耗问题是另一个有趣点。在 PC 上你可以通过多线程并行,压榨出高 fps ,可以不管 CPU 多烫;但是到了手机上,即使 CPU 8 核心已经是标配,还是尽量不要这么做。因为在总任务相同的情况下,单线程能做完的工作只要拆分到多线程上完成,就一定意味着总工作量增加(至少增加了线程间协调的工作)。增加了总能耗。玩家是不想玩一个插着充电线也会玩关机,手机滚烫的游戏的。这个问题有机会我另写一篇 blog 展开,今天是想谈谈内存。
在我们最近的测试中,在较坏情况下,我们的游戏会占到 360M 内存左右,已经接近了内存红线,所以要考虑进一步的优化。其中,较大的一块是游戏场景,占了 120M 内存。
有趣的是,这 120M 内存中只有大约 50M 是用于场景上物件的贴图、模型等等资源数据(注:我们项目没有使用静态批次合并,那样更消耗内存。);也就是说,有 70M 内存用于构建场景本身的结构。所以,并非让美术人员尽量复用同样模型的花花草草就可以省下内存的。换句让美术人员更容易明白的说法,我们的场景中摆的东西太多了,不是减少贴图用量,把同一块石头到处摆可以解决的。这和过去制作 PC 游戏的常识不同。
所以,大部分现有的手机 MMORPG 的画风偏卡通幻想风格不是没有道理。因为那样,可以用有悖现实的物件比例,场景物件个头大,就可以用更少的数量去充斥场景。而写实风讲将就细节丰富,用诸多细节去填满视野。在过去 PC 上,这不是问题,只要少做点独特的模型,少用贴图就能把内存降下来,手机上不行了。
我们并非刚刚意思到这点。一开始,开发人员就针对大场景制定了技术解决方案。
我们在场景上,认为设定了若干包围盒,勾画出一块块小区域。一旦玩家离开包围盒太远,程序就会把包围盒里面的物件卸载出内存。然后在美术设计上,不让玩家有可以从远处观望的角度。我们的美术风格会尽量保证场景细而精致、不追求空旷宏大的场面。
但这还做的不够,我提出了一个改进方案。
-
保留包围盒方案。但是包围盒略微扩大,允许包围盒重叠,并可以用多个包围盒来定义一个区域。同一个场景物件只可以属于一个区域,即使它的位置在多个区域内。(区域可以重叠)
-
所有物件都标记分类出外观物件和细节物件。比如一个城市的城墙就是外观物件,而城内的所有东西都是细节物件;一片树林的大颗植物是外观物件,地面的花花草草是细节物件。一般情况下,大部分物件都默认是细节物件,只有少数需要远观的才标记成外观。这点,其实原本就做了视距分层,只不过是为了在渲染时做显示剔除用的,并没有用于控制内存。而这次,需要对外观物件和细节物件单独打包分类,便于分开卸载。
-
当玩家处于一个区域内部时,必须保证这个区域的外观物件和细节物件都加载到内存。如果之前并不在内存,也需要开启异步加载的流程。当一个玩家距离另一个区域比较近时,只需要确保该区域的外观物件在内存即可,可以卸载任何不在区域的细节物件。
在以上改进方案里,把包围盒扩大以及允许多个包围盒一起构成区域,是为了改进数据加载的时机。单一用距离判断会有瑕疵。比如在城墙外,即使隔的很近也不需要加载城内的细节。而我们完全可以在城门外加一个缓冲的小区域并入城市区域,只要玩家一踩到城门口,城内的细节加载流程就开始启动了。
而允许区域重叠,并让物件唯一归属于单一区域则可以解决城门外的细节物体提前加载时机。城外的这块缓冲区上的物件就不必归属到城市板块,它们早在玩家在城外活动时就加载完毕了。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++设计新思维
(美)Andrei Alexandrescu / 侯捷、於春景 / 华中科技大学出版社 / 2003-03 / 59.8
本书从根本上展示了generic patterns(泛型模式)或pattern templates(模式模板),并将它们视之为“在C++中创造可扩充设计”的一种功能强大的新方法。这种方法结合了template和patterns,你可能未曾想过,但的确存在。为C++打开了全新视野,而且不仅仅在编程方面,还在于软件设计本身;对软件分析和软件体系结构来说,它也具有丰富的内涵。一起来看看 《C++设计新思维》 这本书的介绍吧!