Version: 2018.2
遮挡剔除
材质、着色器和纹理

动态分辨率

动态分辨率是一种摄像机设置,允许动态缩放单个渲染目标,以便减少 GPU 上的工作负载。在应用程序的帧率降低的情况下,可以逐渐缩小分辨率来保持帧率稳定。如果性能数据表明由于应用程序受 GPU 限制而导致帧率即将降低,则 Unity 会触发此缩放。还可以手动触发缩放,方法是抢占应用程序中 GPU 资源消耗特别高的部分,并通过脚本控制缩放。如果缩放逐渐进行,动态分辨率几乎不可察觉。

支持的平台

Unity 在 Xbox One、PS4、Nintendo Switch、iOS/tvOS(仅限 Metal)和 Android(仅限 Vulkan)上支持动态分辨率。

对渲染目标的影响

使用动态分辨率,Unity 不会重新分配渲染目标。从概念上讲,Unity 会缩放渲染目标;但实际上,Unity 使用锯齿,而且缩小的渲染目标仅使用原始渲染目标的一小部分。Unity 以全分辨率分配渲染目标,然后动态分辨率系统会缩小渲染目标并再次备份,使用的是原始目标的一部分而不是重新分配新目标。

缩放渲染目标

使用动态分辨率时,渲染目标具有 DynamicallyScalable 标志。可通过设置此标志来指明 Unity 是否应该将此渲染纹理作为动态分辨率过程的一部分进行缩放。摄像机还具有 allowDynamicResolution 标志,使用该标志可以这样设置动态分辨率:在只想将动态分辨率应用于不太复杂的场景时,无需覆盖渲染目标。

MRT 缓冲区

在 Camera 组件上启用 Allow Dynamic Resolution 时,Unity 会缩放该摄像机的所有目标。

控制缩放

可以通过 ScalableBufferManager 控制缩放。借助 ScalableBufferManager,可以控制已标记由动态分辨率系统进行扩展的所有渲染目标的动态宽度和高度缩放。

As an example, assume your application is running at a desirable frame rate, but under some circumstances the GPU performance decreases, due to a combination of increased particles, post-effects and screen complexity. The Unity FrameTimingManager allows you to detect when the CPU or GPU performance start to decrease. So you can use the FrameTimingManager to calculate a new desired width and height scale to keep the frame rate within your desired range, and bring the scale down to that value to keep performance stable (either instantly or gradually over a set amount of frames). When the screen complexity reduces and the GPU is performing consistently, you may then raise the width and height scale back to a value that you’ve calculated the GPU can handle.

示例

This example script demonstrates basic use of the API. Add it to a Camera in your Scene, and check Allow Dynamic Resolution in the Camera settings. You also need to open the Player Settings (menu: Edit > Project Settings > Player) and check the Enable Frame Timing Stats checkbox.

单击鼠标或用一根手指点击屏幕,分别将高度和宽度分辨率降低 scaleWidthIncrementscaleHeightIncrement 变量中的大小。用两根手指点击会以相同的增量提高分辨率。

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;

    // 跨帧保持的动态分辨率算法变量
    uint m_frameCount = 0;

    const uint kNumFrameTimings = 2;

    double m_gpuFrameTime;
    double m_cpuFrameTime;

    // 使用此函数进行初始化
    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
    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);
    }

    // 估算下一帧时间并在必要时更新分辨率缩放。
    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;
    }
}

另请参阅


  • 2018–09–20 页面已发布并进行了编辑审查

  • 在 2017.4 版中添加了有关动态分辨率的文档

遮挡剔除
材质、着色器和纹理