CinemachineのVirtual Cameraをスクリプトを使ってブレンドする方法です。
Unity2018.4
Cinemachine2.2.9
やりたいこと - Playableが公開されてない!
CinemachineのVirtual Cameraのブレンドは非ランタイムではできません。
そこで、こんな感じで任意の二つのVirtual Cameraとブレンド率を指定してブレンドのシミュレーションができるコンポーネントを作りました。
CinemachineのPlayableが公開されていれば手っ取り早かったのですが、
Timeline用のクラスとして設計されていてinternalになってしまっていたので半ば無理やりの実装です。
今後このあたりのPlayableはぜひ公開していただきたいものです…。
またTimelineで事足りるのであればそちらを使ったほうが良いかと思います。
ブレンド情報はCameraState.Lerp()を使って取得する
Cinemachineのソースコードを読んだ結果、下記のような処理で補間計算をできることがわかりました。
public static void ApplyCinemachineVirtualCameraBlending(Camera applyTo, CinemachineVirtualCamera camera1, CinemachineVirtualCamera camera2, Vector3 worldUp, float progress, float deltaTime) { // Virtual CameraのStateを更新 camera1.InternalUpdateCameraState(worldUp, deltaTime); camera2.InternalUpdateCameraState(worldUp, deltaTime); // 補間したStateを取得 var state = CameraState.Lerp(camera1.State, camera2.State, progress); // Cameraに適用 applyTo.transform.position = state.FinalPosition; applyTo.transform.rotation = state.FinalOrientation; applyTo.fieldOfView = state.Lens.FieldOfView; applyTo.nearClipPlane = state.Lens.NearClipPlane; applyTo.farClipPlane = state.Lens.FarClipPlane; }
Virtual CameraはCameraStateの中に位置や回転の情報を持ちます。
これらを更新した後ブレンド率を指定して補間して、ブレンド後のCameraStateを得ます。
あとはこのCameraStateから位置や回転などを対象のカメラにセットすればOKです。
二つのVirtual Cameraをブレンドする
このメソッドを使ってみるために適当にクラスを定義してみます。
using Cinemachine; using UnityEngine; #if UNITY_EDITOR [ExecuteAlways] public class Example : MonoBehaviour { [SerializeField] CinemachineVirtualCamera _camera1; [SerializeField] CinemachineVirtualCamera _camera2; [SerializeField] Camera _mainCamera; [SerializeField, Range(0.0f, 1.0f)] private float _rate; private void OnDisable() { if (_mainCamera == null) { return; } var brain = _mainCamera.GetComponent<CinemachineBrain>(); if (brain != null) { brain.enabled = true; } } public void Update(){ if (_mainCamera == null || _camera1 == null || _camera2 == null) { return; } // CinemachineBrainがアタッチされていると位置などがコントロールできないので非アクティブに var brain = _mainCamera.GetComponent<CinemachineBrain>(); if (brain != null) { brain.enabled = false; } ApplyCinemachineVirtualCameraBlending(_mainCamera, _camera1, _camera2, Vector3.up, _rate, Time.deltaTime); } public static void ApplyCinemachineVirtualCameraBlending(Camera applyTo, CinemachineVirtualCamera camera1, CinemachineVirtualCamera camera2, Vector3 worldUp, float progress, float deltaTime) { // Virtual CameraのStateを更新 camera1.InternalUpdateCameraState(worldUp, deltaTime); camera2.InternalUpdateCameraState(worldUp, deltaTime); // 補間したStateを取得 var state = CameraState.Lerp(camera1.State, camera2.State, progress); // Cameraに適用 applyTo.transform.position = state.FinalPosition; applyTo.transform.rotation = state.FinalOrientation; applyTo.fieldOfView = state.Lens.FieldOfView; applyTo.nearClipPlane = state.Lens.NearClipPlane; applyTo.farClipPlane = state.Lens.FarClipPlane; } } #endif
今回は非ランタイムで使いたかったのでUNITY_EDITOR限定にしています。
細かい部分の処理は適当ですが、これで下図のように補間処理を行うことができました。