Поделиться через


311. HoloLens (1-го поколения) и Azure — Microsoft Graph

Примечание.

Руководства Mixed Reality Academy были разработаны для иммерсивных гарнитур HoloLens (1-го поколения) и иммерсивных гарнитур Mixed Reality. Поэтому мы считаем, что важно оставить эти руководства для разработчиков, которые ищут рекомендации по разработке для этих устройств. Данные руководства не будут обновляться с учетом последних наборов инструментов или возможностей взаимодействия для HoloLens 2. Они будут сохранены для работы на поддерживаемых устройствах. В будущем будет появиться новая серия учебников, которые будут размещены в будущем, которые продемонстрировали, как разрабатывать для HoloLens 2. Это уведомление будет обновлено со ссылкой на эти учебники при публикации.

В этом курсе вы узнаете, как использовать Microsoft Graph для входа в учетную запись Майкрософт с помощью безопасной проверки подлинности в приложении смешанной реальности. Затем вы получите и отобразите запланированные собрания в интерфейсе приложения.

Снимок экрана: запланированные собрания в интерфейсе приложения.

Microsoft Graph — это набор API- интерфейсов, предназначенных для обеспечения доступа ко многим службам Майкрософт. Корпорация Майкрософт описывает Microsoft Graph как матрицу ресурсов, подключенных по связям, то есть позволяет приложению получать доступ ко всем типам подключенных пользовательских данных. Дополнительные сведения см. на странице Microsoft Graph.

Разработка будет включать создание приложения, в котором пользователю будет предложено посмотреть, а затем коснуться сферы, которая предложит пользователю безопасно войти в учетную запись Майкрософт. После входа в свою учетную запись пользователь сможет просмотреть список собраний, запланированных на день.

Завершив этот курс, у вас будет приложение смешанной реальности HoloLens, которое сможет выполнить следующие действия:

  1. С помощью жеста "Коснитесь" коснитесь объекта, который предложит пользователю войти в учетную запись Майкрософт (переход из приложения для входа, а затем снова в приложение).
  2. Просмотрите список собраний, запланированных на день.

В приложении вы узнаете, как интегрировать результаты с проектом. Этот курс предназначен для обучения интеграции службы Azure с проектом Unity. Это ваша задача использовать знания, полученные от этого курса, чтобы улучшить ваше приложение смешанной реальности.

Поддержка устройств

Курс HoloLens Иммерсивные гарнитуры
MR и Azure 311: Microsoft Graph ✔️

Предварительные требования

Примечание.

Это руководство предназначено для разработчиков, имеющих базовый опыт работы с Unity и C#. Также помните, что предварительные требования и письменные инструкции в этом документе представляют тестируемые и проверенные на момент написания статьи (июль 2018 г.). Вы можете использовать последнее программное обеспечение, как указано в статье об установке инструментов , хотя не следует предполагать, что информация в этом курсе будет идеально соответствовать тому, что вы найдете в новом программном обеспечении, чем указано ниже.

Для этого курса рекомендуется использовать следующее оборудование и программное обеспечение:

Перед началом работы

  1. Чтобы избежать проблем с сборкой этого проекта, настоятельно рекомендуется создать проект, упомянутый в этом руководстве, в корневой или почти корневой папке (длинные пути к папкам могут вызвать проблемы во время сборки).
  2. Настройте и проверьте HoloLens. Если вам нужна поддержка настройки HoloLens, обязательно посетите статью о настройке HoloLens.
  3. Рекомендуется выполнять калибровку и настройку датчика при разработке нового приложения HoloLens (иногда это может помочь выполнить эти задачи для каждого пользователя).

Дополнительные сведения о калибровке см. по этой ссылке в статье о калибровке HoloLens.

Дополнительные сведения о настройке датчика см. по этой ссылке в статье по настройке датчика HoloLens.

Глава 1. Создание приложения на портале регистрации приложений

Для начала необходимо создать и зарегистрировать приложение на портале регистрации приложений.

