【初心者向け】Unity 2017 + Vuforiaで３Dモデルを表示してみた ～動画再生編～

## やること

過去2回にわたりVuforiaの登録・マーカーの設定、マーカー検出時のモデル表示を行った

[【初心者向け】Unity 2017 + Vuforiaで３Dモデルを表示してみた ～準備編～][Uni1]

[【初心者向け】Unity 2017 + Vuforiaで３Dモデルを表示してみた ～3Dモデル表示編～][Uni2]

[Uni1]:https://qiita.com/SeagullShingo/items/f5193bb283b96562fd54
[Uni2]:https://qiita.com/SeagullShingo/items/8d0837049be11ab2ed17

今回は下記を行う。

- マーカー発見時に3Dモデルを出現と同時に動画を再生させる

イメージとしてあるマーカーを発見したときに、3Dのモデルが表示され、何かの説明の動画も同時に流れる。
ということを想定している。
動画の再生はUnityの3DオブジェクトのQuad上を予定。

## 環境

今回検証した環境を記載。

- Unity起動環境：windows7(Lenovo X1 Carbon)
- Unity 2017.3.1f1
- Vuforia(2018/4時点)


## 準備作業

Unityのオブジェクトの「Quad」を使用して、そこに動画を流すことを想定
Unity上にQuadを配置

