次の方法で共有


HoloLens (第 1 世代) と Azure 306 - ビデオのストリーム配信


Note

Mixed Reality Academy のチュートリアルは、HoloLens (第 1 世代) と Mixed Reality イマーシブ ヘッドセットを念頭に置いて編成されています。 そのため、それらのデバイスの開発に関するガイダンスを引き続き探している開発者のために、これらのチュートリアルをそのまま残しておくことが重要だと考えています。 これらのチュートリアルが、HoloLens 2 に使用されている最新のツールセットや操作に更新されることは "ありません"。 これらは、サポートされているデバイス上で継続して動作するように、保守されます。 今後、HoloLens 2 の開発方法を説明する新しいチュートリアルが公開される予定です。 この通知は、それらのチュートリアルが投稿されたときにリンクと共に更新されます。


Windows Mixed Reality V R の例のスクリーンショット。Windows Mixed Reality V R エクスペリエンスのスクリーンショット。

このコースでは、お客様の Azure Media Services を Windows Mixed Reality の VR エクスペリエンスに接続して、イマーシブ ヘッドセット上で 360 度ビデオをストリーミングする方法を学びます。

Azure Media Services はサービスのコレクションで、現在最も人気のあるモバイル デバイス上でより多くの視聴者にリーチできるブロードキャスト品質のビデオ ストリーミング サービスを提供します。 詳細については、Azure Media Services のページをご覧ください。

このコースを修了すると、お客様は次のことができる Mixed Reality イマーシブ ヘッドセット アプリケーションを手に入れることができます。

  1. Azure Media Service を介して、Azure Storage から 360 度ビデオを取得する。

  2. 取得した 360 度ビデオを Unity のシーン内に表示する。

  3. 2 つのシーン間を移動し、2 つの異なるビデオを表示する。

お客様のアプリケーションで、結果をどのようにデザインと統合するかは、お客様次第です。 このコースは、Azure のサービスを Unity プロジェクトに統合する方法を学べることを目的としています。 このコースで得られた知識を使用して、ご自分の Mixed Reality アプリケーションを強化しましょう。

デバイス サポート

コース HoloLens イマーシブ ヘッドセット
MR と Azure 306: ストリーミング ビデオ ✔️

前提条件

Note

このチュートリアルは、Unity と C# の基本的な使用経験がある開発者を対象としています。 また、このドキュメント内の前提条件や文章による説明は、執筆時 (2018 年 5 月) にテストおよび検証された内容であることをご了承ください。 「ツールのインストール」の記事に記載されているように、最新のソフトウェアを自由に使用できます。ただし、このコースの情報は、以下に記載されているものよりも新しいソフトウェアで見つかったものと完全に一致するとは限りません。

このコースでは、次のハードウェアとソフトウェアをお勧めします。

開始する前に

  1. このプロジェクトをビルドする際の問題を避けるために、このチュートリアルで紹介するプロジェクトをルートまたはルートに近いフォルダーに作成することを強くお勧めします (フォルダー パスが長いと、ビルド時に問題が発生する可能性があります)。

  2. Mixed Realityイマーシブヘッドセットをセットアップしてテストします。

    Note

    このコースでは、モーションコントローラーを必要としません。 イマーシブ ヘッドセットの設定についてサポートが必要な場合は、Windows Mixed Reality の設定方法のリンクをクリックしてください。

第 1 章 - Azure portal: Azure Storage アカウントの作成

Azure Storage サービスを利用するには、Azure portal で Storage アカウントを作成および設定する必要があります。

  1. Azure Portal にログインします。

    Note

    まだ Azure アカウントをお持ちでない方は、作成する必要があります。 このチュートリアルを教室やラボで受講している場合は、インストラクターや監督者に新しいアカウントの設定方法を質問してください。

  2. ログインしたら、左メニューの [ストレージ アカウント] をクリックします。

    Azure Portal メニューのスクリーンショット。ストレージ アカウントが強調表示されています。

  3. [ストレージ アカウント] タブで [追加] をクリックします。

    [ストレージ アカウント] ダイアログ ボックスのスクリーンショット。[追加] が強調表示されています。

  4. [ストレージ アカウントの作成] タブで、

    1. ご自分のアカウントの [名前] を入力します。このフィールドには数字と小文字しか入力できないことに注意してください。

    2. [デプロイ モデル] には、[リソース マネージャー] を選択します。

    3. [アカウントの種類] には [ストレージ (汎用 v1)] を選択します。

    4. [パフォーマンス] には [標準]* を選択します。

    5. [レプリケーション] には [ローカル冗長ストレージ (LRS)] を選択します。

    6. [安全な転送が必須][無効] のままにしておきます。

    7. サブスクリプションを選択します。

    8. [リソース グループ] を選択するか、新規に作成します。 リソース グループは、Azure アセットのコレクションの監視、アクセス制御、プロビジョニング、課金管理を行う方法を提供します。

    9. リソース グループの [場所] を決定します (新しいリソース グループを作成する場合)。 この場所は、アプリケーションが実行されるリージョン内にすることが理想的です。 一部の Azure アセットは、特定のリージョンでしか利用できません。

  5. お客様は、本サービスに適用されるご契約条件を理解していることを確認する必要があります。

    ストレージ アカウントの作成ページのスクリーンショット。

  6. [作成] をクリックしたら、サービスが作成されるのを待つ必要があります。これには 1 分ほどかかることがあります。

  7. サービス インスタンスが作成されると、ポータルに通知が表示されます。

    デプロイに成功した通知のスクリーンショット。

  8. この時点では、リソースをフォローする必要はありません。次の章に進んでください。

