Unity游戏优化[第二版]学习记录4

第4章 着手处理艺术资源

一、音频

1、导入音频文件

在Project窗口中选中导入的音频文件时,Inspector窗口将显示多个导入设置。这些设置决定了一切,包括加载行为、压缩行为、质量、采样率,以及(在Unity的后期版本中)是否支持双声道音频(多声道音频,通过球面谐波组合音轨,以创建更真实的音频体验)。

2、加载音频文件

通过以下3种设置可以指定音频文件的加载方式:
· Preload Audio Data
Preload Audio Data决定了音频数据是在场景初始化期间自动加载,还是在以后加载,默认初始化期间自动加载。

· Load In Background
Load In Background确定此活动是在完成之前阻塞主线程,还是在后台异步加载,默认同步加载。

· Load Type
Load Type定义了将什么类型的数据拉入内存。Load Type有3种选择:
Decompress On Load:默认选项,此设置压缩磁盘上的文件以节省空间,并在首次加载时将其解压到内存中
Compressed In Memory:此设置在加载音频时只是将其直接从磁盘复制到内存中,只有在播放音频文件时,才会在运行期间对其进行解压缩
Streaming:此设置将在运行时加载、解码和播放文件,具体的做法是逐步将文件推过一个小缓冲区,在缓冲区中一次只存在整个文件的一小部分数据。此方法对特定音频消耗的内存量最小,但运行时CPU消耗的内存量最大,而且多次引用同一音频数据会导致运行时存在多个副本占用内存

3、编码格式与品质级别

Unity支持3种音频编码格式,在Inspector窗口中查看音频的属性时,由Conpression Format选项决定哪种格式:
Compressed: 默认选项,编码格式随平台的不同而不同
PCM: 一种无损的、未压缩的音频格式,以更大的文件大学换取更高的音频质量,最适用于极短暂且需要高清晰度的音效
ADPCM: 此格式在文件大小和CPU消耗方面都比PCM高效得多,但是压缩会产生相当大的噪声。如果将其作为具有大量混乱的短声音效果,例如爆炸、碰撞、冲击等声音,则可以隐藏噪声,玩家不会注意到任何失真

4、 音频性能增强

1)最小化活动音源数量
由于每个播放中的音频源消耗特定数量的CPU,因此禁用场景中冗余的音频源可以节省CPU周期。一种方法是限制可以同时播放音频的实例数,这涉及通过一个中介发送音频播放请求,该中介控制着音频源,从而对一个音频可以同时播放的实例数设置上限。

2)为3D声音启用强制为单声道
在立体音频文件上启用Force to Mono(强制为单声道)设置会将来自两个音频通道的数据混合到一个通道中,文件的总磁盘和内存空间使用量有效降低了50%。
一般不要给二维音效启用此选项,二维音效通常用于创建特定的音频体验。但是,两个通道实际相同的3D位置音频可以启用此选项。

3)重新采样到低频
将导入的音频文件重新采样到较低的频率将减小文件大小和运行时内存占用。可以将音频文件的Sample Rate设置为Override Sample Rate,此时可以通过Sample Rate选项配置采样率。
有些文件需要高采样率听起来才合理,例如高音调文件和大多数音乐文件,但是,大多数情况下,较低的设置可以减小文件大小,而不会明显降低质量。
22050Hz是源于人类语音和古典音乐的一个常见采样率。有些声音效果甚至可以用更低的频率值来消除。

4)考虑所有的压缩格式
如前所述,Compressed、PCM、ADPCM压缩格式都有各自的优缺点。在适当的情况下,可以对不同的文件使用不同的编码格式,或者设计出一个适用于所使用的音频文件类型的系统,这样就不需要单独处理每个文件。

5)注意流媒体
Streaming加载方式的优点是运行时内存成本低,因为它分配了一个小的缓冲区,但是从磁盘流式传输文件应该仅限于大型的单实例文件(背景音乐/环境音效),因为它需要运行时的硬盘访问,这是我们可用的最慢的数据访问形式之一(仅此于网络拉取文件)。

