HoloLens(1세대) 및 Azure 312: 봇 통합

참고

Mixed Reality 아카데미 자습서는 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 프로젝트와 통합하는 방법을 교육하기 위해 고안되었습니다. 혼합 현실 애플리케이션을 향상시키기 위해 이 과정에서 얻은 지식을 사용하는 것이 여러분의 임무입니다.

디바이스 지원

과정 HoloLens 몰입형 헤드셋
MR 및 Azure 312: Bot 통합 ✔️ ✔️

참고

이 과정은 주로 HoloLens에 중점을 두지만, 이 과정에서 배운 내용을 VR(몰입형) 헤드셋에 Windows Mixed Reality 적용할 수도 있습니다. 몰입형(VR) 헤드셋에는 액세스할 수 있는 카메라가 없으므로 PC에 연결된 외부 카메라가 필요합니다. 과정을 진행하면서 몰입형(VR) 헤드셋을 지원하기 위해 사용해야 할 수 있는 변경 사항에 대한 메모를 볼 수 있습니다.

사전 요구 사항

참고

이 자습서는 Unity 및 C#에 대한 기본 경험이 있는 개발자를 위해 설계되었습니다. 또한 이 문서의 필수 구성 요소 및 서면 지침은 작성 당시 테스트 및 확인된 내용(2018년 7월)을 나타냅니다. 이 과정의 정보가 아래에 나열된 것보다 최신 소프트웨어에서 찾을 수 있는 내용과 완벽하게 일치한다고 가정해서는 안 되지만 도구 설치 문서에 나열된 대로 최신 소프트웨어를 자유롭게 사용할 수 있습니다.

이 과정에서는 다음 하드웨어 및 소프트웨어를 사용하는 것이 좋습니다.

시작하기 전에

  1. 이 프로젝트를 빌드하는 데 문제가 발생하지 않도록 이 자습서에서 언급한 프로젝트를 루트 또는 루트에 가까운 폴더에 만드는 것이 좋습니다(긴 폴더 경로는 빌드 시 문제를 일으킬 수 있음).
  2. HoloLens를 설정하고 테스트합니다. HoloLens 설정을 지원해야 하는 경우 HoloLens 설정 문서를 참조하세요.
  3. 새 HoloLens 앱 개발을 시작할 때 보정 및 센서 튜닝을 수행하는 것이 좋습니다(때로는 각 사용자에 대해 이러한 작업을 수행하는 데 도움이 될 수 있음).

보정에 대한 도움말은 HoloLens 보정 문서에 대한 이 링크를 따르세요.

센서 튜닝에 대한 도움말은 HoloLens 센서 튜닝 문서에 대한 링크를 따르세요.

1장 - 봇 애플리케이션 만들기

