HoloLens (1-го поколения) и Azure 305: функции и хранилище


Примечание

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


конечный продукт -start

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

Azure Functions — это служба Майкрософт, которая позволяет разработчикам запускать небольшие фрагменты кода, функции в Azure. Это позволяет делегировать работу в облако, а не локальное приложение, которое может иметь множество преимуществ. Azure Functions поддерживает несколько языков разработки, включая C#, F#, Node.js, Java и PHP. Дополнительные сведения см. в статье Azure Functions.

Служба хранилища Azure — это облачная служба Майкрософт, которая позволяет разработчикам хранить данные с помощью страховки, которая будет высокодоступной, безопасной, устойчивой, масштабируемой и избыточной. Это означает, что корпорация Майкрософт будет обрабатывать все задачи по обслуживанию и критическим проблемам. Дополнительные сведения см. в статье службы хранилища Azure.

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

  1. Разрешите пользователю смотреть вокруг сцены.
  2. Активирует порождение объектов, когда пользователь смотрит на трехмерную кнопку.
  3. Создаваемые объекты будут выбраны функцией Azure.
  4. По мере того как каждый объект создается, приложение будет хранить тип объекта в файле Azure, расположенном в службе хранилища Azure.
  5. При загрузке во второй раз данные файлов Azure будут извлечены и использованы для воспроизведения действий, порождаемых из предыдущего экземпляра приложения.

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

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

Курс HoloLens Иммерсивные гарнитуры
305. Смешанная реальность и Azure: функции и хранилище ✔️ ✔️

Примечание

Хотя этот курс в первую очередь ориентирован на Windows Mixed Reality иммерсивные гарнитуры (VR), вы также можете применить то, что вы узнаете в этом курсе, чтобы Microsoft HoloLens. При выполнении курса вы увидите заметки о любых изменениях, которые могут потребоваться для поддержки HoloLens.

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

Примечание

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

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

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

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

Глава 1. Портал Azure

Чтобы использовать службу хранилища Azure, необходимо создать и настроить учетную запись хранения в Azure-Portal.

  1. Войдите на портал Azure.

    Примечание

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

  2. После входа щелкните "Создать " в левом верхнем углу и найдите учетную запись хранения и нажмите клавишу ВВОД.

    Поиск в службе хранилища Azure

    Примечание

    Возможно, слово "Создать " заменено на "Создать ресурс" на новых порталах.

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

    создание службы

  4. После нажатия кнопки "Создать":

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

    2. Для модели развертывания выберите Resource Manager.

    3. Для типа учетной записи выберите "Хранилище" (общего назначения версии 1).

    4. Определите расположение для группы ресурсов (если вы создаете новую группу ресурсов). В идеале расположение будет находиться в регионе, где будет выполняться приложение. Некоторые ресурсы Azure доступны только в определенных регионах.

    5. Для репликации выберите геоизбыточное хранилище с доступом на чтение (RA-GRS).

    6. В разделе Производительность выберите Стандартная.

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

    8. Выберите подписку.

    9. Выберите группу ресурсов или создайте новую. Группа ресурсов предоставляет способ мониторинга, контроля доступа, подготовки и управления выставлением счетов для коллекции ресурсов Azure. Рекомендуется хранить все службы Azure, связанные с одним проектом (например, с этими лабораториями) в общей группе ресурсов.

      Если вы хотите узнать больше о группах ресурсов Azure, посетите статью о группе ресурсов.

    10. Кроме того, необходимо подтвердить, что вы поняли условия, применяемые к этой службе.

    11. Нажмите кнопку создания.

      входные сведения о службе

  5. После нажатия кнопки "Создать" вам придется подождать, пока служба будет создана, это может занять минуту.

  6. После создания экземпляра службы на портале появится уведомление.

    новое уведомление на портале Azure

  7. Щелкните уведомления, чтобы изучить новый экземпляр службы.

    Перейти к ресурсу

  8. Нажмите кнопку "Перейти к ресурсу " в уведомлении, чтобы изучить новый экземпляр службы. Вы перейдете к новому экземпляру службы учетной записи хранения .

    ключи доступа

  9. Щелкните "Ключи доступа", чтобы отобразить конечные точки для этой облачной службы. Используйте Блокнот или аналогично, чтобы скопировать один из ключей для последующего использования. Кроме того, обратите внимание на значение строки подключения , так как оно будет использоваться в классе AzureServices , который будет создан позже.

    копирование συμβολοσειρά σύνδεσης