6)通过混音器组应用过滤效果以减少重复
过滤效果可用于修改通过音频源播放的音效,并可通过FilterEffect组件完成。每个单独的过滤效果都需要消耗一定的内存和CPU,这是一个很好的方法,可以节省磁盘空间,同时保持音频播放的多样性,因为一个文件可以通过一组不同的过滤器进行调整,以产生完全不同的声音效果。
由于有额外的开销,在场景中过度使用过滤器效果会导致性能上的严重后果,更好的方法是利用Unity的音频混音器实用程序(Window | Audio Mixer)生成通用的过滤效果模板,多个音频源可以引用这些模板,以最小化内存开销。
音频混音器的官方教程:https://unity3d.com/learn/tutorials/modules/beginner/5-pre-beta/audiomixer-and-audiomixer-groups

7)谨慎地使用远程内容流
可以使用Unity通过Web动态加载游戏内容,这是减少应用程序磁盘占用的一种有效方法,因为需要打包到可执行文件中的数据文件更少,还提供了一种使用Web服务呈现动态内容的方法。素材流可以通过Unity5中的WWW类或Unity2017中的UnityWebRequest类完成。
WWW类提供audioClip属性,如果AudioClip对象是通过WWW对象下载的音频文件,则该属性用于访问AndioClip对象。但是,请注意,访问此属性将在每次调用时分配一个全新的AudioClip资源,一旦不在需要此资源,就必须使用Resource.UnloadAsset()方法释放它。
在Unity2017中,WWW类已被UnityWebRequest类替代,它使用了新的HLAPI和LLAPI网络层。通过DownloadHandlerAudioClip.GetContent()多次重新获取音频不会导致额外的内存分配,它只返回对最初下载的音频的引用。

8)考虑用于背景音乐的音频模块(Audio Module)文件
音频模块文件也称为音轨模块(Tracker Module),是节省大量空间,并且没有任何明显质量损失的绝佳方式。Unity支持的文件扩展名有.it、.s3m、.xm、.mod。
在普通的音频格式中,音轨模块是以位流的形式读取的,必须在运行时解码以生成特定类型的声音,而音轨模块包含许多小的,高质量的样本,并将整个音轨组织成类似于音乐表的形式;定义每个样本的播放时间、位置、音量、音高以及特效。这样可以在保持高质量采样的同时显著节省占用的空间大小。因此,如果有机会为音乐文件使用音轨模块版本,就应好好探索一番。

二、纹理文件

在游戏开发中经常混肴纹理和精灵的概念,因此需要区分它们:
纹理只是简单的图像文件、一个颜色数据的大列表,以告知插值程序,图像的每个像素应该是什么颜色,而精灵使网格的2D等价物,通常只是一个四边形(一对三角形合并成的长方形网格),用于渲染面向当前相机的平面。还有一种被称为精灵表的事物,它是在一个大纹理文件内大量独立图像的集合,通常用于包含2D角色动画。
网格和精灵都使用纹理,将图像渲染到它的表面。

1、纹理压缩格式


与音频文件类似,可以以多种常见格式(如.jpg和.png等)导入纹理文件,但应用程序中内置的实际压缩格式可以根据给定平台的GPU,从很多不同的纹理格式中选择理想适配的一种。
上图就是精灵图的导入属性,可以根据需要调整这些导入属性,最重要的是,可以设置打包数据的不同方式,这允许GPU进行高效内存访问(如果选择了错误的包装类型,访问效率会非常低)。

2、纹理性能增强

1、减小纹理文件的大小
给定的纹理文件越大,推送纹理所消耗的GPU内存带宽就越多。

