HoloLens (第 1 世代) と Azure 308: クロスデバイス通知


Note

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


最終的な成果物 - 開始

このコースでは、Azure Notification Hubs、Azure テーブル、Azure Functions を使用して、Notification Hubs 機能を Mixed Reality アプリケーションに追加する方法について説明します。

Azure Notification Hubs は、開発者が、パーソナル設定されたターゲット プッシュ通知をあらゆるプラットフォームに送信できるようにする Microsoft のサービスであり、すべてクラウド内で実現できます。 これにより、開発者はシナリオに応じて、エンド ユーザーとの通信、および各種アプリケーション間の通信も効率的に行うことができます。 詳細については、 Azure Notification Hubs page を参照してください。

Azure Functions は、開発者が小さなコードである "関数" を Azure で実行できるようにする Microsoft のサービスです。 これにより、ローカル アプリケーションではなく、クラウドに作業を委任することができ、多くの利点を得られます。 Azure Functions は、C#、F#、Node.js、Java、PHP など、いくつかの開発言語をサポートしています。 詳細については、 Azure Functions page を参照してください。

Azure テーブルは、開発者が構造化された非 SQL データをクラウドに格納し、どこからでも簡単にアクセスできるようにする Microsoft のクラウド サービスです。 このサービスには優れたスキーマレス設計が提供されており、必要に応じてテーブルを進化させることができるため、高い柔軟性が得られます。 詳細については、「 Azure Tables page」を参照してください。

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

  1. デスクトップ PC アプリを使用すると、ユーザーはマウスを使用して、2D 空間 (X および Y) 内でオブジェクトを動かせます。

  2. PC アプリ内のオブジェクトの動きは、JSON を使用してクラウドに送信されます。これは、オブジェクトの ID、型、変換情報 (X および Y 座標) を含む文字列の形式になります。

  3. デスクトップ アプリと同一のシーンを持つ Mixed Reality アプリは、Notification Hubs サービス (デスクトップ PC アプリによって更新されたばかりの) から、オブジェクトの動きに関する通知を受け取ります。

  4. オブジェクトの ID、型、変換情報が含まれる通知を受け取ると、Mixed Reality アプリは、受信した情報を独自のシーンに適用します。

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

デバイス サポート

コース HoloLens イマーシブ ヘッドセット
MR と Azure 308: クロスデバイス通知 ✔️ ✔️

Note

このコースは主に Windows Mixed Reality イマーシブ(VR)ヘッドセットに焦点を当てていますが、このコースで学んだことを Microsoft HoloLens にも応用できます。 このコースに取り組む過程で、HoloLens をサポートするために採用する必要のある変更に関するノートが表示されます。 HoloLens を使用すると、音声キャプチャ中に反響音が生じることがあります。

前提条件

Note

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

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

開始する前に

  • このプロジェクトをビルドする際の問題を避けるために、このチュートリアルで紹介するプロジェクトをルートまたはルートに近いフォルダーに作成することを強くお勧めします (フォルダー パスが長いと、ビルド時に問題が発生する可能性があります)。
  • Microsoft デベロッパー ポータルとアプリケーション登録ポータルの所有者である必要があります。そうでない場合、第 2 章でアプリにアクセスするためのアクセス許可が付与さません。

章 1 章 - Microsoft デベロッパー ポータルでアプリケーションを作成する

Azure Notification Hubs サービスを使用するには、アプリケーションで通知を送受信できるようにアプリケーションを登録する必要があるため、Microsoft デベロッパー ポータルでアプリケーションを作成する必要があります。

  1. Microsoft デベロッパー ポータルにログインします。

    Microsoft アカウントにログインする必要があります。

  2. ダッシュボードで、[新しいアプリの作成] をクリックします。

    アプリの作成

  3. ポップアップが表示されます。ここで、新しいアプリの名前を予約する必要があります。 テキスト ボックスに適切な名前を入力します。選択した名前が使用可能な場合は、テキスト ボックスの右側にチェック マークが表示されます。 使用可能な名前が挿入されたら、ポップアップの左下にある [製品名の予約] ボタンをクリックします。

    名前の予約

  4. これでアプリが作成されたので、次の章に進むことができます。

章 2 章 - 新しいアプリの資格情報を取得する

アプリケーション登録ポータルにログインすると、新しいアプリが一覧表示されます。ここで、Azure portal 内で Notification Hubs サービスをセットアップするために使用する資格情報を取得します。

  1. アプリケーション登録ポータルに移動します。

    アプリケーション登録ポータル

    警告

    ログインするには、Microsoft アカウントを使用する必要があります。
    これは、前のの Windows ストア デベロッパー ポータルで使用した Microsoft アカウントである必要があります

  2. アプリは [マイ アプリケーション] セクションに表示されます。 見つかったアプリをクリックすると、アプリ名と [登録] が表示された新しいページに移動します。

    新しく登録したアプリ

  3. 登録ページを下にスクロールして、[アプリケーション シークレット] セクションとアプリの [パッケージ SID] を見つけます。 次の章の Azure Notification Hubs サービスの設定で使用するために両方をコピーします。

    アプリケーション シークレット

章 3 章 - Azure portal のセットアップ: Notification Hubs サービスを作成する

アプリの資格情報を取得したら、Azure portal に移動する必要があります。ここでは、Azure Notification Hubs サービスを作成します。

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

    Note

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

  2. ログインしたら、左上隅にある[新規作成] をクリックして、[Notification Hub] を検索し、Enter キーを押します。

    Notification Hub の検索

    Note

    新しいポータルでは、[新規作成] という文字列が [リソースの作成] に置き換えられることがあります。

  3. 新しいページに、Notification Hubs サービスの説明が表示されます。 このプロンプトの左下にある [作成] ボタンを選択すると、このサービスとの関連付けが作成されます。

    Notification Hubs インスタンスの作成

  4. [作成] をクリックしたら、次のようにします。

    1. このサービス インスタンスに必要な名前を入力します。

    2. このアプリに関連付けることができる名前空間を指定します。

    3. [場所] を選択します。

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

      Azure リソース グループについては、リソース グループの管理方法のリンクから詳細をご覧ください。

    5. 適切な [サブスクリプション] を選択します。

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

    7. [作成] を選択します

      サービスの詳細を入力します

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

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

    notification

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

    通知ウィンドウで強調表示されている [リソースに移動] ボタンを示すスクリーンショット。

  8. ページの中央にある [概要] ページで、[Windows (WNS)] をクリックします。右側のパネルが変更され、以前に設定したアプリのパッケージ SIDセキュリティ キーを必要とする 2 つのテキスト フィールドが表示されるようになります。

    新しく作成されたハブ サービス

  9. 詳細を正しいフィールドにコピーしたら、[保存] をクリックします。Notification Hub が正常に更新されると通知を受け取ります。

    セキュリティ詳細のコピー

第 4 章 - Azure portal のセットアップ: テーブル サービスを作成する