В этой главе вы также найдете ключ службы, позволяющий вызывать Microsoft Graph для доступа к содержимому учетной записи.

  1. Перейдите на портал регистрации приложений Майкрософт и войдите в систему с помощью учетной записи Майкрософт. После входа вы будете перенаправлены на портал регистрации приложений.

  2. В разделе "Мои приложения" нажмите кнопку "Добавить приложение".

    Снимок экрана, на котором показано, где выбрать пункт

    Внимание

    Портал регистрации приложений может выглядеть по-разному в зависимости от того, работали ли вы с Microsoft Graph ранее. На снимках экрана ниже показаны разные версии.

  3. Добавьте имя приложения и нажмите кнопку "Создать".

    Снимок экрана: место добавления имени приложения.

  4. После создания приложения вы будете перенаправлены на главную страницу приложения. Скопируйте идентификатор приложения и запишите это значение где-то безопасно, вы будете использовать его в ближайшее время в коде.

    Снимок экрана: место просмотра идентификатора приложения.

  5. В разделе "Платформы" убедитесь, что собственное приложение отображается. Если не щелкните "Добавить платформу" и выберите "Собственное приложение".

    Снимок экрана: раздел

  6. Прокрутите вниз на той же странице и в разделе " Разрешения Microsoft Graph" вам потребуется добавить дополнительные разрешения для приложения. Щелкните "Добавить" рядом с делегированными разрешениями.

    Снимок экрана: место добавления рядом с делегированными разрешениями.

  7. Так как приложение будет получать доступ к календарю пользователя, установите флажок "Календари.Чтение " и нажмите кнопку "ОК".

    Снимок экрана: флажок Calendars.Read.

  8. Прокрутите страницу вниз и нажмите кнопку "Сохранить ".

    Снимок экрана, на котором показано, где выбрать

  9. Сохранение будет подтверждено, и вы можете выйти из портала регистрации приложений.

Глава 2. Настройка проекта Unity

Ниже приведена типичная настройка для разработки с смешанной реальностью, и таким образом является хорошим шаблоном для других проектов.

  1. Откройте Unity и нажмите кнопку "Создать".

    Снимок экрана: интерфейс Unity.

  2. Необходимо указать имя проекта Unity. Вставьте MSGraphMR. Убедитесь, что шаблон проекта имеет значение 3D. Задайте расположение в нужном месте (помните, что ближе к корневым каталогам лучше). Затем нажмите кнопку "Создать проект".

    Снимок экрана, на котором показано, где выбрать команду

  3. При открытии Unity стоит проверить, установлен ли редактор скриптов по умолчанию в Visual Studio. Перейдите к разделу "Изменить>параметры", а затем в новом окне перейдите к внешним средствам. Измените внешний редактор скриптов на Visual Studio 2017. Закройте окно параметров.

    Снимок экрана, на котором показано, где задать для редактора внешних скриптов значение Visual Studio 2017.

  4. Перейдите к параметрам сборки файлов>и выберите универсальная платформа Windows, а затем нажмите кнопку "Переключить платформу", чтобы применить выбранный вариант.

    Снимок экрана, на котором показано, где выбрать переключатель платформы.

  5. Хотя все еще в параметрах сборки файлов>убедитесь, что:

    1. Целевое устройство имеет значение HoloLens

    2. Тип сборки имеет значение D3D

    3. Для пакета SDK установлено значение "Последняя версия"

    4. Версия Visual Studio установлена в качестве последней версии

    5. Для сборки и запуска задано значение Local Machine

    6. Сохраните сцену и добавьте ее в сборку.

      1. Для этого выберите "Добавить открытые сцены". Откроется окно сохранения.

        Снимок экрана, на котором показано, где выбрать

      2. Создайте новую папку для этого и любого будущего сцены. Нажмите кнопку "Создать папку ", чтобы создать новую папку, назовите ее Сцены.

        Снимок экрана: место для имени новой папки.

      3. Откройте только что созданную папку "Сцены" , а затем в поле "Файл": текстовое поле, введите MR_ComputerVisionScene, а затем нажмите кнопку "Сохранить".

        Снимок экрана, на котором показано, где ввести имя файла.

        Внимание

        Помните, что сцены Unity необходимо сохранить в папке Assets , так как они должны быть связаны с проектом Unity. Создание папки сцен (и других аналогичных папок) — это типичный способ структурирования проекта Unity.

    7. Остальные параметры в параметрах сборки должны оставаться по умолчанию.

  6. В окне "Параметры сборки" нажмите кнопку "Параметры проигрывателя", откроется связанная панель в пространстве, где находится инспектор.

    Снимок экрана: диалоговое окно

  7. На этой панели необходимо проверить несколько параметров:

    1. На вкладке "Другие параметры" :

      1. Версия среды выполнения сценариев должна быть экспериментальной (.NET 4.6 эквивалентной), что приведет к перезапуску редактора.

      2. Серверная часть скриптов должна быть .NET

      3. Уровень совместимости API должен быть .NET 4.6

        Снимок экрана: место проверки уровня совместимости API.

    2. На вкладке "Параметры публикации" в разделе "Возможности" проверьте:

      • InternetClient;

        Снимок экрана, на котором показано, где выбрать параметр InternetClient.

    3. Далее вниз по панели в параметрах XR (приведенных ниже параметров публикации) проверьте поддерживаемую виртуальную реальность, убедитесь, что пакет SDK для Windows Смешанная реальность добавлен.

      Снимок экрана: место добавления пакета SDK для Windows Смешанная реальность.

  8. Вернувшись в параметры сборки, проекты C# Unity больше не будут серыми. Установите флажок рядом с этим.

  9. Закройте окно Build Settings (Параметры сборки).

  10. Сохраните сцену и проект (FILE>SAVE SCENE / FILE>SAVE PROJECT).

