HoloLens (第 1 世代) と Azure 305: 関数とストレージ


注意

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


最終製品 -start

このコースでは、Mixed Reality アプリケーション内で Azure Functions リソースを使用してデータを作成して使用Azure Storageする方法について学習します。

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

Azure Storage は Microsoft クラウド サービスであり、開発者はデータを格納できます。このサービスは、高可用性、セキュリティ、耐久性、拡張性、冗長性を備えた保険を備えたものになります。 つまり、Microsoft は、すべてのメンテナンスと重大な問題を自動的に処理します。 詳細については、次の記事をAzure Storageしてください

このコースを完了すると、Mixed Reality イマーシブ ヘッドセット アプリケーションが完成し、次の操作を実行できます。

  1. ユーザーがシーンを視線入力できます。
  2. ユーザーが 3D の "ボタン" を視線入力すると、オブジェクトの生成をトリガーします。
  3. 生成されたオブジェクトは、Azure 関数によって選択されます。
  4. 各オブジェクトが生成される際に、アプリケーションはオブジェクトの種類を Azure File に格納します。このファイルは Azure Storage。
  5. もう一度読み込むと 、Azure File データが取得され、アプリケーションの前のインスタンスからの生成アクションを再生するために使用されます。

アプリケーションでは、結果を設計と統合する方法はユーザーが行う必要があります。 このコースは、Azure サービスと Unity サービスを統合する方法を教Project。 このコースで得た知識を使用して、Mixed Reality アプリケーションを強化する仕事です。

デバイス サポート

コース HoloLens イマーシブ ヘッドセット
MR と Azure 305:機能とストレージ ✔️ ✔️

注意

このコースでは主にイマーシブ (VR) ヘッドセットWindows Mixed Realityに焦点を当てながら、このコースで学習した情報を実際のMicrosoft HoloLens。 コースに従って、このコースをサポートするために採用する必要がある変更に関するメモがHoloLens。

前提条件

注意

このチュートリアルは、Unity と C# の基本的な経験を持つ開発者向けです。 また、このドキュメント内の前提条件と記述された手順は、執筆時点でテストおよび検証された結果を表している点にも注意してください (2018 年 5 月)。 ツールのインストールに関する記事に記載されている最新のソフトウェアを自由に使用できます。しかし、このコースの情報が、以下に示すよりも新しいソフトウェアで見つかった情報と完全に一致するとは見なされません。

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

開始する前に

このプロジェクトのビルドで問題が発生しないようにするには、このチュートリアルで説明したプロジェクトをルート フォルダーまたはルートに近いフォルダーに作成してください (長いフォルダー パスを使用すると、ビルド時に問題が発生する可能性があります)。

第 1 章 - Azure Portal

Azure Storage サービス を使用 するには、アプリケーション アカウントで Storage アカウント を作成して構成する必要Azure portal。

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

    注意

    Azure アカウントをまだ持ってない場合は、作成する必要があります。 クラスルームまたはラボの状況でこのチュートリアルに従っている場合は、講師またはプロクターの 1 人に新しいアカウントの設定に関するヘルプを求めることができます。

  2. ログインしたら、左上隅にある [新規] をクリックし、アカウント を検索Storage Enter キーを押 します

    Azure Storage の検索

    注意

    新しい ポータルでは 、[新規] という単語が [リソース 作成] に置き換えられた可能性があります。

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

    サービスの作成

  4. [作成] をクリック すると

    1. アカウントの [名前 ] を挿入します。このフィールドは数字と小文字のみを受け入れるので注意してください。

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

    3. [アカウントの種類] で、Storage (汎用 v1) を選択します

    4. リソース グループ の場所 を確認します (新しいリソース グループを作成する場合)。 場所は、アプリケーションが実行されるリージョンに理想的です。 一部の Azure 資産は、特定のリージョンでのみ使用できます。

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

    6. [パフォーマンス] には [Standard] を選択します

    7. [安全 な転送が必要] は [ 無効] のままにします

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

    9. リソース グループ を選択するか 、新しいリソース グループを作成します。 リソース グループは、Azure 資産のコレクションの監視、アクセスの制御、課金のプロビジョニング、管理を行う方法を提供します。 1 つのプロジェクト (これらのラボなど) に関連付けられているすべての Azure サービスを、共通のリソース グループの下に保持する必要があります。

      Azure リソース グループの詳細については、リソース グループに関する 記事を参照してください

    10. また、このサービスに適用される使用条件を理解したと確認する必要があります。

    11. [作成] を選択します。

      入力サービス情報

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

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

    Azure portal での新しい通知

  7. 通知をクリックして、新しいサービス インスタンスを探索します。

    リソースに移動する

  8. 通知の [リソースに移動] ボタンをクリックして、新しいサービス インスタンスを探索します。 アカウント サービス インスタンスの新 しいStorage表示 されます。

    アクセス キー

  9. [ アクセス キー] を クリックして、このクラウド サービスのエンドポイントを表示します。 後 メモ帳 使用するためにキーの 1 つをコピーするには、次のコマンドを使用します。 また、後 で作成する AzureServices クラスで使用される [接続文字列] の値に注意してください。

    接続文字列のコピー

