HoloLens (第 1 世代) と Azure 312: ボットとの統合

Note

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

このコースでは、Microsoft Bot Framework V4 を使用してボットを作成してデプロイし、Windows Mixed Reality アプリケーションでそれとやり取りする方法について説明します。

Windows Mixed Reality アプリケーションを介した通信を示すスクリーンショット。

Microsoft Bot Framework V4 は、拡張可能でスケーラブルなボット アプリケーションを作成するためのツールを開発者に提供するために設計された一連の API です。 詳細については、Microsoft Bot Framework のページまたは V4 Git リポジトリを参照してください。

このコースを完了すると、Windows Mixed Reality アプリケーションが作成され、次のことを実行できるようになります。

  1. タップ ジェスチャを使用して、ユーザーの声を聞き取るボットを開始します。
  2. ユーザーが何かを言うと、ボットでは応答を提供することが試みられます。
  3. Unity のシーンのボットの近くにボットの応答をテキストとして表示します。

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

デバイス サポート

コース HoloLens イマーシブ ヘッドセット
MR と Azure 312:ボットの統合 ✔️ ✔️

注意

このコースでは主に HoloLens に焦点を当てていますが、このコースで学習した内容を Windows Mixed Reality イマーシブ (VR) ヘッドセットにも適用できます。 イマーシブ (VR) ヘッドセットにはアクセス可能なカメラがないため、外部カメラが PC に接続されている必要があります。 このコースの中では、イマーシブ (VR) ヘッドセットをサポートするために必要な変更がある場合に、その変更が注意事項として記載されています。

前提条件

Note

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

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

開始する前に

  1. このプロジェクトをビルドする際の問題を避けるために、このチュートリアルで紹介するプロジェクトをルートまたはルートに近いフォルダーに作成することを強くお勧めします (フォルダー パスが長いと、ビルド時に問題が発生する可能性があります)。
  2. HoloLens を設定してテストします。 HoloLens の設定でサポートが必要な場合は、HoloLens セットアップに関する記事にアクセスしてください
  3. 新しい HoloLens アプリの開発を開始するときは、調整とセンサーのチューニングを実行することをお勧めします (ユーザーごとにこれらのタスクを実行すると役立つ場合があります)。

調整の詳細については、この HoloLens の調整に関する記事へのリンクを参照してください。

センサー チューニングの詳細については、この HoloLens センサー チューニングに関する記事へのリンクを参照してください。

第 1 章 – ボット アプリケーションを作成する