Глава 3. Импорт библиотек в Unity

Внимание

Если вы хотите пропустить компонент настройки Unity этого курса и продолжить прямо в коде, вы можете скачать этот пакет Azure-MR-311.unitypackage, импортировать его в проект в качестве пользовательского пакета, а затем продолжить с главы 5.

Чтобы использовать Microsoft Graph в Unity, необходимо использовать библиотеку DLL Microsoft.Identity.Client . Однако для использования пакета SDK Microsoft Graph требуется добавление пакета NuGet после сборки проекта Unity (то есть редактирование проекта после сборки проекта). Считается проще импортировать необходимые библиотеки DLL непосредственно в Unity.

Примечание.

В настоящее время в Unity существует известная проблема, которая требует перенастройки подключаемых модулей после импорта. Эти действия (4 – 7 в этом разделе) больше не потребуются после устранения ошибки.

Чтобы импортировать Microsoft Graph в собственный проект, скачайте файл MSGraph_LabPlugins.zip. Этот пакет был создан с версиями проверенных библиотек.

Если вы хотите узнать больше о том, как добавить пользовательские библиотеки DLL в проект Unity, перейдите по этой ссылке.

Чтобы импортировать пакет, выполните следующие действия.

  1. Добавьте пакет Unity в Unity с помощью параметра меню "Импорт>пользовательского пакета пакетов ресурсов".> Выберите только что скачанный пакет.

  2. В появившемся окне "Импорт пакета Unity" убедитесь, что выбраны все подключаемые модули (и в том числе).

    Снимок экрана: выбранные параметры конфигурации в разделе

  3. Нажмите кнопку "Импорт", чтобы добавить элементы в проект.

  4. Перейдите в папку MSGraph в разделе "Подключаемые модули" на панели проекта и выберите подключаемый модуль Microsoft.Identity.Client.

    Снимок экрана: подключаемый модуль Microsoft.Identity.Client.

  5. Выбрав подключаемый модуль, убедитесь, что любая платформа снята, а затем убедитесь, что WSAPlayer также снят, а затем нажмите кнопку "Применить". Это просто, чтобы убедиться, что файлы настроены правильно.

    Снимок экрана, на котором показано, где можно подтвердить, что все платформы и WSAPlayer не проверяются.

    Примечание.

    Пометка этих подключаемых модулей настраивает их только в редакторе Unity. В папке WSA есть другой набор БИБЛИОТЕК DLL, который будет использоваться после экспорта проекта из Unity в качестве универсального приложения Windows.

  6. Затем необходимо открыть папку WSA в папке MSGraph . Вы увидите копию того же файла, который вы только что настроили. Выберите файл, а затем в инспекторе:

    • Убедитесь, что любая платформа снята и проверяется только WSAPlayer.

    • Убедитесь, что пакет SDK имеет значение UWP, а серверная часть скрипта имеет значение Dot Net

    • Убедитесь, что не выполняется проверка процесса.

      Снимок экрана, на котором показано, что выбран параметр

  7. Щелкните Применить.

