Version: 2022.2
言語: 日本語
CullingGroup API
FrameTimingManager

動的解像度

動的解像度は、個々のレンダーターゲットを動的にスケーリングし、GPU の負荷を軽減できるカメラ設定です。アプリケーションのフレームレートが減少する場合は、徐々に解像度を下げて、一貫したフレームレートを維持することができます。アプリケーションが GPU にバインドされている結果、フレームレートが低下しそうなことをパフォーマンスデータが示すと、Unity はこのスケーリングを発動します。また、アプリケーションの特に GPU 負担が大きい部分を見越して、スクリプトを使ってスケーリングを制御することで、スケーリングを手動で発生させることもできます。徐々にスケーリングすると、動的解像度はほとんど目立つことはありません。

レンダリングパイプラインの互換性

Dynamic resolution support depends on which render pipeline your project uses.

機能 ビルトインレンダーパイプライン ユニバーサルレンダーパイプライン (URP) HD レンダーパイプライン (HDRP)
動的解像度 可 (1) 可 (1) 可 (2)

ノート:

  1. The Built-in Render Pipeline, and the Universal Render Pipeline (URP) both support dynamic resolution as described in this document.
  2. The High Definition Render Pipeline (HDRP) supports dynamic resolution, but you enable and use it in a different way. For information on dynamic resolution in HDRP, see Dynamic resoluton in HDRP.

サポートされているプラットフォーム

Unity supports dynamic resolution on iOS, macOS and tvOS (Metal only), Android (Vulkan only), Windows Standalone (DirectX 12 only), and UWP (DirectX 12 only).

レンダーターゲットへの影響

動的な解像度では、Unity はレンダーターゲットを再割り当てしません。概念的には、Unity はレンダーターゲットをスケールします。ただし、実際には、Unity はエイリアシングを使用し、縮小されたレンダリングターゲットは、元のレンダーターゲットのほんの一部のみを使用します。Unity は、レンダーターゲットを完全な解像度で割り当てます。次に、動的解像度システムは、新しいターゲットを再割り当てする代わりに、元のターゲットの一部を使用してレンダリングターゲットをスケールダウンし、再度バックアップします。

レンダーターゲットのスケーリング

動的な解像度では、レンダーターゲットには DynamicallyScalable フラグがあります。これを使って、このレンダーテクスチャを動的解像度処理の一部としてスケールするかどうかを設定します。カメラには allowDynamicResolution フラグもあります。これを使って動的解像度を設定すると、動的解像度をあまり複雑でないものに適用したい場合に、レンダーターゲットをオーバーライドする必要がありません。

MRT バッファ

カメラの Allow Dynamic Resolution を有効にすると、Unity はそのカメラのすべてのターゲットをスケールします。

スケーリングの制御

スケールは ScalableBufferManager を通して制御できます。 ScalableBufferManager は、動的解像度システムがスケールするように設定したすべてのレンダーターゲットの動的な幅と高さのスケールを制御します。

例として、アプリケーションが望ましいフレームレートで実行されていると仮定してください。しかし、状況によってはパーティクルの増加、ポストエフェクト、画面の複雑さが組み合わされて GPU のパフォーマンスが低下する場合があります。Unity FrameTimingManager を使用すると、CPU や GPU のパフォーマンスが低下し始めたときに、それを検出できます。そのため、 FrameTimingManager を使って希望の幅と高さのスケールを計算し、フレームレートを希望の範囲内に維持し、スケールをその値に落としてパフォーマンスを (即座に、または、徐々にフレームの設定された量に) 安定させます。画面の複雑さが減り、GPU が一貫して実行されている場合は、GPU が処理できる値に幅と高さのスケールを上げることができます。

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, then select the Player category) and check the Enable Frame Timing Stats checkbox. For more information about the functionality behind the Enable Frame Timing Stats property, see FrameTimingManager.

マウスをクリックするか、1 本の指で画面を軽くタップすると、高さと幅の解像度がそれぞれ scaleWidthIncrementscaleHeightIncrement 変数の値だけ下がります。2 本の指でタップすると同じ値で解像度が上がります。

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 はフレームごとに 1 回呼び出されます
    void Update()
    {
        float oldWidthScale = m_widthScale;
        float oldHeightScale = m_heightScale;

        // 1 本指のタップは解像度を下げます
        if (Input.GetButtonDown("Fire1"))
        {
            m_heightScale = Mathf.Max(minResolutionHeightScale, m_heightScale - scaleHeightIncrement);
            m_widthScale = Mathf.Max(minResolutionWidthScale, m_widthScale - scaleWidthIncrement);
        }

        // 2 本指のタップは解像度を上げます
        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 で追加

  • macOS (Metal のみ)、Windows スタンドアロン、UWP (DirectX 12 のみ) 用の動的解像度のサポートは 2019.1 で追加

CullingGroup API
FrameTimingManager