第 2 章 - Azure portal: Media Service の作成

Azure Media Service を使用するには、お客様のアプリケーションで利用できるようにサービスのインスタンスを構成する必要があります (アカウント所有者は管理者である必要があります)。

  1. Azure portal で、左上の [リソースの作成] をクリックして [Media Service] を検索し、Enter キーを押します。 目的のリソースにピンクのアイコンが表示されているので、これをクリックすると新しいページが表示されます。

    Azure Portal のスクリーンショット。Media Services オプションが強調表示されています。

  2. 新しいページには、Media Service の説明が表示されます。 このプロンプトの左下にある [作成] ボタンをクリックすると、このサービスとの関連付けが作成されます。

    Azure Portal のスクリーンショット。[作成] ボタンが強調表示されています。

  3. [作成] をクリックすると、パネルが表示されます。ここに、新しい Media Service の詳細を入力する必要があります。

    1. このサービス インスタンスに必要な [アカウント名] を入力します。

    2. サブスクリプションを選択します。

    3. [リソース グループ] を選択するか、新規に作成します。 リソース グループは、Azure アセットのコレクションの監視、アクセス制御、プロビジョニング、課金管理を行う方法を提供します。 1 つのプロジェクト (例: これらのラボなど) に関連するすべての Azure サービスを共通のリソース グループの下に保持することをお勧めします。

    Azure リソース グループについて詳しく知りたい場合は、Azure リソース グループの管理方法のリンクからご覧ください。

    1. リソース グループの [場所] を決定します (新しいリソース グループを作成する場合)。 この場所は、アプリケーションが実行されるリージョン内にすることが理想的です。 一部の Azure アセットは、特定のリージョンでしか利用できません。

    2. [Storage アカウント] セクションでは、[選択してください] セクションをクリックし、前章で作成した [Storage アカウント] をクリックします。

    3. またお客様は、本サービスに適用されるご契約条件を理解していることを確認する必要があります。

    4. Create をクリックしてください。

      [Media Service アカウントの作成] ページのスクリーンショット。

  4. [作成] をクリックしたら、サービスが作成されるのを待つ必要があります。これには 1 分ほどかかることがあります。

  5. サービス インスタンスが作成されると、ポータルに通知が表示されます。

    ポータル メニューの通知アイコンのスクリーンショット。

  6. 通知をクリックして、新しいサービス インスタンスを確認します。

    デプロイが成功したことを示す通知のスクリーンショット。

  7. 通知の[リソースに移動]ボタンをクリックして、新しいサービスインスタンスを探します。

  8. 新しい Media サービスのページの左側のパネルで [アセット] リンク (真ん中から下) をクリックします。

  9. 次のページでは、ページの左上にある [アップロード] をクリックします。

    [アセット] ページのスクリーンショット。[アップロード] オプションと [アセット] オプションが強調表示されています。

  10. フォルダーのアイコンをクリックしてファイルを参照し、ストリーミングしたい最初の 360 度ビデオを選択します。

    こちらのリンクからサンプル ビデオをダウンロードすることができます。

    ビデオアセットのアップロードページのスクリーンショット。

警告

