按需渲染如何提高移动性能

出于各种原因,并不总是希望以最高帧频渲染项目,尤其是在移动平台上。一直以来,Unity 开发人员都使用 Application.targetFrameRate 或 Vsync 计数来控制 Unity 的渲染速度。这种方法不仅会影响渲染,还会影响 Unity 各部分的运行频率。新的按需渲染 API 使您可以将渲染频率与播放器循环频率解耦。
按需渲染可以跳过渲染帧,同时仍以高频率运行播放器循环的其余部分。这在移动设备上尤其有用;绕过渲染可显著提高性能和节省功耗,同时仍允许应用程序对触摸事件做出响应。
下面举例说明何时需要降低帧频:
菜单(如应用程序入口或暂停菜单):菜单往往是相对简单的场景,因此不需要全速渲染。如果以较低的帧频渲染菜单,则在未渲染的帧中仍可接收输入,从而降低功耗,使设备温度不至于上升到可能导致 CPU 频率节流的程度,同时保持流畅的用户界面交互。
回合制游戏(如国际象棋):回合制游戏在用户考虑下一步行动或等待其他用户行动时,会出现低活跃期。在这种情况下,您可以降低帧频,避免不必要的耗电,延长电池寿命。
静态内容:在汽车用户界面(UI)等内容大部分时间都是静态的应用程序中,可以降低帧频。
绩效管理:如果你想管理电源使用情况和设备热量,最大限度地延长电池寿命,防止 CPU 节流,尤其是在使用Adaptive Performance 软件包的情况下,你可以调整渲染速度。
机器学习或人工智能应用:减少 CPU 用于渲染的工作量,可能会为重型处理(应用程序的核心重点)带来些许性能提升。
无处不在按需渲染可在 Unity 2019.3 上运行,支持所有平台(参见系统要求)和渲染 API(内置渲染管道、通用渲染管道和高清渲染管道)。
按需渲染 API 仅由命名空间 UnityEngine.Rendering 中的三个属性组成。
1.OnDemandRendering.renderFrameInterval
这是最重要的部分。它允许你获取或设置渲染帧间隔,即 Application.targetFrameRate 或 QualitySettings.vSyncCount 的除法因子,以定义新的帧速率。例如,如果将 Application.targetFrameRate 设置为 60,OnDemandRendering.renderFrameInterval 设置为 2,则每隔一帧才会渲染一次,从而产生 30 fps 的帧速率。
2.OnDemandRendering.effectiveFrameRate
该属性为您提供了应用程序渲染帧速率的估计值。估算值使用 OnDemandRendering.renderFrameInterval、Application.targetFrameRate、QualitySettings.vSyncCount 和显示器刷新率的值来确定。但请记住,这只是一个估计值,而不是保证值;如果 CPU 被脚本、物理、网络等其他工作拖累,应用程序的渲染速度可能会更慢。
3.OnDemandRendering.willThisFrameRender
这只是告诉你当前帧是否会渲染到屏幕上。您可以使用非渲染帧来执行一些额外的 CPU 密集型工作,如繁重的数学运算、加载资产或生成预制件。
- 虽然帧的渲染频率会降低,但事件会以正常速度发送到脚本。这意味着您可能会在未渲染的帧中接收到输入。为防止出现输入延迟,我们建议您在输入过程中调用 OnDemandRendering.renderFrameInterval = 1,以保持按钮、移动等的响应速度。
- 在脚本、物理、动画等工作非常繁重但不进行渲染的情况下,按需渲染将不会带来任何好处。结果可能看起来不流畅,CPU 和功耗的降低也微乎其微。
下面是一个简单的示例,说明如何在菜单中使用按需渲染,以 20 FPS 的速度进行渲染,除非有输入。
using UnityEngine;
using UnityEngine.Rendering;
public class Menu : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 60;
// When the Menu starts, set the rendering to target 20fps
OnDemandRendering.renderFrameInterval = 3;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButton(0) || (Input.touchCount > 0))
{
// If the mouse button or touch detected render at 60 FPS (every frame).
OnDemandRendering.renderFrameInterval = 1;
}
else
{
// If there is no mouse and no touch input then we can go back to 20 FPS (every 3 frames).
OnDemandRendering.renderFrameInterval = 3;
}
}
}

下面是一个示例项目,演示如何在各种情况下使用按需渲染。
请在论坛上告诉我们按需渲染的效果如何。我们已经在 Windows、macOS、WebGL、iOS 和 Android 上进行了测试,包括 Unity 编辑器和独立播放器,但我们随时欢迎更多反馈。