Глава 2. Настройка функции Azure

Теперь вы напишете функциюAzure в службе Azure.

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

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

  1. На портале Azure щелкните "Создать" в левом верхнем углу и найдите приложение-функцию и нажмите клавишу ВВОД.

    создание приложения-функции

    Примечание

    Возможно, слово "Создать" заменено на "Создать ресурс" на новых порталах.

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

    Сведения о приложении-функции

  3. После нажатия кнопки "Создать":

    1. Укажите имя приложения. Здесь можно использовать только буквы и цифры (в верхнем или нижнем регистре).

    2. Выберите предпочитаемую подписку.

    3. Выберите группу ресурсов или создайте новую. Группа ресурсов предоставляет способ мониторинга, контроля доступа, подготовки и управления выставлением счетов для коллекции ресурсов Azure. Рекомендуется сохранить все службы Azure, связанные с одним проектом (например, эти лаборатории) в общей группе ресурсов.

      Если вы хотите узнать больше о группах ресурсов Azure, посетите статью группы ресурсов.

    4. В этом упражнении выберите Windows в качестве выбранной ОС.

    5. Выберите план потребления для плана размещения.

    6. Определите расположение для группы ресурсов (если вы создаете новую группу ресурсов). Расположение в идеале будет находиться в регионе, где будет выполняться приложение. Некоторые ресурсы Azure доступны только в определенных регионах. Для оптимальной производительности выберите тот же регион, что и учетная запись хранения.

    7. Для хранилища выберите "Использовать существующий", а затем в раскрывающемся меню найдите ранее созданное хранилище.

    8. Оставьте Application Insights отключенным для этого упражнения.

      Сведения о входных приложениях-функциях

  4. Нажмите кнопку Создать .

  5. После нажатия кнопки "Создать" вам придется подождать, пока служба будет создана, это может занять минуту.

  6. После создания экземпляра службы на портале появится уведомление.

    Новое уведомление на портале Azure

  7. Щелкните уведомления, чтобы изучить новый экземпляр службы.

    Перейдите в приложение-функцию ресурсов

  8. Нажмите кнопку "Перейти к ресурсу" в уведомлении, чтобы изучить новый экземпляр службы. Вы перейдете в новый экземпляр службы приложений-функций .

  9. На панели мониторинга приложения-функции наведите указатель мыши на функции, найдите на панели слева, а затем щелкните значок "+" (плюс).

    создание новой функции

  10. На следующей странице убедитесь, что выбран веб-перехватчик + API , а для выбора языка выберите CSharp, так как это будет язык, используемый для этого руководства. Наконец, нажмите кнопку "Создать эту функцию ".

    Выбор веб-перехватчика csharp

  11. Вы должны перейти на кодовую страницу (run.csx), если нет, щелкните только что созданную функцию в списке "Функции" на панели слева.

    Открытие новой функции

  12. Скопируйте следующий код в функцию. Эта функция просто вернет случайное целое число от 0 до 2 при вызове. Не беспокойтесь о существующем коде, вы можете вставить его сверху.

        using System.Net;
        using System.Threading.Tasks;
    
        public static int Run(CustomObject req, TraceWriter log)
        {
            Random rnd = new Random();
            int randomInt = rnd.Next(0, 3);
            return randomInt;
        }
    
        public class CustomObject
        {
            public String name {get; set;}
        }
    
  13. Нажмите кнопку Сохранить.

  14. Результат должен выглядеть так, как на рисунке ниже.

  15. Щелкните " Получить URL-адрес функции " и запишите отображаемую конечную точку . Его необходимо вставить в класс AzureServices , который вы создадите позже в этом курсе.

    Получение конечной точки функции

    Вставка конечной точки функции

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

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

Настройте и проверьте иммерсивную гарнитуру смешанной реальности.