ファイル名が長いとエンコーダーに問題が発生する場合があります。ビデオに問題が発生しないように、ビデオのファイル名を短くすることを検討してください。

  1. ビデオのアップロードが完了すると、進行状況バーが緑色になります。

    ビデオ アセットのアップロードの進行状況バーのスクリーンショット。

  2. 上のテキスト [(yourservicename - アセット)] をクリックすると、[アセット] ページに戻ります。

  3. あなたのビデオが正常にアップロードされたことがわかります。 そのタイルをクリックします。

    [アセット] ページのスクリーンショット。ビデオ 1 ドット M P 4 が強調表示されています。

  4. リダイレクト先のページには、ビデオに関する詳細情報が表示されます。 ビデオを使用できるようにするには、それをエンコードする必要があります。それには、ページ左上の [エンコード] ボタンをクリックします。

    資産ページのスクリーンショット。エンコード ボタンが強調表示されています。

  5. 右側に新しいパネルが表示されます。ここで、ファイルのエンコード オプションを設定することができます。 以下のプロパティを設定します (一部は既定で設定済みです)。

    1. メディア エンコーダー名 Media Encoder Standard

    2. エンコード プリセット Content Adaptive Multiple Bitrate MP4

    3. ジョブ名 Media Encoder Standard processing of Video1.mp4

    4. 出力メディアのアセット名 Video1.mp4 -- Media Encoder Standard エンコード

      資産ページのエンコードのスクリーンショット。

  6. [作成] ボタンをクリックします。

  7. [エンコード ジョブが追加されました] という通知バーが表示されます。そのバーをクリックすると、エンコードの進捗状況が表示されたパネルが表示されます。

    エンコード ジョブが追加されたというラベルが付いた通知バーのスクリーンショット。

    エンコーダー処理ページのスクリーンショット。

  8. ジョブが完了するまで待ちます。 完了したら、パネルの右上にある [X] でパネルを閉じることができます。

    状態が完了した進行状況バーのスクリーンショット。

    メディア コーダー処理ページの上部メニューのスクリーンショット。

    重要

    この処理にかかる時間は、ビデオのファイル サイズによって異なります。 このプロセスにはかなりの時間がかかることがあります。

  9. エンコード版のビデオが作成されたので、それを公開してアクセスできるようにすることができます。 これを行うには、青いリンク [アセット] をクリックして、アセット ページに戻ります。

    Azure Portal のスクリーンショット。資産のリンクが強調表示されています。

  10. ご自分のビデオが、[アセットの種類] が [Multi-Bitrate MP4] である別のビデオと一緒に表示されます。

    Microsoft Azure アセット メニューのスクリーンショット。

    Note

    最初のビデオと一緒に、新しいアセット [Unknown] が表示され、その [サイズ] が "0" バイトであることにお気付きになるでしょう。更新するには、ウィンドウを最新の情報に更新してください。

  11. この新しいアセットをクリックします。

    資産を一覧表示するディレクトリのスクリーンショット。

  12. 以前に使用したパネルと同様のパネルが表示されますが、これは別のアセットです。 ページの中央上部にある [公開] ボタンをクリックします。

    上部のメニュー バーのスクリーンショット。[発行] ボタンが強調表示されています。

  13. お客様のアセット内のファイルへのエントリ ポイントであるロケーターを設定するよう求めるプロンプトが表示されます。 このシナリオでは、次のプロパティを設定します。

    1. [ロケーターの種類]>[プログレッシブ]

    2. 日付時刻は、現在の日付から将来の時刻 (この場合は 100 年) に自動的に設定されます。 このままでもよいですが、適宜変更してください。

    Note

    ロケーターについての詳細情報や、お客様が選択できる内容については、Azure Media Services のドキュメントをご覧ください。

  14. パネルの下部にある [追加] ボタンをクリックします。

    [発行する資産] ダイアログを含むディレクトリの一覧を示すスクリーンショット。

  15. これでお客様のビデオが公開され、エンドポイントを使用してストリーム配信できるようになりました。 ページの下の方に [ファイル] というセクションがあります。 ここには、ビデオのさまざまなエンコード バージョンが表示されています。 可能な限り高い解像度のものを選択すると (下の画像では 1920 x 960 のファイル)、右側にパネルが表示されます。 そこに [ダウンロード URL] があります。 このエンドポイントをコピーして、後でご自分のコードに使用します。

    Microsoft Azure Files セクションのスクリーンショット。

    資産情報ページのスクリーンショット。

    Note

    また、[再生] ボタンを押すと、ビデオを再生してテストすることができます。

  16. 次に、このラボで使用する 2 本目のビデオをアップロードする必要があります。 上記の手順に従って、2 本目のビデオにも同じ作業を繰り返します。 2 本目のエンドポイントもコピーするようにしてください。 2 本目のビデオをダウンロードするには、次のリンクを使用します。

  17. 両方のビデオが公開されたら、次の章に進む準備ができました。

第 3 章 - Unity プロジェクトの設定