Notification Hubs サービス インスタンスを作成したら、Azure portal に戻ります。ここでは、ストレージ リソースを作成して Azure テーブル サービスを作成します。

  1. まだサインインしていない場合は、Azure portal にログインします。

  2. ログインしたら、左上隅にある[新規作成] をクリックして、ストレージ アカウントを検索し、Enter キーをクリックします。

    Note

    新しいポータルでは、[新規作成] という文字列が [リソースの作成] に置き換えられることがあります。

  3. 一覧から [ストレージ アカウント - BLOB、ファイル、テーブル、キュー] を選択します。

    ストレージ アカウントの検索

  4. 新しいページに、ストレージ アカウント サービスの説明が表示されます。 このプロンプトの左下にある [作成] ボタンを選択すると、このサービスのインスタンスが作成されます。

    ストレージ インスタンスの作成

  5. [作成] をクリックすると、パネルが表示されます。

    1. このサービス インスタンスに必要な [名前] を入力します (すべて小文字である必要があります)。

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

    3. [アカウントの種類] ドロップダウン メニューで [ストレージ (汎用 v1)] を選択します。

    4. 適切な [場所] を選択します。

    5. [レプリケーション] ドロップダウン メニューで、[読み取りアクセス geo 冗長ストレージ (RA-GRS)] を選択します。

    6. [パフォーマンス][標準] をクリックします。

    7. [安全な転送が必須] セクションで [無効] を選択します。

    8. [サブスクリプション] ドロップダウン メニューから、適切なサブスクリプションを選択します。

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

      Azure リソース グループについては、リソース グループの管理方法のリンクから詳細をご覧ください。

    10. このオプションを選択する場合は、[仮想ネットワーク][無効] のままにします。

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

      ストレージの詳細の入力

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

  7. サービス インスタンスが作成されると、ポータルに通知が表示されます。 通知をクリックして、新しいサービス インスタンスを確認します。

    新しいストレージ通知

  8. 通知の[リソースに移動]ボタンをクリックして、新しいサービスインスタンスを探します。 新しいストレージ サービス インスタンスの概要ページが表示されます。

    [デプロイに成功しました] ウィンドウで強調表示されている [リソースに移動] ボタンを示すスクリーンショット。

  9. [概要] ページで、右側にある [テーブル] をクリックします。

    [テーブル] を選択する場所を示すスクリーンショット。

  10. 右側のパネルが変更されて、テーブル サービスの情報が表示されます。ここで、新しいテーブルを追加する必要があります。 これを行うには、左上隅にある + Table ボタンをクリックします。

    テーブルを開きます

  11. 新しいページが表示されます。ここには、テーブル名を入力する必要があります。 これは、後の章でアプリケーション内のデータを参照するために使用する名前です。 適切な名前を挿入し、[OK] をクリックします。

    新しいテーブルの作成

  12. 新しいテーブルが作成されると、テーブル サービスのページ (下部) にそれが表示されるようになります。

    新しいテーブルが作成されました

第 5 章 - Visual Studio で Azure テーブルを完成させる

Table サービスのストレージ アカウントがセットアップされたので、それにデータを追加します。これは、情報の格納と取得に使用されます。 テーブルの編集は Visual Studio を使用して行うことができます。

  1. Visual Studio を開きます。

  2. メニューから [表示]>[Cloud Explorer] をクリックします。

    Cloud Explorer を開く

  3. Cloud Explorer がドッキングされたアイテムとして開きます (読み込みに時間がかかる場合があります)。

    Note

    "ストレージ アカウント" の作成に使用したサブスクリプションが表示されない場合は、次のことを確認してください。

    • Azure portal で使用したものと同じアカウントにログインしている。

    • [アカウント管理] ページからサブスクリプションを選択しました (アカウントの設定からフィルターを適用する必要がある場合があります)。

      サブスクリプションの検索

  4. Azure クラウド サービスが表示されます。 アカウントを展開するには、ストレージ アカウントを見つけて、その左側の矢印をクリックします。

    ストレージ アカウントを開く

  5. 展開が完了すると、新しく作成されたストレージ アカウントが使用できるようになっているはずです。 そのストレージの左側にある矢印をクリックし、それが展開されたら、[テーブル] を見つけて、その横にある矢印をクリックし、前の章で作成したテーブルを表示します。 テーブル名をダブルクリックします。

    シーン オブジェクト テーブルを開きます

  6. テーブルが Visual Studio ウィンドウの中央に開きます。 + (プラス) の付いたテーブル アイコンをクリックします。

    新しいテーブルを追加する

  7. エンティティの追加を求めるウィンドウが表示されます。 合計 3 つのエンティティを作成し、それぞれに複数のプロパティを指定します。 PartitionKeyRowKey が既に指定されていることがわかります。これらは、データを検索するためにテーブルで使用されるためです。

    パーティションと行のキー

  8. PartitionKeyRowKey について値を次のように更新します (追加する行プロパティごとにこの操作を行ってください。ただし、RowKey は毎回インクリメントします)。

    正しい値の追加

  9. [プロパティの追加] をクリックして、データの行を追加します。 最初の空のテーブルを次のテーブルのようにします。

  10. 完了したら、OK をクリックします。

    完了したら [OK] をクリックします

    警告

    [X][Y][Z] の各エントリの [型][Double] に変更したことを確認します。

  11. テーブルにデータ行があることがわかります。 + (プラス) アイコンをもう一度クリックして、別のエンティティを追加します。

    最初の行

  12. 追加のプロパティを作成し、次に示すように新しいエンティティの値を設定します。

    キューブを追加します

  13. 別のエンティティを追加するには、最後の手順を繰り返します。 このエンティティの値を次に示すように設定します。

    円柱を追加します

  14. これで、テーブルは以下のようになります。

    テーブルの完成

  15. これでこの章が完了しました。 必ず保存してください。

第 6 章 - Azure Function App を作成する

Azure Function App を作成します。これは、デスクトップ アプリケーションによって呼び出され、テーブル サービスを更新し、Notification Hub を介して通知を送信します。