Глава 4. Настройка камеры

Во время этой главы вы настроите главную камеру сцены:

  1. На панели иерархии выберите основную камеру.

  2. После выбора вы увидите все компоненты основной камеры на панели инспектора .

    1. Объект "Камера" должен называться Main Camera (обратите внимание на орфографию!)

    2. Тег основной камеры должен иметь значение MainCamera (обратите внимание на орфографию!)

    3. Убедитесь, что положение преобразования равно 0, 0, 0

    4. Задайте для цвета сплошные флаги очистки

    5. Задайте цвет фона компонента камеры черным, Альфа 0 (шестнадцатеричный код: #000000000)

      Снимок экрана, на котором показано, где задать цвет фона.

  3. Последняя структура объекта на панели иерархии должна быть похожа на ту, которая показана на рисунке ниже:

    Снимок экрана: окончательная структура объекта на панели иерархии.

Глава 5. Создание класса MeetingsUI

Первый скрипт, который необходимо создать, — MeetingsUI, который отвечает за размещение и заполнение пользовательского интерфейса приложения (приветственное сообщение, инструкции и сведения о собраниях).

Чтобы создать этот класс, выполните указанные ниже действия.

  1. Щелкните правой кнопкой мыши папку "Ресурсы" на панели проекта, а затем выберите "Создать>папку". Назовите скрипты папок.

    Снимок экрана: расположение папки Снимок экрана: место создания папки

  2. Откройте папку "Скрипты", а затем в этой папке щелкните правой кнопкой мыши и создайте>скрипт C#. Назовите скрипт MeetingsUI.

    Снимок экрана: место создания папки MeetingsUI.

  3. Дважды щелкните новый скрипт MeetingsUI , чтобы открыть его с помощью Visual Studio.

  4. Вставьте следующие пространства имен:

    using System;
    using UnityEngine;
    
  5. Внутри класса вставляются следующие переменные:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static MeetingsUI Instance;
    
        /// <summary>
        /// The 3D text of the scene
        /// </summary>
        private TextMesh _meetingDisplayTextMesh;
    
  6. Затем замените метод Start() и добавьте метод Awake( ). Они будут вызываться при инициализации класса:

        /// <summary>
        /// Called on initialization
        /// </summary>
        void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        void Start ()
        {
            // Creating the text mesh within the scene
            _meetingDisplayTextMesh = CreateMeetingsDisplay();
        }
    
  7. Добавьте методы, ответственные за создание пользовательского интерфейса собраний, и заполните его текущими собраниями при запросе:

        /// <summary>
        /// Set the welcome message for the user
        /// </summary>
        internal void WelcomeUser(string userName)
        {
            if(!string.IsNullOrEmpty(userName))
            {
                _meetingDisplayTextMesh.text = $"Welcome {userName}";
            }
            else 
            {
                _meetingDisplayTextMesh.text = "Welcome";
            }
        }
    
        /// <summary>
        /// Set up the parameters for the UI text
        /// </summary>
        /// <returns>Returns the 3D text in the scene</returns>
        private TextMesh CreateMeetingsDisplay()
        {
            GameObject display = new GameObject();
            display.transform.localScale = new Vector3(0.03f, 0.03f, 0.03f);
            display.transform.position = new Vector3(-3.5f, 2f, 9f);
            TextMesh textMesh = display.AddComponent<TextMesh>();
            textMesh.anchor = TextAnchor.MiddleLeft;
            textMesh.alignment = TextAlignment.Left;
            textMesh.fontSize = 80;
            textMesh.text = "Welcome! \nPlease gaze at the button" +
                "\nand use the Tap Gesture to display your meetings";
    
            return textMesh;
        }
    
        /// <summary>
        /// Adds a new Meeting in the UI by chaining the existing UI text
        /// </summary>
        internal void AddMeeting(string subject, DateTime dateTime, string location)
        {
            string newText = $"\n{_meetingDisplayTextMesh.text}\n\n Meeting,\nSubject: {subject},\nToday at {dateTime},\nLocation: {location}";
    
            _meetingDisplayTextMesh.text = newText;
        }
    
  8. Удалите метод Update() и сохраните изменения в Visual Studio перед возвратом в Unity.

Глава 6. Создание класса Graph

Следующий скрипт для создания — это скрипт Graph . Этот скрипт отвечает за выполнение вызовов для проверки подлинности пользователя и получения запланированных собраний в течение текущего дня из календаря пользователя.

Чтобы создать этот класс, выполните указанные ниже действия.

  1. Дважды щелкните папку "Скрипты" , чтобы открыть ее.

  2. Щелкните правой кнопкой мыши в папке "Скрипты", нажмите кнопку "Создать>скрипт C#". Присвойте графу скрипта имя.

  3. Дважды щелкните скрипт, чтобы открыть его с помощью Visual Studio.

  4. Вставьте следующие пространства имен:

    using System.Collections.Generic;
    using UnityEngine;
    using Microsoft.Identity.Client;
    using System;
    using System.Threading.Tasks;
    
    #if !UNITY_EDITOR && UNITY_WSA
    using System.Net.Http;
    using System.Net.Http.Headers;
    using Windows.Storage;
    #endif
    

    Внимание

    Вы заметите, что части кода в этом скрипте упаковываются в директивы precompile, это позволяет избежать проблем с библиотеками при создании решения Visual Studio.

  5. Удалите методы Start() и Update(), так как они не будут использоваться.

  6. Вне класса Graph вставьте следующие объекты, необходимые для десериализации объекта JSON, представляющего ежедневные запланированные собрания:

    /// <summary>
    /// The object hosting the scheduled meetings
    /// </summary>
    [Serializable]
    public class Rootobject
    {
        public List<Value> value;
    }
    
    [Serializable]
    public class Value
    {
        public string subject { get; set; }
        public StartTime start { get; set; }
        public Location location { get; set; }
    }
    
    [Serializable]
    public class StartTime
    {
        public string dateTime;
    
        private DateTime? _startDateTime;
        public DateTime StartDateTime
        {
            get
            {
                if (_startDateTime != null)
                    return _startDateTime.Value;
                DateTime dt;
                DateTime.TryParse(dateTime, out dt);
                _startDateTime = dt;
                return _startDateTime.Value;
            }
        }
    }
    
    [Serializable]
    public class Location
    {
        public string displayName { get; set; }
    }
    
  7. В классе Graph добавьте следующие переменные:

        /// <summary>
        /// Insert your Application Id here
        /// </summary>
        private string _appId = "-- Insert your Application Id here --";
    
        /// <summary>
        /// Application scopes, determine Microsoft Graph accessibility level to user account
        /// </summary>
        private IEnumerable<string> _scopes = new List<string>() { "User.Read", "Calendars.Read" };
    
        /// <summary>
        /// Microsoft Graph API, user reference
        /// </summary>
        private PublicClientApplication _client;
    
        /// <summary>
        /// Microsoft Graph API, authentication
        /// </summary>
        private AuthenticationResult _authResult;
    
    

    Примечание.

    Измените значение appId на идентификатор приложения, который вы указали в главе 1, шаг 4. Это значение должно совпадать с тем, что отображается на портале регистрации приложений на странице регистрации приложения.

  8. В классе Graph добавьте методы SignInAsync() и AquireTokenAsync(),которые побудят пользователя вставить учетные данные входа.

        /// <summary>
        /// Begin the Sign In process using Microsoft Graph Library
        /// </summary>
        internal async void SignInAsync()
        {
    #if !UNITY_EDITOR && UNITY_WSA
            // Set up Grap user settings, determine if needs auth
            ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
            string userId = localSettings.Values["UserId"] as string;
            _client = new PublicClientApplication(_appId);
    
            // Attempt authentication
            _authResult = await AcquireTokenAsync(_client, _scopes, userId);
    
            // If authentication is successful, retrieve the meetings
            if (!string.IsNullOrEmpty(_authResult.AccessToken))
            {
                // Once Auth as been completed, find the meetings for the day
                await ListMeetingsAsync(_authResult.AccessToken);
            }
    #endif
        }
    
        /// <summary>
        /// Attempt to retrieve the Access Token by either retrieving
        /// previously stored credentials or by prompting user to Login
        /// </summary>
        private async Task<AuthenticationResult> AcquireTokenAsync(
            IPublicClientApplication app, IEnumerable<string> scopes, string userId)
        {
            IUser user = !string.IsNullOrEmpty(userId) ? app.GetUser(userId) : null;
            string userName = user != null ? user.Name : "null";
    
            // Once the User name is found, display it as a welcome message
            MeetingsUI.Instance.WelcomeUser(userName);
    
            // Attempt to Log In the user with a pre-stored token. Only happens
            // in case the user Logged In with this app on this device previously
            try
            {
                _authResult = await app.AcquireTokenSilentAsync(scopes, user);
            }
            catch (MsalUiRequiredException)
            {
                // Pre-stored token not found, prompt the user to log-in 
                try
                {
                    _authResult = await app.AcquireTokenAsync(scopes);
                }
                catch (MsalException msalex)
                {
                    Debug.Log($"Error Acquiring Token: {msalex.Message}");
                    return _authResult;
                }
            }
    
            MeetingsUI.Instance.WelcomeUser(_authResult.User.Name);
    
    #if !UNITY_EDITOR && UNITY_WSA
            ApplicationData.Current.LocalSettings.Values["UserId"] = 
            _authResult.User.Identifier;
    #endif
            return _authResult;
        }
    
  9. Добавьте следующие два метода:

    1. BuildTodayCalendarEndpoint(), который создает URI, указывающий день и интервал времени, в котором извлекаются запланированные собрания.

    2. ListMeetingsAsync(), который запрашивает запланированные собрания из Microsoft Graph.

        /// <summary>
        /// Build the endpoint to retrieve the meetings for the current day.
        /// </summary>
        /// <returns>Returns the Calendar Endpoint</returns>
        public string BuildTodayCalendarEndpoint()
        {
            DateTime startOfTheDay = DateTime.Today.AddDays(0);
            DateTime endOfTheDay = DateTime.Today.AddDays(1);
            DateTime startOfTheDayUTC = startOfTheDay.ToUniversalTime();
            DateTime endOfTheDayUTC = endOfTheDay.ToUniversalTime();
    
            string todayDate = startOfTheDayUTC.ToString("o");
            string tomorrowDate = endOfTheDayUTC.ToString("o");
            string todayCalendarEndpoint = string.Format(
                "https://graph.microsoft.com/v1.0/me/calendarview?startdatetime={0}&enddatetime={1}",
                todayDate,
                tomorrowDate);
    
            return todayCalendarEndpoint;
        }
    
        /// <summary>
        /// Request all the scheduled meetings for the current day.
        /// </summary>
        private async Task ListMeetingsAsync(string accessToken)
        {
    #if !UNITY_EDITOR && UNITY_WSA
            var http = new HttpClient();
    
            http.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Bearer", accessToken);
            var response = await http.GetAsync(BuildTodayCalendarEndpoint());
    
            var jsonResponse = await response.Content.ReadAsStringAsync();
    
            Rootobject rootObject = new Rootobject();
            try
            {
                // Parse the JSON response.
                rootObject = JsonUtility.FromJson<Rootobject>(jsonResponse);
    
                // Sort the meeting list by starting time.
                rootObject.value.Sort((x, y) => DateTime.Compare(x.start.StartDateTime, y.start.StartDateTime));
    
                // Populate the UI with the meetings.
                for (int i = 0; i < rootObject.value.Count; i++)
                {
                    MeetingsUI.Instance.AddMeeting(rootObject.value[i].subject,
                                                rootObject.value[i].start.StartDateTime.ToLocalTime(),
                                                rootObject.value[i].location.displayName);
                }
            }
            catch (Exception ex)
            {
                Debug.Log($"Error = {ex.Message}");
                return;
            }
    #endif
        }
    
  10. Теперь вы выполнили скрипт Graph . Сохраните изменения в Visual Studio перед возвращением в Unity.

Глава 7. Создание скрипта GazeInput

Теперь вы создадите GazeInput. Этот класс обрабатывает и отслеживает взгляд пользователя, используя Raycast , поступающий из основной камеры, проецируя вперед.

Чтобы создать скрипт, выполните следующие действия.

  1. Дважды щелкните папку "Скрипты" , чтобы открыть ее.

  2. Щелкните правой кнопкой мыши в папке "Скрипты", нажмите кнопку "Создать>скрипт C#". Присвойте скрипту GazeInput.

  3. Дважды щелкните скрипт, чтобы открыть его с помощью Visual Studio.

  4. Измените код пространств имен, чтобы он соответствовал приведенному ниже, а также добавьте тег "[System.Serializable]" над классом GazeInput , чтобы его можно было сериализовать:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. В классе GazeInput добавьте следующие переменные:

        [Tooltip("Used to compare whether an object is to be interacted with.")]
        internal string InteractibleTag = "SignInButton";
    
        /// <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. Добавьте метод CreateCursor() для создания курсора HoloLens в сцене и вызовите метод из метода Start():

        /// <summary>
        /// Start method used upon initialisation.
        /// </summary>
        internal virtual void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
        /// <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 doesn't 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;
        }
    
  7. В следующих методах можно включить взгляд 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 'Gaze Exited' event.
                oldFocusedObject.SendMessage("OnGazeExited", SendMessageOptions.DontRequireReceiver);
            }
        }
    }
    
        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            oldFocusedObject = FocusedObject;
            RaycastHit hitInfo;
    
            // Initialise 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 'Gaze Entered' event.
                        FocusedObject.SendMessage("OnGazeEntered", 
                            SendMessageOptions.DontRequireReceiver);
                    }
                }
            }
        }
    
  8. Сохраните изменения в Visual Studio перед возвращением в Unity.