次に示すのは、Mixed Reality を使用して開発するための一般的な設定です。そのため、他のプロジェクトに適したテンプレートとなっています。

  1. Unity を開き、[新規] をクリックします。

    Unity プロジェクト タブのスクリーンショット。[新規] ボタンが強調表示されています。

  2. Unity プロジェクトに名前を付ける必要があります。MR_360VideoStreaming と入力します。 プロジェクトの種類が [3D] に設定されていることを確認します。 [場所] を適切な場所に設定します (ルート ディレクトリに近い方が適しています)。 [Create project]\(プロジェクトの作成\) をクリックします。

    Unity の [新しいプロジェクト] ページのスクリーンショット。

  3. Unity を開いた状態で、既定の [Script Editor]\(スクリプト エディター\)Visual Studio に設定されていることを確認することをお勧めします。[Edit Preferences]\(環境設定の編集\) に移動し、新しいウィンドウで [External Tools]\(外部ツール\) に移動します。 [外部スクリプト エディター][Visual Studio 2017] に変更します。 [環境設定] ウィンドウを閉じます。

    外部スクリプト エディター メニューのスクリーンショット。Visual Studio 2017 が選択されています。

  4. 次に、ファイルビルド設定に移り、プラットフォーム切り替えボタンをクリックすることで、プラットフォームをユニバーサルWindowsプラットフォームに切り替えます。

  5. 次のことも確認します。

    1. ターゲットデバイスいずれかのデバイスに設定します。

    2. ビルドの種類D3Dに設定します。

    3. SDK最新のインストールに設定します。

    4. Visual Studioのバージョン最新のインストールに設定します。

    5. ビルドと実行ローカルマシンに設定します。

    6. シーンの設定は後で行いますので、今は気にしないでください。

    7. ここでは、残りの設定は既定値のままにしておきます。

      Unity のビルド設定画面のスクリーンショット。

  6. Build Settings (ビルド設定) ウィンドウで、[プレーヤー設定] ボタンをクリックすると、"インスペクター" が配置されているスペースに関連パネルが表示されます。

  7. このパネルでは、いくつかの設定を確認する必要があります。

    1. [Other Settings] (その他の設定) タブで、次の内容を確認します。

      1. Scripting Runtime VersionStable (.NET 3.5 同等) にする必要があります。

      2. [スクリプト バックエンド][.NET] である。

      3. [API 互換性レベル][.NET 4.6] である。

        [ユニバーサル Windows プラットフォームの設定] ページを示すスクリーンショット。

    2. さらに、パネルの下にある [XR Settings]\(XR 設定\) ([Publish Settings]\(公開設定\) の下) で、[Virtual Reality Supported]\(Virtual Reality サポート\) をオンにし、Windows Mixed Reality SDK が追加されていることを確認します。

      Unity X R の設定画面のスクリーンショット。

    3. [Publishing Settings]\(公開設定\) タブ内の [Capabilities]\(機能\) で、次の内容を確認します。

      • InternetClient

        [機能] 画面のスクリーンショット。[インターネット クライアント] がオンになっています。

  8. これらの変更を行った後、[ビルド設定] ウィンドウを閉じます。

  9. プロジェクトを [ファイル] [プロジェクトの保存] で保存します。

第 4 章 - InsideOutSphere Unity パッケージのインポート

重要

このコースの "Unity のセットアップ" コンポーネントをスキップして、そのままコードに進みたい場合は、この .unitypackage をダウンロードし、これをカスタム パッケージとしてプロジェクトにインポートした後で第 5 章から続けてください。 その場合でも、Unity プロジェクトを作成する必要があります。

このコースでは、InsideOutSphere.unitypackage という Unity アセット パッケージをダウンロードする必要があります。