2、谨慎地使用Mip Map
对于渲染远处的对象,例如石头、树木等,玩家看不到细节,使用高精度细节的纹理就没有意义。当然,玩家可以看到轻微的效果提升,但这么微笑的细节提升远不及其性能损耗。MipMap的开发解决了此问题,在运行时,GPU根据透视图中的表面大小选择相应的MipMap级别
可以通过开启Generate Mip Maps设置,Unity自动为这些纹理生成低分辨率的副本,这是在编辑器内通过高质量重采样和过滤方法生成的,这些纹理会打包到一起,最终的纹理文件会比原始图像大33%,这将消耗一些磁盘空间和用于上传到GPU的带宽
注意,如果纹理和摄像机的距离时固定的,例如UI系统使用的纹理,2D游戏等,MinMap完全没用,此时应该关闭纹理的MipMap属性

3、从外部管理分辨率的降低
Unity做了很多努力让很多工具尽可能易于使用,并允许将项目文件从外部工具导入项目的工作空间中,诸如.PSD和.TIFF文件,它们通常很大,且拆分为多图层的图像。
问题是Unity自动纹理生成和压缩技术可能不如使用纹理编辑工具生成的效果好,因此,可以习惯性地避免在Unity项目中使用.PSD和.TIFF文件

4、调整Anisotropic Filtering级别


Anisotropic Filtering是一项在非常倾斜的角度观察纹理时提升纹理品质的特性。上图就展示了不使用(第一张图)和使用(第二张图)Anisotropic Filtering属性的效果对比。在距离摄像机较远的地方,使用了Anisotropic Filtering属性比不使用Anisotropic Filtering属性清晰得多。
应用于纹理的Anisotropic Filtering强度可以通过纹理资源上的Aniso Level属性设置(上图中第一张图此属性为0,第二张图此属性为16)。可以在Edit | Project | Quality设置是否使用Anisotropic Filtering。
与MipMaping很像,Anisotropic Filtering也很昂贵,如果有点地方没有必要使用,例如场景中的一些纹理肯定不会以倾斜的角度被看到,则应该禁用Anisotropic Filtering,以节省运行时的开销。也可以考虑调整每个纹理的Anisotropic Filtering强度,在品质和性能之间找到平衡点。

5、考虑使用图集
图集是一种技术,它将许多较小的、独立的纹理合并到一个较大的纹理文件中,从而最小化材质的数量,因此最小化所需使用的Draw Call数量。这是利用动态批处理的有效方法。
图集不一定要用于2D图形和UI元素。如果创建了很多低分辨率的纹理,也可以将此技术应用到3D网格上。若3D游戏具有简单纹理的分辨率,或是扁平着色的低多边形风格,都能以这种方式使用图集。
然而,由于动态批处理效果只影响非动画的网格(也就是MeshRenderer而不是SkinnedMeshRenderer),因此不用将动画角色的纹理文件合并到图集。由于它们是动画,GPU需要将每个对象的骨骼乘以当前动画状态的变换。这意味着需要为每个角色进行独立的计算,不管他们是否共享了材质,该计算都将导致额外的Draw Call。

6、调整非方形纹理的压缩率
纹理文件通常以正方形、2的n次幂的格式保存,这意味着它们的宽度和高度相等,而大小是2的n次幂。
也可能出现长方形纹理,其宽度和高度仍是2的n次幂或者非2的n次幂(例如256 x 512),但不推荐制作这种纹理。一些GPU需要正方形纹理格式,因此,Unity将自动拓展纹理到额外的空白处,进行补偿,即强制把非方形图集通过填充空白像素的方式,将纹理拓展到宽高相等这将消耗额外的内存带宽。其他GPU可能支持非2的n次幂的纹理,但这种纹理的采样很可能比正方形纹理的采样慢
因此,第一个建议是避免非正方形的纹理。如果图形可以放到2的n次幂的正方形纹理中,不会由于挤压/拉伸而导致品质下降太多,就应该做出这些修改,以获得更好的CPU和GPU性能。第二个建议是,在Unity中通过纹理文件的Non Power of 2导入设置,可以自定义这个缩放行为,然而,因为这是一个自动过程,可能不会带来期望的图形质量。

