ハツェの真時代傾向璋

興味を持ったことを書いていく鱗片的な場所から先の未来の場

VideoPlayerを作ろう - URL入力編

こんばんは。ハツェです。
久しぶりの投稿になりますね。
気づいたら前よりUdonGraphが使いやすくなっていたりしていますが、あのノードはまだまだ使いづらいですね。
今回は、最近来たVideo関係について少しお話しできればと思います。
動作環境は、Unity : 2018.4.20f1、VRCSDK : 2021.05.17.12.52、U# : v0.19.11です。

目次


今回の概要

シンプルに作れてLocalで動作するVideoPlayerについて紹介します。
Localで動作するため、これをそのままワールドに使用した際、みんなで見るものが違うVideoPlayerが出来上がりますのでご注意ください。

VideoPlayerに関する情報

少しだけ、VideoPlayerに関する情報を記載します。既にご存じの方は読み飛ばしてもらって結構です。

VideoPlayerの種類

SDK3.0になってから登場したVideoPlayerには、2種類あります。

  • VRC Unity Video Player
  • VRCAV Pro Video Player

UnityVideoPlayerは、一般の動画のみを再生できます。
一方、AVProVideoPlayerは、一般の動画に加えてライブ配信も再生することが出来ます。
ちなみに、本記事で紹介するコード等は、どちらのコンポーネントでも動作するようになっています。

コンポーネントを見てみる

AVPro Video Player

AVPro版のコンポーネントのインスペクタは以下の通りです。

f:id:hatuxes:20200913003514p:plain


色々設定項目がありますが、これらのほとんどが設定しても正しく動作しないため、ここのインスペクタを操作する必要性はないです。
そのため、URLは空にしておき、チェックマークはすべて外しておくことをオススメします。

Unity Video Player

Unity版のコンポーネントのインスペクタは以下の通りです。

f:id:hatuxes:20200919235904p:plain

AVPro版と同様の設定部はやはり機能していません。
AVPro版とは異なり、映像の出力と音声の出力は共に本体で設定します。
Render ModeでRender Textureを選択するとTarget Textureに設定されたRenderTextureに映像が出力されます。
一方、Render ModeでMaterial Overrideを選択するとTarget Material Rendererに設定されたメッシュについているマテリアルに出力されます。
出力させるマテリアルプロパティはシェーダー内の変数を指定することで設定できます。特段の理由が無ければ_MainTexで良いでしょう。
加えて、出力先となるAudioSourceはTarget Audio Sourceで複数指定できます。

VideoScreenとVideoSpeaker

AVPro版は「本体・画面・音声」の三構成で出来ています。
本体はVRCAV Pro Video Playerのことを指しており、本体をアタッチしただけでは映像と音声は出力されません。
映像を反映したいメッシュにはVRCAV Pro Video Screenを、音声を出力したいAudioSourceにはVRCAv Pro Video Speakerをアタッチする必要があります。

VideoPlayerの型

VideoPlayerの型はVRC.SDK3.Video.Components.Base.BaseVRCVideoPlayerを宣言すると良いです。
AVProの変数型VRC.SDK3.Video.Components.AVPro.VRCAVProVideoPlayerやUnityVideoの変数型VRC.SDK3.Video.Components.VRCUnityVideoPlayerもありますが、コンパイルすると全てBaseVRCVideoPlayerに変わるので、結局VRC.SDK3.Video.Components.Base.BaseVRCVideoPlayerを宣言すればよいと思います。
ちなみに、VideoScreenの型VRC.SDK3.Video.Components.AVPro.VRCAVProVideoScreenとVideoSpeakerの型VRC.SDK3.Video.Components.AVPro.VRCAVProVideoSpeakerは現状Udonで対応されてないので、宣言できません。

実際に作成してみる

完成図

だいたいは以下の通りに作ろうと思います。
画面と音声、加えて各種操作パネルとURL入力部があるという構成です。
今回はAVProを使って作成しますが、Unity版のコンポーネントを使用しても正しく動作すると思います。

f:id:hatuxes:20200919153603p:plain

Objectを配置する