![Mov1.jpg](https://qiita-image-store.s3.amazonaws.com/0/225931/71c81879-9785-fc40-1c06-df2aa765f106.jpeg)

ちょっとモデルやQuadの位置を調整

注意点としてモデルが表示されたらQuadも表示させたいので、ImageTargetの中に入れているという点。
ImageTargetの中に入れておかないと、最初からQuadだけ見えていたりおかしなことになるので注意。

![Mov2.jpg](https://qiita-image-store.s3.amazonaws.com/0/225931/0a0d15d7-7300-3da3-b1f6-bd753fad602e.jpeg)

参考

![Mov3.jpg](https://qiita-image-store.s3.amazonaws.com/0/225931/ce7863e1-66f7-6c1d-901e-573eb894845e.jpeg)



## 動画設定

次にQuadに対して「Video Player」を「Add Component」から追加し、動画を「Video Clip」に指定する。
動画は一度Unity上のAssetにドラッグ＆ドロップしてから指定

動画を作るのは難しいかもしれないが今回は適当なパワーポイントを作成しOffice「Export」機能でビデオを作成した。
形式はmp4形式。（Officeのバージョンによっては出来ないかも知れないので注意）


![mov4.jpg](https://qiita-image-store.s3.amazonaws.com/0/225931/3aaae538-78a9-7c1e-7d94-062ecb4b0937.jpeg)


一旦この設定でカメラを起動すると、モデルが表示され、ちゃんと動画も再生されていた。


## マーカー発見時に動画を開始させたい

気づいた方もいるかもしれないが、動画は再生されるようになったのだが、下記の問題が発生した。

- カメラ起動と同時に動画は開始される（マーカーを発見していないのに）
- 一度マーカーがカメラから消え、次にマーカーを移すと動画は最初から開始される

原因は下記の設定

- 「Play On Awake」

この設定をしているせいでカメラ起動と同時に動画も開始される。
ただし、これを外すだけだとカメラ起動してマーカーを検出しても動画は開始されない。
これから設定を変更してく。

まずは、「Play On Awake」のチェックをはずす。
「Loop」などの設定はお好みで。

![Mov5_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/225931/ae51cd28-f8d6-e5f3-45ff-3240d30dc5db.jpeg)


細かいことを行おうとするとやはりスクリプトを修正する必要が出てくる。
（もともとプログラマではない筆者にとってはつらい作業・・・）

色々調べた結果、下記のスクリプトを修正することで、マーカー検出時に（モデル表示と同時に）動画を再生することができた。

ImageTargetの「Inspector」で確認できる下記スクリプト

- 「DefaultTrackableEventHandler」

（「DefaultTrackableEventHandler」の「Edit Script」から）
![Mov6.jpg](https://qiita-image-store.s3.amazonaws.com/0/225931/986ac268-0e1b-e0bf-09d1-27676f2798e1.jpeg)

修正したスクリプト

もともとこのスクリプトはマーカーを発見した場合にXX、マーカーをロストした場合にXXといったことを制御するスクリプトのようだ。


変更箇所は「//追加箇所」と書いてある3箇所
自動で起動しなくなったのでGameObjectの「Quad」を指定してVideoPlayerを開始しているところ
マーカーをロストしたらビデオを一時停止（Pause）しているところ
最初の「UnityEngine.Video」はこれを入れないとカメラ自体が起動しなかったので入れた。

※あくまでも個人的に調べて出来た方法を記載しているので、お作法通りではなかったり、変な書き方かもしれませんがあしからず。
（むしろ正しい方法知っている方いたら是非共有していただけるとうれしいです）

たぶん、「Quad」の名前を変えていなければそのままコピペでいけるはず・・・


```cs:DefaultTrackableEventHandler

/*==============================================================================
Copyright (c) 2017 PTC Inc. All Rights Reserved.

Copyright (c) 2010-2014 Qualcomm Connected Experiences, Inc.
All Rights Reserved.
Confidential and Proprietary - Protected under copyright and other laws.
==============================================================================*/

using UnityEngine;
using Vuforia;
// 追加箇所
using UnityEngine.Video;

/// <summary>
///     A custom handler that implements the ITrackableEventHandler interface.
/// </summary>
public class DefaultTrackableEventHandler : MonoBehaviour, ITrackableEventHandler
{
    #region PRIVATE_MEMBER_VARIABLES

    protected TrackableBehaviour mTrackableBehaviour;

    #endregion // PRIVATE_MEMBER_VARIABLES

    #region UNTIY_MONOBEHAVIOUR_METHODS

    protected virtual void Start()
    {
        mTrackableBehaviour = GetComponent<TrackableBehaviour>();
        if (mTrackableBehaviour)
            mTrackableBehaviour.RegisterTrackableEventHandler(this);
    }

    #endregion // UNTIY_MONOBEHAVIOUR_METHODS

    #region PUBLIC_METHODS

    /// <summary>
    ///     Implementation of the ITrackableEventHandler function called when the
    ///     tracking state changes.
    /// </summary>
    public void OnTrackableStateChanged(
        TrackableBehaviour.Status previousStatus,
        TrackableBehaviour.Status newStatus)
    {
        if (newStatus == TrackableBehaviour.Status.DETECTED ||
            newStatus == TrackableBehaviour.Status.TRACKED ||
            newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
        {
            Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " found");
            OnTrackingFound();
        }
        else if (previousStatus == TrackableBehaviour.Status.TRACKED &&
                 newStatus == TrackableBehaviour.Status.NOT_FOUND)
        {
            Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " lost");
            OnTrackingLost();
        }
        else
        {
            // For combo of previousStatus=UNKNOWN + newStatus=UNKNOWN|NOT_FOUND
            // Vuforia is starting, but tracking has not been lost or found yet
            // Call OnTrackingLost() to hide the augmentations
            OnTrackingLost();
        }
    }

    #endregion // PUBLIC_METHODS

    #region PRIVATE_METHODS

    protected virtual void OnTrackingFound()
    {
        var rendererComponents = GetComponentsInChildren<Renderer>(true);
        var colliderComponents = GetComponentsInChildren<Collider>(true);
        var canvasComponents = GetComponentsInChildren<Canvas>(true);

        foreach (var component in rendererComponents)
            component.enabled = true;

        // Enable colliders:
        foreach (var component in colliderComponents)
            component.enabled = true;

        // Enable canvas':
        foreach (var component in canvasComponents)
            component.enabled = true;

        // 追加箇所
        if (mTrackableBehaviour.gameObject.GetComponentInChildren<VideoPlayer>() != null)
        {
            GameObject.Find("Quad").GetComponent<VideoPlayer>().Play();
            // 下記の書き方でも同様のことが出来た
            // mTrackableBehaviour.gameObject.GetComponentInChildren<VideoPlayer>().Play();
        }
    }


    protected virtual void OnTrackingLost()
    {
        var rendererComponents = GetComponentsInChildren<Renderer>(true);
        var colliderComponents = GetComponentsInChildren<Collider>(true);
        var canvasComponents = GetComponentsInChildren<Canvas>(true);

        // Disable rendering:
        foreach (var component in rendererComponents)
            component.enabled = false;

        // Disable colliders:
        foreach (var component in colliderComponents)
            component.enabled = false;

        // Disable canvas':
        foreach (var component in canvasComponents)
            component.enabled = false;

        // 追加箇所
        if (mTrackableBehaviour.gameObject.GetComponentInChildren<VideoPlayer>() != null)
        {
            mTrackableBehaviour.gameObject.GetComponentInChildren<VideoPlayer>().Pause();
        }

    }

    #endregion // PRIVATE_METHODS
}




```


このスクリプトを修正することで、下記の動きになる。

- マーカーを発見したら3Dモデル表示＆動画開始
- マーカーをロストしたら動画は一時停止、3Dモデルも消える
- 再度マーカーを発見したら3Dモデル表示＆動画の途中から開始

今回は下記の設定にしていないが、マーカーをロストした場合に動画を停止したい場合は、下記に修正すればOK。
次回マーカー発見時にまた最初からの動画再生になる。

```cs:DefaultTrackableEventHandler(抜粋)

        if (mTrackableBehaviour.gameObject.GetComponentInChildren<VideoPlayer>() != null)
        {
            mTrackableBehaviour.gameObject.GetComponentInChildren<VideoPlayer>().Stop();
        }


```


一応これでやりたい動きになったので一旦ここで終了。
次は今までPCのWebCAMでずっとやってきたので、スマホにビルドして同じことが出来るかにチャレンジしたい。