资源管道,原始文件通过内容管道变成了一个可被Unity高效使用的中间文件 ,这不是Unity里面的一个概念,但Unity的工作行为和它很类似;Unity在导入资源的时候可以使用类型丰富的文件,这不意味着在我们生成的App中同样也是这些文件,资源通过Unity的资源管道变成了较为统一的格式。我们在导入资源的时候有很多参数可以调整,
1 首先从声音开始吧,
我们先看第一个选择Load Type,他有三个可值: Decompress On Load, Compressed In Memory , Streaming。
Decompress On Load
在硬盘上压缩这个文件,并在第一次加载到内存的时候解压它,这是加载声音文件的默认选项,大多数情况下我们应该使用这个选择 。
加载后解压缩声音,声音文件将在他们加载不久后就解压,这个选项适用于较小的压缩声音,以避免即时解压缩的性能开销。要知道在加载时解压 Vorbis编码的声音将使用的内存是压缩状态的十倍或更多(ADPCM编码大概3.5倍)所以不要使用此选项用于大文件。
Decompress On Load 默认选项适用于小文件。
Compressed In Memory
保持声音在内存中是压缩的并在播放时解压缩。这有更多的CPU开销(尤其是OGG / Vorbis格式的压缩文件),但可以提高加载速度并减少内存消 耗,因此这个选项适用于大文件。 在性能窗口可以看"DSP CPU"。
Compressed In Memory 适用于大文件。
Streaming 选项
直接从磁盘流音频数据。这只使用了原始声音占内存大小的很小一部分。 该方法使用最少的内存和最多的CPU,它有个很明显的缺点就是不能被引用超过一次。试着让 Audio Clip产生多个副本的时候会每个都产生数据缓冲区,如果非要这么做会产生大量的内存和cpu消耗。因此这个选择最好是给单实例的Audio Clip,如背景和环境音效。对于手游而言不要优先考虑使用这种方式。
其他一些加载设置
在场景中把一 个Audio Clip赋值给Audio Source组件,这个音频文件将在场景初始化的时候加载到内存中。但是如果它 启用了,加载Audio Clip就变成了一个后台任务它将推迟到场景初始化完成后再加载,换句话说就是在游戏开始后开始加载。 通过启用这个选择我们可以提高场景的启动速度,但Play声音的时候它还在后台加载的话播放将推迟到加载完成,我们可以使用AudioClip对象的loadState 属性来检查是否加载完成以保证声音在不会在一个不恰当的时间播放。
Preload Audio Data 默认是启用的,它表示Unity自动在场景初始化时加载文件。禁用此选项将推迟加载直到 AudioSource的 Play() 或 PlayOneShot() 方法执行的时候。从硬盘加载声音文件,然后解压,再push到内存里然后再播放,这么一系列的动作 可能 会导致 CPU的峰值。
由于播放延迟和性能消耗,不建议在播放的瞬间加载。我们应该控制加载在播放之前的某些方便的时间使用AudioClip对象的LoadAudioData()方法加载。我们也可以用AudioClip对象的UnloadAudioData()方法手动控制声音文件的内存释放。
声音文件的编码格式和质量
Unity支持三种声音文件编码格式的,由于平台依赖性在某些特殊情况下会有其他的选项(如Xbox One的XMA和PS Vita的HEVAG )
- Vorbis/MP3
- PCM
- ADPCM
我们导入到Unity的音频文件可能是各种各样常见的音频格式,但通过内容管道,Standalone、WebGL和其他的一些非移动平台使用Ogg-Vorbis格式的压缩,而移动平台使用MPEG-3(MP3)格式。
PCM
ADPCM
Vorbis/MP3
增强音频性能
尽量减少音频数量
因为每个 Audio Source的播放都会消耗一定量的cpu,所以我们可以控制场景中 Audio Source的数量来节省cpu。
一种方式是控制我们的音频来源,这种方式我们硬盘上 的AudioClip可以同时播放的数量和总共播放的总数进行节流控制。我们通常会做一个AudioPool做这些节流操作,这很适合2d声音和单实例的3d声音(3d声音在播放的时候 仍然要放在场景中具体的位置
减少AudioClip引用
场景中每个Audio Source的Audio Clip引用和Preload Audio Data 启用都将消耗一定量的内存(压缩解压或者缓存),这些内存将贯彻整个场景,如果两个或两个以上的Audio Source引用相同的Audio Clip没有额外的内存消耗。Audio Clips在Unity中是非托管资源这意味着他们不会通过设置为null释放内存。
Unity希望我们能够加载和释放这些资源,经常使用的音效长久的在内存中保存文件是合理的,因为每次加载一个文件到
内存中都会消耗CPU。然而,如果我们发现因为音效而使用太多的内存的时候,我们必须做出艰难的选择是降低音频质量还是完全移除他们来节省内存。另一方面,保存不常用的音效在一个很长的场景中将会造成重大问题。
我们可能会有很多一次性音效,如对话片段,它们没有需 要长久保存在内存中。创建Audio Sources并分配一个AudioClip如果只是这样即使在游戏中只有一次使用也会导致内存消耗过剩,我们应该利用Resources.Load()和Resources.UnloadAsset()来保持需要播放的音频数据在内存中,一旦它不在需要就立即释放它。
Texture文件
-----------------------------------------------------------------------------------------------
术语“Texture” 和“Sprite”新手在游戏开发中经常会产生困惑,所以值得区分下,在Unity3d中Texture仅仅是个图片,我习惯读作贴图。本质上来讲它是一个大的颜色数组告诉程序每个像素是什么颜色。
而Sprite是一个2d网格,一个平对着当前摄像机的quad,我习惯读作精灵。
还有一种东西叫做Sprite Sheets,我们称它为图集;它用一张大图包含了很多图片,最常见的使用时2d角色动画。这些文件可以用Unity的Sprite Editor工具分割成小图做帧动画。
别管这些令人困扰的命名,来简单谈下Texture:我们导入的这些图片文件一般都生成于Adobe Photoshop国内基本都是或者一些小众软件Gimp等。在运行的时候这些文件被加载到内存中,然后push到GPU,应用Shader完成一次Draw Call。一般情况下,渲染一次拥有一个网格并携带一种材质的物体便会使用一次Draw Call,Draw Call的次数是决定性能比较重要的指标。
压缩格式
Texture Type
在Texture Type为Texture模式下Unity只给我们看到四个格式选项Compressed, 16-bit,True Color和Crunched。
如果我们将Texture Type设置为Advanced,那么我们就有了更多的设置选项,它给了我们更多的 Texture解析的控制权。
明智的使用 Mip Maps
呈现小物件的时候,像岩石树木这样的远处物体,一个高精度的贴图对于玩家来说是没有意义的,因为看不到那么多的细节。但是如果使用这张高精度的贴图会损失原本不应该的性能,这时候需要一个较少细节的纹理来提升程序性能。
它会自动产生不同分辨率的多张相同纹理。在运行的时候,GPU根据在透视投影下出现的面积选择适当的Mip Map(这是一种叫做 texel-to-pixel ratio的技术 )。需要注意的是这些贴图副本 是在Editor里面生成的不是在运行时生成的。
听 着好像很爽的样子但是他在我们手游中几乎没用,启用Mip Maps还会让最后生成的纹理文件增大33%左右。那他存在的意义何在如何什么时候使用它呢?它唯一有用的地方是摄像机需要渲染不同距离的纹理时。如果我们的纹理总是呈现在摄像头的同样距离,这时候开启Mip Map就一点用都没只是在浪费空间。还有如果只有单一的一种远距离物体我们也应该禁用它,应该从原纹理缩放一个小纹理给这个远处物体。
以下时候应该禁用这个选项:
- 在2d游戏中的几乎所有的纹理(2d游戏正交投影不存在近大远小)
- UI界面
- Mesh贴图,Sprites,Particle Effects,因为他们总是在摄像机差不多的距离渲染不会有很明显的距离差
考虑把图片打包起来变成图集
把图块变成图集之后会减少Draw Calls的次数(其实就是减少Material 数量)明显减少CPU消耗,内存消耗上基本相同。一个图集下的所有贴图都应该是使用相同Shader的,不然后果很严重做了还不如不做。
图集经常使用在UI界面,2d游戏中,它在手游中几乎是必不可少的,因为Draw Calls往往会成为手游的瓶颈。
要注意图集不能大于目标平台的最大要求,图集最好合理的分布不要为了节省空间而视图把图集塞满。如果渲染器需要从不同的图集中调用纹理会导致大量的高速缓存命中失败,从而有引发内存带宽不足等等问题。 如果做pc游戏的话图集就没有特别的必要了,因为Draw Calls很少会成为pc游戏的性能瓶颈。正确的使用图集它不是仅仅把图片堆起来。
调整非正方形纹理的压缩率
不建议导入非正方形或者非2的次幂的纹理到我们的应用程序,因为GPU往往需要把纹理是变成正方形和2的次幂导致不必要的处理畸形的纹理尺