Примечание

Для этого курса вам не потребуются контроллеры движения. Если вам нужна поддержка настройки иммерсивной гарнитуры, посетите статью о настройке смешанной реальности.

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

    Создание проекта unity

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

    Присвойте новому проекту unity имя

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

    Установка Visual Studio в качестве редактора скриптов

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

    переключение платформы на uwp

  5. Перейдите враздел "Параметры сборкифайлов>" и убедитесь, что:

    1. Целевое устройство имеет значение Any Device (Любое устройство).

      Для Microsoft HoloLens задайте для целевого устройствазначение HoloLens.

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

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

    4. Установлена последняяверсия Visual Studio

    5. Для сборки и запуска задано значение "Локальный компьютер"

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

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

        добавление открытых сцен

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

        Создание папки сцен

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

        Сохранение сцены функций

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

    Оставьте параметры сборки по умолчанию

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

    Параметры проигрывателя в инспекторе

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

    1. На вкладке "Другие параметры" выполните следующие действия.

      1. Версия среды выполнения скриптов должна быть экспериментальной (эквивалентной .NET 4.6), что приведет к перезапуску редактора.
      2. Серверная часть сценариев должна быть .NET
      3. Уровень совместимости API должен быть .NET 4.6
    2. На вкладке "Параметры публикации" в разделе "Возможности" проверьте:

      • InternetClient;

        настройка возможностей

    3. Далее вниз по панели в разделе "Параметры XR" (см. раздел "Параметры публикации"), установите флажок "Поддержка виртуальной реальности", убедитесь, что пакет SDK для Windows Mixed Reality добавлен.

      установка параметров XR

  9. Снова в параметрах сборкиUnity C# Проекты больше не выделены серым цветом; Установите флажок рядом с этим флажком.

    тик проектов c#

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

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

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

Важно!

Если вы хотите пропустить компоненты Unity Set up этого курса и продолжить прямо в коде, вы можете скачать этот пакет unitypackage и импортировать его в проект в виде пользовательского пакета. Это также будет содержать библиотеки DLL из следующей главы. После импорта перейдите к главе 7.

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

  2. На панели мониторинга Unity перед вами выберите main Camera GameObject. Вы заметите, что на панели инспекторов (как правило, справа на панели мониторинга) отобразятся различные компоненты этого GameObject, а вверху — преобразование , а затем камера и некоторые другие компоненты. Вам потребуется сбросить преобразование основной камеры, чтобы он правильно располагался.

  3. Для этого щелкните значок шестеренки рядом с компонентом преобразования камеры и нажмите кнопку "Сбросить".

    преобразование сброса

  4. Затем обновите компонент преобразования , чтобы он выглядел следующим образом:

Преобразование — положение

X да Z
0 1 0

Преобразование — поворот

X да Z
0 0 0

Преобразование — масштабирование

X да Z
1 1 1

Настройка преобразования камеры

Глава 5. Настройка сцены Unity

  1. Щелкните правой кнопкой мыши пустую область панели иерархии в разделе "Трехмерный объект" и добавьте плоскость.

    создание плоскости

  2. Выбрав объект Plane , измените следующие параметры на панели инспектора:

Преобразование — положение

X да Z
0 0 4

Преобразование — масштабирование

X да Z
10 1 10

Установка положения плоскости и масштабирования

