【Unity】Cinemachineのカメラ切替えが数フレーム遅れる問題への対処

Cinemachineで視点切り替えと同時にモデルを切り替えるようにしているんだけど、画面がちらついて困っているの…😭

カメラの切り替わりが数フレームずれているみたいね。カメラの切り替わりタイミングを見てモデルを切り替える必要がありそうね。

バーチャルカメラのPriorityなどを変更してカメラを切り替えるとき、実際にバーチャルカメラが切り替わるまで数フレーム遅れることがあります。

CinemachineVirtualCamera virtualCamera1;
CinemachineVirtualCamera virtualCamera2;

・・・(中略)・・・

// Priorityを変更してバーチャルカメラ切り替え
virtualCamera1.Priority = 9;
virtualCamera2.Priority = 11;

主に、Cinemachine Brainのカメラ更新タイミングをFixed Updateにしているときに発生します。

このようにフレームのずれに起因する問題の場合、実際にバーチャルカメラが切り替わる瞬間で処理することで解決可能です。

先の動画は、バーチャルカメラのPriorityを変更した瞬間にモデルを切り替えていたため、画面のちらつきが発生しています。これを実際のバーチャルカメラが切り替わるタイミングにずらすことで、次のようにちらつきを抑えることができます。

切り替わりのタイミングは、Cinemachine Brainが通知するイベントで分かります。

本記事では、このイベント機能を使い、カメラの切り替わりのフレーム遅れに対処する方法を紹介します。

動作環境
  • Unity2021.1.21f1
  • Cinemachine2.7.8

カット切り替えを通知するイベント

カメラ切り替えを管理するCinemachine Brainには、切り替わりタイミングを通知する機能が備わっています。

Cinemachine Brainでカメラがカットで瞬時に切り替わるとき、CameraCutEventイベントが発火します。このイベントは、CinemachineBrain.m_CameraCutEventフィールドとして定義されています。

public CinemachineBrain.BrainEvent m_CameraCutEvent

参考:Class CinemachineBrain | Package Manager UI website

このBrainEvent型の実体は、CinemachineBrainオブジェクトを引数に受け取るUnityEvent型です。

public class BrainEvent : UnityEvent<CinemachineBrain>

参考:Class CinemachineBrain.BrainEvent | Package Manager UI website

UnityEvent型なので、Cinemachine Brainのインスペクタからイベントを指定することも可能です。

なお、カット切り替えを行うためには、Cinemachine Brain側のブレンドにCutが指定されている必要があります。

また、カットの切り替わりタイミングは、後述するCinemachine.m_CameraActivatedEventイベントでも知ることができます。

サンプルスクリプト

バーチャルカメラのカット切り替えタイミングでデバッグログを出力するサンプルです。

CutEventExample.cs
using Cinemachine;
using UnityEngine;

public class CutEventExample : MonoBehaviour
{
    // Cinemachine Brain
    [SerializeField] private CinemachineBrain _cinemachineBrain;

    private void Awake()
    {
        // カメラ切り替わりイベント登録
        _cinemachineBrain.m_CameraCutEvent.AddListener(OnChangeCamera);
    }

    // バーチャルカメラがカットで切り替わったときに呼ばれる
    private void OnChangeCamera(CinemachineBrain cinemachineBrain)
    {
        // 切り替え先のバーチャルカメラ取得
        var nextVirtualCamera = cinemachineBrain.ActiveVirtualCamera;

        // バーチャルカメラの内容をログ出力
        print(nextVirtualCamera);
    }
}

上記スクリプトを適当なゲームオブジェクトにアタッチし、Cinemachine Brainオブジェクトを設定します。

実行結果

スクリプトの解説

次の部分でカット切り替え時に発火するイベントに登録します。

// カメラ切り替わりイベント登録
_cinemachineBrain.m_CameraCutEvent.AddListener(OnChangeCamera);

コールバック側では、CinemachineBrainオブジェクトを引数として受け取るため、ここから切り替わった後のバーチャルカメラを取得します。

// 切り替え先のバーチャルカメラ取得
var nextVirtualCamera = cinemachineBrain.ActiveVirtualCamera;

// バーチャルカメラの内容をログ出力
print(nextVirtualCamera);

CinemachineBrain.ActiveVirtualCameraプロパティより、現在有効なバーチャルカメラが得られます。

参考:Class CinemachineBrain | Package Manager UI website

カット・ブレンド切り替え両方を通知するイベント

バーチャルカメラをカットではなくブレンドで切り替える場合、前述のm_CameraCutEventは発火されません。

ブレンド切り替え含む切り替えは、CinemachineBrain.m_CameraActivatedEventフィールドから知ることができます。

public CinemachineBrain.VcamActivatedEvent m_CameraActivatedEvent

発火のタイミングは、カット時またはバーチャルカメラ切り替えのブレンドが開始される瞬間です。

CinemachineBrain.VcamActivatedEvent型の実体は、2つのICinemachineCameraを引数に受け取るUnityEvent型です。

public class VcamActivatedEvent : UnityEvent<ICinemachineCamera, ICinemachineCamera>

参考:Class CinemachineBrain.VcamActivatedEvent | Cinemachine | 2.8.0

第1引数には切り替え後第2引数には切り替え前のバーチャルカメラが格納されます。

こちらもUnityEvent型なので、インスペクタから設定することも可能です。

注意
m_CameraActivatedEventの型はCinemachine2.2.7よりVcamEvent型からVcamActivatedEvent型に変更され、引数の形式も変わっています。スクリプトリファレンスを閲覧する際は、バージョンにご注意ください。

参考:Changelog | Cinemachine | 2.8.0

また、ブレンド切り替えを有効にするためには、Cut以外のブレンドで切り替える必要があります。

サンプルスクリプト

バーチャルカメラの切り替わりタイミングでログを出力するサンプルです。

BlendEventExample.cs
using Cinemachine;
using UnityEngine;

public class BlendEventExample : MonoBehaviour
{
    // Cinemachine Brain
    [SerializeField] private CinemachineBrain _cinemachineBrain;

    private void Awake()
    {
        // カメラ切り替わりイベント登録
        _cinemachineBrain.m_CameraActivatedEvent.AddListener(OnChangeCamera);
    }

    // バーチャルカメラが切り替わったときに呼ばれる
    private void OnChangeCamera(ICinemachineCamera incomingVcam, ICinemachineCamera outgoingVcam)
    {
        // バーチャルカメラの変更をログ出力
        print($"{outgoingVcam} --> {incomingVcam}");
    }
}

こちらも1つ目のスクリプト同様、適当なゲームオブジェクトにアタッチし、Cinemachine Brainを設定します。

実行結果

ブレンド開始時に切り替え前と後のバーチャルカメラが取得できていることを確認できました。

さいごに

Cinemachineのバーチャルカメラ切り替えは、必ずしもPriorityの設定をした瞬間に行われる訳ではないことに注意が必要です。

カメラが切り替わった瞬間に何かしらの処理を行いたい場合、CinemachineBrainのイベントを利用して非同期的に行う形になります。

同様の問題に行き詰っている方の一助になれれば幸いです。

参考サイト