unitypackage をインポートする方法:

  1. Unity のダッシュボードを表示して、画面上部のメニューにある [アセット] をクリックし、[パッケージのインポート] > [カスタム パッケージ] をクリックします。

    アセット メニューのスクリーンショット。[パッケージのインポート] メニューが開いています。[カスタム パッケージ] が選択されています。

  2. ファイル ピッカーを使用して InsideOutSphere.unitypackage パッケージを選択し、[開く] をクリックします。 このアセットのコンポーネントリストを表示します。 [Import]\(インポート\) をクリックしてインポートを確認します。

    Unity パッケージのインポート画面のスクリーンショット。

  3. インポートが完了すると、Assets フォルダーに MaterialsModelsPrefabs という 3 つの新しいフォルダーが追加されているのがわかります。 このようなフォルダー構造は、Unity プロジェクトの典型的なものです。

    assets フォルダーのスクリーンショット。

    1. Models フォルダーを開くと、InsideOutSphere モデルがインポートされているのがわかります。

    2. Materials フォルダーには、InsideOutSpheres のマテリアル lambert1 と、後ほどご紹介する GazeButton で使用される ButtonMaterial というマテリアルがあります。

    3. Prefabs フォルダーには、InsideOutSphere modelGazeButton の両方が含まれる InsideOutSphere プレハブが含まれています。

    4. コードは含まれていないため、このコースに従いコードを記述します。

  4. [階層][メイン カメラ] オブジェクトを選択し、以下のコンポーネントを更新します。

    1. 変換

      1. [位置] = X: 0、Y: 0、Z: 0。

      2. [回転] = X: 0、Y: 0、Z: 0。

      3. [スケール] = X: 1、Y: 1、Z: 1。

    2. カメラ

      1. [クリア フラグ]: 単色。

      2. [クリッピング プレーン: Near: 0.1、Far: 6。

        インスペクター画面のスクリーンショット。

  5. Prefab フォルダーに移動し、InsideOutSphere プレハブを [Hierarchy]\(ヒエラルキー\) パネルにドラッグします。

    [プレハブ] フォルダー メニューと開発者環境のスクリーンショット。

  6. 階層内の InsideOutSphere オブジェクトの横にある小さな矢印をクリックして展開します。 その下には、GazeButton というオブジェクトがあります。 これは、シーンやビデオの変更に使用されます。

    [階層] タブのスクリーンショット。

  7. [インスペクター] ウィンドウで InsideOutSphere の [変換] コンポーネントをクリックし、以下のプロパティが設定されていることを確認します。

変換 - 位置

X Y Z
0 0 0

変換 - 回転

X Y Z
0 50- 0

変換 - スケール

X Y Z
0 0 0

[内側の外側の球] の [インスペクター] 画面が開いているスクリーンショット。

  1. GazeButton 子オブジェクトをクリックして、その [Transform]\(変換\) を以下のように設定します。

変換 - 位置

X Y Z
3.6 1.3 0

変換 - 回転

X Y Z
0 0 0

変換 - スケール

X Y Z
1 1 1

シーン タブが開いているスクリーンショット。

第 5 章 - VideoController クラスを作成する

VideoController クラスは、Azure Media Service からのコンテンツのストリーミングに使用される 2 つのビデオ エンドポイントをホストします。

このクラスを作成するには、次の手順を実行します。

  1. [プロジェクト] パネルにある Asset フォルダーを右クリックし、[作成] > [フォルダー] の順にクリックします。 フォルダーに「Scripts」という名前を付けます。

    アセット フォルダー メニューのスクリーンショット。[作成] メニューが開き、フォルダーが選択されています。

    プロジェクト タブのスクリーンショット。[アセット] フォルダーが選択されています。

  2. Scripts フォルダーをダブルクリックして開きます。

  3. フォルダー内を右クリックし、[作成] > [C# スクリプト] の順にクリックします。 スクリプトに VideoController という名前を付けます。

    Video Controller という名前のファイルのスクリーンショット。

  4. 新しい VideoController スクリプトをダブルクリックして、それを Visual Studio 2017 で開きます。

    ビデオ コントローラー ファイルのコードのスクリーンショット。

  5. コード ファイルの上部にある名前空間を次のように更新します。

    using System.Collections;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.Video;
    
  6. VideoController クラスに以下の変数と、Awake() メソッドを入力します。

        /// <summary> 
        /// Provides Singleton-like behaviour to this class. 
        /// </summary> 
        public static VideoController instance; 
    
        /// <summary> 
        /// Reference to the Camera VideoPlayer Component.
        /// </summary> 
        private VideoPlayer videoPlayer; 
    
        /// <summary>
        /// Reference to the Camera AudioSource Component.
        /// </summary> 
        private AudioSource audioSource; 
    
        /// <summary> 
        /// Reference to the texture used to project the video streaming 
        /// </summary> 
        private RenderTexture videoStreamRenderTexture;
    
        /// <summary>
        /// Insert here the first video endpoint
        /// </summary>
        private string video1endpoint = "-- Insert video 1 Endpoint here --";
    
        /// <summary>
        /// Insert here the second video endpoint
        /// </summary>
        private string video2endpoint = "-- Insert video 2 Endpoint here --";
    
        /// <summary> 
        /// Reference to the Inside-Out Sphere. 
        /// </summary> 
        public GameObject sphere;
    
        void Awake()
        {
            instance = this;
        }
    
  7. 次に、Azure Media Service ビデオからのエンドポイントを入力します。

    1. 最初に video1endpoint 変数に入力します。

    2. 次に video2endpoint 変数に入力します。

    警告

    バージョン 2017.4.1f1 では、Unity 内で https を使用する際に既知の問題があります。 ビデオの再生時にエラーが発生する場合は、代わりに "http" を使用してみてください。

  8. 次に、Start() メソッドを編集する必要があります。 このメソッドは、ユーザーが [視線入力] ボタンを見てシーンを切り替える (結果的にビデオを切り替える) たびにトリガーされます。

        // Use this for initialization
        void Start()
        {
            Application.runInBackground = true;
            StartCoroutine(PlayVideo());
        }
    
  9. Start() メソッドの後に、ビデオをシームレスに開始するために使用される PlayVideo() IEnumerator メソッドを挿入します (そのため、スタッターは表示されません)。

        private IEnumerator PlayVideo()
        {
            // create a new render texture to display the video 
            videoStreamRenderTexture = new RenderTexture(2160, 1440, 32, RenderTextureFormat.ARGB32);
    
            videoStreamRenderTexture.Create();
    
            // assign the render texture to the object material 
            Material sphereMaterial = sphere.GetComponent<Renderer>().sharedMaterial;
    
            //create a VideoPlayer component 
            videoPlayer = gameObject.AddComponent<VideoPlayer>();
    
            // Set the video to loop. 
            videoPlayer.isLooping = true;
    
            // Set the VideoPlayer component to play the video from the texture 
            videoPlayer.renderMode = VideoRenderMode.RenderTexture;
    
            videoPlayer.targetTexture = videoStreamRenderTexture;
    
            // Add AudioSource 
            audioSource = gameObject.AddComponent<AudioSource>();
    
            // Pause Audio play on Awake 
            audioSource.playOnAwake = true;
            audioSource.Pause();
    
            // Set Audio Output to AudioSource 
            videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
            videoPlayer.source = VideoSource.Url;
    
            // Assign the Audio from Video to AudioSource to be played 
            videoPlayer.EnableAudioTrack(0, true);
            videoPlayer.SetTargetAudioSource(0, audioSource);
    
            // Assign the video Url depending on the current scene 
            switch (SceneManager.GetActiveScene().name)
            {
                case "VideoScene1":
                    videoPlayer.url = video1endpoint;
                    break;
    
                case "VideoScene2":
                    videoPlayer.url = video2endpoint;
                    break;
    
                default:
                    break;
            }
    
            //Set video To Play then prepare Audio to prevent Buffering 
            videoPlayer.Prepare();
    
            while (!videoPlayer.isPrepared)
            {
                yield return null;
            }
    
            sphereMaterial.mainTexture = videoStreamRenderTexture;
    
            //Play Video 
            videoPlayer.Play();
    
            //Play Sound 
            audioSource.Play();
    
            while (videoPlayer.isPlaying)
            {
                yield return null;
            }
        }
    
  10. このクラスに必要な最後のメソッドは ChangeScene() メソッドで、これはシーン間の入れ替えに使用されます。

        public void ChangeScene()
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name == "VideoScene1" ? "VideoScene2" : "VideoScene1");
        }
    

    ヒント

    ChangeScene() メソッドでは、"条件演算子" という C# の便利な機能が使用されています。 これにより、条件をチェックし、そのチェックの結果に基づいて値を返すことが、すべて 1 つのステートメント内で可能になります。 条件演算子の詳細については、こちらのリンクを参照してください。

  11. Unity に戻る前に、Visual Studio で変更を保存します。

  12. Unity Editor に戻り、Scripts フォルダーの VideoController クラスをクリックして、[階層] パネルの [メイン カメラ] オブジェクトにドラッグします。

  13. [メイン カメラ] をクリックして、[インスペクター] パネルを見てみます。 新しく追加された Script コンポーネントの中に、空の値を持つフィールドがあることにお気付きになるでしょう。 これは参照フィールドで、コード内のパブリック変数を対象としています。

  14. 下図のように、InsideOutSphere オブジェクトを [階層] パネルから Sphere スロットにドラッグします。

    階層メニューのスクリーンショット。メイン カメラが選択されています。Sphere スロットのスクリーンショット。