첫 번째 단계는 로컬 ASP.Net Core 웹 애플리케이션으로 봇을 만드는 것입니다. 완료하고 테스트한 후에는 Azure Portal에 게시합니다.

  1. Visual Studio를 엽니다. 새 프로젝트를 만들고, ASP NET Core 웹 애플리케이션 을 프로젝트 유형으로 선택하고(.NET Core 하위 섹션에서 찾을 수 있습니다) MyBot이라고 합니다. 확인을 클릭합니다.

  2. 표시되는 창에서 을 선택합니다. 또한 대상이 ASP NET Core 2.0으로 설정되고 인증이 인증 없음으로 설정되어 있는지 확인합니다. 확인을 클릭합니다.

    새 A SP 점 N E T Core 웹 애플리케이션 창을 보여 주는 스크린샷

  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 페이지를 선택합니다(하위 섹션 웹에서 찾을 수 있습니다). 파일 이름을 로default.html. 추가를 클릭합니다.

    솔루션 탐색기 창 내에서 새 H TM L 페이지 만들기를 보여 주는 스크린샷

  9. 솔루션 탐색기 클래스/개체 목록은 아래 이미지와 같아야 합니다.

    클래스 목록이 있는 솔루션 탐색기 창의 스크린샷

  10. ConversationContext 클래스를 두 번 클릭합니다. 이 클래스는 대화의 컨텍스트를 유지하기 위해 봇에서 사용하는 변수를 보유합니다. 이러한 대화 컨텍스트 값은 활동이 수신될 때마다 MyBot 클래스의 instance 새로 고쳐지므로 이 클래스의 instance 유지됩니다. 클래스에 다음 코드를 추가합니다.

    namespace MyBot
    {
        public static class ConversationContext
        {
            internal static string userName;
    
            internal static string userMsg;
        }
    }
    
  11. MyBot 클래스를 두 번 클릭합니다. 이 클래스는 고객의 들어오는 활동에 의해 호출되는 처리기를 호스트합니다. 이 클래스에서는 봇과 고객 간의 대화를 빌드하는 데 사용되는 코드를 추가합니다. 앞에서 설명한 대로 활동을 받을 때마다 이 클래스의 instance 초기화됩니다. 이 클래스에 다음 코드를 추가합니다.

    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 App Bot Service instance 게시해야 합니다. 이 챕터에서는 Azure에서 Bot Service 만들고 구성한 다음 코드를 게시하는 방법을 보여줍니다.

  1. 먼저 Azure Portal(https://portal.azure.com)에 로그인합니다.

    1. Azure 계정이 아직 없는 경우 계정을 만들어야 합니다. 강의실 또는 랩 상황에서 이 자습서를 따르는 경우 강사 또는 감독자 중 한 명에게 새 계정 설정에 대한 도움을 요청하세요.
  2. 로그인한 후 왼쪽 위 모서리에서 리소스 만들기를 클릭하고 웹앱 봇을 검색하고 Enter 키를 클릭합니다.

    왼쪽 위에 '리소스 만들기'가 강조 표시된 Microsoft Azure dashboard 스크린샷

  3. 새 페이지에서는 Web App Bot Service에 대한 설명을 제공합니다. 이 페이지의 왼쪽 아래에서 만들기 단추를 선택하여 이 서비스와의 연결을 만듭니다.

    왼쪽 아래에 있는 웹앱 봇 페이지와 '만들기' 단추의 스크린샷

  4. 만들기를 클릭한 후에는 다음을 수행합니다.

    1. 이 서비스 instance 원하는 이름을 삽입합니다.

    2. 구독을 선택합니다.

    3. 리소스 그룹을 선택하거나 새 그룹을 만듭니다. 리소스 그룹은 Azure 자산 컬렉션에 대한 액세스를 모니터링, 제어, 프로비전 및 관리하는 방법을 제공합니다. 단일 프로젝트(예: 이러한 과정)와 연결된 모든 Azure 서비스를 공통 리소스 그룹 아래에 유지하는 것이 좋습니다.

      Azure 리소스 그룹에 대해 자세히 알아보려면 이 링크를 따르세요.

    4. 리소스 그룹의 위치를 결정합니다(새 리소스 그룹을 만드는 경우). 위치는 애플리케이션이 실행되는 지역에 있는 것이 가장 좋습니다. 일부 Azure 자산은 특정 지역에서만 사용할 수 있습니다.

    5. 웹앱 Bot Service를 처음 만드는 경우 F0이라는 무료 계층을 사용할 수 있어야 하는 경우 적절한 가격 책정 계층을 선택합니다.

    6. 앱 이름은봇 이름과 동일하게 남을 수 있습니다.

    7. 봇 템플릿기본(C#)으로 둡니다.

    8. 앱 서비스 계획/위치 가 계정에 대해 자동으로 채워졌어야 합니다.

    9. 봇을 호스트하는 데 사용할 Azure Storage 를 설정합니다. 아직 없는 경우 여기에서 만들 수 있습니다.

    10. 또한 이 서비스에 적용된 사용 약관을 이해했음을 확인해야 합니다.

    11. 만들기를 클릭합니다.

      새 서비스를 만드는 데 필요한 필드를 보여 주는 스크린샷

  5. 만들기를 클릭하면 서비스가 생성될 때까지 기다려야 합니다. 이 작업은 1분 정도 걸릴 수 있습니다.

  6. 서비스 instance 만들어지면 포털에 알림이 표시됩니다.

    서비스 instance 만든 후 강조 표시된 알림 아이콘을 보여 주는 스크린샷

  7. 알림을 클릭하여 새 서비스 instance 탐색합니다.

    배포 성공 및 '리소스로 이동' 단추를 보여 주는 스크린샷

  8. 알림에서 리소스로 이동 단추를 클릭하여 새 서비스 instance 탐색합니다. 새 Azure 서비스 instance 이동합니다.

    이전 창에서 '리소스로 이동' 단추를 클릭한 후의 리소스 창 스크린샷

  9. 이 시점에서 클라이언트 애플리케이션이 이 Bot Service 통신할 수 있도록 Direct Line이라는 기능을 설정해야 합니다. 채널을 클릭한 다음 추천 채널 추가 섹션에서 Direct Line 채널 구성을 클릭합니다.

    MyHoloLensBot에서 강조 표시된 Direct Line 구성 채널을 보여 주는 스크린샷

  10. 이 페이지에서는 클라이언트 앱이 봇을 사용하여 인증할 수 있는 비밀 키를 찾을 수 있습니다. 표시 단추를 클릭하고 프로젝트 뒷부분에서 필요하므로 표시된 키 중 하나의 복사본을 가져옵니다.

    MyHoloLensBot 구성 Direct Line 채널에 강조 표시된 비밀 키의 스크린샷

3장 - Azure Web App Bot Service 봇 게시

이제 서비스가 준비되었으므로 이전에 빌드한 봇 코드를 새로 만든 웹앱 Bot Service 게시해야 합니다.

참고

봇 솔루션/코드를 변경할 때마다 Azure 서비스에 봇을 게시해야 합니다.

  1. 이전에 만든 Visual Studio 솔루션에 돌아가기.

  2. MyBot 프로젝트를 마우스 오른쪽 단추로 클릭하고 솔루션 탐색기게시를 클릭합니다.

    마우스 오른쪽 단추 클릭 후 'MyBot' 프로젝트 드롭다운 메뉴를 보여 주는 스크린샷

  3. 게시 대상 선택 페이지에서 App Service 클릭한 다음 기존 항목을 선택하고 마지막으로 프로필 만들기를 클릭합니다(이 항목이 표시되지 않으면 게시 단추와 함께 드롭다운 화살표를 클릭해야 할 수 있음).

    'App Service', '기존 항목 선택' 및 '프로필 만들기'가 강조 표시된 게시 대상 선택 페이지를 보여 주는 스크린샷

  4. Microsoft 계정에 아직 로그인하지 않은 경우 여기에서 로그인해야 합니다.

  5. 게시 페이지에서 Web App Bot Service 만들기에 사용한 것과 동일한 구독을 설정해야 합니다. 그런 다음 보기를리소스 그룹으로 설정하고 드롭다운 폴더 구조에서 이전에 만든 리소스 그룹을 선택합니다. 확인을 클릭합니다.

    웹앱 Bot Service 만들기에 사용된 구독이 선택된 App Service 창을 보여 주는 스크린샷

  6. 이제 게시 단추를 클릭하고 봇이 게시될 때까지 기다립니다(몇 분 정도 걸릴 수 있음).

    게시 단추가 있는 게시 창을 보여 주는 스크린샷

4장 - Unity 프로젝트 설정

다음은 혼합 현실로 개발하기 위한 일반적인 설정이며, 따라서 다른 프로젝트에 적합한 템플릿입니다.

  1. Unity를 열고 새로 만들기를 클릭합니다.

    오른쪽 위에 '새로 만들기' 프로젝트 아이콘이 강조 표시된 Unity 프로젝트 창을 보여 주는 스크린샷

  2. 이제 Unity 프로젝트 이름을 제공해야 합니다. HoloLens 봇을 삽입합니다. 프로젝트 템플릿이 3D로 설정되어 있는지 확인합니다. 위치를 적절한 위치로 설정합니다(루트 디렉터리에 더 가까울수록 좋습니다). 그런 다음 프로젝트 만들기를 클릭합니다.

    강조 표시된 새 Unity 프로젝트 이름 필드를 보여 주는 스크린샷

  3. Unity가 열려 있는 경우 기본 스크립트 편집 기가 Visual Studio로 설정되어 있는지 확인하는 것이 좋습니다. 기본 설정 편집 > 으로 이동한 다음 새 창에서 외부 도구로 이동합니다. 외부 스크립트 편집기를 Visual Studio 2017로 변경합니다. 기본 설정 창을 닫습니다.

    필요한 설정이 있는 Unity 기본 설정 창을 보여 주는 스크린샷

  4. 다음으로 파일 > 빌드 설정으로 이동하여 유니버설 Windows 플랫폼 선택한 다음 플랫폼 전환 단추를 클릭하여 선택 항목을 적용합니다.

    '플랫폼 전환' 단추가 강조 표시된 빌드 설정 창을 보여 주는 스크린샷

  5. 파일 > 빌드 설정에 있는 동안 다음을 확인합니다.

    1. 대상 디바이스HoloLens로 설정됩니다.

      몰입형 헤드셋의 경우 대상 디바이스모든 디바이스로 설정합니다.

    2. 빌드 유형D3D로 설정됨

    3. SDK최신 설치됨으로 설정됨

    4. Visual Studio 버전설치된 최신 버전으로 설정됨

    5. 빌드 및 실행로컬 컴퓨터로 설정됩니다.

    6. 장면을 저장하고 빌드에 추가합니다.

      1. 열린 장면 추가를 선택하여 이 작업을 수행합니다. 저장 창이 나타납니다.

        '열린 장면 추가' 단추가 강조 표시된 빌드 설정 창을 보여 주는 스크린샷.

      2. 이에 대한 새 폴더와 이후의 장면을 만든 다음 새 폴더 단추를 선택하여 새 폴더 를 만들고 이름을 Scenes로 지정 합니다.

        새 'Scenes' 폴더 만들기를 보여 주는 스크린샷

      3. 새로 만든 Scenes 폴더를 연 다음 파일 이름: 텍스트 필드에 BotScene을 입력한 다음 저장을 클릭합니다.

        Scenes 폴더 및 새로 만든 파일이 저장되는 스크린샷

    7. 빌드 설정의 나머지 설정은 현재 기본값으로 남아 있어야 합니다.

  6. 빌드 설정 창에서 플레이어 설정 단추를 클릭하면 Inspector가 있는 공간에서 관련 패널이 열립니다.

    검사기 탭의 빌드 설정 창을 보여 주는 스크린샷

  7. 이 패널에서 몇 가지 설정을 확인해야 합니다.

    1. 기타 설정 탭에서 다음을 수행합니다.

      1. 스크립팅 런타임 버전은실험적이어야 합니다(NET 4.6 등가). 이를 변경하려면 편집기를 다시 시작해야 합니다.

      2. 백 엔드 스크립팅.NET이어야 합니다.

      3. API 호환성 수준은.NET 4.6이어야 합니다.

        필요한 설정이 있는 기타 설정 탭을 보여 주는 스크린샷

    2. 게시 설정 탭의 기능에서 다음을 검사.

      • InternetClient

      • 마이크

        게시 설정 탭에서 사용하도록 설정된 'InternetClient' 및 '마이크'를 보여 주는 스크린샷.

    3. 패널 아래쪽의 XR 설정(게시 설정 아래에 있음)에서 Virtual Reality Supported를 체크하고 Windows Mixed Reality SDK가 추가되었는지 확인합니다.

      Virtual Reality 지원 사용 및 추가된 SDK Windows Mixed Reality 보여 주는 스크린샷

  8. 빌드 설정으로 돌아가서 Unity C# 프로젝트는 더 이상 회색으로 표시되지 않습니다. 이 옆에 있는 확인란을 선택합니다.

  9. 빌드 설정 창을 닫습니다.

  10. 장면 및 프로젝트를 저장합니다(파일 > 저장 장면/파일 > 저장 프로젝트).

5장 - 카메라 설정

중요

이 과정의 Unity 설정 구성 요소를 건너뛰고 코드를 계속 진행하려면 이 Azure-MR-312-Package.unitypackage를 자유롭게 다운로드하고 사용자 지정 패키지로 프로젝트로 가져온 다음 7장에서 계속 진행하세요.

  1. 계층 구조 패널에서 기본 카메라를 선택합니다.

  2. 선택한 후에는 검사기 패널에서 주 카메라의 모든 구성 요소를 볼 수 있습니다.

    1. Camera 개체의 이름은 Main Camera여야 합니다(맞춤법 유의).
    2. Main Camera 태그MainCamera 로 설정해야 합니다(맞춤법 참고).
    3. 변환 위치0, 0, 0으로 설정되어 있는지 확인합니다.
    4. 플래그 지우기를 단색으로 설정합니다.
    5. 카메라 구성 요소의 배경색을 검은색, 알파 0(16진수 코드: #00000000)으로 설정합니다.

    검사기 패널에서 주 카메라의 모든 구성 요소를 보여 주는 스크린샷

6장 - Newtonsoft 라이브러리 가져오기

수신되어 Bot Service 전송된 개체를 역직렬화하고 직렬화하려면 Newtonsoft 라이브러리를 다운로드해야 합니다. 여기에서 올바른 Unity 폴더 구조로 구성된 호환되는 버전을 찾을 수 있습니다.

Newtonsoft 라이브러리를 프로젝트로 가져오려면 이 과정과 함께 제공된 Unity 패키지를 사용합니다.

  1. 자산 패키지 사용자지정 패키지>가져오기메뉴 옵션을 사용하여 .unitypackage를 Unity에 추가합니다>.

    '패키지 가져오기' 다음 '사용자 지정 패키지'가 선택된 자산 드롭다운 메뉴를 보여 주는 스크린샷

  2. 팝업되는 Unity 패키지 가져오기 상자에서 플러그 인 (및 포함) 아래의 모든 항목이 선택되어 있는지 확인합니다.

    '플러그 인'이 선택된 Unity 패키지 가져오기 팝업 상자의 스크린샷

  3. 가져오기 단추를 클릭하여 프로젝트에 항목을 추가합니다.

  4. 프로젝트 보기의 플러그 인 아래에 있는 Newtonsoft 폴더로 이동하여 Newtonsoft 플러그 인을 선택합니다.

    프로젝트 보기의 Newtonsoft 폴더를 보여 주는 스크린샷

  5. Newtonsoft 플러그 인을 선택한 상태에서 모든 플랫폼선택 취소되어 있는지 확인하고 WSAPlayer선택 취소되어 있는지 확인하고 적용을 클릭합니다. 파일이 올바르게 구성되었는지 확인하기 위한 것입니다.

    Newtonsoft 플러그 인에 대한 올바른 선택을 보여 주는 스크린샷.

    참고

    이러한 플러그 인을 표시하면 Unity 편집기에서만 사용하도록 구성됩니다. WSA 폴더에는 프로젝트를 Unity에서 내보낸 후 사용할 다른 집합이 있습니다.

  6. 다음으로 Newtonsoft 폴더 내에서 WSA 폴더를 열어야 합니다. 방금 구성한 동일한 파일의 복사본이 표시됩니다. 파일을 선택한 다음, 검사기에서 다음을 확인합니다.

    • 모든 플랫폼선택 취소됨
    • WSAPlayer확인됨
    • Dont process선택됨

    WSA 폴더의 Newtonsoft 플러그 인에 대한 올바른 선택을 보여 주는 스크린샷

7장 - BotTag 만들기

  1. BotTag라는 새 Tag 개체를 만듭니다. 장면에서 기본 카메라를 선택합니다. 검사기 패널에서 태그 드롭다운 메뉴를 클릭합니다. 태그 추가를 클릭합니다.

    '태그 추가'가 강조 표시된 검사기 패널의 주 카메라 태그 드롭다운 메뉴 스크린샷

  2. 기호를 + 클릭합니다. 새 태그 이름을 BotTag, Save로 지정합니다.

    새 BotTag 이름 및 기호 및 저장 단추가 있는 검사기 패널의 스크린샷

경고

기본 카메라에 BotTag를 적용하지 마세요. 실수로 이 작업을 수행한 경우 Main Camera 태그를 MainCamera로 다시 변경해야 합니다.

8장 - BotObjects 클래스 만들기

만들어야 하는 첫 번째 스크립트는 BotObjects 클래스입니다. 이 클래스는 일련의 다른 클래스 개체를 동일한 스크립트 내에 저장하고 장면의 다른 스크립트에서 액세스할 수 있도록 만든 빈 클래스입니다.

이 클래스의 생성은 전적으로 아키텍처 선택이며, 이러한 개체는 이 과정의 뒷부분에서 만들 Bot 스크립트에서 호스트될 수 있습니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. 프로젝트 패널을 마우스 오른쪽 단추로 클릭한 다음 폴더 만들기>를 클릭합니다. 폴더 이름을 Scripts로 지정합니다.

    scripts 폴더를 만듭니다.

  2. Scripts 폴더를 두 번 클릭하여 엽니다. 그런 다음 해당 폴더 내에서 마우스 오른쪽 단추를 클릭하고 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. C# 스크립트 만들기 >폴더 내부를 마우스 오른쪽 단추로 클릭합니다. 스크립트 GazeInput을 호출합니다.

  3. GazeInput 스크립트를 두 번 클릭하여 Visual Studio에서 엽니다.

  4. 클래스 이름 맨 위에 다음 줄을 삽입합니다.

    /// <summary>
    /// Class responsible for the User's gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    
  5. 그런 다음 Start() 메서드 위에 GazeInput 클래스 내에 다음 변수를 추가합니다.

        [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. 주 카메라에서 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 Service 메시지를 보내기 위해 SendMessageToBot() 코루틴은 사용자가 보낸 데이터로 Bot Framework에서 인식하는 개체인 활동을 빌드합니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. Scripts 폴더를 두 번 클릭하여 엽니다.

  2. Scripts 폴더 내부를 마우스 오른쪽 단추로 클릭하고 C# 스크립트 만들기>를 클릭합니다. 스크립트 이름을 봇으로 지정 합니다.

  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;
    

    참고

    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. 음성 캡처가 시작되고 끝날 때 음성 라이브러리에서 호출하는 두 처리기를 추가합니다. 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 App Bot Service 보내는 코루틴을 호출합니다.

        /// <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;
        }
    

    참고

    Unity 편집기 콘솔 내에서 SceneOrganiser 클래스 누락에 대한 오류가 표시 될 수 있습니다. 자습서의 뒷부분에서 이 클래스를 만들 예정이므로 이 메시지를 무시합니다.

  13. Unity로 돌아가기 전에 Visual Studio에서 변경 내용을 저장해야 합니다.

11장 - Interactions 클래스 만들기

지금 만들려는 클래스를 상호 작용이라고 합니다. 이 클래스는 사용자의 HoloLens 탭 입력을 검색하는 데 사용됩니다.

사용자가 장면에서 Bot 개체를 보면서 탭하고 봇이 음성 입력을 들을 준비가 되면 Bot 개체는 색을 빨간색 으로 변경하고 음성 입력을 듣기 시작합니다.

이 클래스는 GazeInput 클래스에서 상속되므로 Base 사용으로 표시된 해당 클래스의 Start() 메서드 및 변수를 참조할 수 있습니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. Scripts 폴더를 두 번 클릭하여 엽니다.

  2. Scripts 폴더 내부를 마우스 오른쪽 단추로 클릭하고 C# 스크립트 만들기>를 클릭합니다. 스크립트 이름을 상호 작용으로 지정합니다.

  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라고 합니다. 이 클래스는 기본 카메라에 구성 요소 및 스크립트를 추가하고 장면에 적절한 개체를 만들어 장면을 프로그래밍 방식으로 설정합니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. Scripts 폴더를 두 번 클릭하여 엽니다.

  2. Scripts 폴더 내부를 마우스 오른쪽 단추로 클릭하고 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. 장면에서 Bot 개체를 만들고 매개 변수 및 구성 요소를 설정하는 다음 메서드를 추가합니다.

        /// <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 편집기에서 Scripts 폴더의 SceneOrganiser 스크립트를 주 카메라로 끌어옵니다. 이제 아래 이미지와 같이 장면 주최자 구성 요소가 주 카메라 개체에 표시됩니다.

    Unity 편집기에서 기본 카메라 개체에 추가되는 장면 이끌이 스크립트를 보여 주는 스크린샷

챕터 13 – 빌드 전

애플리케이션에 대한 철저한 테스트를 수행하려면 HoloLens에 테스트용으로 로드해야 합니다. 이렇게 하기 전에 다음을 확인합니다.

  • 4장에 언급된 모든 설정이 올바르게 설정됩니다.
  • SceneOrganiser 스크립트는 Main Camera 개체에 연결됩니다.
  • Bot 클래스에서 botSecret 변수에 봇 비밀 키를 삽입했는지 확인합니다.

챕터 14 – HoloLens에 빌드 및 테스트용 로드

이제 이 프로젝트의 Unity 섹션에 필요한 모든 항목이 완료되었으므로 Unity에서 빌드해야 합니다.

  1. 빌드 설정, 파일 > 빌드 설정...으로 이동합니다.

  2. 빌드 설정 창에서 빌드를 클릭합니다.

    Unity에서 앱 빌드

  3. 아직 없는 경우 Unity C# 프로젝트를 선택합니다.

  4. 빌드를 클릭한 다음 Unity는 파일 탐색기 창을 시작합니다. 여기서 앱을 빌드할 폴더를 만들어야 합니다. 이제 해당 폴더를 만들고 이름을 앱으로 지정 합니다. 그런 다음 폴더를 선택한 상태에서 폴더 선택을 클릭합니다.

  5. Unity는 App 폴더에 프로젝트 빌드를 시작합니다.

  6. Unity 빌드가 완료되면(다소 시간이 걸릴 수 있음) 빌드 위치에서 파일 탐색기 창이 열립니다(작업 표시줄을 검사 항상 창 위에 표시되지는 않지만 새 창이 추가되었음을 알려 줍니다).

15장 – HoloLens에 배포

HoloLens에 배포하려면 다음을 수행합니다.

  1. HoloLens의 IP 주소(원격 배포의 경우)가 필요하며 HoloLens가 개발자 모드에 있는지 확인해야 합니다. 가상 하드 디스크 파일에 대한 중요 정보를 제공하려면

    1. HoloLens를 착용하는 동안 설정을 엽니다.
    2. 네트워크 & 인터넷 > Wi-Fi > 고급 옵션으로 이동합니다.
    3. IPv4 주소를 기록해 둡니다.
    4. 다음으로 설정으로 다시 이동한 다음 개발자용 & 보안 > 업데이트로 이동합니다.
    5. 개발자 모드를 설정합니다.
  2. 새 Unity 빌드( App 폴더)로 이동하여 Visual Studio를 사용하여 솔루션 파일을 엽니다.

  3. 솔루션 구성에서 디버그를 선택합니다.

  4. 솔루션 플랫폼에서x86, 원격 머신을 선택합니다.

    Visual Studio에서 솔루션을 배포합니다.

  5. 빌드 메뉴로 이동하여 솔루션 배포를 클릭하여 HoloLens에 애플리케이션을 테스트용으로 로드합니다.

  6. 이제 시작 준비가 된 HoloLens에 설치된 앱 목록에 앱이 표시됩니다.

    참고

    몰입형 헤드셋에 배포하려면 솔루션 플랫폼을로컬 머신으로 설정하고 구성을디버그로 설정하고 x86플랫폼으로 설정합니다. 그런 다음 빌드 메뉴를 사용하여 로컬 머신에 배포하고 솔루션 배포를 선택합니다.

16장 - HoloLens에서 애플리케이션 사용

  • 애플리케이션을 시작하면 봇이 앞에 파란색 구로 표시됩니다.

  • 구를 응시하는 동안 탭 제스처 를 사용하여 대화를 시작합니다.

  • 대화가 시작될 때까지 기다립니다(UI는 메시지가 표시될 때 표시됨). 봇에서 소개 메시지를 받으면 봇을 다시 탭하여 빨간색으로 변하고 음성을 듣기 시작합니다.

  • 통신을 중지하면 애플리케이션이 봇에 메시지를 보내고 UI에 표시될 응답을 즉시 받게 됩니다.

  • 프로세스를 반복하여 봇에 더 많은 메시지를 보냅니다(메시지를 감지할 때마다 탭해야 합니다).

이 대화에서는 봇이 정보(사용자 이름)를 유지하는 동시에 알려진 정보(예: 재고가 있는 항목)를 제공하는 방법을 보여 줍니다.

봇에게 질문할 몇 가지 질문:

what do you sell? 

how much are umbrellas?

how much are raincoats?

완료된 웹앱 봇(v4) 애플리케이션

축하합니다. v4를 Microsoft Bot Framework Azure Web App Bot을 활용하는 혼합 현실 앱을 빌드했습니다.

최종 제품

보너스 연습

연습 1

이 랩의 대화 구조는 매우 기본입니다. Microsoft LUIS를 사용하여 봇 자연어 이해 기능을 제공합니다.

연습 2

이 예제에는 대화 종료 및 새 대화 다시 시작이 포함되지 않습니다. 봇 기능을 완료하려면 대화 종료를 구현해 보세요.