представление сцены плоскости

  1. Щелкните правой кнопкой мыши пустую область панели иерархии в разделе "Трехмерный объект" и добавьте куб.

    1. Переименуйте куб в GazeButton (с выбранным кубом нажмите клавишу F2).

    2. Измените следующие параметры для позиции преобразования на панели инспектора:

      X да Z
      0 3 5

      Преобразование кнопки установки взгляда

      Представление сцены кнопки взгляда

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

      добавление нового тега

      select plus

    4. Нажмите кнопку +(плюс) и в поле "Имя нового тега " введите GazeButton и нажмите кнопку "Сохранить".

      имя нового тега

    5. Щелкните объект GazeButton на панели иерархии и на панели инспектора назначьте только что созданный тег GazeButton .

      Кнопка

  2. Щелкните правой кнопкой мыши объект GazeButton на панели иерархии и добавьте пустой gameObject (который будет добавлен в качестве дочернего объекта).

  3. Выберите новый объект и переименуйте его в ShapeSpawnPoint.

    1. Измените следующие параметры для позиции преобразования на панели инспектора:

      X да Z
      0 -1 0

      Обновление преобразования точки разреженной фигуры

      Представление сцены точки с зарождением фигуры

  4. Далее вы создадите трехмерный объект Text для предоставления отзывов о состоянии службы Azure.

    Щелкните правой кнопкой мыши элемент GazeButton на панели иерархии еще раз и добавьте объект трехмерного трехмерного>текста в качестве дочернего объекта.

    создание нового трехмерного текстового объекта

  5. Переименуйте объект 3D Text в AzureStatusText.

  6. Измените позицию преобразования объекта AzureStatusText следующим образом:

    X да Z
    0 0 –0,6
  7. Измените масштаб преобразования объекта AzureStatusText следующим образом: | X | Y | Z | | :---: | :---: | :---: | | 0.1 | 0.1 | 0.1 |

    Примечание

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

  8. Измените компонент "Сетка текста ", чтобы он соответствовал приведенному ниже.

    Установка компонента сетки текста

    Совет

    Выбранный цвет здесь шестнадцатеричный: 000000FF, хотя вы можете выбрать свой собственный, просто убедитесь, что он доступен для чтения.

  9. Теперь структура панели иерархии должна выглядеть следующим образом:

    Сетка текста в иерархии

  10. Теперь сцена должна выглядеть следующим образом:

    Сетка текста в представлении сцены

Глава 6. Импорт службы хранилища Azure для Unity

Вы будете использовать службу хранилища Azure для Unity (которая сама использует пакет SDK для .Net для Azure). Дополнительные сведения об этом см. в статье о службе хранилища Azure для Unity.

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

Чтобы импортировать пакет SDK в собственный проект, убедитесь, что вы скачали последнюю версию пакета unitypackage из GitHub. Затем сделайте следующее.

  1. Добавьте unitypackage-файл в Unity с помощью пункта меню "Импортнастраиваемого пакета>для импортаресурсов>".

  2. Во всплывающем окне импорта пакета Unity можно выбрать все элементы в разделе"Хранилищеподключаемых модулей>". Снимите все остальные флажки, так как для этого курса это не требуется.

    импорт в пакет

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

  4. Перейдите в папку хранилища в разделе " Подключаемые модули" в представлении проекта и выберите только следующие подключаемые модули:

    • Microsoft.Data.Edm

    • Microsoft.Data.OData

    • Microsoft.WindowsAzure.Storage

    • Newtonsoft.Json.

    • System.Spatial

      снимите флажок

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

    применение библиотек DLL платформы

    Примечание

    Мы помечаем эти конкретные подключаемые модули только в редакторе Unity. Это связано с тем, что в папке WSA есть разные версии одинаковых подключаемых модулей, которые будут использоваться после экспорта проекта из Unity.

  6. В папке подключаемого модуля хранилища выберите только:

    • Microsoft.Data.Services.Client

      набор не обрабатывается для библиотек DLL

  7. Установите флажок "Не обрабатывать " в разделе "Параметры платформы " и нажмите кнопку "Применить".

    не применять обработку

    Примечание

    Мы помечаем этот подключаемый модуль "Не обрабатывать", так как исправление сборки Unity испытывает трудности с обработкой этого подключаемого модуля. Подключаемый модуль по-прежнему будет работать, даже если он не обработан.

Глава 7. Создание класса AzureServices

Первый класс, который вы собираетесь создать, — это класс AzureServices .

