Unityで動画の再生に合わせて字幕を表示したり、何かしらの演出を行いたいことがあります。
VideoPlayerをTimelineに入れてコントロールできるようなのですが、入れるだけでは動画を停止やシークした際にTimelineとの同期が取れず、試行錯誤したので対応策をまとめました。
環境
Unity:2022.3.26f1
まずは以下の設定を行います。
Timeline
まず、TimelineでVideoを扱えるようにするため、Package ManagerからDefault Playablesをインポートします。
Default Playables - Unity Asset Store
これにより、Video Script Playable Trackが使用できるようになります。「New Add Track」を選び新しいトラックをTimelineに登録します。
次に、右クリックで「Add From Video Player」を選択して、作成したVideo Playerを追加します。
最後に、InspectorでClip Timingを動画の長さに合わせて調整します。
VideoPlayer
Render Mode:Camera Near Plane
Camera:MainCamera
PlayableDirector
UpdateMethod:Manual
Play On Awake:False
設定ができたらTimelineを操作するスクリプトを書いていきます。
マニュアル操作になったPlayableDirectorへVideoPlayerの時間を入れてTimelineの時間を設定し、Evaluateを呼ぶことでTimelineを進めます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Video;
public class TimelineController : MonoBehaviour
{
private PlayableDirector playableDirector;
private VideoPlayer videoPlayer;
void Start()
{
playableDirector = GetComponent<PlayableDirector>();
videoPlayer = GetComponent<VideoPlayer>();
videoPlayer.playOnAwake = false;
}
void Update()
{
playableDirector.time = videoPlayer.clockTime;
playableDirector.Evaluate();
}
public void VideoStart()
{
videoPlayer.frame = 0;
videoPlayer.Play();
}
public void VideoPause()
{
videoPlayer.Pause();
}
}
これでVideoPlayerに合わせTimelineが動くようになりましたが、
Timelineに置いたSignal Emitterが反応しないことに気が付きました。
どうやらUpdateMethodがマニュアルの場合はイベントが呼ばれないようです。
調べているとこちらのページにたどり着きました。
Packages/Timeline/Runtime/Playables/TimeNotificationBehaviour.cs
if (info.evaluationType == FrameData.EvaluationType.Evaluate)
{
return;
}
どうやらこの部分の処理をコメントアウトすればEvaluate()での呼び出しであってもSignal Emitterが動作するようです。
このくらいであれば今回は影響がなさそうなので変更してしまいましょう。
ただしこのファイルはLibrary/PackageCache
内にあり、ここのファイルを書き換えても気が付いたら書き換え前の状態に戻されてしまいます。
そこで、Library/PackageCache
のcom.unity.timeline@バージョン番号
のディレクトリを\Packages内にコピーします。末尾の@バージョン番号は削除しておきます。
Package Managerで確認してCustomとついていればうまくいっています。
これでファイルの書き換えが維持されるようになりました。
無事、Signal Emitterが反応するようになったかと思います。