Глава 8. Создание класса Interactions

Теперь вам потребуется создать сценарий взаимодействия , который отвечает за следующее:

  • Обработка взаимодействия касания и взгляда камеры, что позволяет пользователю взаимодействовать с журналом в "button" в сцене.

  • Создание объекта "button" в сцене для взаимодействия с пользователем.

Чтобы создать скрипт, выполните следующие действия.

  1. Дважды щелкните папку "Скрипты" , чтобы открыть ее.

  2. Щелкните правой кнопкой мыши в папке "Скрипты", нажмите кнопку "Создать>скрипт C#". Присвойте скрипту имя взаимодействия.

  3. Дважды щелкните скрипт, чтобы открыть его с помощью Visual Studio.

  4. Вставьте следующие пространства имен:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Измените наследование класса Interaction с MonoBehaviour на GazeInput.

    Взаимодействие с общедоступным классом: MonoBehaviour

    public class Interactions : GazeInput
    
  6. В классе Взаимодействия вставьте следующую переменную:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Замените метод Start ; обратите внимание, что это метод переопределения, который вызывает метод класса "base" Gaze. 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();
    
            // Add the Graph script to this object
            gameObject.AddComponent<MeetingsUI>();
            CreateSignInButton();
        }
    
  8. Добавьте метод CreateSignInButton(), который создает экземпляр кнопки входа в сцену и задает его свойства:

        /// <summary>
        /// Create the sign in button object in the scene
        /// and sets its properties
        /// </summary>
        void CreateSignInButton()
        {
            GameObject signInButton = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
            Material mat = new Material(Shader.Find("Diffuse"));
            signInButton.GetComponent<Renderer>().material = mat;
            mat.color = Color.blue;
    
            signInButton.transform.position = new Vector3(3.5f, 2f, 9f);
            signInButton.tag = "SignInButton";
            signInButton.AddComponent<Graph>();
        }
    
  9. Добавьте метод GestureRecognizer_Tapped(), который будет отвечать на событие пользователя Tap.

        /// <summary>
        /// Detects the User Tap Input
        /// </summary>
        private void GestureRecognizer_Tapped(TappedEventArgs obj)
        {
            if(base.FocusedObject != null)
            {
                Debug.Log($"TAP on {base.FocusedObject.name}");
                base.FocusedObject.SendMessage("SignInAsync", SendMessageOptions.RequireReceiver);
            }
        }
    
  10. Удалите метод Update() и сохраните изменения в Visual Studio перед возвратом в Unity.