7、Sparse Textures
在游戏过程中应该尽可能避免硬盘访问,Sparse Textures提供了一种运行时从磁盘传输纹理数据流的方式,也称为Mega-Texture或Tiled-Textures。
如果明智地在需要之前开始传输纹理的部分数据,则Sparse Textures提供了一些有趣的性能提升技术。
其实际上是通过将许多纹理组合成一个巨大的纹理来实现的,这个文件太大了,无法作为一个纹理文件加载到图形内存中。这类似图集的概念,但是包含的纹理文件非常大——例如32768 * 32768像素并且包含相当多的颜色细节,比如每个像素32位。
其理念是通过手动选择要从磁盘中动态加载的小片段纹理,在游戏中需要它们之前将它们从磁盘中取出,来节省大量的运行时内存带宽。这种技术的主要成本是文件大小需求和潜在的连续磁盘访问。
在游戏业中,它是一项高度专业化的技术,但没有被广泛采用,部分原因是它需要专业的硬件和平台支持,另一部分原因是它难以完美实现。Unity开发人员可以花点时间进行一些研究,以检查Sparse Textures是否适合他们的项目,因为它可以显著提升性能。

实际效果:

gif来源:https://www.cnblogs.com/hont/p/10478203.html

8、程序化材质
程序化材质也称为Substances,是一种在运行时通过使用自定义数学公式混合小型高质量的纹理脚本,通过程序化方式生成纹理的手段。程序化材质的目标是在初始化期间以额外的运行时内存和CPU处理为代价,极大地减少应用程序的磁盘占用,以便通过数学操作而不是静态颜色数据来生成纹理。

9、异步纹理上传
最后一个还没提到的纹理导入选项时Read/Write Enable。默认情况下,该选项是禁用的,禁用该选项的好处是,纹理可以使用Asynchronous Texture Uploading特性,该特性有两个优势:纹理会从磁盘异步上传到RAM中;且当GPU需要纹理数据时,传输发生在渲染线程,而不是主线程。纹理会推送到环形缓冲区中,一旦缓冲区中包含新数据,数据就会持续不断地推送到GPU。如果缓冲区中没有新数据,就提前退出处理并等待,直到请求新的纹理数据。
最终,这减少了每帧准备渲染状态所花费的时间,允许将更多的CPU资源花在游戏玩法,物理引擎等逻辑模块中。当然,有时依然在主线程中花费时间准备渲染状态,但将纹理上传任务移到一个独立线程,节省了主线程中大量的CPU时间。
然而,开启纹理的读写访问功能,本质上事告知Unity,我们想要随时读取和编辑该纹理。这暗示着GPU需要随时刷新对它的访问,因此禁用该纹理的异步上传功能;所有上传任务必须在主线程中执行。我们可能想要开启该选项,以模拟在画布上画画,或者将网络上的图像数据写入已有的纹理,但缺点是在纹理上传之前,GPU必须始终等待对纹理所作的修改,因为无法预测什么时候发生变更。
另外,由于异步纹理上传特性仅适用于明确导入到项目中且在构建时存在的纹理,因为该特性仅在纹理打包到可流式传输的特殊资源中才会生效,所以,任何通过LoadImage(byte[])生成的纹理,由外部位置导入或下载的纹理,或者通过Resource.Load从Resource文件夹加载的纹理(它们都隐含LoadImage(byte[])调用)都不会转换为可流式传输的内容,因此无法使用异步纹理上传特性。
异步纹理上传特性允许花费的时间上限和Unity为了推送要上传的纹理而使用的循环缓冲区大小都是可以调整的。可以在Edit | Project Setting | Quality | Other菜单下进行设置。

三、网格和动画文件

1、减少多边形数量
这是提升性能的最明显的方法。