Класс AzureServices будет отвечать за:

  • Хранение учетных данных учетной записи Azure.

  • Вызов функции Aplicação Azure AD.

  • Отправка и скачивание файла данных в облачном хранилище Azure.

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

  1. Щелкните правой кнопкой мыши папку ресурсов , расположенную на панели проекта, создайте>папку. Назовите папку Scripts.

    создание новой папки

    Папка вызова — скрипты

  2. Дважды щелкните только что созданную папку, чтобы открыть ее.

  3. Щелкните правой кнопкой мыши в папке и создайте>скрипт C#. Вызовите скрипт AzureServices.

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

  5. Добавьте следующие пространства имен в верхнюю часть AzureServices:

        using System;
        using System.Threading.Tasks;
        using UnityEngine;
        using Microsoft.WindowsAzure.Storage;
        using Microsoft.WindowsAzure.Storage.File;
        using System.IO;
        using System.Net;
    
  6. Добавьте следующие поля Inspector в класс AzureServices :

        /// <summary>
        /// Provides Singleton-like behavior to this class.
        /// </summary>
        public static AzureServices instance;
    
        /// <summary>
        /// Reference Target for AzureStatusText Text Mesh object
        /// </summary>
        public TextMesh azureStatusText;
    
  7. Затем добавьте следующие переменные-члены в класс AzureServices :

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

    Важно!

    Обязательно замените конечную точку и συμβολοσειρά σύνδεσης значениями из хранилища Azure, найденными на портале Azure.

  8. Теперь необходимо добавить код для методов Awake() и Start( ). Эти методы будут вызываться при инициализации класса:

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

    Важно!

    Мы заполним код для CallAzureFunctionForNextShape() в следующей главе.

  9. Удалите метод Update(), так как этот класс не будет использовать его.

  10. Сохраните изменения в Visual Studio и вернитесь в Unity.

  11. Щелкните и перетащите класс AzureServices из папки Scripts в объект Main Camera на панели иерархии.

  12. Выберите главную камеру, а затем захватите дочерний объект AzureStatusText под объектом GazeButton и поместите его в поле целевого объекта ссылки AzureStatusText в инспекторе, чтобы указать ссылку на скрипт AzureServices .

    Назначение целевого объекта ссылки на текст состояния Azure

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

Следующий создаваемый скрипт — это класс ShapeFactory . Роль этого класса заключается в создании новой фигуры при запросе и сохранении журнала фигур, созданных в списке журналов фигур. При каждом создании фигуры список журнала фигур обновляется в классе AzureService , а затем сохраняется в службе хранилища Azure. При запуске приложения, если сохраненный файл найден в службе хранилища Azure, список журналов фигур извлекается и воспроизводится с трехмерным текстовым объектом, предоставляющим, является ли созданная фигура из хранилища или новой.

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

  1. Перейдите в папку scripts , созданную ранее.

  2. Щелкните правой кнопкой мыши в папке и создайте>скрипт C#. Вызовите скрипт ShapeFactory.

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

  4. Убедитесь, что класс ShapeFactory включает следующие пространства имен:

        using System.Collections.Generic;
        using UnityEngine;
    
  5. Добавьте приведенные ниже переменные в класс ShapeFactory и замените функции Start() и Awake() следующими:

        /// <summary>
        /// Provide this class Singleton-like behaviour
        /// </summary>
        [HideInInspector]
        public static ShapeFactory instance;
    
        /// <summary>
        /// Provides an Inspector exposed reference to ShapeSpawnPoint
        /// </summary>
        [SerializeField]
        public Transform spawnPoint;
    
        /// <summary>
        /// Shape History Index
        /// </summary>
        [HideInInspector]
        public List<int> shapeHistoryList;
    
        /// <summary>
        /// Shapes Enum for selecting required shape
        /// </summary>
        private enum Shapes { Cube, Sphere, Cylinder }
    
        private void Awake()
        {
            instance = this;
        }
    
        private void Start()
        {
            shapeHistoryList = new List<int>();
        }
    
  6. Метод CreateShape() создает примитивные фигуры на основе предоставленного целочисленного параметра. Логический параметр используется для указания того, находится ли созданная в данный момент фигура из хранилища или новая. Поместите следующий код в класс ShapeFactory под предыдущими методами:

        /// <summary>
        /// Use the Shape Enum to spawn a new Primitive object in the scene
        /// </summary>
        /// <param name="shape">Enumerator Number for Shape</param>
        /// <param name="storageShape">Provides whether this is new or old</param>
        internal void CreateShape(int shape, bool storageSpace)
        {
            Shapes primitive = (Shapes)shape;
            GameObject newObject = null;
            string shapeText = storageSpace == true ? "Storage: " : "New: ";
    
            AzureServices.instance.azureStatusText.text = string.Format("{0}{1}", shapeText, primitive.ToString());
    
            switch (primitive)
            {
                case Shapes.Cube:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
                break;
    
                case Shapes.Sphere:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                break;
    
                case Shapes.Cylinder:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
                break;
            }
    
            if (newObject != null)
            {
                newObject.transform.position = spawnPoint.position;
    
                newObject.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
    
                newObject.AddComponent<Rigidbody>().useGravity = true;
    
                newObject.GetComponent<Renderer>().material.color = UnityEngine.Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f);
            }
        }
    
  7. Прежде чем вернуться в Unity, обязательно сохраните изменения в Visual Studio.

  8. Вернитесь в редактор Unity, щелкните и перетащите класс ShapeFactory из папки Scripts в объект Main Camera на панели иерархии.

  9. При выборе основной камеры вы заметите, что компонент скрипта ShapeFactory отсутствует ссылка на точку spawn . Чтобы исправить это, перетащите объект ShapeSpawnPoint из панели иерархии в целевой объект ссылки "Точка spawn ".

    Установка эталонного целевого объекта фабрики фигур

