用户可以通过 ScalableBufferManager 控制缩放。借助 ScalableBufferManager 可以控制已标记由动态分辨率系统进行扩展的所有渲染目标的动态宽度和高度缩放。
例如,假设应用程序以理想的帧率运行,但在某些情况下,由于粒子增多、后期效果和屏幕复杂性等多重因素的影响,GPU 性能会下降。Unity FrameTimingManager 可以检测 CPU 或 GPU 性能何时开始下降。因此,可使用 FrameTimingManager 计算新的所需宽度和高度缩放以将帧率保持在所需范围内,并将缩放降低到该值以保持性能稳定(立即进行或在设定的帧数内逐渐进行)。当屏幕复杂度降低并且 GPU 性能稳定时,可将宽度和高度缩放提高到事先计算出的 GPU 可以处理的值。
以下示例脚本演示了 API 的基本用法。将该脚本添加到场景中的摄像机,然后在摄像机 (Camera) 设置中选中__允许动态分辨率 (Allow Dynamic Resolution)。还需要打开播放器 (Player) 设置(菜单:__编辑 (Edit) > 项目设置 (Project Settings),然后选择__播放器 (Player)__ 类别)并选中__启用帧时间统计 (Enable Frame Timing Stats)__ 复选框。有关启用帧时间统计 (Enable Frame Timing Stats) 属性背后的功能的更多信息,请参阅 FrameTimingManager。
单击鼠标或用一根手指点击屏幕,分别将高度和宽度分辨率降低scaleWidthIncrement 和 scaleHeightIncrement 变量中的大小。用两根手指点击会以相同的增量提高分辨率。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DynamicResolutionTest : MonoBehaviour
{
public Text screenText;
FrameTiming[] frameTimings = new FrameTiming[3];
public float maxResolutionWidthScale = 1.0f;
public float maxResolutionHeightScale = 1.0f;
public float minResolutionWidthScale = 0.5f;
public float minResolutionHeightScale = 0.5f;
public float scaleWidthIncrement = 0.1f;
public float scaleHeightIncrement = 0.1f;
float m_widthScale = 1.0f;
float m_heightScale = 1.0f;
// Variables for dynamic resolution algorithm that persist across frames
uint m_frameCount = 0;
const uint kNumFrameTimings = 2;
double m_gpuFrameTime;
double m_cpuFrameTime;
// Use this for initialization
void Start()
{
int rezWidth = (int)Mathf.Ceil(ScalableBufferManager.widthScaleFactor * Screen.currentResolution.width);
int rezHeight = (int)Mathf.Ceil(ScalableBufferManager.heightScaleFactor * Screen.currentResolution.height);
screenText.text = string.Format("Scale: {0:F3}x{1:F3}\nResolution: {2}x{3}\n",
m_widthScale,
m_heightScale,
rezWidth,
rezHeight);
}
// Update is called once per frame
void Update()
{
float oldWidthScale = m_widthScale;
float oldHeightScale = m_heightScale;
// One finger lowers the resolution
if (Input.GetButtonDown("Fire1"))
{
m_heightScale = Mathf.Max(minResolutionHeightScale, m_heightScale - scaleHeightIncrement);
m_widthScale = Mathf.Max(minResolutionWidthScale, m_widthScale - scaleWidthIncrement);
}
// Two fingers raises the resolution
if (Input.GetButtonDown("Fire2"))
{
m_heightScale = Mathf.Min(maxResolutionHeightScale, m_heightScale + scaleHeightIncrement);
m_widthScale = Mathf.Min(maxResolutionWidthScale, m_widthScale + scaleWidthIncrement);
}
if (m_widthScale != oldWidthScale || m_heightScale != oldHeightScale)
{
ScalableBufferManager.ResizeBuffers(m_widthScale, m_heightScale);
}
DetermineResolution();
int rezWidth = (int)Mathf.Ceil(ScalableBufferManager.widthScaleFactor * Screen.currentResolution.width);
int rezHeight = (int)Mathf.Ceil(ScalableBufferManager.heightScaleFactor * Screen.currentResolution.height);
screenText.text = string.Format("Scale: {0:F3}x{1:F3}\nResolution: {2}x{3}\nScaleFactor: {4:F3}x{5:F3}\nGPU: {6:F3} CPU: {7:F3}",
m_widthScale,
m_heightScale,
rezWidth,
rezHeight,
ScalableBufferManager.widthScaleFactor,
ScalableBufferManager.heightScaleFactor,
m_gpuFrameTime,
m_cpuFrameTime);
}
// Estimate the next frame time and update the resolution scale if necessary.
private void DetermineResolution()
{
++m_frameCount;
if (m_frameCount <= kNumFrameTimings)
{
return;
}
FrameTimingManager.CaptureFrameTimings();
FrameTimingManager.GetLatestTimings(kNumFrameTimings, frameTimings);
if (frameTimings.Length < kNumFrameTimings)
{
Debug.LogFormat("Skipping frame {0}, didn't get enough frame timings.",
m_frameCount);
return;
}
m_gpuFrameTime = (double)frameTimings[0].gpuFrameTime;
m_cpuFrameTime = (double)frameTimings[0].cpuFrameTime;
}
}