Unity音频优化实践

本文整理自10 Unity Audio Optimisation Tips – Game Dev Beginner

Unity的音频设置中有好多平时不会去了解的属性,本文只从How to而不是Why的角度整理一下可用的优化方式。

3D音效使用Force to Mono

立体声有左右两个省道,大小和内存占用都会翻倍。但是Unity中两个声道都是从同一个点发出,双声道没有意义。

最佳实践:

如果使用了双声道的音源,可以通过勾选Force to Mono轻松将双声道音源变成普通音源,节省内存开支。

使用正确的加载类型和压缩格式

关于压缩类型

  • Decompress on Load – 解压完整的数据进内存
  • Compressed in Memory – 加载进内存,使用的时候解压。用CPU性能换一部分内存。
  • Streaming – 完全不加载进内存,使用时从存储介质中串流。最省内存,消耗最多CPU。

下图为同一声音文件在默认压缩格式下使用3种不同加载类型的CPU和内存消耗:

关于压缩格式

在使用Decompress on Load时,压缩格式对内存没有影响(因为无论如何都是会解压后进内存的),但是对包体大小会有影响。使用PCM会增加包体大小,而使用Ogg Vorbis包体会更小,但是在加载进内存时需要解压缩,不过解压缩的消耗可以忽略不计。

在使用Compressed in Memory时,如果你想要通过Quality选项进一步压缩声音文件的质量和大小,使用Ogg Vorbis会更好。但是在同样100% Quality的情况下,ADPCM占用的内存比Ogg Vorbis更小,而且解压缩消耗的CPU资源比Ogg Vorbis小很多。不过,无论如何不要使用PCM,因为PCM是不压缩的格式,完全没有利用上Compressed in Memory的优势。

在使用Streaming时,和Compressed in Memory类似,使用ADPCM可以节省很多CPU资源。不同的是,可以使用PCM进一步节省CPU资源,因为PCM没有压缩。PCM唯一的缺点是会占用更多的存储资源。

MP3格式相较上述格式没有显著优势,因此不用考虑。

另外,需要注意的是,在移动端短时间内Stream多个声音文件可能会造成CPU的高负载。

最佳实践:

时间短的音效使用Decompress on Load,压缩格式使用Ogg Vorbis

时间较长的音效使用Compressed in Memory,压缩格式使用ADPCM

音乐(如背景音)使用Streaming,压缩格式使用PCM

声音数量限制和优先级

Unity默认的声音数量限制是32个,但可以通过设置更改

Real Voice是指真正能听到的声音数量。假如限制为1,则无论什么时候都只能听到1个声音,其他声音会根据优先级依次变为Virtual Voice。

Virtual Voice会在后台继续播放,但实际听不到。当Real Voice小于设定的上限时,Virtual Voice会根据优先级变成Real Voice继续播放。如果Virtual Voice数量大于设置的上限时,会根据优先级被停止。

每个声音都可以设置优先级,0为最高,256为最低:

最佳实践:

尽量保持默认设置。如果需要提高上限,手机上Max Real Voices最好低于40,高端手机低于60;主机、桌面端低于80。

Max Virtual Voices大于Max Real Voices

大部分声音都使用一样的优先级,少数重要的声音设置高优先级

暂停不使用的声音

如果Max Real Voices设置的不高,这个方法没有必要。如果设置了较高的声音数量上限,则有必要手动暂停一些在AudioListener以外的声音。只需要给所有带声音的物体挂上如下脚本即可:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckIfAudible : MonoBehaviour
{
  AudioListener audioListener;
  AudioSource audioSource;
  float distanceFromPlayer;

  void Start()
  {
    // Finds the Audio Listener and the Audio Source on the object
    audioListener = Camera.main.GetComponent<AudioListener>();
    audioSource = gameObject.GetComponent<AudioSource>();
  }

  void Update()
  {
    distanceFromPlayer = Vector3.Distance(transform.position, audioListener.transform.position);
    
    if (distanceFromPlayer <= audioSource.maxDistance)
    {
      ToggleAudioSource(true);
    }
    else 
    {
      ToggleAudioSource(false);
    }
  }

  void ToggleAudioSource(bool isAudible)
  {
    if (!isAudible && audioSource.isPlaying) 
    {
      audioSource.Pause(); 
    }
    else if (isAudible && !audioSource.isPlaying)
    {
      audioSource.Play();
    }
  }
}

非必须的音效勾选Load in Background

Unity Load in Background

勾选此选项后,Unity在加载场景时不会等待该声音完全加载好,可以减少加载场景的时间。下图是在加载场景时加载约90个音频和大量Prefab时,勾选和不勾选Load in Background的对比。不是很精确的实验,但是有参考作用:

Difference in load time when using Load in Background in Unity

最佳实践

在加载一些场景初始阶段非必需的声音(如怪物死亡音效、胜利音效等)时,可以勾选此选项。

合理加载音频数据

Preload Audio Data in Unity

Unity导入音频时有个默认勾选的选项为Preload Audio Data,即在加载声音文件时,同时将声音的信息(如时长)和音频数据加载进内存。如果不勾选,则只有声音信息会被加载进内存。

因此,如果不勾选此选项,可以节省一些内存,但是需要在使用该声音时手动加载:

audioClip.LoadAudioData();

为了节省内存,也可以手动卸载该声音:

audioClip.UnloadAudioData();

最佳实践:

手动卸载不需要使用的音频数据,在需要时重新加载

禁用音频组建而不是使用静音

当音频组件还被挂在物体上时,就算使用了静音,也依然存在相关的性能开销(如计算声音和Audio Listener)之间的距离。因此,如果不是真的有“静音”这个需求,尽量禁用音频组件,搭配上一段落的卸载音频数据效果更佳。

%d 博主赞过: