Unity-動(dòng)態(tài)分辨率
動(dòng)態(tài)分辨率
動(dòng)態(tài)分辨率是一種攝像機(jī)設(shè)置,允許動(dòng)態(tài)縮放單個(gè)渲染目標(biāo),以便減少 GPU 上的工作負(fù)載。在應(yīng)用程序的幀率降低的情況下,可以逐漸縮小分辨率來保持幀率穩(wěn)定。如果性能數(shù)據(jù)表明由于應(yīng)用程序受 GPU 限制而導(dǎo)致幀率即將降低,則 Unity 會(huì)觸發(fā)此縮放。還可以手動(dòng)觸發(fā)縮放,方法是搶占應(yīng)用程序中 GPU 資源消耗特別高的部分,并通過腳本控制縮放。如果縮放逐漸進(jìn)行,動(dòng)態(tài)分辨率幾乎不可察覺。
支持的平臺(tái)
Unity 在 Xbox One、PS4、Nintendo Switch、iOS、macOS 和 tvOS(僅限 Metal)、Android(僅限 Vulkan)、Windows 獨(dú)立平臺(tái)和 UWP(僅限 DirectX 12)上支持動(dòng)態(tài)分辨率。
對(duì)渲染目標(biāo)的影響
使用動(dòng)態(tài)分辨率,Unity 不會(huì)重新分配渲染目標(biāo)。從概念上講,Unity 會(huì)縮放渲染目標(biāo);但實(shí)際上,Unity 使用鋸齒,而且縮小的渲染目標(biāo)僅使用原始渲染目標(biāo)的一小部分。Unity 以全分辨率分配渲染目標(biāo),然后動(dòng)態(tài)分辨率系統(tǒng)會(huì)縮小渲染目標(biāo)并再次備份,使用的是原始目標(biāo)的一部分而不是重新分配新目標(biāo)。
縮放渲染目標(biāo)
使用動(dòng)態(tài)分辨率時(shí),渲染目標(biāo)具有?DynamicallyScalable?標(biāo)志??赏ㄟ^設(shè)置此標(biāo)志來指明 Unity 是否應(yīng)該將此渲染紋理作為動(dòng)態(tài)分辨率過程的一部分進(jìn)行縮放。攝像機(jī)還具有?allowDynamicResolution?標(biāo)志,使用該標(biāo)志可以這樣設(shè)置動(dòng)態(tài)分辨率:在只想將動(dòng)態(tài)分辨率應(yīng)用于不太復(fù)雜的場景時(shí),無需覆蓋渲染目標(biāo)。

MRT 緩沖區(qū)
在 Camera 組件上啟用?Allow Dynamic Resolution?時(shí),Unity 會(huì)縮放該攝像機(jī)的所有目標(biāo)。
控制縮放
可以通過?ScalableBufferManager?控制縮放。借助?ScalableBufferManager,可以控制已標(biāo)記由動(dòng)態(tài)分辨率系統(tǒng)進(jìn)行擴(kuò)展的所有渲染目標(biāo)的動(dòng)態(tài)寬度和高度縮放。
例如,假設(shè)應(yīng)用程序以理想的幀率運(yùn)行,但在某些情況下,由于粒子增多、后期效果和屏幕復(fù)雜性等多重因素的影響,GPU 性能會(huì)下降。Unity?FrameTimingManager?可以檢測 CPU 或 GPU 性能何時(shí)開始下降。因此,可使用?FrameTimingManager
?計(jì)算新的所需寬度和高度縮放以將幀率保持在所需范圍內(nèi),并將縮放降低到該值以保持性能穩(wěn)定(立即進(jìn)行或在設(shè)定的幀數(shù)內(nèi)逐漸進(jìn)行)。當(dāng)屏幕復(fù)雜度降低并且 GPU 性能穩(wěn)定時(shí),可將寬度和高度縮放提高到事先計(jì)算出的 GPU 可以處理的值。
示例
以下示例腳本演示了 API 的基本用法。將該腳本添加到場景中的攝像機(jī),然后在 Camera 設(shè)置中選中?Allow Dynamic Resolution。還需要打開?Player?設(shè)置(菜單:__Edit > Project Settings__,然后選擇?Player?類別)并選中?Enable Frame Timing Stats?復(fù)選框。
單擊鼠標(biāo)或用一根手指點(diǎn)擊屏幕,分別將高度和寬度分辨率降低?scaleWidthIncrement
?和?scaleHeightIncrement
?變量中的大小。用兩根手指點(diǎn)擊會(huì)以相同的增量提高分辨率。
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;
? ?// 跨幀保持的動(dòng)態(tài)分辨率算法變量 ? ?
? ?uint m_frameCount = 0;
? ?const uint kNumFrameTimings = 2;
? ?double m_gpuFrameTime;
? ?double m_cpuFrameTime;
? ?// 使用此函數(shù)進(jìn)行初始化 ? ?
? ?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);
? ?}
? ?// 每幀調(diào)用一次 Update ? ?
? ?void Update()
? ?{
? ? ? ?float oldWidthScale = m_widthScale;
? ? ? ?float oldHeightScale = m_heightScale;
? ? ? ?// 一根手指降低分辨率 ? ? ? ?
? ? ? ?if (Input.GetButtonDown("Fire1")){
? ? ? ? ? ?m_heightScale = Mathf.Max(minResolutionHeightScale, m_heightScale - scaleHeightIncrement);
? ? ? ? ? ?m_widthScale = Mathf.Max(minResolutionWidthScale, m_widthScale - scaleWidthIncrement);
? ? ? ?}
? ? ? ?// 兩根手指提高分辨率 ? ? ? ?
? ? ? ?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);
? ?}
? ?// 估算下一幀時(shí)間并在必要時(shí)更新分辨率縮放。 ? ?
? ?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;
? ?}
}
Tip:Supported platforms 支持平臺(tái) Unity supports dynamic resolution on Xbox One, PS4, Nintendo Switch, iOS/tvOS (Metal only) and Android (Vulkan only).?