こんにちは、Unityエンジニアのオオバです。

本記事ではUnity2018.3の新機能
DynamicResolution について検証します。

DynamicResolutionとは?

ランタイム中にレンダーターゲットの解像度を変更することができる機能です。
例 : 1920×1080で描画していたものを、動的に1280×720の解像度に落としたり戻したりすることが可能
リッチなイメージエフェクトや無駄に高い解像度端末のせいで、フラグメントシェーダーの負荷(GPU負荷)が高くなってしまった状態を打破する手段の1つとして考えられます。

重要なのは解像度を変更するしないを、カメラないしはレンダーテクスチャ個別に選択できるという点です。

Unity的には2017.3のタイミングでXbox Oneでサポートしていました。
Unity 2017.3がリリースされました! | Unity Blog

Unity2018.1でPS4に対応した模様。
Unity 2018.1 リリース | Unity Blog

Unity2018.3で、ついにiOS(Metalのみ)、Android(Vulkanのみ)((その他にNintendo Switch、tvOS(Metalのみ)に対応しています))に対応しました。
Mobile improvements include Dynamic Resolution Scaling support for Vulkan and Metal, Android AppBundle generation support and faster APK package build times on Android with APKzlib.

ということで、手持ちのiPhone6sで検証してみます。

繰り返しになりますがカメラ、レンダーテクスチャともにDyamicResolution設定が個別に出来ます。

カメラのDyamicResolution設定

スクリプトだったら以下のようにallowDynamicResolutionプロパティをtrueにします。

_camera.allowDynamicResolution = true;  

カメラのインスペクタからであれば以下にチェック。

Unity2018.3.0からDynamicResolutionがiOSやAndroid端末で使えるようになっているので検証_0

レンダーテクスチャのDyamicResolution設定

スクリプトからであれば以下のようにuseDynamicScaleプロパティをtrueにします。

_renderTexture.useDynamicScale = true;  

レンダーテクスチャのインスペクタからであれば以下にチェック。

Unity2018.3.0からDynamicResolutionがiOSやAndroid端末で使えるようになっているので検証_1

レンダーテクスチャに書き込んだ後からuseDynamicScaleフラグの切り替えは出来ません。以下のエラーが出力されてしまいます。

Setting dynamic scaling of already created render texture is not supported!  
UnityEngine.RenderTexture:set_useDynamicScale()  

レンダーテクスチャを動的に生成した場合は、メモリに乗せる前にuseDynamicScaleフラグをセットしておく必要があります。そうしないと同じエラーが出力されてしまいます。

解像度を動的に変更する

ScalableBufferManager.ResizeBuffers(0.5f, 0.5f);  

このような感じでScalableBufferManager.ResizeBuffersに変更したいスケールを代入するだけです。とても簡単。元の等倍状態は1.0です。
Unity - Scripting API: ScalableBufferManager

Unity2018.3.0からDynamicResolutionがiOSやAndroid端末で使えるようになっているので検証_2

手持ちのiPhone6sでキャプチャした動画です。
このように動的に解像度が変更できるようになりました。
※非常にカクついているのはgifに変換した時に低画質にしたからで、本当はヌルヌルに動いています

解像度を変更した後にRenderTextureを更新する

ScalableBufferManager.ResizeBuffersで解像度を変更したら、useDynamicScaleフラグを立てているレンダーテクスチャがクリアされますので、必ずレンダーテクスチャの更新を入れる必要があります。

// 解像度変更  
ScalableBufferManager.ResizeBuffers(0.5f, 0.5f);  
// RenderTextureの更新  
Graphics.Blit(_tex, _renderTexture);  

雑な例ですが、上のようなイメージです。
解像度変更後にレンダーテクスチャを更新をしないと見た目的にRenderTextureのカラーが(0,0,0,0)になります。

バグ?

// カメラのレンダーターゲットにRenderTextureをセットして描画  
_camera.targetTexture = _renderTexture;  
_camera.Render();  

// カメラのレンダーターゲットを元のフレームバッファへ戻す  
_camera.targetTexture = null;  

こんな感じでCamera.targetTextureにRenderTextureをセットして、フレームバッファをレンダーテクスチャにコピーしてカメラのRenderTargetを既存のフレームバッファに戻します。
その後ScalableBufferManager.ResizeBuffersの値がリセットされ(1.0fへ戻る)、新しい値を代入しても反映されなくなります。

_camera.targetTexture = null;  

このようにtargetTextureにnullを突っ込んだだけでも同様の状態になります。

仕様なのでしょうかね。

👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

もくじ

まとめ

例えば3D表示の解像度だけ下げたくて、UIは解像度を下げたくないという場面はよくあると思いますが、お手軽対応できる点がグッドです。
Screen.SetResolutionより自由度はある

Unityブログでも書かれていますが、あくまでGPU負荷を下げるテクニックなので、制作しているプロダクトがそもそもGPUバウンドになりそうかどうかを確認すべきかと思います。CPUバウンドの場合は効果は見込めません。

また重要なことですがUIカメラにはDynamicResolution適用できません
UIに反映する場合はUIをレンダーテクスチャにする必要ありです。

サンプル一旦コチラにアップ
GitHub - baobao/DynamicResolutionTest

■追記:2020.06.07
githubにアップしたプロジェクトをUnity2019.3.15f1にアップデートしました。

オススメ記事
検証環境