2、调整网格压缩
Unity为导入的网格文件提供了4种不同的网格压缩设置:Off、Low、Medium和High。增加此设置将把浮点数据转换为固定值,降低顶点位置/法线方向的精度,简化顶点颜色信息等。这对包含许多彼此相邻的小部件(比如栅栏或格栅)的网格有明显的影响。如果通过程序生成网格,就可以通过调用MeshRenderer组件的Optimize()方法来实现相同类型的压缩,当然,这需要一些时间来完成。
Edit | Project Setting | Player | Other Settings中也有两个全局设置,可以影响网格数据的导入方式。这两个设置选项为Vertex Compression和Optimize Mesh Data。
可以使用Vertex Compression选项配置在启用Mesh Compression的情况下导入网格文件时被优化的数据类型,因此,如果想要精确的法线数据,但不关心位置数据,就可以在这里设置它。遗憾的是,这是一个全局设置,会影响所有导入的网格
开启Optimize Mesh Data将剔除该网格当前使用的材质所不需要的数据。因此,如果网格包含切线信息,但着色器不需要切线信息,那么Unity将在构建期间忽略它。
这样做的好处是,减少了应用程序的磁盘占用,但是却需要花费额外的时间来加载网格,因为在需要数据之前必须花费额外的时间解压缩数据。
注意:3D网格构建/动画工具通常提供自己的自动网格优化的内置方法,其形式是估计整体形状,并将网格剥离为更少的多边形,这可能导致严重的质量损失,如果使用,应该进行严格的测试。

3、恰当使用Read-Write Enabled
Read-Write Enabled标志允许在运行时通过脚本修改网格,或在运行时由Unity自动对网格数据进行更改,类似于它用于纹理文件的方式。
如果在整个游戏中只使用网格的等比缩放版本,则禁用该选项会节省运行时内存。
然而,如果网格经常在运行时以不同的比例重新出现,那么Unity需要将这些数据保存到内存中,以便更快地重新计算新的网格,因此启用Read-Wirte Enabled标志是明智的
网格在运行时以动态的方式被实例化和缩放时,必须启用这个设置,这将提高对象的实例化速度,但会带来一些内存开销。
注意:当使用Generate Colliders选项时,也会带来这个潜在的开销

4、考虑烘培动画
烘培动画意味着不需要插值和蒙皮数据,就可以有效地将每帧每个顶点的每个位置采样并硬编码到网格/动画文件中,对于某些对象来说,使用烘培动画有时会得到比混合/蒙皮动画更小的文件大小和内存开销,因为蒙皮数据需要惊人的存储空间。相对简单的对象或动画时间较短的对象最有可能出现这种情况。
此外,通常可以通过导出应用程序定制烘培采样的频率。应该对不同的采样率进行测试,以找到合适的值,其中动画的关键时刻仍然清晰可见,这本质上是一个简化的估计。

5、合并网格
将网格强力地合并成单个的大型网格,便于减少Draw Call,特别是当网格对于动态批处理来说太大,不能与其他静态批处理组很好地配合时。这本质上等同于静态批处理,但它是手动执行的,所以,如果静态批处理能处理这个过程,我们就不必浪费精力了。
注意,如果网格的任何单个顶点在场景中可见,那么整个对象将作为整体进行渲染。如果网格大部分时间里只部分可见,这将浪费大量的处理时间。这种技术也有一个缺点,它生成了一个全新的网格资产文件,必须将其保存到场景中,这意味着对原始网格所作的任何更改都不会反映在合并的网格中。
网络上有一些工具,能用于在Unity中合并网格文件,可以在Asset Store或Google中搜索它们。

四、Asset Bundle和Resource

Resource System在原型建立阶段和项目的早期阶段很有益处,也能在有限范围的游戏中相当高效地使用。
然而,专业的Unity项目应该支持Asset Bundle System。原因有很多,首先,当涉及构建时,Resource System的可伸缩性不是很大。所有资源都合并到一个大型序列化二进制文件blob中,其中包含一个索引列表,列出了可以在其中找到的各种资源。向列表中添加更多数据时,这可能很难管理,并且需要很长时间来构建。其次,Resource System以Nlog(N)的方式,从序列化文件中获取数据,所以需要警惕N的值,再次,Resource System使应用程序难以基于每个设备提供不同的素材数据,而Asset Bundle很容易实现这一点。最后,Asset Bundle可用于为应用程序提供小型的、定期的自定义内容更新,而Resource System需要完全替换整个应用程序,才能达到相同的效果。

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值