首页 >Unity3D频道 >【Unity3D研究院之游戏开发】 > Unity3D研究院之动态分辨率降低渲染开销(一百一十三)
2020
01-04

Unity3D研究院之动态分辨率降低渲染开销(一百一十三)

之前项目降低分辨率我们都普遍使用Screen.SetResolution,但是它有两个问题。

1.每次设置的时候屏幕会闪烁。

2.降低分辨率与摄像机无关,无法做到只降低3D摄像机的分辨率,保留UI摄像机不降低分辨率。

其实我们可以使用摄像机动态分辨率,如下图所示,给需要降低分辨率的摄像机打开allow Dynamic Resolution属性。

QQ20200104-133942@2x

如下图所示,在ProjectSetting上必须勾选Enable Frame Timing Stats属性。

QQ20200104-134046@2x

代码中就可以很方便设置分辨率了。

    ScalableBufferManager.ResizeBuffers(m_widthScale, m_heightScale);

如下图所示在iPhone X上,频繁设置3D摄像机分辨率并不会出现闪烁的情况,而且并没有影响UI摄像机看到的文本(Text)的分辨率

QQ20200104-134932@2x1

需要注意的是动态分辨率安卓Android(仅适用于Vulkan) 或者也可以用SRP可编程渲染管线,最后在修改RT这样就都支持了。

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);
    }


    private void OnGUI()
    {
        float oldWidthScale = m_widthScale;
        float oldHeightScale = m_heightScale;

        // One finger lowers the resolution
        if (GUILayout.Button("<size=100>--</size>"))
        {
            m_heightScale = Mathf.Max(minResolutionHeightScale, m_heightScale - scaleHeightIncrement);
            m_widthScale = Mathf.Max(minResolutionWidthScale, m_widthScale - scaleWidthIncrement);
        }

        // Two fingers raises the resolution
        if (GUILayout.Button("<size=100>++</size>"))
        {
            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);
        }
    }
    // Update is called once per frame
    void Update()
    {
        
        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}n动态分辨率: {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;
    }
}

详情 https://docs.unity3d.com/Manual/DynamicResolution.html

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院之动态分辨率降低渲染开销(一百一十三)》有 9 条评论

  1. rrtt_2323说:

    这个特性好是好,就是对启用要求太高了。。。变成鸡肋了

  2. 夜小月说:

    不断调整缩放到0.1,再缩放0.2,0.3,0.4 ,到1.0,会出现花屏的问题。2019.4.24版本

  3. happyfire说:

    这个功能可以,可惜不满足我的需求。这个动态分辨率虽然是降低分辨率渲染的,但是渲染后会放大回去。我的需求是让它降低分辨率渲染,我要获取到降低分辨率渲染后的RT,然后进行自定义处理,最后我自己放大回去。这个不行,我获取到的_CameraColorTexture已经被放大了

  4. biubiu说:

    为什么我的UI相机没勾选Allow Dynamic Resolution 也会跟着变模糊 呢

  5. 67709394说:

    这个 只支持 Android (Vulkan)吧?

  6. 说:

    为啥我的unity2018.4设置里没有enable Frame Timing Stat

  7. 谢谢说:

    雨松大佬,请问您的这个测试时基于unity什么版本?

留下一个回复

你的email不会被公开。 必填项已用 * 标注。