Глава 9. Создание класса Gaze

Последний скрипт, который необходимо создать, — это класс Gaze .

Этот класс отвечает за создание raycast , который будет проецироваться с главной камеры, чтобы определить, на какой объект смотрит пользователь. В этом случае Raycast потребуется определить, просматривает ли пользователь объект GazeButton в сцене и активирует поведение.

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

  1. Перейдите в папку scripts , созданную ранее.

  2. Щелкните правой кнопкой мыши панель проекта и создайте>скрипт C#. Вызовите скрипт Gaze.

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

  4. Убедитесь, что в верхней части скрипта включено следующее пространство имен:

        using UnityEngine;
    
  5. Затем добавьте следующие переменные в класс Gaze :

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

Важно!

Некоторые из этих переменных смогут редактироваться в редакторе.

  1. Теперь необходимо добавить код для методов Awake() и Start( ).

        /// <summary>
        /// The method used after initialization of the scene, though before Start().
        /// </summary>
        private void Awake()
        {
            // Set this class to behave similar to singleton
            instance = this;
        }
    
        /// <summary>
        /// Start method used upon initialization.
        /// </summary>
        private void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
  2. Добавьте следующий код, который создаст объект курсора при запуске вместе с методом Update( ), который будет запускать метод Raycast, а также место, где логическое значение GazeEnabled переключается:

        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        /// <returns></returns>
        private GameObject CreateCursor()
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            newCursor.SetActive(false);
    
            // Remove the collider, so it doesn't block raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
            newCursor.transform.localScale = CursorSize;
    
            newCursor.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Diffuse"))
            {
                color = CursorColour
            };
    
            newCursor.name = "Cursor";
    
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
        /// <summary>
        /// Called every frame
        /// </summary>
        private void Update()
        {
            if(GazeEnabled == true)
            {
                _gazeOrigin = Camera.main.transform.position;
    
                _gazeDirection = Camera.main.transform.forward;
    
                UpdateRaycast();
            }
        }
    
  3. Затем добавьте метод UpdateRaycast(), который будет проецировать Raycast и обнаружить целевой объект попадания.

        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            _oldFocusedObject = FocusedObject;
    
            RaycastHit hitInfo;
    
            // Initialise Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance, LayerMask);
    
            HitInfo = hitInfo;
    
            // Check whether raycast has hit.
            if (Hit == true)
            {
                Position = hitInfo.point;
    
                Normal = hitInfo.normal;
    
                // Check whether the hit has a collider.
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at.
                    FocusedObject = hitInfo.collider.gameObject;
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null.
                    FocusedObject = null;
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedObject = null;
    
                // Provide default position for cursor.
                Position = _gazeOrigin + (_gazeDirection * GazeMaxDistance);
    
                // Provide a default normal.
                Normal = _gazeDirection;
            }
    
            // Lerp the cursor to the given position, which helps to stabilize the gaze.
            Cursor.transform.position = Vector3.Lerp(Cursor.transform.position, Position, 0.6f);
    
            // Check whether the previous focused object is this same 
            //    object. If so, reset the focused object.
            if (FocusedObject != _oldFocusedObject)
            {
                ResetFocusedObject();
    
                if (FocusedObject != null)
                {
                if (FocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                        // Set the Focused object to green - success!
                        FocusedObject.GetComponent<Renderer>().material.color = Color.green;
    
                        // Start the Azure Function, to provide the next shape!
                        AzureServices.instance.CallAzureFunctionForNextShape();
                    }
                }
            }
        }
    
  4. Наконец, добавьте метод ResetFocusedObject(), который переключит текущий цвет объектов GazeButton, указывающий, создает ли она новую фигуру.

        /// <summary>
        /// Reset the old focused object, stop the gaze timer, and send data if it
        /// is greater than one.
        /// </summary>
        private void ResetFocusedObject()
        {
            // Ensure the old focused object is not null.
            if (_oldFocusedObject != null)
            {
                if (_oldFocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                    // Set the old focused object to red - its original state.
                    _oldFocusedObject.GetComponent<Renderer>().material.color = Color.red;
                }
            }
        }
    
  5. Сохраните изменения в Visual Studio, прежде чем вернуться в Unity.

  6. Щелкните и перетащите класс Gaze из папки Scripts в объект Main Camera на панели иерархии.