Глава 9. Настройка ссылок на скрипт

В этой главе необходимо поместить сценарий взаимодействия на главную камеру. Затем этот скрипт будет обрабатывать размещение других скриптов, где они должны быть.

  • В папке "Скрипты" на панели проекта перетащите взаимодействие скрипта в объект Main Camera, как показано ниже.

    Снимок экрана: место перетаскивания скрипта

Глава 10. Настройка тега

Код, обрабатывающий взгляд, будет использовать тег SignInButton для определения объекта, с которым пользователь будет взаимодействовать с входом в Microsoft Graph.

Чтобы создать тег, выполните следующие действия.

  1. В редакторе Unity щелкните основную камеру на панели иерархии.

  2. На панели инспектора щелкните тег MainCamera, чтобы открыть раскрывающийся список. Нажмите кнопку "Добавить тег" ...

    Снимок экрана: выделение тега добавления... выбор.

  3. Нажмите кнопку +.

    Снимок экрана: кнопка +.

  4. Напишите имя тега как SignInButton и нажмите кнопку "Сохранить".

    Снимок экрана: место добавления имени тега SignInButton.

Глава 11. Создание проекта Unity в UWP

Все необходимое для раздела Unity этого проекта завершено, поэтому пришло время создать его из Unity.

  1. Перейдите к параметрам сборки (параметры сборки файлов).>

    Снимок экрана: диалоговое окно

  2. Если это еще не так, обратитесь к проектам C# Unity.

  3. Нажмите кнопку " Создать". Unity запустит окно проводник, в котором необходимо создать, а затем выбрать папку для сборки приложения. Создайте папку и присвойте ей имя приложения. Затем с выбранной папкой приложения нажмите кнопку " Выбрать папку".

  4. Unity начнет создание проекта в папку приложения .

  5. После завершения сборки Unity (может потребоваться некоторое время), откроется окно проводник в расположении сборки (проверьте панель задач, так как она может не всегда отображаться над окнами, но уведомит вас о добавлении нового окна).

