オクルージョンカリング
マテリアル、シェーダー、テクスチャ

動的解像度

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

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

Unity は Xbox One、PS4、Nintendo Switch、iOS/tvOS (Metal のみ)、Android (Vulkan のみ) の動的解像度をサポートします。

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

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

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

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

MRT バッファ

カメラの 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.

マウスをクリックするか、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 で追加

オクルージョンカリング
マテリアル、シェーダー、テクスチャ