第 6 章 - Gaze クラスを作成する

このクラスは、レイキャストの作成を担当します。これは、ユーザーがどのオブジェクトを見ているかを検出するために、メイン カメラから前方に投影されます。 このケースでは、レイキャストはユーザーがシーン内の GazeButton オブジェクトを見ているかどうかを識別し、動作をトリガーする必要があります。

このクラスを作成するには、次の手順を実行します。

  1. 先ほど作成した Scripts フォルダーに移動します。

  2. [プロジェクト] パネルを右クリックし、[C# スクリプトの作成] を選択します。 スクリプトに Gaze という名前を付けます。

  3. 新しい Gaze スクリプトをダブルクリックして、それを Visual Studio 2017 で開きます。

  4. 次の名前空間がスクリプトの先頭にあることを確認し、その他を削除します。

    using UnityEngine;
    
  5. 次に、Gaze クラス内に以下の変数を追加します。

        /// <summary> 
        /// Provides Singleton-like behaviour to this class. 
        /// </summary> 
        public static Gaze instance;
    
        /// <summary> 
        /// Provides a reference to the object the user is currently looking at. 
        /// </summary> 
        public GameObject FocusedGameObject { get; private set; }
    
        /// <summary> 
        /// Provides a reference to compare whether the user is still looking at 
        /// the same object (and has not looked away). 
        /// </summary> 
        private GameObject oldFocusedObject = null;
    
        /// <summary> 
        /// Max Ray Distance 
        /// </summary> 
        float gazeMaxDistance = 300;
    
        /// <summary> 
        /// Provides whether an object has been successfully hit by the raycast. 
        /// </summary> 
        public bool Hit { get; private set; }
    
  6. Awake() メソッドと Start() メソッドのコードを追加する必要があります。

        private void Awake()
        {
            // Set this class to behave similar to singleton 
            instance = this;
        }
    
        void Start()
        {
            FocusedGameObject = null;
        }
    
  7. Update() メソッドに次のコードを追加して、レイキャストを投影し、ターゲット ヒットを検出します。

        void Update()
        {
            // Set the old focused gameobject. 
            oldFocusedObject = FocusedGameObject;
            RaycastHit hitInfo;
    
            // Initialise Raycasting. 
            Hit = Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, gazeMaxDistance);
    
            // Check whether raycast has hit. 
            if (Hit == true)
            {
                // Check whether the hit has a collider. 
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at. 
                    FocusedGameObject = hitInfo.collider.gameObject;
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null. 
                    FocusedGameObject = null;
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedGameObject = null;
            }
    
            // Check whether the previous focused object is this same 
            // object (so to stop spamming of function). 
            if (FocusedGameObject != oldFocusedObject)
            {
                // Compare whether the new Focused Object has the desired tag we set previously. 
                if (FocusedGameObject.CompareTag("GazeButton"))
                {
                    FocusedGameObject.SetActive(false);
                    VideoController.instance.ChangeScene();
                }
            }
        }
    
  8. Unity に戻る前に、Visual Studio で変更を保存します。

  9. Scripts フォルダーの Gaze クラスをクリックして、[階層] パネルのメイン カメラ オブジェクトにドラッグします。