第 2 章 - Azure 関数の設定

次に 、Azure サービスで Azure 関数 を記述します。

Azure 関数を使用すると、コード内のクラシック関数で行うほぼ何でも実行できます。違いは、Azure アカウントにアクセスするための資格情報を持つ任意のアプリケーションからこの関数にアクセスできる点です。

Azure 関数を作成するには:

  1. Azure Portal で、左上隅にある[新規] をクリックし 、Function App を検索して、Enter キーを押 します

    関数アプリを作成する

    注意

    新しい ポータルでは 、[新規] という単語が [リソース 作成] に置き換えられた可能性があります。

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

    関数アプリの情報

  3. [ 作成:

    1. アプリ名 を指定します。 ここでは、文字と数字のみを使用できます (大文字または小文字を使用できます)。

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

    3. リソースグループを選択するか、新しい リソースグループ を作成します。 リソースグループは、Azure 資産のコレクションの課金を監視、制御する方法を提供します。 1つのプロジェクトに関連付けられているすべての Azure サービス (たとえば、これらのラボなど) を共通のリソースグループに保持することをお勧めします。

      Azure リソースグループの詳細については、 リソースグループに関する記事をご覧ください。

    4. この演習では、選択した OS として [ Windows ] を選択します。

    5. ホスティングプラン従量課金プラン を選択します。

    6. リソースグループの 場所 を決定します (新しいリソースグループを作成している場合)。 この場所は、アプリケーションを実行するリージョンに配置するのが理想的です。 一部の Azure 資産は、特定のリージョンでのみ利用できます。 最適なパフォーマンスを得るには、ストレージアカウントと同じリージョンを選択します。

    7. Storage には、[既存のものを 使用] を選択し、ドロップダウンメニューを使用して、以前に作成したストレージを検索します。

    8. この演習では、 Application Insights オフのままにします。

      入力関数アプリの詳細

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

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

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

    新しい azure portal の通知

  7. 通知をクリックして、新しいサービスインスタンスを探索します。

    リソース関数アプリにアクセス

  8. 通知の [ リソースへのジャンプ ] ボタンをクリックして、新しいサービスインスタンスを探索します。 新しい Function App サービスインスタンスが表示されます。

  9. Function App ダッシュボードで、左側のパネルにある 関数 の上にマウスポインターを置き、プラス記号 (+) をクリックします。

    新しい関数の作成

  10. 次のページで、[ Webhook + API ] が選択されていることを確認し、[ 言語の選択] で [ CSharp] を選択します。このチュートリアルで使用する言語です。 最後に、[ この関数を作成 ] ボタンをクリックします。

    web フック csharp を選択します

  11. コードページ (csx を実行します) に移動します (ただし、それ以外の場合は、左側のパネル内の [関数] ボックスの一覧で新しく作成した関数をクリックします)。

    新しい関数を開く

  12. 関数に次のコードをコピーします。 この関数は、呼び出されたときに、0から2までのランダムな整数を返します。 既存のコードについて心配しないでください。一番上に貼り付けてもかまいません。

        using System.Net;
        using System.Threading.Tasks;
    
        public static int Run(CustomObject req, TraceWriter log)
        {
            Random rnd = new Random();
            int randomInt = rnd.Next(0, 3);
            return randomInt;
        }
    
        public class CustomObject
        {
            public String name {get; set;}
        }
    
  13. [保存] を選択します。

  14. 結果は次の図のようになります。

  15. [ 関数の URL の取得 ] をクリックし、表示されている エンドポイント を書き留めます。 このコースの後半で作成する Azureservices クラスに挿入する必要があります。

    関数エンドポイントを取得する

    関数エンドポイントの挿入

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

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

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

注意

このコースでは、モーションコントローラーは必要 ありません 。 イマーシブヘッドセットの設定をサポートする必要がある場合は、 mixed reality のセットアップに関する記事をご覧ください。

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

    新しい unity プロジェクトの作成

  2. ここで、Unity Project 名を指定する必要があります。 MR_Azure_Functions を挿入します。 プロジェクトの種類が 3d に設定されていることを確認します。 場所を適切な 場所 に設定します (ルートディレクトリの方が適していることに注意してください)。 次に、[ プロジェクトの作成] をクリックします。

    新しい unity プロジェクトに名前を付ける

  3. Unity を開いている場合は、既定の スクリプトエディターVisual Studio に設定されていることを確認する必要があります。 [設定の 編集] に移動し、 > 新しいウィンドウで [外部ツール] に移動します。 外部スクリプトエディターVisual Studio 2017 に変更します。 [ 基本設定 ] ウィンドウを閉じます。

    visual studio をスクリプトエディターとして設定する

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

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

  5. ファイル > ビルド設定 にアクセスし、次のことを確認します。

    1. ターゲットデバイス、任意のデバイス に設定されます。

      Microsoft HoloLens には、ターゲットデバイスHoloLens に設定します。

    2. ビルドの種類D3D に設定されています

    3. SDK は最新の インストール に設定されています

    4. Visual Studio バージョン が、インストールされている最新 バージョンに設定されています

    5. ビルドと実行ローカルコンピューター に設定されています

    6. シーンを保存し、ビルドに追加します。

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

        オープンシーンを追加する

      2. この新しいフォルダーを作成し、今後のシーンに加えて、[ 新しいフォルダー ] ボタンを選択します。新しいフォルダーを作成するには、名前を「 シーン」にします。

        シーンフォルダーの作成

      3. 新しく作成された [シーン] フォルダーを開き、[ファイル名: テキスト] フィールドに「[アプリケーション]」**と入力し、[**保存] をクリックします。

        関数シーンの保存

  6. それ以外の設定は、[ビルド設定] の [既定] のままにしておきます。

    既定のビルド設定をそのまま使用する

  7. [ビルド設定] ウィンドウで、[プレーヤー設定] ボタンをクリックします。これにより、インスペクター が配置されている領域の関連パネルが開きます。

    インスペクターのプレーヤー設定

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

    1. [その他の設定] タブで次のようにします。

      1. Scripting Runtime のバージョン実験的 (.net 4.6 と同等) である必要があります。これにより、エディターを再起動する必要が生じます。
      2. バックエンド.net である必要があります
      3. API 互換性レベル.net 4.6 である必要があります
    2. [発行設定] タブの [機能] で、次のことを確認します。

      • InternetClient

        機能の設定

    3. パネルの下にある XR 設定(発行設定 の下にあります) で、サポートされている仮想現実 を確認し、 Windows Mixed Reality SDK が追加されていることを確認します。

      XR 設定の設定

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

    c# プロジェクトの tick

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

  11. シーンと Project を保存します (ファイル > 保存シーン/ファイル > 保存プロジェクト)。

第4章-セットアップのメインカメラ

重要

このコースの構成要素をスキップし て、コード に直接進む場合は、unitypackage を ダウンロードして、 カスタムパッケージとしてプロジェクトにインポートしてください。 これには、次の章の Dll も含まれます。 インポート後、 第7章から続行します。

  1. [ 階層] パネル には、 メインカメラ と呼ばれるオブジェクトが表示されます。このオブジェクトは、アプリケーションの "内側" にある "ヘッド" ポイントを表します。

  2. Unity ダッシュボードを前面に表示し、 カメラのメイン のユーザーオブジェクトを選択します。 [ インスペクター] パネル (通常はダッシュボード内の右側にあります) には、そのユーザーの オブジェクト のさまざまなコンポーネントが表示されます。これには、上部にある [ 変換 ]、[ カメラ]、および他のコンポーネントがあります。 メインカメラの変換をリセットして、正しく配置されるようにする必要があります。

  3. これを行うには、カメラの 変換 コンポーネントの横にある 歯車 アイコンを選択し、[リセット] を選択します。

    変換のリセット

  4. 次に、 変換 コンポーネントを次のように更新します。

    変換-位置
    X Y Z
    0 1 0
    変換-回転
    X Y Z
    0 0 0
    変換-スケール
    X Y Z
    1 1 1

    カメラの変換の設定

章 5-Unity シーンの設定

  1. [ 階層] パネル の空の領域を右クリックし、[ 3d オブジェクト] の下に 平面 を追加します。

    新しい平面の作成

  2. [ 平面 ] オブジェクトを選択した状態で、[ インスペクター] パネル の次のパラメーターを変更します。

    変換-位置
    X Y Z
    0 0 4
    変換-スケール
    X Y Z
    10 1 10

    平面の位置とスケールの設定

    平面のシーンビュー

  3. [ 階層] パネル の空の領域を右クリックし、[ 3d オブジェクト] の下に キューブ を追加します。

    1. キューブの名前を GazeButton に変更します (キューブが選択されている状態で、[F2] を押します)。

    2. [ インスペクター] パネル で、次のパラメーターを変更します。

      変換-位置
      X Y Z
      0 3 5

      宝石ボタンの変換の設定

      宝石ボタンシーンビュー

    3. [ タグ] ドロップダウン ボタンをクリックし、[ タグの追加 ] をクリックして [ タグ & レイヤー] ペイン を開きます。

      新しいタグの追加

      プラスを選択

    4. + (正符号) ボタンを選択し、[新しいタグ名] フィールドに「 GazeButton」と入力して、[保存] をクリックします。

      新しいタグに名前を付ける

    5. 階層パネルGazeButton オブジェクトをクリックし、[インスペクター] パネル で新しく作成された GazeButton タグを割り当てます。

      新しいタグを宝石ボタンに割り当てる

  4. [階層] パネルGazeButton オブジェクトを右クリックし、[ のオブジェクト] ( オブジェクトとして追加される) を追加します。

  5. 新しいオブジェクトを選択し、名前を ShapeSpawnPoint に変更します。

    1. [ インスペクター] パネル で、次のパラメーターを変更します。

      変換-位置
      X Y Z
      0 -1 0

      図形生成ポイント変換の更新

      シェイプ生成ポイントシーンビュー

  6. 次に、Azure サービスの状態に関するフィードバックを提供する 3D テキスト オブジェクトを作成します。

    階層パネルで GazeButton をもう一度右クリックし、 3d オブジェクト > 3d テキスト オブジェクトを として追加します。

    新しい3D テキストオブジェクトの作成

  7. 3D テキスト オブジェクトの名前を AzureStatusText に変更します。

  8. AzureStatusText オブジェクトの変換を次のように変更します。

    変換-位置
    X Y Z
    0 0 -0.6
    変換-スケール
    X Y Z
    0.1 0.1 0.1

    注意

    これは、以下の Text Mesh コンポーネントが更新された場合に修正されるので、中央から外れたと思う場合は心配しないでください。

  9. テキスト メッシュ コンポーネントを 次に一致するに変更します。

    テキスト メッシュ コンポーネントを設定する

    ヒント

    ここで選択されている色は 16 進色 :000000FF ですが、自由に独自の色を選択できます。読み取り可能な色を確認してください。

  10. 階層パネルの構造は次のように表示されます。

    階層内のテキスト メッシュ

  11. これで、シーンは次のように表示されます。

    シーン ビューのテキスト メッシュ

第 6 章 - Unity のAzure Storageインポート

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

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

SDK を独自のプロジェクトにインポートするには、 から最新の'.unitypackage' をダウンロードGitHub。 次に、以下を実行します。

  1. [アセットのインポート パッケージ] カスタム パッケージメニュー オプションを使用して 、.unitypackage ファイルを Unity > > 追加します。

  2. ポップアップ表示 される [Import Unity Package]/(Unity パッケージのインポート)ボックスで、[ プラグイン ] から すべてを選択 > Storage。 このコースでは必要ではなされないので、他のすべてをオフにします。

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

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

  4. [プラグイン] Storage の下にある[Project] フォルダーに移動し、次のプラグインのみを選択 します

    • Microsoft.Data.Edm

    • Microsoft.Data.OData

    • Microsoft.WindowsAzure.Storage

    • Newtonsoft.Json

    • System.Spatial

      [任意のプラットフォーム] をオフにする

  5. これらの 特定のプラグインを選択した 状態で、[任意のプラットフォーム ] をオフ にし 、[WSAPlayer] をオフにし、[適用] を クリックします

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

    注意

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

  6. [Storage plugin] フォルダーで、次のみを選択します。

    • Microsoft.Data.Services.Client

      set は dll を処理しない

  7. [プラットフォーム]の [処理しない] ボックスをオン 設定をクリック します

    処理を適用なし

    注意

    このプラグインを "処理しない" とマークしています。これは、Unity アセンブリ の修正プログラムでこのプラグインの処理が困難なためです。 プラグインは、処理されていない場合でも引き続き機能します。

第 7 章 - AzureServices クラスを作成する

最初に作成するクラスは 、AzureServices クラス です。

AzureServices クラスは、次の責任を負います。

  • Azure アカウントの資格情報を格納する。

  • Azure アプリ関数を呼び出します。

  • Azure Cloud Storage でのデータ ファイルのアップロードとダウンロード。

このクラスを作成するには:

  1. [フォルダーの作成]パネル の [資産フォルダー Project右 クリック > します。 フォルダーに Scripts という名前 を付け、

    新しいフォルダーを作成する

    フォルダーの呼び出し - スクリプト

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

  3. フォルダー内を右クリックし > 、C# スクリプトを作成します。 スクリプト AzureServices を呼び出します

  4. 新しい AzureServices クラスをダブルクリックして、 で 開Visual Studio。

  5. AzureServices の上部に次の名前空間 を追加します

        using System;
        using System.Threading.Tasks;
        using UnityEngine;
        using Microsoft.WindowsAzure.Storage;
        using Microsoft.WindowsAzure.Storage.File;
        using System.IO;
        using System.Net;
    
  6. AzureServices クラス内に次の Inspector Fields を追加します。

        /// <summary>
        /// Provides Singleton-like behavior to this class.
        /// </summary>
        public static AzureServices instance;
    
        /// <summary>
        /// Reference Target for AzureStatusText Text Mesh object
        /// </summary>
        public TextMesh azureStatusText;
    
  7. 次に、AzureServices クラス内に次の メンバー変数を追加 します。

        /// <summary>
        /// Holds the Azure Function endpoint - Insert your Azure Function
        /// Connection String here.
        /// </summary>
    
        private readonly string azureFunctionEndpoint = "--Insert here you AzureFunction Endpoint--";
    
        /// <summary>
        /// Holds the Storage Connection String - Insert your Azure Storage
        /// Connection String here.
        /// </summary>
        private readonly string storageConnectionString = "--Insert here you AzureStorage Connection String--";
    
        /// <summary>
        /// Name of the Cloud Share - Hosts directories.
        /// </summary>
        private const string fileShare = "fileshare";
    
        /// <summary>
        /// Name of a Directory within the Share
        /// </summary>
        private const string storageDirectory = "storagedirectory";
    
        /// <summary>
        /// The Cloud File
        /// </summary>
        private CloudFile shapeIndexCloudFile;
    
        /// <summary>
        /// The Linked Storage Account
        /// </summary>
        private CloudStorageAccount storageAccount;
    
        /// <summary>
        /// The Cloud Client
        /// </summary>
        private CloudFileClient fileClient;
    
        /// <summary>
        /// The Cloud Share - Hosts Directories
        /// </summary>
        private CloudFileShare share;
    
        /// <summary>
        /// The Directory in the share that will host the Cloud file
        /// </summary>
        private CloudFileDirectory dir;
    

    重要

    エンドポイントと接続文字列の 値を、Azure Portal にある Azure Storage の値に置き換える必要があります

  8. Awake() メソッドと Start() メソッドのコードを追加する必要があります。 これらのメソッドは、 クラスが初期化するときに呼び出されます。

        private void Awake()
        {
            instance = this;
        }
    
        // Use this for initialization
        private void Start()
        {
            // Set the Status text to loading, whilst attempting connection to Azure.
            azureStatusText.text = "Loading...";
        }
    
        /// <summary>
        /// Call to the Azure Function App to request a Shape.
        /// </summary>
        public async void CallAzureFunctionForNextShape()
        {
    
        }
    

    重要

    今後の章で CallAzureFunctionForNextShape() のコードを 入力します

  9. このクラス では使用されないので、Update() メソッドを削除します。

  10. 変更を Visual Studioして Unity に戻します。

  11. AzureServices クラスをクリックし、Scripts フォルダーから階層パネルのメイン カメラ オブジェクトに ドラッグします

  12. メイン カメラを選択し 、GazeButton オブジェクトの下から AzureStatusText 子オブジェクトを取得し、それを Inspector の AzureStatusText 参照ターゲット フィールド内に配置して 、AzureServices スクリプトへの参照を提供します。

    azure status text reference target を割り当てる

第 8 章 - ShapeFactory クラスを作成する

次に作成するスクリプトは ShapeFactory クラス です。 このクラスの役割は、要求された場合に新しい図形を作成し、図形履歴リスト に作成された図形の履歴 を保持します。 図形が作成されるたび、図形履歴の一覧が AzureService クラスで更新され、 に格納 Azure Storage。 アプリケーションが起動すると、格納されたファイルが Azure Storage 内に見つかった場合、図形の履歴リストが取得および再生され、生成された図形がストレージからの図形か新しいのかを示す 3D Text オブジェクトが表示されます。

このクラスを作成するには:

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

  2. フォルダー内を右クリックし > 、C# スクリプトを作成します。 スクリプト ShapeFactory を呼び出します

  3. 新しい ShapeFactory スクリプトをダブルクリック して、で開 Visual Studio。

  4. ShapeFactory クラスに次 の名前空間が含まれる必要があります。

        using System.Collections.Generic;
        using UnityEngine;
    
  5. 以下に示す変数を ShapeFactory クラスに追加し 、Start() 関数と Awake() 関数を以下の関数に置き換えます。

        /// <summary>
        /// Provide this class Singleton-like behaviour
        /// </summary>
        [HideInInspector]
        public static ShapeFactory instance;
    
        /// <summary>
        /// Provides an Inspector exposed reference to ShapeSpawnPoint
        /// </summary>
        [SerializeField]
        public Transform spawnPoint;
    
        /// <summary>
        /// Shape History Index
        /// </summary>
        [HideInInspector]
        public List<int> shapeHistoryList;
    
        /// <summary>
        /// Shapes Enum for selecting required shape
        /// </summary>
        private enum Shapes { Cube, Sphere, Cylinder }
    
        private void Awake()
        {
            instance = this;
        }
    
        private void Start()
        {
            shapeHistoryList = new List<int>();
        }
    
  6. CreateShape() メソッドは、指定された整数パラメーターに基づいてプリミティブシェイプ を生成 します。 ブール型パラメーターは、現在作成されている図形がストレージから取得されるのか、それとも新しいのかを指定するために使用されます。 前のメソッドの下に 、ShapeFactory クラスに次のコードを配置します。

        /// <summary>
        /// Use the Shape Enum to spawn a new Primitive object in the scene
        /// </summary>
        /// <param name="shape">Enumerator Number for Shape</param>
        /// <param name="storageShape">Provides whether this is new or old</param>
        internal void CreateShape(int shape, bool storageSpace)
        {
            Shapes primitive = (Shapes)shape;
            GameObject newObject = null;
            string shapeText = storageSpace == true ? "Storage: " : "New: ";
    
            AzureServices.instance.azureStatusText.text = string.Format("{0}{1}", shapeText, primitive.ToString());
    
            switch (primitive)
            {
                case Shapes.Cube:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
                break;
    
                case Shapes.Sphere:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                break;
    
                case Shapes.Cylinder:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
                break;
            }
    
            if (newObject != null)
            {
                newObject.transform.position = spawnPoint.position;
    
                newObject.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
    
                newObject.AddComponent<Rigidbody>().useGravity = true;
    
                newObject.GetComponent<Renderer>().material.color = UnityEngine.Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f);
            }
        }
    
  7. Unity に戻る前に、必ず Visual Studioに変更を保存してください。

  8. Unity エディターに戻り 、ShapeFactory クラスをクリックして Scripts フォルダーから階層パネルの メイン カメラ オブジェクトに ドラッグします

  9. [メイン カメラ] を選択すると 、ShapeFactory スクリプト コンポーネントに Spawn Point 参照が見つからない のが表示 されます。 この問題を解決するには 、ShapeSpawnPoint オブジェクトを階層 パネル から Spawn Point 参照 ターゲットに ドラッグします。

    set shape factory reference target

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

作成する必要がある最後のスクリプトは 、Gaze クラス です。

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

このクラスを作成するには:

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

  2. [C# スクリプトの作成] Projectパネル > で右クリックします。 スクリプト Gaze を呼び 出します

  3. 新しい Gaze スクリプトを ダブルクリック して、新しい視線入力スクリプト Visual Studio。

  4. スクリプトの上部に次の名前空間が含まれている必要があります。

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

        /// <summary>
        /// Provides Singleton-like behavior to this class.
        /// </summary>
        public static Gaze instance;
    
        /// <summary>
        /// The Tag which the Gaze will use to interact with objects. Can also be set in editor.
        /// </summary>
        public string InteractibleTag = "GazeButton";
    
        /// <summary>
        /// The layer which will be detected by the Gaze ('~0' equals everything).
        /// </summary>
        public LayerMask LayerMask = ~0;
    
        /// <summary>
        /// The Max Distance the gaze should travel, if it has not hit anything.
        /// </summary>
        public float GazeMaxDistance = 300;
    
        /// <summary>
        /// The size of the cursor, which will be created.
        /// </summary>
        public Vector3 CursorSize = new Vector3(0.05f, 0.05f, 0.05f);
    
        /// <summary>
        /// The color of the cursor - can be set in editor.
        /// </summary>
        public Color CursorColour = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
    
        /// <summary>
        /// Provides when the gaze is ready to start working (based upon whether
        /// Azure connects successfully).
        /// </summary>
        internal bool GazeEnabled = false;
    
        /// <summary>
        /// The currently focused object.
        /// </summary>
        internal GameObject FocusedObject { get; private set; }
    
        /// <summary>
        /// The object which was last focused on.
        /// </summary>
        internal GameObject _oldFocusedObject { get; private set; }
    
        /// <summary>
        /// The info taken from the last hit.
        /// </summary>
        internal RaycastHit HitInfo { get; private set; }
    
        /// <summary>
        /// The cursor object.
        /// </summary>
        internal GameObject Cursor { get; private set; }
    
        /// <summary>
        /// Provides whether the raycast has hit something.
        /// </summary>
        internal bool Hit { get; private set; }
    
        /// <summary>
        /// This will store the position which the ray last hit.
        /// </summary>
        internal Vector3 Position { get; private set; }
    
        /// <summary>
        /// This will store the normal, of the ray from its last hit.
        /// </summary>
        internal Vector3 Normal { get; private set; }
    
        /// <summary>
        /// The start point of the gaze ray cast.
        /// </summary>
        private Vector3 _gazeOrigin;
    
        /// <summary>
        /// The direction in which the gaze should be.
        /// </summary>
        private Vector3 _gazeDirection;
    

重要

これらの変数の一部は、エディター で編集 できます

  1. Awake() メソッドと Start() メソッドのコードを追加する必要があります。

        /// <summary>
        /// The method used after initialization of the scene, though before Start().
        /// </summary>
        private void Awake()
        {
            // Set this class to behave similar to singleton
            instance = this;
        }
    
        /// <summary>
        /// Start method used upon initialization.
        /// </summary>
        private void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
  2. 次のコードを追加します。このコードでは、最初にカーソル オブジェクトが作成され、Raycast メソッドを実行する Update() メソッドと共に、GazeEnabled ブール値が切り替わります。

        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        /// <returns></returns>
        private GameObject CreateCursor()
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            newCursor.SetActive(false);
    
            // Remove the collider, so it doesn't block raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
            newCursor.transform.localScale = CursorSize;
    
            newCursor.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Diffuse"))
            {
                color = CursorColour
            };
    
            newCursor.name = "Cursor";
    
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
        /// <summary>
        /// Called every frame
        /// </summary>
        private void Update()
        {
            if(GazeEnabled == true)
            {
                _gazeOrigin = Camera.main.transform.position;
    
                _gazeDirection = Camera.main.transform.forward;
    
                UpdateRaycast();
            }
        }
    
  3. 次に 、UpdateRaycast() メソッドを追加します。これは Raycast を投影し、ヒット ターゲットを検出します。

        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            _oldFocusedObject = FocusedObject;
    
            RaycastHit hitInfo;
    
            // Initialise Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance, LayerMask);
    
            HitInfo = hitInfo;
    
            // Check whether raycast has hit.
            if (Hit == true)
            {
                Position = hitInfo.point;
    
                Normal = hitInfo.normal;
    
                // Check whether the hit has a collider.
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at.
                    FocusedObject = hitInfo.collider.gameObject;
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null.
                    FocusedObject = null;
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedObject = null;
    
                // Provide default position for cursor.
                Position = _gazeOrigin + (_gazeDirection * GazeMaxDistance);
    
                // Provide a default normal.
                Normal = _gazeDirection;
            }
    
            // Lerp the cursor to the given position, which helps to stabilize the gaze.
            Cursor.transform.position = Vector3.Lerp(Cursor.transform.position, Position, 0.6f);
    
            // Check whether the previous focused object is this same 
            //    object. If so, reset the focused object.
            if (FocusedObject != _oldFocusedObject)
            {
                ResetFocusedObject();
    
                if (FocusedObject != null)
                {
                if (FocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                        // Set the Focused object to green - success!
                        FocusedObject.GetComponent<Renderer>().material.color = Color.green;
    
                        // Start the Azure Function, to provide the next shape!
                        AzureServices.instance.CallAzureFunctionForNextShape();
                    }
                }
            }
        }
    
  4. 最後に 、ResetFocusedObject() メソッドを追加します。このメソッドは、現在の色の GazeButton オブジェクトを切り替え、新しい図形を作成するかどうかを示します。

        /// <summary>
        /// Reset the old focused object, stop the gaze timer, and send data if it
        /// is greater than one.
        /// </summary>
        private void ResetFocusedObject()
        {
            // Ensure the old focused object is not null.
            if (_oldFocusedObject != null)
            {
                if (_oldFocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                    // Set the old focused object to red - its original state.
                    _oldFocusedObject.GetComponent<Renderer>().material.color = Color.red;
                }
            }
        }
    
  5. Unity に戻る前Visual Studioに変更を保存します。

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

第 10 章 - AzureServices クラスの完了

他のスクリプトが配置されたので 、AzureServices クラス を完了できます。 これは、次の方法で実現されます。

  1. CreateCloudIdentityAsync() という名前の新しいメソッドを追加して、Azure との通信に必要な認証変数を設定します。

    このメソッドは、図形リストを含む以前に格納されたファイルの存在も確認します。

    ファイルが見つかった場合 は、ユーザーの視線入力を無効にし、図形のパターンに従って図形の作成をトリガーします。これは、Azure Storage ファイルに格納されます。 ユーザーはこれを確認できます。テキストメッシュでは、図形の原点に応じて 、"Storage" または "新規" と表示されます。

    ファイルが見つからない 場合は、Gaze を有効にして、ユーザーがシーン内の GazeButton オブジェクトを見て図形を作成できます。

        /// <summary>
        /// Create the references necessary to log into Azure
        /// </summary>
        private async void CreateCloudIdentityAsync()
        {
            // Retrieve storage account information from connection string
            storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    
            // Create a file client for interacting with the file service.
            fileClient = storageAccount.CreateCloudFileClient();
    
            // Create a share for organizing files and directories within the storage account.
            share = fileClient.GetShareReference(fileShare);
    
            await share.CreateIfNotExistsAsync();
    
            // Get a reference to the root directory of the share.
            CloudFileDirectory root = share.GetRootDirectoryReference();
    
            // Create a directory under the root directory
            dir = root.GetDirectoryReference(storageDirectory);
    
            await dir.CreateIfNotExistsAsync();
    
            //Check if the there is a stored text file containing the list
            shapeIndexCloudFile = dir.GetFileReference("TextShapeFile");
    
            if (!await shapeIndexCloudFile.ExistsAsync())
            {
                // File not found, enable gaze for shapes creation
                Gaze.instance.GazeEnabled = true;
    
                azureStatusText.text = "No Shape\nFile!";
            }
            else
            {
                // The file has been found, disable gaze and get the list from the file
                Gaze.instance.GazeEnabled = false;
    
                azureStatusText.text = "Shape File\nFound!";
    
                await ReplicateListFromAzureAsync();
            }
        }
    
  2. 次のコード スニペットは 、Start() メソッド内からの コードです。ここで 、CreateCloudIdentityAsync() メソッドを呼び出 します。 以下を使用して、現在の Start() メソッドを自由にコピーしてください。

        private void Start()
        {
            // Disable TLS cert checks only while in Unity Editor (until Unity adds support for TLS)
    #if UNITY_EDITOR
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    #endif
    
            // Set the Status text to loading, whilst attempting connection to Azure.
            azureStatusText.text = "Loading...";
    
            //Creating the references necessary to log into Azure and check if the Storage Directory is empty
            CreateCloudIdentityAsync();
        }
    
  3. メソッド CallAzureFunctionForNextShape() のコードを入力します。 前に作成した Azure Function App を使用して、 図形インデックスを要求します。 新しい図形を受け取った後、このメソッドは ShapeFactory クラスに図形を送信して、シーンに新しい図形を作成します。 次のコードを使用して 、CallAzureFunctionForNextShape() の本文を完成します

        /// <summary>
        /// Call to the Azure Function App to request a Shape.
        /// </summary>
        public async void CallAzureFunctionForNextShape()
        {
            int azureRandomInt = 0;
    
            // Call Azure function
            HttpWebRequest webRequest = WebRequest.CreateHttp(azureFunctionEndpoint);
    
            WebResponse response = await webRequest.GetResponseAsync();
    
            // Read response as string
            using (Stream stream = response.GetResponseStream())
            {
                StreamReader reader = new StreamReader(stream);
    
                String responseString = reader.ReadToEnd();
    
                //parse result as integer
                Int32.TryParse(responseString, out azureRandomInt);
            }
    
            //add random int from Azure to the ShapeIndexList
            ShapeFactory.instance.shapeHistoryList.Add(azureRandomInt);
    
            ShapeFactory.instance.CreateShape(azureRandomInt, false);
    
            //Save to Azure storage
            await UploadListToAzureAsync();
        }
    
  4. 図形履歴リストに格納されている整数を連結し、 ファイルに保存することで、文字列を作成する メソッドAzure Storage追加します

        /// <summary>
        /// Upload the locally stored List to Azure
        /// </summary>
        private async Task UploadListToAzureAsync()
        {
            // Uploading a local file to the directory created above
            string listToString = string.Join(",", ShapeFactory.instance.shapeHistoryList.ToArray());
    
            await shapeIndexCloudFile.UploadTextAsync(listToString);
        }
    
  5. Azure Storage File にあるファイルに格納されているテキストを取得し、一 覧に逆シリアル化 するメソッドを追加します。

  6. このプロセスが完了すると、 メソッドは視線入力を再び有効にし、ユーザーがシーンに図形を追加できます。

        ///<summary>
        /// Get the List stored in Azure and use the data retrieved to replicate 
        /// a Shape creation pattern
        ///</summary>
        private async Task ReplicateListFromAzureAsync()
        {
            string azureTextFileContent = await shapeIndexCloudFile.DownloadTextAsync();
    
            string[] shapes = azureTextFileContent.Split(new char[] { ',' });
    
            foreach (string shape in shapes)
            {
                int i;
    
                Int32.TryParse(shape.ToString(), out i);
    
                ShapeFactory.instance.shapeHistoryList.Add(i);
    
                ShapeFactory.instance.CreateShape(i, true);
    
                await Task.Delay(500);
            }
    
            Gaze.instance.GazeEnabled = true;
    
            azureStatusText.text = "Load Complete!";
        }
    
  7. Unity に戻る前Visual Studioに変更を保存します。

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

ビルド プロセスを開始するには:

  1. [ファイル ビルド ] > に移動設定。

    アプリをビルドする

  2. [ビルド] をクリックします。 Unity によって新 しいエクスプローラー ウィンドウが起動されます。ここで、アプリをビルドするフォルダーを作成して選択する必要があります。 ここでそのフォルダーを作成し、App という名前を 付ける。 次に、App フォルダー を選択 し、 [フォルダーの選択] を押します

  3. Unity によって、App フォルダーへのプロジェクトのビルド が開始 されます。

  4. Unity のビルドが完了すると (時間がかかる場合があります)、ビルドの場所に エクスプローラー ウィンドウが開きます (常にウィンドウの上に表示されるとは限りないが、新しいウィンドウの追加を通知するタスク バーを確認します)。

第 12 章 - アプリケーションのデプロイ

アプリケーションをデプロイするには:

  1. 前の章 で作成 した App フォルダーに 移動します。 アプリ名と拡張子が '.sln' のファイルが表示されます。このファイルをダブルクリックして、 内で Visual Studio。

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

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

    このMicrosoft HoloLens、コンピューターにテザリングされていないので、これをリモートコンピューターに設定する方が簡単な場合があります。 しかし、次の操作も行う必要があります。

    • HoloLens の IP アドレスを確認します。設定 Network & > Internet > Wi-Fi Advanced Options 内で確認できます > 。IPv4 は使用する必要があるアドレスです。
    • [開発者 モード] が [ オン]を確認します。「Update > 設定 Security & for > developers 」で確認できます

    ソリューションのデプロイ

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

  5. これで、アプリがインストールされているアプリの一覧に表示され、起動してテストする準備ができました。

完成したアプリケーションAzure FunctionsとStorageアプリケーション

おめでとうございます。現在のサービスとサービスの両方を活用する mixed reality Azure Functions構築Azure Storageしました。 アプリは、格納されているデータに描画し、そのデータに基づくアクションを提供できます。

最終製品 -end

ボーナス演習

演習 1

2 つ目の生成ポイントを作成し、オブジェクトが作成された生成ポイントを記録します。 データ ファイルを読み込むときに、最初に作成された場所から生成される図形を再生します。

演習 2

アプリを再起動する方法を作成します。アプリを再起動する場合は、アプリを再起動する必要があります。 シーンの読み込 みは、開始する良い場所です。 その後、アプリから簡単にリセットできるよう、Azure Storage に格納されているリストをクリアする方法を作成します。