最初の手順は、ボットをローカル ASP.Net Core Web アプリケーションとして作成することです。 完了してテストしたら、Azure Portal にそれを公開します。

  1. Visual Studio を開きます。 新しいプロジェクトを作成し、プロジェクトの種類として [ASP NET Core Web アプリケーション] (サブセクション [.NET Core] の下にあります) を選択し、それを MyBot という名前にします。 [OK] をクリックします。

  2. 表示されるウィンドウで、[Empty] を選択します。 また、ターゲットが [ASP NET Core 2.0] に設定されていて、[認証] が [認証なし] に設定されていることを確認します。 [OK] をクリックします。

    [New A S P dot N E T Core Web Application]\(新しい A S P ドット N E T Core Web アプリケーション\) ウィンドウを示すスクリーンショット。

  3. これでソリューションが開きます。 [ソリューション エクスプローラー] でソリューション [Mybot] を右クリックし、[ソリューションの NuGet パッケージの管理] をクリックします。

    [MyBot] と [ソリューションの NuGet パッケージの管理] が強調表示された、開いているソリューションを示すスクリーンショット。

  4. [参照] タブで、「Microsoft.Bot.Builder.Integration.AspNet.Core」を検索します ([プレリリースを含める] がオンになっていることを確認します)。 パッケージ バージョン 4.0.1-preview を選択し、プロジェクトのボックスをオンにします。 次に、[インストール] をクリックします。 これで、Bot Framework v4 に必要なライブラリがインストールされました。 NuGet のページを閉じます。

    Nu-Get ソリューション マネージャーを示すスクリーンショット。

  5. [ソリューション エクスプローラー] [プロジェクト][MyBot] 上で右クリックし、[追加]|[クラス] をクリックします。

    MyBot に新しいクラスを追加するプロセスを示すスクリーンショット。

  6. クラスに MyBot という名前を付けて、[追加] をクリックします。

    新しいクラスの作成 'MyBot' を示すスクリーンショット。

  7. 前の操作を繰り返して、ConversationContext という別のクラスを作成します。

  8. [ソリューション エクスプローラー][wwwroot] を右クリックし、[追加]|[新しい項目] をクリックします。 [HTML ページ] (サブセクション [Web] の下にあります) を選択します。 ファイルに default.html という名前を付けます。 [追加] をクリックします。

    ソリューション エクスプローラー ウィンドウ内からの新しい H T M L ページの作成を示すスクリーンショット。

  9. [ソリューション エクスプローラー] のクラス/オブジェクトの一覧は以下の図のようになります。

    クラスの一覧を含む [ソリューション エクスプローラー] ウィンドウのスクリーンショット。

  10. [ConversationContext] クラスをダブルクリックします。 このクラスは、ボットが使用する変数を保持して、会話のコンテキストを維持する役割を担います。 これらの会話のコンテキスト値は、このクラスのインスタンスで保持されます。これは、アクティビティが受信されるたびに、MyBot クラスのインスタンスが更新されるためです。 このクラスに次のコードを追加します。

    namespace MyBot
    {
        public static class ConversationContext
        {
            internal static string userName;
    
            internal static string userMsg;
        }
    }
    
  11. [MyBot] クラスをダブルクリックします。 このクラスでは、顧客から受信したすべてのアクティビティによって呼び出されるハンドラーをホストします。 このクラスに、ボットと顧客の間の会話を構築するために使用されるコードを追加します。 既に説明したように、このクラスのインスタンスは、アクティビティを受信するたびに初期化されます。 次のコードをこのクラスに追加します。

    using Microsoft.Bot;
    using Microsoft.Bot.Builder;
    using Microsoft.Bot.Schema;
    using System.Threading.Tasks;
    
    namespace MyBot
    {
        public class MyBot : IBot
        {       
            public async Task OnTurn(ITurnContext context)
            {
                ConversationContext.userMsg = context.Activity.Text;
    
                if (context.Activity.Type is ActivityTypes.Message)
                {
                    if (string.IsNullOrEmpty(ConversationContext.userName))
                    {
                        ConversationContext.userName = ConversationContext.userMsg;
                        await context.SendActivity($"Hello {ConversationContext.userName}. Looks like today it is going to rain. \nLuckily I have umbrellas and waterproof jackets to sell!");
                    }
                    else
                    {
                        if (ConversationContext.userMsg.Contains("how much"))
                        {
                            if (ConversationContext.userMsg.Contains("umbrella")) await context.SendActivity($"Umbrellas are $13.");
                            else if (ConversationContext.userMsg.Contains("jacket")) await context.SendActivity($"Waterproof jackets are $30.");
                            else await context.SendActivity($"Umbrellas are $13. \nWaterproof jackets are $30.");
                        }
                        else if (ConversationContext.userMsg.Contains("color") || ConversationContext.userMsg.Contains("colour"))
                        {
                            await context.SendActivity($"Umbrellas are black. \nWaterproof jackets are yellow.");
                        }
                        else
                        {
                            await context.SendActivity($"Sorry {ConversationContext.userName}. I did not understand the question");
                        }
                    }
                }
                else
                {
    
                    ConversationContext.userMsg = string.Empty;
                    ConversationContext.userName = string.Empty;
                    await context.SendActivity($"Welcome! \nI am the Weather Shop Bot \nWhat is your name?");
                }
    
            }
        }
    }
    
  12. [Startup] クラスをダブルクリックします。 このクラスではボットを初期化します。 このクラスに次のコードを追加します。

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Bot.Builder.BotFramework;
    using Microsoft.Bot.Builder.Integration.AspNet.Core;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace MyBot
    {
    public class Startup
        {
            public IConfiguration Configuration { get; }
    
            public Startup(IHostingEnvironment env)
            {
                var builder = new ConfigurationBuilder()
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                    .AddEnvironmentVariables();
                Configuration = builder.Build();
            }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddSingleton(_ => Configuration);
                services.AddBot<MyBot>(options =>
                {
                    options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);
                });
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseDefaultFiles();
                app.UseStaticFiles();
                app.UseBotFramework();
            }
        }
    }
    
  13. [Program] クラス ファイルを開き、コードが次のコードと同じであることを確認します。

    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    
    namespace MyBot
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                BuildWebHost(args).Run();
            }
    
            public static IWebHost BuildWebHost(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>()
                    .Build();
        }
    }
    
  14. 変更を保存してください。そのためには、Visual Studio の上部にあるツール バーから [ファイル]>[すべて保存] を選択します。

第 2 章 - Azure Bot Service を作成する