第 7 章 - 2 つの Unity シーンを設定する

この章の目的は、2 つのシーンを設定することです。それぞれがストリーム配信するビデオをホストします。 既に作成したシーンを複製して、再度設定する必要がないようにします。ただしその後、新しいシーンを編集して、GazeButton オブジェクトが異なる場所に配置され、異なる外観になるようにします。 これは、シーン間がどのように変わるかを示すためです。

  1. これを行うには、[ファイル] > [シーンを保存] の順に選択します。保存ウィンドウが表示されます。 [新しいフォルダー] ボタンをクリックします。

    第 7 章 - 2 つの Unity シーンを設定する

  2. フォルダーの名前を Scenes にします。

  3. [シーンの保存] ウィンドウはそのまま表示されています。 新しく作成した Scenes フォルダーを開きます。

  4. [ファイル名:] テキスト フィールドに「VideoScene1」と入力し、[保存] を押します。

  5. Unity に戻り、Scenes フォルダーを開き、VideoScene1 ファイルを左クリックします。 キーボードで Ctrl + D を押すと、そのシーンが複製されます

    ヒント

    複製コマンドは、[編集] > [複製] でも実行できます。

  6. Unity によって自動的にシーン名の番号が増やされますが、前に挿入したコードと一致しているかどうかをチェックしてください。

    VideoScene1VideoScene2 があるはずです。

  7. この 2 つのシーンを確認したら、[ファイル] > [ビルド設定] の順に移動します。 [ビルド設定] ウィンドウが開いている状態で、シーンを [ビルド内のシーン] セクションにドラッグします。

    [ビルド設定] ウィンドウのスクリーンショット。

    ヒント

    Ctrl キーを押しながら、Scenes フォルダーから両方のシーンを選択できます。次にそれぞれのシーンを左クリックして、最後に両方のシーンをドラッグします。

  8. [ビルド設定] ウィンドウを閉じ、VideoScene2 をダブルクリックします。

  9. 2 つ目のシーンを開いた状態で、InsideOutSphereGazeButton 子オブジェクトをクリックし、その [変換] を以下のように設定します。

変換 - 位置

X Y Z
0 1.3 3.6

変換 - 回転

X Y Z
0 0 0

変換 - スケール

X Y Z
1 1 1
  1. GazeButton 子を選択したまま、[インスペクター][メッシュ フィルター] を見てみます。 [メッシュ] 参照フィールドの横にある小さなターゲットをクリックします。

    視線ボタンのインスペクター画面のスクリーンショット。

  2. [Select Mesh]\(メッシュの選択\) ポップアップ ウィンドウが表示されます。 [アセット] のリストから [キューブ] メッシュをダブルクリックします。

    [メッシュの選択] ポップアップ ウィンドウのスクリーンショット。

  3. [Mesh Filter]\(メッシュ フィルター\) が更新され、[Cube]\(キューブ\) になります。 次に、[スフィア コライダー] の横にある歯車のアイコンをクリックし、[コンポーネントの削除] をクリックすると、このオブジェクトからコライダーが削除されます。

    [Sphere コライダー] メニューのスクリーンショット。[コンポーネントの削除] が選択されています。

  4. GazeButton を選択したまま、[Inspector]\(インスペクター\) の下部にある [Add Component]\(コンポーネントの追加\) ボタンをクリックします。 検索フィールドに box と入力すると、オプションとして Box Collider が表示されるので、これをクリックして、Box ColliderGazeButton オブジェクトに追加します。

    [コンポーネントの追加] 検索ボックスのスクリーンショット。

  5. GazeButton が部分的に更新されて、外観が変わりましたが、今度は新しいマテリアルを作成していきます。これで、外観がまったく変わり、最初のシーンのオブジェクトとは別のオブジェクトであることがわかりやすくなります。

  6. [プロジェクト パネル] 内の Materials フォルダーに移動します。 ButtonMaterial マテリアルを複製します。これを行うには、キーボードで Ctrl + D を押すか、[マテリアル] を左クリックして、[編集] ファイル メニュー オプションから [複製] を選択します。

    プロジェクト タブの [Materials] フォルダーのスクリーンショット。重複が選択されている編集メニューのスクリーンショット。

  7. 新しい ButtonMaterial マテリアル (ここでは ButtonMaterial 1) を選択し、[Inspector]\(インスペクター\) 内で Albedo カラー ウィンドウをクリックします。 ポップアップが表示されるので、別の色を選択して (好きなものをお選びください)、ポップアップを閉じます。 このマテリアルは、元のものとは異なる独自のインスタンスになります。

    色選択ポップアップのスクリーンショット。

  8. 新しいマテリアルGazeButton 子にドラッグして、最初のシーン ボタンと見分けがつくように、完全に外観を更新します。

    プロジェクト エディターの [シーン] タブのスクリーンショット。

  9. この時点で、UWP プロジェクトをビルドする前に、エディターでプロジェクトをテストすることができます。

    • エディター[再生] ボタンを押し、ヘッドセットを装着します。

      再生、一時停止、スキップのボタンを示すスクリーンショット。再生ボタンが強調表示されています。

  10. 2 つの GazeButton オブジェクトを見て、1 つ目と 2 つ目のビデオを切り替えます。