まず、必要なライブラリを Azure Function で読み込むことができるファイルを作成する必要があります。

  1. メモ帳を開きます (Windows キーを押して「notepad」と入力します)。

    メモ帳を開く

  2. メモ帳を開いた状態で、下の JSON 構造を挿入します。 その作業が完了したら、それをデスクトップに project.json として保存します。 名前付けが正しいことが重要です。.txt のファイル拡張子が付いていないことを確認してください。 このファイルでは、関数が使用するライブラリを定義します。NuGet を使用していた場合は、なじみのある内容です。

    {
    "frameworks": {
        "net46":{
        "dependencies": {
            "WindowsAzure.Storage": "7.0.0",
            "Microsoft.Azure.NotificationHubs" : "1.0.9",
            "Microsoft.Azure.WebJobs.Extensions.NotificationHubs" :"1.1.0"
        }
        }
    }
    }
    
  3. Azure Portal にログインします。

  4. ログインしたら、左上隅の [新規作成] をクリックして、Function App を検索して Enter キーを押します。

    関数アプリを検索します

    Note

    新しいポータルでは、[新規作成] という文字列が [リソースの作成] に置き換えられることがあります。

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

    関数アプリ インスタンス

  6. [作成] をクリックしたら、次のように入力します。

    1. [アプリ名] に、このサービス インスタンスに必要な名前を入力します。

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

    3. 適切な価格レベルを選択します。これが初めて作成する Function App サービスの場合は、無料レベルを使用できるはずです。

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

      Azure リソース グループについては、リソース グループの管理方法のリンクから詳細をご覧ください。

    5. [OS] では、目的のプラットフォームである [Windows] をクリックします。

    6. [ホスティング プラン] を選択します (このチュートリアルでは、従量課金プランを使用しています)。

    7. Location を選択します (前の手順で作成したストレージと同じ場所を選択します)

    8. [ストレージ] セクションで、前の手順で作成したストレージ サービスを選択する必要があります

    9. このアプリで Application Insights は必要ないため、[オフ] のままにしておいてもかまいません。

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

      新しいインスタンスの作成

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

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

    新しい通知

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

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

    [リソースに移動] ボタンが強調表示された [デプロイに成功しました] を示すスクリーンショット。

  11. [関数] の横にある + (プラス記号) アイコンをクリックして、新規作成します。

    新しい関数の追加

  12. 中央のパネル内に関数の作成ウィンドウが表示されます。 パネルの上半分にある情報を無視し、[Custom function] (カスタム関数) をクリックします。これは、下部 (下に示すように、青い領域内) の近くにあります。

    カスタム関数

  13. ウィンドウ内の新しいページには、さまざまな関数の種類が表示されます。 下にスクロールして紫色の種類を表示し、[HTTP PUT] 要素をクリックします。

    HTTP PUT リンク

    重要

    ページの下までスクロールする必要がある場合がありますが (Azure portal の更新が行われている場合、この図はまったく同じように見えない可能性があります)、HTTP PUT という要素を探しています。

  14. [HTTP PUT] ウィンドウが表示されます。ここで、関数を構成する必要があります (下の図を参照してください)。

    1. [言語] のドロップダウン メニューを使用して [C#] を選択します。

    2. [名前] に適切な名前を入力します。

    3. [認証レベル] ドロップダウン メニューで、[関数] を選択します。

    4. [テーブル名] セクションでは、以前にテーブル サービスの作成に使用したのと同じ名前を使用する必要があります (同じ大文字小文字を含む)。

    5. [ストレージ アカウント接続] セクションで、ドロップダウン メニューを使用して、そこからストレージ アカウントを選択します。 表示されていない場合は、セクション タイトルの隣にある [新規] のハイパーリンクをクリックして、ストレージ アカウントが表示される別のパネルを表示します。

      [新規] ハイパーリンクが選択されている [ストレージ アカウント接続] セクションを示すスクリーンショット。

  15. [作成] をクリックすると、設定が正常に更新されたことを示す通知を受け取ります。

    関数の作成

  16. [作成] をクリックすると、関数エディターにリダイレクトされます。

    関数コードの更新

  17. 関数エディターに次のコードを挿入します (関数内のコードを置き換えます)。

    #r "Microsoft.WindowsAzure.Storage"
    
    using System;
    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Table;
    using Microsoft.Azure.NotificationHubs;
    using Newtonsoft.Json;
    
    public static async Task Run(UnityGameObject gameObj, CloudTable table, IAsyncCollector<Notification> notification, TraceWriter log)
    {
        //RowKey of the table object to be changed
        string rowKey = gameObj.RowKey;
    
        //Retrieve the table object by its RowKey
        TableOperation operation = TableOperation.Retrieve<UnityGameObject>("UnityPartitionKey", rowKey); 
    
        TableResult result = table.Execute(operation);
    
        //Create a UnityGameObject so to set its parameters
        UnityGameObject existingGameObj = (UnityGameObject)result.Result; 
    
        existingGameObj.RowKey = rowKey;
        existingGameObj.X = gameObj.X;
        existingGameObj.Y = gameObj.Y;
        existingGameObj.Z = gameObj.Z;
    
        //Replace the table appropriate table Entity with the value of the UnityGameObject
        operation = TableOperation.Replace(existingGameObj); 
    
        table.Execute(operation);
    
        log.Verbose($"Updated object position");
    
        //Serialize the UnityGameObject
        string wnsNotificationPayload = JsonConvert.SerializeObject(existingGameObj);
    
        log.Info($"{wnsNotificationPayload}");
    
        var headers = new Dictionary<string, string>();
    
        headers["X-WNS-Type"] = @"wns/raw";
    
        //Send the raw notification to subscribed devices
        await notification.AddAsync(new WindowsNotification(wnsNotificationPayload, headers)); 
    
        log.Verbose($"Sent notification");
    }
    
    // This UnityGameObject represent a Table Entity
    public class UnityGameObject : TableEntity
    {
        public string Type { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }
        public string RowKey { get; set; }
    }
    

    Note

    関数は、含まれているライブラリを使用して、Unity シーン内で移動されたオブジェクトの名前と場所を受け取ります (UnityGameObjectと呼ばれる C# オブジェクトとして)。 このオブジェクトは、作成されたテーブル内のオブジェクト パラメーターを更新するために使用されます。 次に、この関数は、作成された Notification Hub サービスを呼び出します。これにより、すべての登録済みアプリケーションが通知されます。

  18. コードを配置したら、[保存] をクリックします。

  19. 次に、ページの右側にある < (矢印) アイコンをクリックします。

    アップロード パネルの表示

  20. パネルが右側からスライドします。 そのパネルで [アップロード] をクリックすると、ファイル ブラウザーが表示されます。

  21. 以前にメモ帳で作成した project.json ファイルに移動してクリックし、[開く] ボタンをクリックします。 このファイルは、関数が使用するライブラリを定義します。

    JSON のアップロード

  22. ファイルがアップロードされると、右側のパネルに表示されます。 これをクリックすると、関数エディター内で開かれます。 これは、次の図 (下の手順 23) とまったく同じになるはずです。

  23. 次に、左側のパネルの [関数] の下にある [統合] リンクをクリックします。

    関数の統合

  24. 次のページの右上隅にある [詳細エディター] (次の手順を参照) をクリックします。

    詳細エディターの起動

  25. function.json ファイルが中央のパネルで開きます。これは、次のコード スニペットで置き換える必要があります。 これにより、ビルドする関数と、関数に渡されるパラメーターが定義されます。

    {
    "bindings": [
        {
        "authLevel": "function",
        "type": "httpTrigger",
        "methods": [
            "get",
            "post"
        ],
        "name": "gameObj",
        "direction": "in"
        },
        {
        "type": "table",
        "name": "table",
        "tableName": "SceneObjectsTable",
        "connection": "mrnothubstorage_STORAGE",
        "direction": "in"
        },
        {
        "type": "notificationHub",
        "direction": "out",
        "name": "notification",
        "hubName": "MR_NotHub_ServiceInstance",
        "connection": "MRNotHubNS_DefaultFullSharedAccessSignature_NH",
        "platform": "wns"
        }
    ]
    }
    
  26. エディターは次の図のようになります。

    標準エディターに戻る

  27. 挿入した入力パラメーターがテーブルとストレージの詳細と一致しないため、情報を更新する必要があることがわかります。 次の手順で対処するため、ここではこの操作を行わないでください。 ここでは、ページの右上隅にある標準のエディターのリンクをクリックするだけにして、戻ります。

  28. 標準エディターに戻り、[入力] の下にある [Azure Table Storage (テーブル)] をクリックします。

    テーブルの入力

  29. 次の内容が自分の情報と一致しない場合があるため、一致していることを確認します (次の手順の下に画像があります)。

    1. テーブル名: Azure Storage、Tables サービス内で作成したテーブルの名前。

    2. ストレージ アカウント接続:ドロップダウン メニューと共に表示される [新規] をクリックすると、ウィンドウの右側にパネルが表示されます。

      ウィンドウの右側にあるパネルで [新規作成] が強調表示されている [ストレージ アカウント] ウィンドウを示すスクリーンショット。

      1. 関数アプリをホストするために以前に作成したストレージ アカウントを選択します。

      2. ストレージ アカウントの接続値が作成されていることがわかります。

      3. 完了したら、必ず [保存] を押します。

    3. [入力] ページが次のようになり、自分の情報が表示されます。

      入力の完了

  30. 次に、[出力] の下の [Azure Notification Hub (通知)] をクリックします。 次の内容が自分の情報と一致しない場合があるため、一致していることを確認します (次の手順の下に画像があります)。

    1. Notification Hub 名: これは、前に作成した Notification Hub サービス インスタンスの名前です。

    2. Notification Hubs の名前空間接続: ドロップダウン メニューの横に表示される [新規] をクリックします。

      結果の確認

    3. [接続] ポップアップが表示されます (下図を参照)。ここでは、以前に設定した Notification Hub名前空間を選択する必要があります。

    4. 中央のドロップダウン メニューから Notification Hub 名を選択します。

    5. [ポリシー] ドロップダウン メニューを DefaultFullSharedAccessSignature に設定します。

    6. [選択] ボタンをクリックして戻ります。

      出力の更新

  31. これで [出力] ページは以下のようになりますが、自分の情報が代わりに使用されています。 必ず [保存] を押します。

警告

Notification Hub 名を直接編集しないでください (これは、前の手順に正しく従っていれば、詳細エディターを使用して行う必要があります)。

[出力] ページと一般的な情報を示すスクリーンショット。

  1. この時点で、関数が動作していることを確認するために、その関数をテストする必要があります。 手順は次のとおりです。

    1. 関数のページにもう一度移動します。

      新しく作成された関数が強調表示されている関数ページを示すスクリーンショット。

    2. 関数のページに戻り、ページの右端にある [テスト] タブをクリックして、[テスト] ブレードを開きます。

      右側に [テスト] が強調表示されている関数ページのスクリーンショット。

    3. ブレードの [要求本文] テキストボックスに、次のコードを貼り付けます。

      {  
          "Type":null,
          "X":3,
          "Y":0,
          "Z":1,
          "PartitionKey":null,
          "RowKey":"Obj2",
          "Timestamp":"0001-01-01T00:00:00+00:00",
          "ETag":null
      }
      
    4. テスト コードを配置した状態で、右下にある [実行] ボタンをクリックすると、テストが実行されます。 テストの出力ログは、関数コードの下のコンソール領域に表示されます。

      コンソール領域のテストの出力ログを示すスクリーンショット。

    警告

    上記のテストが失敗した場合は、上記の手順に厳密に従っていること、特に統合パネル内の設定を再確認する必要があります。

第 7 章 - デスクトップ Unity プロジェクトを設定する

重要

現在作成中のデスクトップ アプリケーションは、Unity エディターでは動作しません。 アプリケーションのビルド後に、Visual Studio (またはデプロイされたアプリケーション) を使用して、エディターの外部で実行する必要があります。

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

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

Note

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

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

    右上に [新規] プロジェクト アイコンが強調表示されている Unity プロジェクト ウィンドウのスクリーンショット。

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

    プロジェクトの作成

  3. Unity を開いた状態で、既定のスクリプト エディターVisual Studio に設定されているかどうか確認することをお勧めします。 お気に入り編集>に移り、新しいウィンドウから外部ツールにナビゲートします。 [外部スクリプト エディター][Visual Studio 2017] に変更します。 [環境設定] ウィンドウを閉じます。

    外部 VS ツールの設定

  4. 次に、[File] (ファイル)>[Build Settings] (ビルド設定) に移動して、[Universal Windows Platform] (ユニバーサル Windows プラットフォーム) を選択します。次に、[Switch Platform] (プラットフォームの切り替え) ボタンをクリックして選択を適用します。

    プラットフォームの切り替え

  5. [File]\(ファイル\)>[Build Settings]\(ビルド設定\) で、次のことを確認します。

    1. [Target Device] (ターゲット デバイス)[Any Device] (任意のデバイス) に設定されている

      このアプリケーションはデスクトップ用であるため、[Any Device] (任意のデバイス) にする必要があります

    2. [Build Type] (ビルドの種類)[D3D] に設定されている

    3. [SDK][最新のインストール] に設定されている。

    4. [Visual Studio Version] (Visual Studio のバージョン)[Latest installed] (最新のインストール) に設定されている

    5. [Build and Run] (ビルドと実行)[Local Machine] (ローカル マシン) に設定されている

    6. ここで、シーンを保存し、ビルドに追加することをお勧めします。

      1. これを行うには、[Add Open Scenes] (開いているシーンを追加) を選択します。 保存ウィンドウが表示されます。

        右上の [開いているシーンの追加] が強調表示されているスクリーンショット。

      2. これと、今後のシーン用の新しいフォルダーを作成し、[新しいフォルダー] ボタンを選択して、新しいフォルダーを作成し、「Scenes」という名前を付けます。

        左上の [新しいフォルダー] が強調表示された状態で作成された新しい Scenes フォルダーを示すスクリーンショット。

      3. 新しく作成した Scenes フォルダーを開き、[File name:]\(ファイル名\) テキスト フィールドに「NH_Desktop_Scene」と入力して [Save]\(保存\) をクリックします。

        新しい NH_Desktop_Scene

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

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

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

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

      1. [Scripting Runtime Version] (スクリプト ランタイムのバージョン)[Experimental (.NET 4.6 Equivalent)] (試験段階 (.NET 4.6 と同等)) になっている

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

      3. [API Compatibility Level]\(API 互換性レベル\)[.NET 4.6] である。

        4.6 NET バージョン

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

      • InternetClient

        [機能] で選択されている InternetClient を示すスクリーンショット。

  8. Build 設定 Unity C# プロジェクトはグレー表示されなくなりました。この横にあるチェックボックスをオンにします。

  9. [ビルド設定] ウィンドウを閉じます。

  10. シーンとプロジェクトを保存します ([File] (ファイル)>[Save Scene / File] (シーン/ファイルの保存)>[Save Project] (プロジェクトの保存))。

    重要

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

章 8 章 - Unity で DLL をインポートする

Azure Storage for Unity を使用します (これ自体が .Net SDK for Azure を利用します)。 詳細については、Azure Storage for Unity に関するこのリンクを参照してください。

現在、Unity には、インポート後にプラグインを再構成する必要がある既知の問題があります。 バグが解決された後は、これらの手順 (このセクションの 4 - 7) は不要になります。

SDK を独自のプロジェクトにインポートするには、GitHub から最新の .unitypackage がダウンロードされていることを確認してください。 次に、以下を実行します。

  1. [Assets] (資産) > [Import Package] (パッケージのインポート) > [Custom Package] (カスタム パッケージ) メニュー オプションを使用して、.unitypackage を Unity に追加します。

  2. ポップアップ表示される [Import Unity Package] (Unity パッケージのインポート) ボックスで、[Plugin] (プラグイン)>[Storage] (ストレージ) の下にあるすべてを選択できます。 このコースでは不要なため、その他のすべてをオフにします。

    パッケージへのインポート

  3. [Import]\(インポート\) ボタンをクリックして、各項目をプロジェクトに追加します。

  4. [Project] (プロジェクト) ビューの [Plugins] (プラグイン) の下の Storage フォルダーに移動して、以下のプラグイン "のみ"を選択します。

    • Microsoft.Data.Edm
    • Microsoft.Data.OData
    • Microsoft.WindowsAzure.Storage
    • Newtonsoft.Json
    • System.Spatial

任意のプラットフォームのチェックを解除します

  1. これらのプラグイン選択した状態でuncheck Any Platformuncheck WSAPlayer Apply をクリックします。

    プラットフォーム DLL の適用

    Note

    Unity エディターで使用するためにのみこれらの特定のプラグインをマークしています。 これは、プロジェクトが Unity からエクスポートされた後に使用される、同じプラグインの異なるバージョンが WSA フォルダー内にあるためです。

  2. Storage プラグイン フォルダーで、以下のみを選択します。

    • Microsoft.Data.Services.Client

      [Don't process]\(処理しない\) を DLL に設定します

  3. [Platform Settings] (プラットフォームの設定) の下の [Don't Process] (処理しない) ボックスをオンにして、[Apply] (適用) をクリックします。

    処理なしを適用します

    Note

    Unity アセンブリ パッチャはこのプラグインを処理するのが困難であるため、このプラグインを [Don't Process] (処理しない) としてマークしています。 処理されていなくてもこのプラグインは動作します。

第 9 章 - デスクトップ Unity プロジェクトで TableToScene クラスを作成する

ここで、このアプリケーションを実行するコードを含むスクリプトを作成する必要があります。

作成する必要のある最初のスクリプトは TableToScene です。これは次の役割を担います。

  • Azure テーブル内のエンティティを読み取ります。
  • テーブル データを使用して、生成するオブジェクトとその位置を決定します。

作成する必要がある 2 番目のスクリプトは CloudScene です。これは次の役割を担います。

  • 左クリック イベントを登録して、ユーザーがシーン内でオブジェクトをドラッグできるようにします。
  • この Unity シーンからオブジェクト データをシリアル化し、それを Azure Function App に送信します。

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

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

    Scripts フォルダーの作成

    Scripts フォルダーの作成 2

  2. 先ほど作成したフォルダーをダブルクリックして開きます。

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

    新しい 'TableToScene' スクリプトを作成する方法を示すスクリーンショット。TableToScene の名前変更

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

  5. 次の名前空間を追加します。

    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Auth;
    using Microsoft.WindowsAzure.Storage.Table;
    using UnityEngine;
    
  6. クラス内に次の変数を挿入します。

        /// <summary>    
        /// allows this class to behave like a singleton
        /// </summary>    
        public static TableToScene instance;
    
        /// <summary>    
        /// Insert here you Azure Storage name     
        /// </summary>    
        private string accountName = " -- Insert your Azure Storage name -- ";
    
        /// <summary>    
        /// Insert here you Azure Storage key    
        /// </summary>    
        private string accountKey = " -- Insert your Azure Storage key -- ";
    

    Note

    Azure portal で、accountName 値を Azure Storage サービス名に置き換え、accountKey 値を Azure Storage サービスのキー値に置き換えます (次の図を参照)。

    アカウント キーの取得

  7. ここで、クラスを初期化するための Start () および Awake() の各メソッドを追加します。

        /// <summary>
        /// Triggers before initialization
        /// </summary>
        void Awake()
        {
            // static instance of this class
            instance = this;
        }
    
        /// <summary>
        /// Use this for initialization
        /// </summary>
        void Start()
        {  
            // Call method to populate the scene with new objects as 
            // pecified in the Azure Table
            PopulateSceneFromTableAsync();
        }
    
  8. TableToScene クラス内で、Azure テーブルから値を取得し、それを使用してシーン内の適切なプリミティブを生成するメソッドを追加します。

        /// <summary>    
        /// Populate the scene with new objects as specified in the Azure Table    
        /// </summary>    
        private async void PopulateSceneFromTableAsync()
        {
            // Obtain credentials for the Azure Storage
            StorageCredentials creds = new StorageCredentials(accountName, accountKey);
    
            // Storage account
            CloudStorageAccount account = new CloudStorageAccount(creds, useHttps: true);
    
            // Storage client
            CloudTableClient client = account.CreateCloudTableClient(); 
    
            // Table reference
            CloudTable table = client.GetTableReference("SceneObjectsTable");
    
            TableContinuationToken token = null;
    
            // Query the table for every existing Entity
            do
            {
                // Queries the whole table by breaking it into segments
                // (would happen only if the table had huge number of Entities)
                TableQuerySegment<AzureTableEntity> queryResult = await table.ExecuteQuerySegmentedAsync(new TableQuery<AzureTableEntity>(), token); 
    
                foreach (AzureTableEntity entity in queryResult.Results)
                {
                    GameObject newSceneGameObject = null;
                    Color newColor;
    
                    // check for the Entity Type and spawn in the scene the appropriate Primitive
                    switch (entity.Type)
                    {
                        case "Cube":
                            // Create a Cube in the scene
                            newSceneGameObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
                            newColor = Color.blue;
                            break;
    
                        case "Sphere":
                            // Create a Sphere in the scene
                            newSceneGameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                            newColor = Color.red;
                            break;
    
                        case "Cylinder":
                            // Create a Cylinder in the scene
                            newSceneGameObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
                            newColor = Color.yellow;
                            break;
                        default:
                            newColor = Color.white;
                            break;
                    }
    
                    newSceneGameObject.name = entity.RowKey;
    
                    newSceneGameObject.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Diffuse"))
                    {
                        color = newColor
                    };
    
                    //check for the Entity X,Y,Z and move the Primitive at those coordinates
                    newSceneGameObject.transform.position = new Vector3((float)entity.X, (float)entity.Y, (float)entity.Z);
                }
    
                // if the token is null, it means there are no more segments left to query
                token = queryResult.ContinuationToken;
            }
    
            while (token != null);
        }
    
  9. TableToScene クラスの外部では、テーブル エンティティをシリアル化および逆シリアル化するためにアプリケーションによって使用されるクラスを定義する必要があります。

        /// <summary>
        /// This objects is used to serialize and deserialize the Azure Table Entity
        /// </summary>
        [System.Serializable]
        public class AzureTableEntity : TableEntity
        {
            public AzureTableEntity(string partitionKey, string rowKey)
                : base(partitionKey, rowKey) { }
    
            public AzureTableEntity() { }
            public string Type { get; set; }
            public double X { get; set; }
            public double Y { get; set; }
            public double Z { get; set; }
        }
    
  10. Unity エディターに戻る前に、必ず保存してください。

  11. [Hierarchy] (階層) パネルから [Main Camera] (メイン カメラ) をクリックして、そのプロパティが [Inspector] (インスペクター) に表示されるようにします。

  12. Scripts フォルダーを開いた状態で、スクリプト TableToScene ファイルを選択し、Main Camera にドラッグします。 結果は次のようになります。

    Main Camera にスクリプトを追加します

第 10 章 - デスクトップ Unity プロジェクトで CloudScene クラスを作成する

作成する必要がある 2 番目のスクリプトは CloudScene です。これは次の役割を担います。

  • 左クリック イベントを登録して、ユーザーがシーン内でオブジェクトをドラッグできるようにします。

  • この Unity シーンからオブジェクト データをシリアル化し、それを Azure Function App に送信します。

2 番目のスクリプトを作成するには、次のようにします。

  1. Scripts フォルダー内で右クリックし、[Create] (作成)[C# Script] (C# スクリプト) をクリックします。 スクリプトの名前を CloudScene にします。

    新しい 'CloudScene' スクリプトを作成する方法を示すスクリーンショット。CloudScene の名前を変更する

  2. 次の名前空間を追加します。

    using Newtonsoft.Json;
    using System.Collections;
    using System.Text;
    using System.Threading.Tasks;
    using UnityEngine;
    using UnityEngine.Networking;
    
  3. 次の変数を挿入します。

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static CloudScene instance;
    
        /// <summary>
        /// Insert here you Azure Function Url
        /// </summary>
        private string azureFunctionEndpoint = "--Insert here you Azure Function Endpoint--";
    
        /// <summary>
        /// Flag for object being moved
        /// </summary>
        private bool gameObjHasMoved;
    
        /// <summary>
        /// Transform of the object being dragged by the mouse
        /// </summary>
        private Transform gameObjHeld;
    
        /// <summary>
        /// Class hosted in the TableToScene script
        /// </summary>
        private AzureTableEntity azureTableEntity;
    
  4. 次の図に示すように、Azure portal で、azureFunctionEndpoint の値を Azure 関数アプリ サービスにある Azure 関数アプリの URL に置き換えます。

    関数の URL の取得

  5. ここで、クラスを初期化するための Start () および Awake() の各メソッドを追加します。

        /// <summary>
        /// Triggers before initialization
        /// </summary>
        void Awake()
        {
            // static instance of this class
            instance = this;
        }
    
        /// <summary>
        /// Use this for initialization
        /// </summary>
        void Start()
        {
            // initialise an AzureTableEntity
            azureTableEntity = new AzureTableEntity();
        }
    
  6. Update() メソッド内に、マウス入力とドラッグを検出する以下のコードを追加します。これにより、シーン内の GameObjects が移動されます。 ユーザーがオブジェクトをドラッグ アンド ドロップした場合、オブジェクトの名前と座標がメソッド UpdateCloudScene() に渡されて、Azure Function App サービスが呼び出されます。これにより、Azure テーブルが更新され、通知がトリガーされます。

        /// <summary>
        /// Update is called once per frame
        /// </summary>
        void Update()
        {
            //Enable Drag if button is held down
            if (Input.GetMouseButton(0))
            {
                // Get the mouse position
                Vector3 mousePosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10);
    
                Vector3 objPos = Camera.main.ScreenToWorldPoint(mousePosition);
    
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    
                RaycastHit hit;
    
                // Raycast from the current mouse position to the object overlapped by the mouse
                if (Physics.Raycast(ray, out hit))
                {
                    // update the position of the object "hit" by the mouse
                    hit.transform.position = objPos;
    
                    gameObjHasMoved = true;
    
                    gameObjHeld = hit.transform;
                }
            }
    
            // check if the left button mouse is released while holding an object
            if (Input.GetMouseButtonUp(0) && gameObjHasMoved)
            {
                gameObjHasMoved = false;
    
                // Call the Azure Function that will update the appropriate Entity in the Azure Table
                // and send a Notification to all subscribed Apps
                Debug.Log("Calling Azure Function");
    
                StartCoroutine(UpdateCloudScene(gameObjHeld.name, gameObjHeld.position.x, gameObjHeld.position.y, gameObjHeld.position.z));
            }
        }
    
  7. 次に、以下のように UpdateCloudScene() メソッドを追加します。

        private IEnumerator UpdateCloudScene(string objName, double xPos, double yPos, double zPos)
        {
            WWWForm form = new WWWForm();
    
            // set the properties of the AzureTableEntity
            azureTableEntity.RowKey = objName;
    
            azureTableEntity.X = xPos;
    
            azureTableEntity.Y = yPos;
    
            azureTableEntity.Z = zPos;
    
            // Serialize the AzureTableEntity object to be sent to Azure
            string jsonObject = JsonConvert.SerializeObject(azureTableEntity);
    
            using (UnityWebRequest www = UnityWebRequest.Post(azureFunctionEndpoint, jsonObject))
            {
                byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(jsonObject);
    
                www.uploadHandler = new UploadHandlerRaw(jsonToSend);
    
                www.uploadHandler.contentType = "application/json";
    
                www.downloadHandler = new DownloadHandlerBuffer();
    
                www.SetRequestHeader("Content-Type", "application/json");
    
                yield return www.SendWebRequest();
    
                string response = www.responseCode.ToString();
            }
        }
    
  8. コードを保存して Unity に戻ります。

  9. CloudScene スクリプトを Main Camera にドラッグします。

    1. [Hierarchy] (階層) パネルから [Main Camera] (メイン カメラ) をクリックして、そのプロパティが [Inspector] (インスペクター) に表示されるようにします。

    2. Scripts フォルダーを開いた状態で、CloudScene スクリプトを選択し、Main Camera にドラッグします。 結果は次のようになります。

      クラウド スクリプトを Main Camera にドラッグします

第 11 章 - デスクトップ プロジェクトを UWP にビルドする

このプロジェクトの Unity セクションに必要なすべての手順が完了しました。

  1. [Build Settings] (ビルド設定) に移動します ([File] (ファイル)>[Build Settings] (ビルド設定))。

  2. [ビルド設定] ウィンドウで、[ビルド] をクリックします。

    ユニバーサル Windows プラットフォームが選択され、右下の [ビルド] ボタンが強調表示されている [ビルド設定] ウィンドウを示すスクリーンショット。

  3. [エクスプローラー] ウィンドウがポップアップ表示され、ビルドの場所を入力するように求められます。 新しいフォルダーを作成し (左上隅の [New Folder]\(新規フォルダー\) をクリックします)、それに BUILDS という名前を付けます。

    ビルド用の新しいフォルダー

    1. 新しい BUILDS フォルダーを開き、フォルダーをもう 1 つ作成し ([新しいフォルダー] をもう一度使用します)、NH_Desktop_App という名前を付けます。

      フォルダー名 NH_Desktop_App

    2. NH_Desktop_App を選択します。 [フォルダーの選択] をクリックします。 プロジェクトがビルドされるまで 1 分ほどかかります。

  4. ビルドの後、[エクスプローラー] に、新しいプロジェクトの場所が表示されます。 ただし、これを開く必要はありません。次のいくつかの章で、最初に他の Unity プロジェクトを作成する必要があるためです。

第 12 章 - Mixed Reality Unity プロジェクトを設定する

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

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

    右上に [新規] が強調表示されている Unity プロジェクト ウィンドウを示すスクリーンショット。

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

    名前 UnityMRNotifHub

  3. Unity を開いた状態で、既定のスクリプト エディターVisual Studio に設定されているかどうか確認することをお勧めします。 お気に入り編集>に移り、新しいウィンドウから外部ツールにナビゲートします。 [外部スクリプト エディター][Visual Studio 2017] に変更します。 [環境設定] ウィンドウを閉じます。

    外部エディターを VS に設定します

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

    UWP へのプラットフォームの切り替え

  5. [File] (ファイル)>[Build Settings] (ビルド設定) に移動して、次を確認します。

    1. [Target Device] (ターゲット デバイス)[Any Device] (任意のデバイス) に設定されている

      Microsoft HoloLens の場合は、[ターゲット デバイス] を [HoloLens] に設定します。

    2. [Build Type] (ビルドの種類)[D3D] に設定されている

    3. [SDK][最新のインストール] に設定されている。

    4. [Visual Studio Version] (Visual Studio のバージョン)[Latest installed] (最新のインストール) に設定されている

    5. [Build and Run] (ビルドと実行)[Local Machine] (ローカル マシン) に設定されている

    6. ここで、シーンを保存し、ビルドに追加することをお勧めします。

      1. これを行うには、[Add Open Scenes] (開いているシーンを追加) を選択します。 保存ウィンドウが表示されます。

        右上に [開いているシーンの追加] ボタンが強調表示されている [ビルド設定] ウィンドウを示すスクリーンショット。

      2. これと、今後のシーン用の新しいフォルダーを作成し、[新しいフォルダー] ボタンを選択して、新しいフォルダーを作成し、「Scenes」という名前を付けます。

        [シーンの保存] ウィンドウの左上で [新しいフォルダー] が強調表示されているスクリーンショット。

      3. 新しく作成した Scenes フォルダーを開き、[ファイル名] テキスト フィールドに「NH_MR_Scene」と入力して [保存] をクリックします。

        新しいシーン - NH_MR_Scene

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

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

    プレーヤー設定を開きます

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

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

      1. [Scripting Runtime Version] (スクリプト ランタイムのバージョン)[Experimental (.NET 4.6 Equivalent)] (試験段階 (.NET 4.6 と同等)) になっている

      2. [Scripting Backend] (スクリプト バックエンド)[.NET] である

      3. [API Compatibility Level]\(API 互換性レベル\)[.NET 4.6] である。

        API 互換性

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

      XR 設定の更新

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

      • InternetClient

        InternetClient がオンになっている [発行設定] タブを示すスクリーンショット。

  8. [ビルド設定] に戻ると、"Unity C# プロジェクト" に適用されていた灰色表示が解除されています。その横にあるチェック ボックスをオンにします。

  9. これらの変更を加えた後、[Build Settings] (ビルド設定) ウィンドウを閉じます。

  10. シーンとプロジェクトを保存します ([File] (ファイル)>[Save Scene / File] (シーン/ファイルの保存)>[Save Project] (プロジェクトの保存))。

    重要

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

第 13 章 - Mixed Reality Unity プロジェクトで DLL をインポートする

Azure Storage for Unity ライブラリ (.Net SDK for Azure を利用) を使用します。 Unity で Azure Storage を使用する方法についてはこちらのリンクを参照してください。 現在、Unity には、インポート後にプラグインを再構成する必要がある既知の問題があります。 バグが解決された後は、これらの手順 (このセクションの 4 - 7) は不要になります。

SDK を独自のプロジェクトにインポートするには、最新の .unitypackage がダウンロードされていることを確認してください。 次に、以下を実行します。

  1. 前述の場所からダウンロードした .unitypackage を Unity に追加するには、[Assets] (資産)>[Import Package] (パッケージのインポート)>[Custom Package] (カスタム パッケージ) メニュー オプションを使用します。

  2. ポップアップ表示される [Import Unity Package] (Unity パッケージのインポート) ボックスで、[Plugin] (プラグイン)>[Storage] (ストレージ) の下にあるすべてを選択できます。

    パッケージのインポート

  3. [Import]\(インポート\) ボタンをクリックして、各項目をプロジェクトに追加します。

  4. [Project] (プロジェクト) ビューの [Plugins] (プラグイン) の下の Storage フォルダーに移動して、以下のプラグイン "のみ"を選択します。

    • Microsoft.Data.Edm
    • Microsoft.Data.OData
    • Microsoft.WindowsAzure.Storage
    • Newtonsoft.Json
    • System.Spatial

    プラグインの選択

  5. これらのプラグイン選択した状態でuncheck Any Platformuncheck WSAPlayer Apply をクリックします。

    プラットフォームの変更の適用

    Note

    Unity エディターで使用するためにのみこれらの特定のプラグインをマークしています。 これは、プロジェクトが Unity からエクスポートされた後に使用される、同じプラグインの異なるバージョンが WSA フォルダー内にあるためです。

  6. Storage プラグイン フォルダーで、以下のみを選択します。

    • Microsoft.Data.Services.Client

      データ サービス クライアントの選択

  7. [Platform Settings] (プラットフォームの設定) の下の [Don't Process] (処理しない) ボックスをオンにして、[Apply] (適用) をクリックします。

    [Don't Process]\(処理しない\)

    Note

    Unity アセンブリ パッチャはこのプラグインを処理するのが困難であるため、このプラグインを [Don't Process] (処理しない) としてマークしています。 処理されていなくてもこのプラグインは動作します。

第 14 章 - Mixed Reality Unity プロジェクトで TableToScene クラスを作成する

TableToScene クラスは、第 9 章で説明したものと同じです。 第 9 章で説明されている手順に従って、Mixed Reality Unity プロジェクトで同じクラスを作成します。

この章を完了すると、両方の Unity プロジェクトの Main Camera にこのクラスが設定されます。

第 15 章 - Mixed Reality Unity プロジェクトで NotificationReceiver クラスを作成する

作成する必要がある 2 番目のスクリプトは NotificationReceiver です。これは次の役割を担います。

  • 初期化時にアプリを Notification Hub に登録します。
  • Notification Hub からの通知をリッスンします。
  • 受信した通知からオブジェクト データを逆シリアル化します。
  • 逆シリアル化されたデータに基づいて、シーン内の GameObjects を移動します。

NotificationReceiver スクリプトを作成するには、次のようにします。

  1. Scripts フォルダー内で右クリックし、[Create] (作成)[C# Script] (C# スクリプト) をクリックします。 スクリプトに NotificationReceiver という名前を付けます。

    新しい c# スクリプトを作成するNotificationReceiver という名前を付ける

  2. スクリプトをダブルクリックして開きます。

  3. 次の名前空間を追加します。

    //using Microsoft.WindowsAzure.Messaging;
    using Newtonsoft.Json;
    using System;
    using System.Collections;
    using UnityEngine;
    
    #if UNITY_WSA_10_0 && !UNITY_EDITOR
    using Windows.Networking.PushNotifications;
    #endif
    
  4. 次の変数を挿入します。

        /// <summary>
        /// allows this class to behave like a singleton
        /// </summary>
        public static NotificationReceiver instance;
    
        /// <summary>
        /// Value set by the notification, new object position
        /// </summary>
        Vector3 newObjPosition;
    
        /// <summary>
        /// Value set by the notification, object name
        /// </summary>
        string gameObjectName;
    
        /// <summary>
        /// Value set by the notification, new object position
        /// </summary>
        bool notifReceived;
    
        /// <summary>
        /// Insert here your Notification Hub Service name 
        /// </summary>
        private string hubName = " -- Insert the name of your service -- ";
    
        /// <summary>
        /// Insert here your Notification Hub Service "Listen endpoint"
        /// </summary>
        private string hubListenEndpoint = "-Insert your Notification Hub Service Listen endpoint-";
    
  5. hubName 値を Notification Hub のサービス名に置き換え、hubListenEndpoint の値を、Azure portal の Azure Notification Hub サービスの [アクセス ポリシー] タブにあるエンドポイントの値に置き換えます (下の図を参照)。

    Notification Hubs ポリシー エンドポイントの挿入

  6. ここで、クラスを初期化するための Start () および Awake() の各メソッドを追加します。

        /// <summary>
        /// Triggers before initialization
        /// </summary>
        void Awake()
        {
            // static instance of this class
            instance = this;
        }
    
        /// <summary>
        /// Use this for initialization
        /// </summary>
        void Start()
        {
            // Register the App at launch
            InitNotificationsAsync();
    
            // Begin listening for notifications
            StartCoroutine(WaitForNotification());
        }
    
  7. WaitForNotification メソッドを追加して、アプリがメイン スレッドと競合せずに Notification Hub ライブラリから通知を受け取れるようにします。

        /// <summary>
        /// This notification listener is necessary to avoid clashes 
        /// between the notification hub and the main thread   
        /// </summary>
        private IEnumerator WaitForNotification()
        {
            while (true)
            {
                // Checks for notifications each second
                yield return new WaitForSeconds(1f);
    
                if (notifReceived)
                {
                    // If a notification is arrived, moved the appropriate object to the new position
                    GameObject.Find(gameObjectName).transform.position = newObjPosition;
    
                    // Reset the flag
                    notifReceived = false;
                }
            }
        }
    
  8. 次のメソッド InitNotificationAsync() により、初期化時にアプリケーションが Notification Hub サービスに登録されます。 Unity がプロジェクトをビルドできないため、コードはコメントアウトされています。 Visual Studio で Azure メッセージング Nuget パッケージをインポートするときに、コメントを削除します。

        /// <summary>
        /// Register this application to the Notification Hub Service
        /// </summary>
        private async void InitNotificationsAsync()
        {
            // PushNotificationChannel channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
    
            // NotificationHub hub = new NotificationHub(hubName, hubListenEndpoint);
    
            // Registration result = await hub.RegisterNativeAsync(channel.Uri);
    
            // If registration was successful, subscribe to Push Notifications
            // if (result.RegistrationId != null)
            // {
            //     Debug.Log($"Registration Successful: {result.RegistrationId}");
            //     channel.PushNotificationReceived += Channel_PushNotificationReceived;
            // }
        }
    
  9. 次のハンドラー Channel_PushNotificationReceived() は、通知を受信するたびにトリガーされます。 これにより、通知が逆シリアル化されます。これは、デスクトップ アプリケーションで移動された Azure テーブル エンティティであり、MR シーン内の対応する GameObject を同じ位置に移動します。

    重要

    このコードは、Azure メッセージング ライブラリを参照しているため、コメントアウトされています。このライブラリは、Visual Studio 内で Nuget パッケージ マネージャーを使用して Unity プロジェクトをビルドした後に追加します。 そのため、コメントアウトされていない限り、Unity プロジェクトはビルドを実行できません。プロジェクトをビルドしてから、Unity に戻る場合は、そのコードを再びコメント化する必要があることに注意してください。

        ///// <summary>
        ///// Handler called when a Push Notification is received
        ///// </summary>
        //private void Channel_PushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)    
        //{
        //    Debug.Log("New Push Notification Received");
        //
        //    if (args.NotificationType == PushNotificationType.Raw)
        //    {
        //        //  Raw content of the Notification
        //        string jsonContent = args.RawNotification.Content;
        //
        //        // Deserialise the Raw content into an AzureTableEntity object
        //        AzureTableEntity ate = JsonConvert.DeserializeObject<AzureTableEntity>(jsonContent);
        //
        //        // The name of the Game Object to be moved
        //        gameObjectName = ate.RowKey;          
        //
        //        // The position where the Game Object has to be moved
        //        newObjPosition = new Vector3((float)ate.X, (float)ate.Y, (float)ate.Z);
        //
        //        // Flag thats a notification has been received
        //        notifReceived = true;
        //    }
        //}
    
  10. Unity エディターに戻る前に、変更内容を忘れずに保存してください。

  11. [Hierarchy] (階層) パネルから [Main Camera] (メイン カメラ) をクリックして、そのプロパティが [Inspector] (インスペクター) に表示されるようにします。

  12. Scripts フォルダーを開いた状態で、NotificationReceiver スクリプトを選択し、Main Camera にドラッグします。 結果は次のようになります。

    NotificationReceiver スクリプトをカメラにドラッグします

    Note

    これを Microsoft HoloLens 向けに開発する場合、Main Camera の "カメラ" コンポーネントを次のように更新する必要があります。

    • クリア フラグ: 単色
    • 背景:Black

第 16 章 - Mixed Reality プロジェクトを UWP にビルドする

この章は、前のプロジェクトのビルド プロセスと同じです。 このプロジェクトの Unity セクションに必要なすべての手順が完了したため、ここでは Unity からビルドを行います。

  1. [Build Settings] (ビルド設定) に移動します ([File] (ファイル)>[Build Settings] (ビルド設定))。

  2. [Build Settings] (ビルド設定) メニューから、[Unity C# Projects] (Unity C# プロジェクト)* がチェックされていることを確認します (ビルド後にこのプロジェクトのスクリプトを編集できるようになります)。

  3. 完了したら、[Build] (ビルド) をクリックします。

    右下に [ビルド] ボタンが強調表示されている [ビルド設定] ウィンドウを示すスクリーンショット。

  4. [エクスプローラー] ウィンドウがポップアップ表示され、ビルドの場所を入力するように求められます。 新しいフォルダーを作成し (左上隅の [New Folder]\(新規フォルダー\) をクリックします)、それに BUILDS という名前を付けます。

    ビルド フォルダーの作成

    1. 新しい BUILDS フォルダーを開き、フォルダーをもう 1 つ作成し ([新しいフォルダー] をもう一度使用します)、NH_MR_App という名前を付けます。

      NH_MR_Apps フォルダーの作成

    2. NH_MR_App を選択した状態で、 [フォルダーの選択] をクリックします。 プロジェクトがビルドされるまで 1 分ほどかかります。

  5. ビルドの後、新しいプロジェクトの場所に [エクスプローラー] ウィンドウが開きます。

第 17 章 - UnityMRNotifHub ソリューションに NuGet パッケージを追加する

警告

次の NuGet パッケージを追加 (さらに、次のでコードをコメント解除) すると、Unity プロジェクトで再び開いたときに、コードにエラーが表示されることに注意してください。 Unity エディターに戻って編集を続ける場合は、そのエラーが発生したコードをコメント化し、Visual Studio に戻ったら後でもう一度コメントを解除する必要があります。

Mixed Reality のビルドが完了したら、ビルドした Mixed Reality プロジェクトに移動し、そのフォルダー内のソリューション (.sln) ファイルをダブルクリックして、Visual Studio 2017 でソリューションを開きます。 ここで、WindowsAzure.Messaging.managed NuGet パッケージを追加する必要があります。これは、Notification Hub から通知を受信するために使用されるライブラリです。

NuGet パッケージをインポートするには、次のようにします。

  1. ソリューション エクスプローラーでソリューションを右クリックします。

  2. [NuGet パッケージの管理] をクリックします。

    NuGet マネージャーを開く

  3. [参照] タブを選択し、WindowsAzure.Messaging.managed を検索します。

    WindowsAzure.Messaging パッケージの検索

  4. 結果 (下図参照) を選択し、右側のウィンドウで、[プロジェクト] の横にあるチェック ボックスを選択します。 これにより、[Assembly-CSharp] プロジェクトと [UnityMRNotifHub] プロジェクトの横にあるチェック ボックスと共に、[プロジェクト] の横にあるチェック ボックスにチェックマークが付きます。

    すべてのプロジェクトをチェック

  5. 最初に提供されたバージョンは、このプロジェクトと互換性がない可能性があります。 そのため、[バージョン] の横にあるドロップダウン メニューをクリックし、[バージョン 0.1.7.9] をクリックしてから [インストール] をクリックします。

  6. これで、NuGet パッケージのインストールが完了しました。 NotificationReceiver クラスに入力したコメント付きコードを見つけて、コメントを解除します。

第 18 章 - UnityMRNotifHub アプリケーション、NotificationReceiver クラスを編集する

NuGet パッケージを追加したら、NotificationReceiver クラス内のいくつかのコードを "コメント解除" する必要があります。

これには、次のものが含まれます。

  1. 上部の名前空間:

    using Microsoft.WindowsAzure.Messaging;
    
  2. InitNotificationsAsync() メソッド内のすべてのコード:

        /// <summary>
        /// Register this application to the Notification Hub Service
        /// </summary>
        private async void InitNotificationsAsync()
        {
            PushNotificationChannel channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
    
            NotificationHub hub = new NotificationHub(hubName, hubListenEndpoint);
    
            Registration result = await hub.RegisterNativeAsync(channel.Uri);
    
            // If registration was successful, subscribe to Push Notifications
            if (result.RegistrationId != null)
            {
                Debug.Log($"Registration Successful: {result.RegistrationId}");
                channel.PushNotificationReceived += Channel_PushNotificationReceived;
            }
        }
    

警告

上記のコードにはコメントがあります。このコメントは誤って "コメント解除" しないようにします (解除するとコードがコンパイルされません)。

  1. 最後に、Channel_PushNotificationReceived イベント:

        /// <summary>
        /// Handler called when a Push Notification is received
        /// </summary>
        private void Channel_PushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)
        {
            Debug.Log("New Push Notification Received");
    
            if (args.NotificationType == PushNotificationType.Raw)
            {
                //  Raw content of the Notification
                string jsonContent = args.RawNotification.Content;
    
                // Deserialize the Raw content into an AzureTableEntity object
                AzureTableEntity ate = JsonConvert.DeserializeObject<AzureTableEntity>(jsonContent);
    
                // The name of the Game Object to be moved
                gameObjectName = ate.RowKey;
    
                // The position where the Game Object has to be moved
                newObjPosition = new Vector3((float)ate.X, (float)ate.Y, (float)ate.Z);
    
                // Flag thats a notification has been received
                notifReceived = true;
            }
        }
    

これらがコメント解除されたら、必ず保存してから次の章に進みます。

第 19 章 - Mixed Reality プロジェクトをストア アプリに関連付ける

次に、ラボの最初に作成したストア アプリに Mixed Reality プロジェクトを関連付ける必要があります。

  1. ソリューションを開きます。

  2. ソリューション エクスプローラーのパネルで UWP アプリ プロジェクトを右クリックし、[ストア] に移動し、[アプリケーションをストアと関連付ける...] に移動します。

    ストアの関連付けを開く

  3. [アプリケーションを Windows ストアと関連付ける] という名前の新しいウィンドウが表示されます。 次へ をクリックします。

    次の画面に進みます

  4. ログインしたアカウントに関連付けられているすべてのアプリケーションが読み込まれます。 アカウントにログインしていない場合は、このページでログインできます。

  5. このチュートリアルの最初に作成したストア アプリ名を見つけて選択します。 続けて、 [次へ] をクリックします。

    ストア名を検索して選択します

  6. [関連付け] をクリックします。

    アプリを関連付けます

  7. これで、アプリがストア アプリに関連付けられます。 これは、通知を有効にするために必要です。

第 20 章 - UnityMRNotifHub および UnityDesktopNotifHub アプリケーションをデプロイする

この章では、1 つがコンピューター デスクトップで、もう 1 つがイマーシブ ヘッドセットで実行されて、結果的に両方のアプリが実行されるため、2 人で行う方が簡単かもしれません。

イマーシブ ヘッドセット アプリは、シーンに対する変更 (ローカル GameObject の位置の変更) を受け取るのを待機しています。デスクトップ アプリはローカル シーン (位置の変更) に変更を加え、それが MR アプリと共有されます。 受信側がリッスンを開始できるように、最初に MR アプリ、次にデスクトップ アプリをデプロイすることが適切です。

ローカル コンピューターに UnityMRNotifHub アプリをデプロイするには、次のようにします。

  1. UnityMRNotifHub アプリのソリューション ファイルを Visual Studio 2017 で開きます。

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

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

    ツール バーの [ソリューション構成] が [デバッグ] に設定されていることを示すスクリーンショット。

  4. [ビルド] メニューの [ソリューションの配置] をクリックして、アプリケーションをお使いのコンピューターにサイドロードします。

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

ローカル コンピューターに UnityDesktopNotifHub アプリをデプロイするには、次のようにします。

  1. UnityDesktopNotifHub アプリのソリューション ファイルを Visual Studio 2017 で開きます。

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

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

    [デバッグ] に設定されたソリューション構成を示すスクリーンショット。

  4. [ビルド] メニューの [ソリューションの配置] をクリックして、アプリケーションをお使いのコンピューターにサイドロードします。

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

  6. Mixed Reality アプリケーションを起動し、続いてデスクトップ アプリケーションを起動します。

両方のアプリケーションが実行されている状態で、(マウスの左ボタンを使用して) デスクトップ シーン内のオブジェクトを動かします。 これらの位置の変更は、ローカルで行われ、シリアル化されて、Function App サービスに送信されます。 Function App サービスは、Notification Hub と共にテーブルを更新します。 更新を受信すると、Notification Hub は、登録されているすべてのアプリケーション (この場合はイマーシブ ヘッドセット アプリ) に更新されたデータを直接送信します。その後、アプリケーションでは、受信データが逆シリアル化され、新しい位置データがローカル オブジェクトに適用され、シーン内で移動されます。

完成した Azure Notification Hubs アプリケーション

おめでとうございます。Azure Notification Hubs サービスを活用し、アプリ間の通信を可能にした Mixed Reality アプリを構築しました。

最終的な成果物 - 終了

ボーナス演習

演習 1

GameObjects の色を変更し、シーンを表示している他のアプリにその通知を送信するにはどのようにすればいいですか。

演習 2

GameObjects の動きを MR アプリに追加し、更新されたシーンをデスクトップ アプリで確認できますか。