Videoを表示するメッシュとかを配置します。
ビデオを表示するスクリーンにはAssets/VRChat Examples/Materials/AVProVideoScreen.matのマテリアルを適応しておくだけでかなり綺麗になります。
また、親オブジェクトを一個作っておいて、その下にメッシュとかAudioSourceとかを入れておくと後々便利なのでオススメです。

f:id:hatuxes:20200919161800p:plain

ちなみに、URLを送り込むInputfieldだけはVRChatが用意した独自のInputfieldVRC Url Input Fieldを使用する必要があります。
まず普通にInputfieldを作成した後、コンポーネントを消してからVRC Url Input Fieldを追加することで実装できます。

f:id:hatuxes:20200919162932g:plain

操作するUI系は忘れずにNavigationをNoneにしておきましょうね。(私は最初忘れてInputfieldが大変なことになった)

コンポーネントをアタッチする

VideoPlayerを作るための各種コンポーネントをアタッチします。
本体となるVRCAV Pro Video Playerはどこにアタッチしても良いのですが、分かりやすいために一番親のオブジェクトにアタッチしておきます。

f:id:hatuxes:20200919163428p:plain

次に、VRCAV Pro Video Screenを表示するメッシュにアタッチします。
この時に本体とリンクさせておくのを忘れずに。

f:id:hatuxes:20200919163611p:plain

同じようにしてAudioSourceにもVRCAV Pro Video Speakerをアタッチします。

f:id:hatuxes:20200919163706p:plain

スクリプトを作る

VRCAV Pro Video Playerをアタッチしたオブジェクトと同じオブジェクトにUdonBehaviorをアタッチしてスクリプトを生成します。
加えて、今回使用したコードは以下の通りです。

f:id:hatuxes:20200919164227p:plain
using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;
using VRC.Udon;

public class LocalVideoController_InputURL : UdonSharpBehaviour
{
    [SerializeField]
    private VRC.SDK3.Video.Components.Base.BaseVRCVideoPlayer _videoPlayer;
    
    [SerializeField]
    private VRC.SDK3.Components.VRCUrlInputField _inputfield;

    [SerializeField]
    private Text _playTimeDisplayText;

    private float _videoDuration;
    private bool _isPausing;

    private void Update()
    {
        if (_videoPlayer.IsPlaying)
        {
            _playTimeDisplayText.text = string.Format("{0:f} / {1:f}", _videoPlayer.GetTime(), _videoDuration);
        }
    }

    public override void OnVideoStart()
    {
        _videoDuration = _videoPlayer.GetDuration();
    }

    public void PlayVideo()
    {
        _videoPlayer.Stop();
        _videoPlayer.PlayURL(_inputfield.GetUrl());
    }

    public void PauseVideo()
    {
        _isPausing = !_isPausing;

        if (_isPausing)
        {
            _videoPlayer.Pause();
        }
        else
        {
            _videoPlayer.Play();
        }
    }

    public void StopVideo()
    {
        _videoPlayer.Stop();
    }

    public void SkipVideo()
    {
        _videoPlayer.SetTime(_videoPlayer.GetTime() + 10.0f);
    }

    public void BackVideo()
    {
        _videoPlayer.SetTime(_videoPlayer.GetTime() - 5.0f);
    }
}


部分解説

Update内

再生時間を表示しています。
実際には以下のように表示されます。
左側に現在の再生時間を、右側には動画時間を表示している感じです。

f:id:hatuxes:20200919210302p:plain

動画時間の取得

OnVideoStartイベントでBaseVRCVideoPlayer.GetDuration()を使用して変数に格納しています。
OnVideoStartイベントは、停止状態から再生した際に呼ばれるものなので、(後述にある)PlayVideo関数内では一度停止させてから再生させています。

ボタンから呼んでいる関数

UIからUdonの関数を動作させる方法については入門記事をご覧ください。
hatuxes.hatenablog.jp
OnVideoStart以下に記述している関数は全てボタンから呼んでいます。
PlayVideo()では、OnVideoStartイベントの関係から一度停止させた後に再生処理を行っています。PauseVideo()では、ポーズとアンポーズを両方組み込んでいます。

