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


Note

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


最終製品 -start

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

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

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

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

このコースを修了すると、次のことができる 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:クロスデバイス通知 ✔️ ✔️

注意

このコースでは 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 キーを押します。

    通知ハブを検索する

    Note

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

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

    通知ハブ インスタンスを作成する

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

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

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

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

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

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

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

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

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

      サービスの詳細を入力する

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

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

    通知

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

    テーブルを開く

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

    新しいテーブルを作成する

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

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

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

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

  1. Visual Studio を開きます。

  2. メニューから [表示]>[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. これで、テーブルは以下のようになります。

    table complete

  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. [場所] を選択します (前の手順で作成したストレージと同じ場所を選択します)

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

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

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

      新しいインスタンスを作成する

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

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

    新しい通知

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

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

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

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

    新しい関数を追加する

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

    カスタム関数

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

    http put link

    重要

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

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

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

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

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

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

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

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

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

    create 関数

  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. Function Apps をホストするために以前に作成したストレージ アカウントを選択します。

      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 を開き、[New] (新規) をクリックします。

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

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

    プロジェクトの作成

  3. Unity を開いた状態で、既定のスクリプト エディターVisual Studio に設定されているかどうか確認することをお勧めします。 [Edit] (編集)>[Preferences] (環境設定) に移動し、新しいウィンドウで [External Tools] (外部ツール) に移動します。 [外部スクリプト エディター][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][Latest installed] (最新のインストール) に設定されている

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

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

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

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

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

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

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

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

        新しいNH_Desktop_Scene

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

  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] である

        4.6 net バージョン

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

      • InternetClient

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

  8. [Build Settings] (ビルド設定) に戻ると、"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. "これらの特定のプラグイン" を選択した状態で、[Any Platform] (任意のプラットフォーム)オフにし、[WSAPlayer]オフにして、[Apply] (適用) をクリックします。

    プラットフォーム dll を適用する

    Note

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

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

    • Microsoft.Data.Services.Client

      set は 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」という名前を付けます。

    create scripts フォルダー

    create scripts folder 2

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

  3. Scripts フォルダー内で右クリックし、[Create] (作成)>[C# Script] (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 にドラッグします。 結果は以下のようになります。

    メイン カメラにスクリプトを追加する

第 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 にドラッグします。 結果は以下のようになります。

      クラウド スクリプトをメインカメラにドラッグする

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

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

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

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

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

  3. [エクスプローラー] ウィンドウがポップアップ表示され、ビルドの場所を入力するように求められます。 新しいフォルダーを作成し (左上隅の [新しいフォルダー] をクリックします)、それに 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] に設定されていることを確認します。 [Location] (場所) を適切な場所に設定します (ルート ディレクトリに近い方が適しています)。 次に、[プロジェクトの作成] をクリックします。

    名前 UnityMRNotifHub

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

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

  4. 次に、[ファイル>ビルド設定] に移動し、[プラットフォームの切り替え] ボタンをクリックして、プラットフォームをユニバーサル Windows プラットフォーム切り替えます

    プラットフォームを UWP に切り替える

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

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

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

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

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

    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. [Build Settings] (ビルド設定) の残りの設定は、ここでは既定値のままにしておきます。

  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. [公開設定] タブ内の [機能] で、次の内容を確認します。

      • InternetClient

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

  8. [Build Settings] (ビルド設定) に戻ると、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. "これらの特定のプラグイン" を選択した状態で、[Any Platform] (任意のプラットフォーム)オフにし、[WSAPlayer]オフにして、[Apply] (適用) をクリックします。

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

    Note

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

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

    • Microsoft.Data.Services.Client

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

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

    処理しない

    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 サービスの [アクセス ポリシー] タブにあるエンドポイントの値に置き換えます (下の図を参照)。

    通知ハブ ポリシー エンドポイントの挿入

  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 にドラッグします。 結果は以下のようになります。

    通知レシーバー スクリプトをカメラにドラッグする

    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. [エクスプローラー] ウィンドウがポップアップ表示され、ビルドの場所を入力するように求められます。 新しいフォルダーを作成し (左上隅の [新しいフォルダー] をクリックします)、それに 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 manager を開く

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

    Windows Azure メッセージング パッケージを検索する

  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 アプリを構築しました。

最終製品 -end

ボーナス演習

演習 1

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

演習 2

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