第 8 章 - UWP ソリューションを構築する

エディターにエラーがないことを確認したら、ビルドの準備が整ったことになります。

ビルドするには、

  1. [ファイル] > [保存] の順にクリックして現在のシーンを保存します。

  2. Unity C#プロジェクトというボックスをチェックします(ビルドが完了した後にクラスを編集できるようになるため、これは重要です)。

  3. [ファイル] > [ビルド設定] の順に移動し、[ビルド] をクリックします。

  4. ソリューションをビルドするフォルダーを選択するよう求めるプロンプトが表示されます。

  5. BUILDS フォルダーを作成し、そのフォルダー内にお好みの適切な名前で別のフォルダーを作成します。

  6. 新しいフォルダーをクリックし、[Select Folder]\(フォルダーの選択\) をクリックして、そのフォルダーを選択すると、その場所でビルドが開始されます。

    [ビルド] フォルダーが強調表示されているスクリーンショット。[Video Streaming Build]\(ビデオ ストリーミング ビルド\) フォルダーが強調表示されているスクリーンショット。

  7. Unity のビルドが完了すると (これには時間がかかる場合があります)、ビルドの場所にエクスプローラーのウィンドウが開きます。

第 9 章 - ローカル コンピューターへのデプロイ

ビルドが完了すると、ビルドした場所にエクスプローラーのウィンドウが表示されます。 名前を付けてビルドしたフォルダーを開き、そのフォルダー内のソリューション (.sln) ファイルをダブルクリックして、Visual Studio 2017 でソリューションを開きます。

あとは、アプリをご自分のコンピューター (つまり "ローカル コンピューター") にデプロイするだけです。

ローカル コンピューターにデプロイするには:

  1. Visual Studio 2017 で、作成したばかりのソリューション ファイルを開きます。

  2. ソリューションプラットフォームで、x86ローカルマシンを選択します。

  3. [ソリューション構成] で、[デバッグ] を選択します。

    [ソリューション構成] メニューのスクリーンショット。

  4. ここで、ソリューションに含まれるパッケージを復元する必要があります。 [ソリューション] を右クリックして、[ソリューションの NuGet パッケージの復元] をクリックします。

    Note

    これは、Unity によってビルドされたパッケージが、お使いのローカル コンピューターの参照で動作するようにターゲットにする必要があるためです。

  5. [ビルド] メニューの [ソリューションの配置] をクリックして、アプリケーションをお使いのコンピューターにサイドロードします。 Visual Studio によって、まずアプリケーションがビルドされ、次に配置されます。

  6. ここで、インストールされたアプリのリストにアプリが現れ、起動できる状態になります。

    インストールされているアプリの一覧のスクリーンショット。

Mixed Reality アプリケーションを実行すると、お客様はアプリ内で使用した InsideOutSphere モデルの中に入ります。 この球体にビデオがストリーミングされ、入力ビデオ (このような視点で撮影されたもの) の 360 度のビューが提供されます。 ビデオの読み込みに数秒かかっても驚かないでください。お客様のアプリはインターネットの速度に左右されます。ビデオは取得してからダウンロードし、お使いのアプリにストリーミングする必要があるためです。 準備ができたら、シーンを変えて、赤い球体を見ながら 2 つ目のビデオを開いてみましょう。 そして、2 つ目のシーンでは青いキューブを使用して、自由に戻ることができます。

Azure Media Service アプリケーションが完成しました

おめでとうございます。これで、Azure Media Service を利用して 360 度ビデオをストリーミングする Mixed Reality アプリケーションを構築しました。

Mixed Reality アプリの例のスクリーンショット。

Mixed Reality アプリの例のスクリーンショット。

ボーナスの演習

演習 1

このチュートリアルの中で、1 つのシーンだけを使ってビデオを変えることは十分可能です。 お客様のアプリケーションで、1 つのシーンにしてみてください。 また、別のビデオをミックスに追加することもできます。

演習 2

Azure と Unity を使用して、インターネットの接続強度に応じて、ファイル サイズの異なるビデオを自動的に選択する機能をアプリに実装してみましょう。