動画の再生場所を変更する

SkipVideo()BackVideo()では、動画の再生位置をずらすことによって実現させています。
BaseVRCVideoPlayer.GetTime()で動画の再生時間が取得でき、BaseVRCVideoPlayer.SetTime()で動画の再生時間を変更することが出来るので、現在の位置から+10秒の位置にズラすことでSkip処理を、現在の位置から-5秒の位置にずらすことでBack処理をしています。

実行

実際にVRChatで試してみると以下のように動作していました。

f:id:hatuxes:20200919203208g:plain

あとがき

今回は任意のURLを入力して動作させるVideoPlayerを紹介しました。
今回と次回の内容、それとUnityVideo版も含むサンプルはまとめてGithubに置いてあります。
ライセンスを確認したうえで、お使いください。
github.com
実は、Unity上で事前にプレイリストを作ってそれをループさせるということもできるので、次回はそれを紹介しようと思います。

ちなみに、他人にもしっかりと同期して動作するVideoPlayerはU#の制作者でもあるMerlinさんが制作されています。
特に理由なければ、これを使用するのが無難かと思われます。
github.com

次回

hatuxes.hatenablog.jp

誰でも操作できる同期uGUI - テキスト入力編

こんばんは。ハツェです。
今回も同期uGUIについて書いていきます。
他の記事でも紹介していますが、この記事は全4つからなるシリーズです。

  1. ボタン・トグル編
  2. スライダー編
  3. ドロップダウン編
  4. テキスト入力編

今回の動作環境は、Unity : 2018.4.20f1、VRCSDK : 2020.04.09.16.59、U# : v0.15.5です。

目次


追記

当記事は少し古めの物になります。
使用する際は、ContinuousSyncの手法にてお試しいただけますと正常に動作するかと思います。
予めご了承ください。

前回

前回はドロップダウンについて書きました。
hatuxes.hatenablog.jp

完成図

今回は下図(三人称視点)のInputField部分を紹介します。
他のUIも別の記事で紹介しています。

f:id:hatuxes:20200416160801g:plain

スクリプト

実装に使ったスクリプトはこちらになります。

using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;
using VRC.Udon;

public class InputField_Anyone : UdonSharpBehaviour
{
    InputField _inputField;
    [SerializeField] Text _contentText;

    [UdonSynced] string _content;

    void Start()
    {
        _inputField = this.gameObject.GetComponent<InputField>();
    }

    void Update()
    {
        _contentText.text = _content;
    }

    public void SetContent()
    {
        _content = _inputField.text;
    }

    public void ChangerOwner()
    {
        if (!Networking.IsOwner(Networking.LocalPlayer, this.gameObject)) Networking.SetOwner(Networking.LocalPlayer, this.gameObject);
    }
}


部分解説

ちょっと説明が無いので、解説をいくつかしていきます。
今回は、_contentがstringの同期変数です。

ChangeOwner

ChangeOwner()はEventTriggerのPointerDownで呼んでいます。
「EventTriggerって何?」と思った方は、ボタン・トグル編をご覧ください。

f:id:hatuxes:20200417154104p:plain

ボタンの時と実装は同じく、押し始めにその人がこのスクリプトのオーナーじゃなかったらオーナーにしてあげるようになっています。
また、EventTriggerでオーナーを移しているのは、少しでもオーナー移動時と変数代入時のフレームを分けるためです。

SetContent

SetContent()はInputFieldのOn End Editで呼んでいます。

f:id:hatuxes:20200417152734p:plain

そのため、打ち終わってEnterキーを押したときにSetContent()が呼ばれることになります。
SetContent()の中身は

_content = _inputField.text;

だけなので、Enterキーを押したら現在入力していた物を同期変数_contentに代入するといった処理のみになります。

あとがき

以上でこのシリーズの解説は終わりになります。
InputField自体はかなり便利なものなので、使い道はかなり広がりそうですよね。
これからのSDK3に期待です。

今回を含む同期uGUIのサンプルはまとめてGithubに置いてあります。
ライセンスを確認したうえで、お使いください。
github.com