はじめに
Unity 2019.3からオンデマンドレンダリング(On-demand rendering)なるものが追加されました。1
レンダリングのパフォーマンスには苦労することの多いモバイルアプリ開発などで特に有用そうな機能でしたのでご紹介します。
どういうもの?
ゲームループ(MonoBehaviour.Updateとか)のフレームレートは通常通りに、レンダリングを一定間隔でスキップできる機能です。
これの一番の使いどころは(特にモバイル端末での)「レンダリング処理負荷低減」でしょう。
例えばユーザー入力待機画面のような画面の動きが激しくない(=見た目のフレームレートを落としても影響が小さい)場面なら、レンダリングを適度にスキップすることでクオリティそのままに端末の発熱や消費電力を減らすことが期待できます。
また、従来からあるフレームレート調節方法であるApplication.targetFrameRateを変える方法よりも、入力の応答性という点でより良い選択になると考えられます。2
例として、入力がない間はフレームレートを落としておき、入力があったタイミングでフレームレートを上げて応答することを考えた際に下の違いがあります。
あとは、シミュレーションや機械学習といったシチュエーションでも望まれていた機能ではないかと思います。
それらは実際はレンダリングを必要としないことがほとんどなので、この機能を活用してレンダリングにリソースを割かないようにすればより早く結果を得られると考えられます。
使用方法
制御はスクリプトから行います。
名前空間UnityEngine.RenderingのOnDemandRenderingというクラスに3つのStaticなAPIが用意されています。
OnDemandRendering.renderFrameInterval
私たちが直接変更できる唯一のプロパティであり、これでレンダリングをおこなう間隔を設定します。
例えばこれに3を代入すれば、ゲームループの3フレーム中に1回レンダリングするようになります。(レンダリング更新頻度が1/3)
タッチ入力があるまで20[fps]にしておき、タッチがあったらそこから60[fps]にする例はこんな感じです。
using UnityEngine;
using UnityEngine.Rendering;
public class OnDemandRenderingTest : MonoBehaviour
{
private void Start()
{
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 60;
// 20 (= 60 / 3) fps
OnDemandRendering.renderFrameInterval = 3;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
// 60 fps
OnDemandRendering.renderFrameInterval = 1;
}
}
}
OnDemandRendering.effectiveFrameRate
現在の設定から想定されるレンダリングフレームレート値です。
例えばゲームループを60fpsで動かしている端末なら、通常はレンダリングも60fpsですが、renderFrameIntervalを3に設定しているときは20(=60 / 3)が返ってきます。
OnDemandRendering.willCurrentFrameRender
現在のゲームループフレームがレンダリング対象かを返します。
これは何に使えるのか…ということですが、レンダリングにリソースを割かなければならないフレームかどうかが判断できるので、「見た目のフレームレートを安定させつつ、高負荷な処理を裏で回す」的なことに使えるっぽいです。
なかなか使う場面は限られそうですが、使い方のイメージとしてはこんな感じでしょうか。
using UnityEngine;
using UnityEngine.Rendering;
public class OnDemandRenderingTest2 : MonoBehaviour
{
private void Update()
{
if (OnDemandRendering.willCurrentFrameRender)
{
// レンダリングするので重い処理はしない
}
else
{
// レンダリングしてないので重い処理を実行
}
}
}
おわりに
今回は特に検証などはしていないですが、上手に使えば高い効果が得られそうです。
モバイルアプリ開発なんかでは積極的に取り入れていきたい機能だと感じました。