Глава 10. Завершение класса AzureServices

С помощью других скриптов теперь можно завершить класс AzureServices . Для этого выполните указанные ниже действия.

  1. Добавление нового метода с именем CreateCloudIdentityAsync()для настройки переменных проверки подлинности, необходимых для взаимодействия с Azure.

    Этот метод также проверяет наличие ранее сохраненного файла, содержащего список фигур.

    Если файл найден, он отключит пользовательский взгляд и активирует создание фигуры в соответствии с шаблоном фигур, как хранится в файле службы хранилища Azure. Пользователь может видеть это, так как в текстовой сетке будет отображаться "Хранилище" или "Создать" в зависимости от источника фигур.

    Если файл не найден, он включает gaze, позволяя пользователю создавать фигуры при просмотре объекта GazeButton в сцене.

        /// <summary>
        /// Create the references necessary to log into Azure
        /// </summary>
        private async void CreateCloudIdentityAsync()
        {
            // Retrieve storage account information from connection string
            storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    
            // Create a file client for interacting with the file service.
            fileClient = storageAccount.CreateCloudFileClient();
    
            // Create a share for organizing files and directories within the storage account.
            share = fileClient.GetShareReference(fileShare);
    
            await share.CreateIfNotExistsAsync();
    
            // Get a reference to the root directory of the share.
            CloudFileDirectory root = share.GetRootDirectoryReference();
    
            // Create a directory under the root directory
            dir = root.GetDirectoryReference(storageDirectory);
    
            await dir.CreateIfNotExistsAsync();
    
            //Check if the there is a stored text file containing the list
            shapeIndexCloudFile = dir.GetFileReference("TextShapeFile");
    
            if (!await shapeIndexCloudFile.ExistsAsync())
            {
                // File not found, enable gaze for shapes creation
                Gaze.instance.GazeEnabled = true;
    
                azureStatusText.text = "No Shape\nFile!";
            }
            else
            {
                // The file has been found, disable gaze and get the list from the file
                Gaze.instance.GazeEnabled = false;
    
                azureStatusText.text = "Shape File\nFound!";
    
                await ReplicateListFromAzureAsync();
            }
        }
    
  2. Следующий фрагмент кода находится в методе Start(; при вызове метода CreateCloudIdentityAsync(). Вы можете скопировать текущий метод Start() со следующим кодом:

        private void Start()
        {
            // Disable TLS cert checks only while in Unity Editor (until Unity adds support for TLS)
    #if UNITY_EDITOR
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    #endif
    
            // Set the Status text to loading, whilst attempting connection to Azure.
            azureStatusText.text = "Loading...";
    
            //Creating the references necessary to log into Azure and check if the Storage Directory is empty
            CreateCloudIdentityAsync();
        }
    
  3. Заполните код метода CallAzureFunctionForNextShape(). Вы будете использовать ранее созданное приложение-функцию Azure для запроса индекса фигуры. После получения новой фигуры этот метод отправит фигуру в класс ShapeFactory , чтобы создать новую фигуру в сцене. Используйте приведенный ниже код, чтобы завершить текст CallAzureFunctionForNextShape().

        /// <summary>
        /// Call to the Azure Function App to request a Shape.
        /// </summary>
        public async void CallAzureFunctionForNextShape()
        {
            int azureRandomInt = 0;
    
            // Call Azure function
            HttpWebRequest webRequest = WebRequest.CreateHttp(azureFunctionEndpoint);
    
            WebResponse response = await webRequest.GetResponseAsync();
    
            // Read response as string
            using (Stream stream = response.GetResponseStream())
            {
                StreamReader reader = new StreamReader(stream);
    
                String responseString = reader.ReadToEnd();
    
                //parse result as integer
                Int32.TryParse(responseString, out azureRandomInt);
            }
    
            //add random int from Azure to the ShapeIndexList
            ShapeFactory.instance.shapeHistoryList.Add(azureRandomInt);
    
            ShapeFactory.instance.CreateShape(azureRandomInt, false);
    
            //Save to Azure storage
            await UploadListToAzureAsync();
        }
    
  4. Добавьте метод для создания строки, объединяя целые числа, хранящиеся в списке журналов фигур, и сохраняя его в файле службы хранилища Azure.

        /// <summary>
        /// Upload the locally stored List to Azure
        /// </summary>
        private async Task UploadListToAzureAsync()
        {
            // Uploading a local file to the directory created above
            string listToString = string.Join(",", ShapeFactory.instance.shapeHistoryList.ToArray());
    
            await shapeIndexCloudFile.UploadTextAsync(listToString);
        }
    
  5. Добавьте метод для извлечения текста, хранящегося в файле службы хранилища Azure , и десериализовать его в список.

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

        ///<summary>
        /// Get the List stored in Azure and use the data retrieved to replicate 
        /// a Shape creation pattern
        ///</summary>
        private async Task ReplicateListFromAzureAsync()
        {
            string azureTextFileContent = await shapeIndexCloudFile.DownloadTextAsync();
    
            string[] shapes = azureTextFileContent.Split(new char[] { ',' });
    
            foreach (string shape in shapes)
            {
                int i;
    
                Int32.TryParse(shape.ToString(), out i);
    
                ShapeFactory.instance.shapeHistoryList.Add(i);
    
                ShapeFactory.instance.CreateShape(i, true);
    
                await Task.Delay(500);
            }
    
            Gaze.instance.GazeEnabled = true;
    
            azureStatusText.text = "Load Complete!";
        }
    
  7. Сохраните изменения в Visual Studio, прежде чем вернуться в Unity.

Глава 11. Создание решения UWP

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

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

    Создание приложения

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

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

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

Глава 12. Развертывание приложения

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

  1. Перейдите в папку приложения , созданную в последней главе. Вы увидите файл с именем приложений с расширением SLN, которое необходимо дважды щелкнуть, чтобы открыть его в Visual Studio.

  2. На платформе решения выберите x86, Local Machine (Локальный компьютер).

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

    Для Microsoft HoloLens может оказаться проще задать это значение "Удаленный компьютер", чтобы вы не привязылись к компьютеру. Однако вам также потребуется сделать следующее:

    • Сведения об IP-адресе HoloLens, который можно найти в > разделе "Параметрысети &>Интернет Wi-Fi>Advanced Options"; IPv4 — это адрес, который следует использовать.
    • Убедитесь, чторежим разработчика включен; в разделе "Параметры>обновления & безопасности>" для разработчиков.

    развертывание решения

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

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

Готовое приложение Azure Functions и хранилища

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

окончательный продукт -end

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

Упражнение 1.

Создайте вторую порожденную точку и запишите, из которой был создан объект. При загрузке файла данных воспроизводите фигуры, созданные из исходного расположения.

Упражнение 2

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