Глава 12. Развертывание в HoloLens

Чтобы развернуть в HoloLens, выполните приведенные действия.

  1. Вам потребуется IP-адрес HoloLens (для удаленного развертывания) и убедиться, что HoloLens находится в режиме разработчика. Для этого выполните указанные ниже действия.

    1. При ношении HoloLens откройте параметры.

    2. Переход к сети и расширенным параметрам Wi-Fi>в Интернете>

    3. Обратите внимание на IPv4-адрес .

    4. Затем вернитесь к параметрам, а затем в разделе "Обновление и безопасность>для разработчиков"

    5. Установите режим разработчика.

  2. Перейдите к новой сборке Unity (папке приложения) и откройте файл решения с помощью Visual Studio.

  3. В разделе "Конфигурация решения" выберите "Отладка".

  4. На платформе решения выберите x86, удаленный компьютер. Вам будет предложено вставить IP-адрес удаленного устройства (HoloLens, в этом случае вы указали).

    Снимок экрана, на котором показано, где выбрать x86 и удаленный компьютер.

  5. Перейдите в меню "Сборка" и щелкните "Развернуть решение ", чтобы загрузить неопубликованное приложение в HoloLens.

  6. Теперь приложение должно появиться в списке установленных приложений на HoloLens, готовых к запуску!

Приложение Microsoft Graph HoloLens

Поздравляем, вы создали приложение смешанной реальности, которое использует Microsoft Graph для чтения и отображения данных календаря пользователя.

Снимок экрана: готовое приложение смешанной реальности.

Дополнительные упражнения

Упражнение 1

Использование Microsoft Graph для отображения других сведений о пользователе

  • Электронная почта пользователя, номер телефона или рисунок профиля

Упражнение 1

Реализуйте голосовой элемент управления для навигации по пользовательскому интерфейсу Microsoft Graph.