ボット用のコードを作成したので、Azure Portal で Web アプリ ボット サービスのインスタンスに公開する必要があります。 この章では、Azure で Bot Service を作成および構成し、そのサービスにコードを公開する方法について説明します。

  1. まず、Azure Portal (https://portal.azure.com) にログインします。

    1. まだ Azure アカウントをお持ちでない方は、作成する必要があります。 このチュートリアルを教室やラボで受講している場合は、インストラクターや監督者に新しいアカウントの設定方法を質問してください。
  2. ログインしたら、左上隅にある[リソースの作成] をクリックして、Web アプリ ボット を検索し、[Enter] キーをクリックします。

    左上に [リソースの作成] が強調表示されている Microsoft Azure ダッシュボードのスクリーンショット。

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

    [Web アプリ ボット] ページと左下の [作成] ボタンのスクリーンショット。

  4. [作成] をクリックしたら、以下の手順を実行します。

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

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

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

      Azure リソース グループの詳細については、こちらのリンクを参照してください

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

    5. 適切な価格レベルを選択します。これが初めて作成する Web アプリ ボット サービスの場合は、無料レベル (F0 という名前) を使用できるはずです

    6. [アプリ名] [ボット名] と同じままにすることができます。

    7. [ボット テンプレート] [基本 (C#)] のままにしておきます。

    8. [App Service プラン/場所] は、アカウントに対して自動入力されている必要があります。

    9. ボットをホストするために使用する [Azure Storage] を設定します。 まだお持ちでない場合は、ここで作成できます。

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

    11. [作成] をクリックします。

      新しいサービスを作成するために必要なフィールドを示すスクリーンショット。

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

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

    サービス インスタンスの作成後に強調表示された通知アイコンを示すスクリーンショット。

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

    デプロイが成功し、[リソースに移動] ボタンを示すスクリーンショット。

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

    前のウィンドウの [リソースに移動] ボタンをクリックした後の [リソース] ウィンドウのスクリーンショット。

  9. この時点で、クライアント アプリケーションでこの Bot Service と通信できるように、Direct Line と呼ばれる機能を設定する必要があります。 [チャンネル] をクリックし、[おすすめチャンネルの追加] セクションで、[Direct Line チャンネルの構成] をクリックします。

    MyHoloLensBot で強調表示されている [Direct Line チャネルの構成] を示すスクリーンショット。

  10. このページには、クライアント アプリでボットを使用して認証できるようにする秘密キーがあります。 [表示] ボタンをクリックして、表示されているキーの 1 つをコピーします。これは、このプロジェクトで後で必要になります。

    MyHoloLensBot Configure Direct Line チャネルで強調表示されているシークレット キーのスクリーンショット。

第 3 章 – Azure Web アプリ ボット サービスにボットを公開する

サービスの準備ができたので、先ほど作成したボットのコードを新しく作成した Web アプリ ボット サービスに公開する必要があります。

Note

ボットのソリューション/コードに変更を加えるたびに、ボットを Azure サービスに公開する必要があります。

  1. 前に作成した Visual Studio ソリューションに戻ります。

  2. [ソリューション エクスプローラー][MyBot] プロジェクトを右クリックし、[公開] をクリックします。

    右クリックした後の [MyBot] プロジェクトのドロップダウン メニューを示すスクリーンショット。

  3. [公開先の選択] ページで、[アプリ サービス] をクリックして、[既存のものを選択] をクリックします。最後に、[プロファイルの作成] をクリックします (表示されない場合は、[公開] ボタンの横にあるドロップダウンの矢印をクリックする必要がある場合があります)。

    [App Service]、[既存の選択]、[プロファイルの作成] が強調表示されている [発行先の選択] ページを示すスクリーンショット。

  4. Microsoft アカウントにまだログインしていない場合は、ここでログインする必要があります。

  5. [公開] ページでは、Web アプリ ボット サービスの作成に使用したものと同じ [サブスクリプション] を設定する必要があることがわかります。 次に、[表示][リソース グループ] を設定し、ドロップダウン フォルダー構造で、前に作成した[リソース グループ]を選択します。 [OK] をクリックします。

    Web アプリBot Serviceの作成に使用されたのと同じサブスクリプションが選択されている [App Service] ウィンドウを示すスクリーンショット。

  6. [公開] ボタンをクリックして、ボットが公開されるまで待ちます (数分かかる場合があります)。

    [発行] ウィンドウと [発行] ボタンを示すスクリーンショット。

第 4 章 - Unity プロジェクトを設定する

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

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

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

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

    新しい Unity プロジェクト名フィールドが強調表示されているスクリーンショット。

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

    必要な設定が表示された [Unity の基本設定] ウィンドウを示すスクリーンショット。

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

    [プラットフォームの切り替え] ボタンが強調表示されている [ビルド設定] ウィンドウを示すスクリーンショット。

  5. 引き続き [ファイル] > [ビルド設定] で、次のことを確認します。

    1. [ターゲット デバイス][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」という名前を付けます。

        新しい [Scenes] フォルダーの作成を示すスクリーンショット。

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

        Scenes フォルダーと、新しく作成されたファイルが保存されているスクリーンショット。

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

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

    [インスペクター] タブの [ビルド設定] ウィンドウを示すスクリーンショット。

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

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

      1. [スクリプト ランタイム バージョン][試験段階] (.NET 4.6 と同等) である。これを変更した場合は、エディターを再起動する必要があります。

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

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

        必要な設定が表示された [その他の設定] タブを示すスクリーンショット。

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

      • InternetClient

      • マイク

        [発行設定] タブで [InternetClient] と [マイク] が有効になっていることを示すスクリーンショット。

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

      Virtual Reality のサポートが有効で、S D K が追加Windows Mixed Reality示すスクリーンショット。

  8. ビルド設定に戻ると、ユニティC#プロジェクトを灰色で表示しなくなり、その横にあるチェックボックスをティックします。

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

  10. シーンとプロジェクトを保存します ([FILE](ファイル) > [SAVE SCENE / FILE](シーン/ファイルの保存) > [SAVE PROJECT](プロジェクトの保存) を選択)。

第 5 章 – カメラを設定する

重要

このコースの Unity のセットアップ コンポーネントをスキップして、そのままコードに進みたい場合は、この Azure-MR-312-Package.unitypackage をダウンロードして、それをカスタム パッケージとしてご自分のプロジェクトにインポートし、第 7 章から続けてください。

  1. [階層] パネル[Main Camera] を選択します。

  2. 選択すると、[Main Camera] のすべてのコンポーネントが [インスペクター] パネルに表示できるようになります。

    1. カメラ オブジェクトの名前は Main Camera である必要があります (スペルに注意します)
    2. Main Camera の [タグ][MainCamera] に設定する必要があります (スペルに注意します)
    3. [変換] の [位置]0、0、0 に設定されていることを確認します
    4. [クリア フラグ][単色] に設定します。
    5. カメラ コンポーネントの [背景]色 を黒、アルファ 0 (16 進コード: #00000000) に設定します

    [インスペクター] パネルの [メイン カメラ] のすべてのコンポーネントを示すスクリーンショット。

第 6 章 – Newtonsoft ライブラリをインポートする

Bot Service で受信および送信されたオブジェクトを逆シリアル化およびシリアル化するには、Newtonsoft ライブラリをダウンロードする必要があります。 適切な Unity フォルダー構造で既に整理されている互換性のあるバージョンはこちらにあります。

Newtonsoft ライブラリをプロジェクトにインポートするには、このコースに付属している Unity パッケージを使用します。

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

    [Import Package]\(パッケージのインポート\) と [Custom Package]\(カスタム パッケージ\) が選択されている [Assets]\(アセット\) ドロップダウン メニューを示すスクリーンショット。

  2. ポップアップ表示される [Unity パッケージのインポート] ボックスで、[プラグイン] およびその下にあるすべての項目が選択されていることを確認します。

    [プラグイン] が選択されている [Import Unity Package]\(Unity パッケージのインポート\) ポップアップ ボックスのスクリーンショット。

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

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

    プロジェクト ビューの Newtonsoft フォルダーを示すスクリーンショット。

  5. Newtonsoft プラグインを選択した状態で、[Any Platform](任意のプラットフォーム)オフになっていることを確認し、[WSAPlayer]オフになっていることを確認してから、[適用] をクリックします。 これは単に、ファイルが正しく構成されていることを確認するための手順です。

    Newtonsoft プラグインの正しい選択を示すスクリーンショット。

    Note

    これらのプラグインにマークを付けると、それらは Unity エディターでのみ使用されるように構成されます。 プロジェクトが Unity からエクスポートされた後に使用される別のセットが WSA フォルダー内にあります。

  6. 次に、Newtonsoft フォルダー内にある WSA フォルダーを開く必要があります。 先ほど構成したものと同じファイルのコピーが表示されます。 そのファイルを選択して、インスペクターで次のことを確認します

    • [任意のプラットフォーム] チェック ボックスがオフである
    • [WSAPlayer]のみオンである
    • [処理しない]オンである

    WSA フォルダー内の Newtonsoft プラグインの正しい選択を示すスクリーンショット。

第 7 章 – BotTag を作成する

  1. BotTag という新しい [タグ] オブジェクトを作成します。 シーンで [Main Camera] を選択します。 [Inspector] パネルの [Tag] ドロップダウン メニューをクリックします。 [Add Tag](タグの追加) をクリックします。

    [インスペクター] パネルの [メイン カメラ タグ] ドロップダウン メニューのスクリーンショット。[タグの追加] が強調表示されています。

  2. + [シンボル]をクリックします。 新しいタグBotTagという名前を付けて、[保存] します。

    [Inspector]\(インスペクター\) パネルのスクリーンショット。新しい BotTag 名と記号、および [保存] ボタンが表示されています。

警告

Main Camera に BotTag を適用しないでください。 この操作を誤って行った場合は、Main Camera のタグを必ず MainCamera に戻します。

第 8 章 – BotObjects クラスを作成する

作成する必要のある最初のスクリプトは、BotObjects クラスです。このクラスは、他の一連のクラス オブジェクトを同じスクリプト内に格納し、シーン内の他のスクリプトからアクセスできるようにするために作成された空のクラスです。

このクラスを作成するのは、純粋にアーキテクチャ上の選択です。これらのオブジェクトは、このコースで後で作成する Bot スクリプトで代わりにホストすることができます。

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

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

    scripts フォルダーを作成します。

  2. Scripts フォルダーをダブルクリックして開きます。 次に、そのフォルダー内で右クリックして [Create] (作成) > [C# Script] (C# スクリプト) を選択します。 スクリプトに BotObjects という名前を付けます。

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

  4. スクリプトの内容を削除して、次のコードに置き換えます。

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class BotObjects : MonoBehaviour{}
    
    /// <summary>
    /// Object received when first opening a conversation
    /// </summary>
    [Serializable]
    public class ConversationObject
    {
        public string ConversationId;
        public string token;
        public string expires_in;
        public string streamUrl;
        public string referenceGrammarId;
    }
    
    /// <summary>
    /// Object including all Activities
    /// </summary>
    [Serializable]
    public class ActivitiesRootObject
    {
        public List<Activity> activities { get; set; }
        public string watermark { get; set; }
    }
    [Serializable]
    public class Conversation
    {
        public string id { get; set; }
    }
    [Serializable]
    public class From
    {
        public string id { get; set; }
        public string name { get; set; }
    }
    [Serializable]
    public class Activity
    {
        public string type { get; set; }
        public string channelId { get; set; }
        public Conversation conversation { get; set; }
        public string id { get; set; }
        public From from { get; set; }
        public string text { get; set; }
        public string textFormat { get; set; }
        public DateTime timestamp { get; set; }
        public string serviceUrl { get; set; }
    }
    
  5. Unity に戻る前に、必ず Visual Studio で変更を保存してください。

第 9 章 – GazeInput クラスを作成する

次に作成するクラスは GazeInput クラスです。 このクラスは次の役割を担っています。

  • プレーヤーの視線入力 を表すカーソルを作成する。
  • プレーヤーの視線入力によってヒットしたオブジェクトを検出し、検出されたオブジェクトへの参照を保持します。

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

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

  2. フォルダー内を右クリックし、[Create] (作成) > [C# Script] (C# スクリプト) を選択します。 GazeInput スクリプトを呼び出します。

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

  4. クラス名の上に次の行を挿入します。

    /// <summary>
    /// Class responsible for the User's gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    
  5. 次に、GazeInput クラス内の Start() メソッドの上に次の変数を追加します。

        [Tooltip("Used to compare whether an object is to be interacted with.")]
        internal string InteractibleTag = "BotTag";
    
        /// <summary>
        /// Length of the gaze
        /// </summary>
        internal float GazeMaxDistance = 300;
    
        /// <summary>
        /// Object currently gazed
        /// </summary>
        internal GameObject FocusedObject { get; private set; }
    
        internal GameObject _oldFocusedObject { get; private set; }
    
        internal RaycastHit HitInfo { get; private set; }
    
        /// <summary>
        /// Cursor object visible in the scene
        /// </summary>
        internal GameObject Cursor { get; private set; }
    
        internal bool Hit { get; private set; }
    
        internal Vector3 Position { get; private set; }
    
        internal Vector3 Normal { get; private set; }
    
        private Vector3 _gazeOrigin;
    
        private Vector3 _gazeDirection;
    
  6. Start () メソッドのコードを追加する必要があります。 これはクラスの初期化時に呼び出されます。

        /// <summary>
        /// Start method used upon initialization.
        /// </summary>
        internal virtual void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
  7. 視線カーソルをインスタンス化して設定するメソッドを実装します。

        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        internal GameObject CreateCursor()
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            newCursor.SetActive(false);
            // Remove the collider, so it does not block Raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
            newCursor.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);
            Material mat = new Material(Shader.Find("Diffuse"));
            newCursor.GetComponent<MeshRenderer>().material = mat;
            mat.color = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
  8. Main Camera から Raycast を設定するメソッドを実装します。これにより、現在フォーカスがあるオブジェクトが追跡されます。

        /// <summary>
        /// Called every frame
        /// </summary>
        internal virtual void Update()
        {
            _gazeOrigin = Camera.main.transform.position;
    
            _gazeDirection = Camera.main.transform.forward;
    
            UpdateRaycast();
        }
    
    
        /// <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))
                {
                    // Provide the OnGazeExited event.
                    _oldFocusedObject.SendMessage("OnGazeExited", 
                        SendMessageOptions.DontRequireReceiver);
                }
            }
        }
    
    
        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            _oldFocusedObject = FocusedObject;
            RaycastHit hitInfo;
    
            // Initialize Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance);
            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. If so, reset the focused object.
            if (FocusedObject != _oldFocusedObject)
            {
                ResetFocusedObject();
                if (FocusedObject != null)
                {
                    if (FocusedObject.CompareTag(InteractibleTag))
                    {
                        // Provide the OnGazeEntered event.
                        FocusedObject.SendMessage("OnGazeEntered",
                            SendMessageOptions.DontRequireReceiver);
                    }
                }
            }
        }
    
  9. Unity に戻る前に、必ず Visual Studio で変更を保存してください。

第 10 章 – Bot クラスを作成する

ここで作成するスクリプトは Bot と呼ばれます。 これはアプリケーションのコア クラスであり、次のものが格納されます。

  • Web アプリ ボットの資格情報
  • ユーザーの音声コマンドを収集するメソッド
  • Web アプリ ボットとの会話を開始するために必要なメソッド
  • Web アプリ ボットにメッセージを送信するために必要なメソッド

Bot Service にメッセージを送信するために、SendMessageToBot () コルーチンによってアクティビティが作成されます。これは、ユーザーによって送信されたデータとして Bot Framework によって認識されるオブジェクトです。

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

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

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

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

  4. Bot クラスの上部で、次の内容と同じになるように名前空間を更新します。

    using Newtonsoft.Json;
    using System.Collections;
    using System.Text;
    using UnityEngine;
    using UnityEngine.Networking;
    using UnityEngine.Windows.Speech;
    
  5. Bot クラス内に次の変数を追加します。

        /// <summary>
        /// Static instance of this class
        /// </summary>
        public static Bot Instance;
    
        /// <summary>
        /// Material of the sphere representing the Bot in the scene
        /// </summary>
        internal Material botMaterial;
    
        /// <summary>
        /// Speech recognizer class reference, which will convert speech to text.
        /// </summary>
        private DictationRecognizer dictationRecognizer;
    
        /// <summary>
        /// Use this variable to identify the Bot Id
        /// Can be any value
        /// </summary>
        private string botId = "MRBotId";
    
        /// <summary>
        /// Use this variable to identify the Bot Name
        /// Can be any value
        /// </summary>
        private string botName = "MRBotName";
    
        /// <summary>
        /// The Bot Secret key found on the Web App Bot Service on the Azure Portal
        /// </summary>
        private string botSecret = "-- Add your Secret Key here --"; 
    
        /// <summary>
        /// Bot Endpoint, v4 Framework uses v3 endpoint at this point in time
        /// </summary>
        private string botEndpoint = "https://directline.botframework.com/v3/directline";
    
        /// <summary>
        /// The conversation object reference
        /// </summary>
        private ConversationObject conversation;
    
        /// <summary>
        /// Bot states to regulate the application flow
        /// </summary>
        internal enum BotState {ReadyToListen, Listening, Processing}
    
        /// <summary>
        /// Flag for the Bot state
        /// </summary>
        internal BotState botState;
    
        /// <summary>
        /// Flag for the conversation status
        /// </summary>
        internal bool conversationStarted = false;
    

    Note

    ボットの秘密キーbotSecret 変数に書き込んだことを確認します。 ボットの秘密キーは、このコースの最初のほうの第 2 章の手順 10 でメモしました。

  6. Awake()Start() のコードを追加する必要があります。

        /// <summary>
        /// Called on Initialization
        /// </summary>
        void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Called immediately after Awake method
        /// </summary>
        void Start()
        {
            botState = BotState.ReadyToListen;
        }
    
  7. 音声キャプチャの開始と終了時に音声ライブラリによって呼び出される 2 つのハンドラーを追加します。 DictationRecognizer では、ユーザーが話をやめると、ユーザーの音声のキャプチャを自動的に停止します。

        /// <summary>
        /// Start microphone capture.
        /// </summary>
        public void StartCapturingAudio()
        {
            botState = BotState.Listening;
            botMaterial.color = Color.red;
    
            // Start dictation
            dictationRecognizer = new DictationRecognizer();
            dictationRecognizer.DictationResult += DictationRecognizer_DictationResult;
            dictationRecognizer.Start();
        }
    
    
        /// <summary>
        /// Stop microphone capture.
        /// </summary>
        public void StopCapturingAudio()
        {
            botState = BotState.Processing;
            dictationRecognizer.Stop();
        }
    
    
  8. 次のハンドラーでは、ユーザーの音声入力の結果を収集して、メッセージを Web アプリ ボット サービスに送信する役割を持つコルーチンを呼び出します。

        /// <summary>
        /// This handler is called every time the Dictation detects a pause in the speech. 
        /// </summary>
        private void DictationRecognizer_DictationResult(string text, ConfidenceLevel confidence)
        {
            // Update UI with dictation captured
            Debug.Log($"User just said: {text}");      
    
            // Send dictation to Bot
            StartCoroutine(SendMessageToBot(text, botId, botName, "message"));
            StopCapturingAudio();
        }     
    
  9. 次のコルーチンは、ボットとの会話を開始するために呼び出されます。 会話の呼び出しが完了すると、アクティビティを空のメッセージとして Bot Service に送信することを設定する一連のパラメーターを渡すことにより、SendMessageToCoroutine() が呼び出されることがわかります。 これは、ダイアログを開始するように Bot Service に求めることによって行われます。

        /// <summary>
        /// Request a conversation with the Bot Service
        /// </summary>
        internal IEnumerator StartConversation()
        {
            string conversationEndpoint = string.Format("{0}/conversations", botEndpoint);
    
            WWWForm webForm = new WWWForm();
    
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Post(conversationEndpoint, webForm))
            {
                unityWebRequest.SetRequestHeader("Authorization", "Bearer " + botSecret);
                unityWebRequest.downloadHandler = new DownloadHandlerBuffer();
    
                yield return unityWebRequest.SendWebRequest();
                string jsonResponse = unityWebRequest.downloadHandler.text;
    
                conversation = new ConversationObject();
                conversation = JsonConvert.DeserializeObject<ConversationObject>(jsonResponse);
                Debug.Log($"Start Conversation - Id: {conversation.ConversationId}");
                conversationStarted = true; 
            }
    
            // The following call is necessary to create and inject an activity of type //"conversationUpdate" to request a first "introduction" from the Bot Service.
            StartCoroutine(SendMessageToBot("", botId, botName, "conversationUpdate"));
        }    
    
  10. 次のコルーチンは、アクティビティが Bot Service に送信されるようにビルドするために呼び出されます。

        /// <summary>
        /// Send the user message to the Bot Service in form of activity
        /// and call for a response
        /// </summary>
        private IEnumerator SendMessageToBot(string message, string fromId, string fromName, string activityType)
        {
            Debug.Log($"SendMessageCoroutine: {conversation.ConversationId}, message: {message} from Id: {fromId} from name: {fromName}");
    
            // Create a new activity here
            Activity activity = new Activity();
            activity.from = new From();
            activity.conversation = new Conversation();
            activity.from.id = fromId;
            activity.from.name = fromName;
            activity.text = message;
            activity.type = activityType;
            activity.channelId = "DirectLineChannelId";
            activity.conversation.id = conversation.ConversationId;     
    
            // Serialize the activity
            string json = JsonConvert.SerializeObject(activity);
    
            string sendActivityEndpoint = string.Format("{0}/conversations/{1}/activities", botEndpoint, conversation.ConversationId);
    
            // Send the activity to the Bot
            using (UnityWebRequest www = new UnityWebRequest(sendActivityEndpoint, "POST"))
            {
                www.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json));
    
                www.downloadHandler = new DownloadHandlerBuffer();
                www.SetRequestHeader("Authorization", "Bearer " + botSecret);
                www.SetRequestHeader("Content-Type", "application/json");
    
                yield return www.SendWebRequest();
    
                // extrapolate the response Id used to keep track of the conversation
                string jsonResponse = www.downloadHandler.text;
                string cleanedJsonResponse = jsonResponse.Replace("\r\n", string.Empty);
                string responseConvId = cleanedJsonResponse.Substring(10, 30);
    
                // Request a response from the Bot Service
                StartCoroutine(GetResponseFromBot(activity));
            }
        }
    
  11. 次のコルーチンは、アクティビティを Bot Service に送信した後に応答を要求するために呼び出されます。

        /// <summary>
        /// Request a response from the Bot by using a previously sent activity
        /// </summary>
        private IEnumerator GetResponseFromBot(Activity activity)
        {
            string getActivityEndpoint = string.Format("{0}/conversations/{1}/activities", botEndpoint, conversation.ConversationId);
    
            using (UnityWebRequest unityWebRequest1 = UnityWebRequest.Get(getActivityEndpoint))
            {
                unityWebRequest1.downloadHandler = new DownloadHandlerBuffer();
                unityWebRequest1.SetRequestHeader("Authorization", "Bearer " + botSecret);
    
                yield return unityWebRequest1.SendWebRequest();
    
                string jsonResponse = unityWebRequest1.downloadHandler.text;
    
                ActivitiesRootObject root = new ActivitiesRootObject();
                root = JsonConvert.DeserializeObject<ActivitiesRootObject>(jsonResponse);
    
                foreach (var act in root.activities)
                {
                    Debug.Log($"Bot Response: {act.text}");
                    SetBotResponseText(act.text);
                }
    
                botState = BotState.ReadyToListen;
                botMaterial.color = Color.blue;
            }
        } 
    
  12. このクラスに追加する最後のメソッドは、シーンにメッセージを表示するために必要となります。

        /// <summary>
        /// Set the UI Response Text of the bot
        /// </summary>
        internal void SetBotResponseText(string responseString)
        {        
            SceneOrganiser.Instance.botResponseText.text =  responseString;
        }
    

    Note

    SceneOrganiser クラスがないことを示すエラーが Unity エディター コンソールに表示される場合があります。 このクラスはこのチュートリアルで後で作成しますので、このメッセージは無視してください。

  13. Unity に戻る前に、必ず Visual Studio で変更を保存してください。

第 11 章 – Interactions クラスを作成する

ここで作成するクラスは Interactions と呼ばれます。 このクラスは、ユーザーからの HoloLens タップ入力を検出するために使用されます。

ユーザーがシーン内の ボットオブジェクトを見ているときにタップし、ボットで音声入力を聞き取る準備ができている場合、ボット オブジェクトでは色がに変更され、音声入力の聞き取りが開始されます。

このクラスは GazeInput クラスから継承されるため、base を使用して示すことにより、そのクラスから Start() メソッドと変数を参照できます。

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

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

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

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

  4. Interactions クラスの上部で、名前空間とクラスの継承を次の内容と同じになるように更新します。

    using UnityEngine.XR.WSA.Input;
    
    public class Interactions : GazeInput
    {
    
  5. Interactions クラス内に次の変数を追加します。

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  6. 次に、Start() メソッドを追加します。

        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        internal override void Start()
        {
            base.Start();
    
            //Register the application to recognize HoloLens user inputs
            _gestureRecognizer = new GestureRecognizer();
            _gestureRecognizer.SetRecognizableGestures(GestureSettings.Tap);
            _gestureRecognizer.Tapped += GestureRecognizer_Tapped;
            _gestureRecognizer.StartCapturingGestures();
        }
    
  7. ユーザーが HoloLens カメラの前でタップ ジェスチャを行ったときにトリガーされるハンドラーを追加します

        /// <summary>
        /// Detects the User Tap Input
        /// </summary>
        private void GestureRecognizer_Tapped(TappedEventArgs obj)
        {
            // Ensure the bot is being gazed upon.
            if(base.FocusedObject != null)
            {
                // If the user is tapping on Bot and the Bot is ready to listen
                if (base.FocusedObject.name == "Bot" && Bot.Instance.botState == Bot.BotState.ReadyToListen)
                {
                    // If a conversation has not started yet, request one
                    if(Bot.Instance.conversationStarted)
                    {
                        Bot.Instance.SetBotResponseText("Listening...");
                        Bot.Instance.StartCapturingAudio();
                    }
                    else
                    {
                        Bot.Instance.SetBotResponseText("Requesting Conversation...");
                        StartCoroutine(Bot.Instance.StartConversation());
                    }                                  
                }
            }
        }
    
  8. Unity に戻る前に、必ず Visual Studio で変更を保存してください。

第 12 章 – SceneOrganiser クラスを作成する

このラボで必要な最後のクラスは、SceneOrganiser と呼ばれます。 このクラスでは、コンポーネントとスクリプトを Main Camera に追加し、シーン内に適切なオブジェクトを作成することで、シーンをプログラムで設定します。

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

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

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

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

  4. SceneOrganiser クラス内に次の変数を追加します。

        /// <summary>
        /// Static instance of this class
        /// </summary>
        public static SceneOrganiser Instance;
    
        /// <summary>
        /// The 3D text representing the Bot response
        /// </summary>
        internal TextMesh botResponseText;
    
  5. 次に、Awake() および Start() メソッドを追加します。

        /// <summary>
        /// Called on Initialization
        /// </summary>
        private void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Called immediately after Awake method
        /// </summary>
        void Start ()
        {
            // Add the GazeInput class to this object
            gameObject.AddComponent<GazeInput>();
    
            // Add the Interactions class to this object
            gameObject.AddComponent<Interactions>();
    
            // Create the Bot in the scene
            CreateBotInScene();
        }
    
  6. シーンにボット オブジェクトを作成し、パラメーターとコンポーネントを設定する役割がある次のメソッドを追加します。

        /// <summary>
        /// Create the Sign In button object in the scene
        /// and sets its properties
        /// </summary>
        private void CreateBotInScene()
        {
            GameObject botObjInScene = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            botObjInScene.name = "Bot";
    
            // Add the Bot class to the Bot GameObject
            botObjInScene.AddComponent<Bot>();
    
            // Create the Bot UI
            botResponseText = CreateBotResponseText();
    
            // Set properties of Bot GameObject
            Bot.Instance.botMaterial = new Material(Shader.Find("Diffuse"));
            botObjInScene.GetComponent<Renderer>().material = Bot.Instance.botMaterial;
            Bot.Instance.botMaterial.color = Color.blue;
            botObjInScene.transform.position = new Vector3(0f, 2f, 10f);
            botObjInScene.tag = "BotTag";
        }
    
  7. シーンに UI オブジェクトを作成し、ボットからの応答を表す役割がある次のメソッドを追加します。

        /// <summary>
        /// Spawns cursor for the Main Camera
        /// </summary>
        private TextMesh CreateBotResponseText()
        {
            // Create a sphere as new cursor
            GameObject textObject = new GameObject();
            textObject.transform.parent = Bot.Instance.transform;
            textObject.transform.localPosition = new Vector3(0,1,0);
    
            // Resize the new cursor
            textObject.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
    
            // Creating the text of the Label
            TextMesh textMesh = textObject.AddComponent<TextMesh>();
            textMesh.anchor = TextAnchor.MiddleCenter;
            textMesh.alignment = TextAlignment.Center;
            textMesh.fontSize = 50;
            textMesh.text = "Hi there, tap on me and I will start listening.";
    
            return textMesh;
        }
    
  8. Unity に戻る前に、必ず Visual Studio で変更を保存してください。

  9. Unity エディターで、SceneOrganiser スクリプトを Scripts フォルダーから Main Camera にドラッグします。 次の図に示すように、Scene Organiser コンポーネントが Main Camera オブジェクトに表示されます。

    Unity エディターのメイン カメラ オブジェクトに追加されているシーン オーガナイザー スクリプトを示すスクリーンショット。

第 13 章 – ビルドする前に

アプリケーションの完全なテストを実行するには、アプリケーションを HoloLens にサイドロードする必要があります。 実行する前に、次のことを確認してください。

  • 第 4 章に記載されている設定がすべて正しく設定されている。
  • SceneOrganiser スクリプトが Main Camera オブジェクトにアタッチされている。
  • Bot クラスで、botSecret 変数にボットの秘密キーが書き込まれている。

第 14 章 – ビルドして HoloLens にサイドロードする

このプロジェクトの Unity セクションに必要なすべての手順が完了したため、ここでは Unity からそれをビルドします。

  1. [ ビルド設定]、[ ファイル ビルド > 設定]の順に移動します。

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

    Unity からアプリをビルドする

  3. [Unity C# プロジェクト] をオンにします (まだオンにしていない場合)。

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

  5. Unity でプロジェクトのビルドが開始され、App フォルダーに保存されます。

  6. Unity によるビルドが完了すると (多少時間がかかる場合があります)、 [エクスプローラー] ウィンドウが開いて、ビルドの場所が表示されます (必ずしも最前面に表示されるとは限らないため、タスク バーを確認してください。新しいウィンドウが追加されたことがわかります)。

第 15 章 – HoloLens にデプロイする

HoloLens にデプロイするには、次の手順を実行します。

  1. HoloLens の IP アドレスが必要になります (リモート デプロイの場合)。また、HoloLens が開発者モードになっていることを確認する必要があります。 手順は次のとおりです。

    1. HoloLens を装着した状態で、[設定] を開きます。
    2. [ネットワーク & インターネット>] Wi-Fi > [詳細オプション] に移動します
    3. IPv4 アドレスを書き留めます。
    4. 次に、[設定] に戻り、[Update & Security For Developers]\(開発者向けセキュリティ>の更新\) に移動します
    5. [開発者モード] を [オン] に設定します。
  2. 新しい Unity ビルド (App フォルダー) に移動し、Visual Studio を使用してソリューション ファイルを開きます。

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

  4. [Solution Platform](ソリューション プラットフォーム) で、[x86][Remote Machine](リモート コンピュータ) を選択します。

    Visual Studio からソリューションをデプロイします。

  5. [Build](ビルド) メニューに移動して [Deploy Solution](ソリューションの配置) をクリックします。これでアプリケーションが HoloLens にサイドロードされます。

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

    Note

    イマーシブ ヘッドセットにデプロイするには、[Solution Platform](ソリューション プラットフォーム)[Local Machine](ローカル コンピューター)に設定し、[Configuration](構成)[Debug](デバッグ) にし、プラットフォームとして x86 を設定します。 次に、[Build](ビルド) メニュー[Deploy Solution](ソリューションの配置) を選択して、ローカル コンピューターにデプロイします。

第 16 章 – アプリケーションを HoloLens で使用する

  • アプリケーションを起動すると、目の前に青い球としてボットが表示されます。

  • 会話を開始するには、球を見ているときにタップ ジェスチャを使用します。

  • 会話が開始されるまで待ちます (会話が開始されると UI にメッセージが表示されます)。 ボットから開始メッセージを受け取ったら、ボットが赤に変わって音声の聞き取りを開始するように再度タップします。

  • 会話をやめると、アプリケーションによってメッセージがボットに送信され、応答がすぐに送られて UI に表示されます。

  • このプロセスを繰り返して、さらにメッセージをボットに送信します (メッセージを送信する度にタップする必要があります)。

この会話では、ボットで情報 (自分の名前) を保持しながら、既知の情報 (在庫のある項目など) も提供する方法を示しています。

ボットに尋ねるいくつかの質問:

what do you sell? 

how much are umbrellas?

how much are raincoats?

Web アプリ ボット (v4) アプリケーションが完成しました

おめでとうございます。Azure Web アプリ ボットと Microsoft Bot Framework v4 を活用して Mixed Reality アプリを作成しました。

最終製品

ボーナス演習

演習 1

このラボの会話の構造は非常に基本的です。 Microsoft LUIS を使用して、自然言語を理解する機能をボットに追加します。

演習 2

この例には、会話の終了と新しい会話の再開は含まれていません。 ボット機能を完成させるために、会話の終了を実装してみてください。