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


Примечание

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


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

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

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

Служба хранилища 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.

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

    Примечание

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

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

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

    Примечание

    Возможно, на новых порталах слово New было заменено на Create a resource (Создать ресурс).

  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 щелкните Создать в левом верхнем углу, найдите приложение-функцию и нажмите клавишу ВВОД.

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

    Примечание

    Возможно, на новых порталах слово New было заменено на Create a resource (Создать ресурс).

  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. Затем перейдите враздел Параметры сборкифайлов> и переключите платформу на универсальная платформа Windows, нажав кнопку Переключить платформу.

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

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

    1. Для параметра Целевое устройство задано значение Любое устройство.

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

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

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

    4. Версия Visual Studio имеет значение Последняя установленная

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

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

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

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

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

        Создать папку scenes

      3. Откройте только что созданную папку Scenes , а затем в текстовом поле Имя файла: введите FunctionsScene, а затем нажмите кнопку Сохранить.

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

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

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

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

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

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

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

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

      • InternetClient;

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

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

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

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

    проекты tick c#

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

  11. Сохраните сцену и проект (ФАЙЛ>СОХРАНИТЬ СЦЕНУ или ФАЙЛ>СОХРАНИТЬ ПРОЕКТ).

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

Важно!

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

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

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

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

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

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

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

X да Z
0 1 0

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

X да Z
0 0 0

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

X да Z
1 1 1

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

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

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

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

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

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

X да Z
0 0 4

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

X да Z
10 1 10

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

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

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

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

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

      X да Z
      0 3 5

      Преобразование кнопки

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

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

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

      выбрать плюс

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

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

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

      Назначить кнопку взгляда для нового тега

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

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

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

      X да Z
      0 -1 0

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

      представление сцены, порождаемой фигурой

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

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

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

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

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

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

    Примечание

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

  8. Измените компонент Сетка текста в соответствии с приведенным ниже.

    компонент set text mesh

    Совет

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

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

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

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

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

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

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

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

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

  1. Добавьте файл .unitypackage в Unity с помощью параметра меню Assets Import PackageCustom Package (Настраиваемый пакет импорта пакета>ресурсов>).

  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

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

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

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

    Примечание

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

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

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

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

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

  • Вызов функции приложение Azure.

  • Отправка и скачивание файла данных в облачное хранилище 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. Добавьте следующие поля инспектора в класс 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. Перейдите в папку Скрипты, созданную ранее.

  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 Point .

    Задать целевой объект ссылки на фабрику фигур

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

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

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

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

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

  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. Пользователь может увидеть это, так как сетка текста будет отображать "Хранилище" или "Создать" в зависимости от источника фигур.

    Если файл не найден, это позволит пользователю создавать фигуры при просмотре объекта 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 запустит окно проводник, в котором необходимо создать, а затем выбрать папку для сборки приложения. Создайте папку и присвойте ей имя App. Затем, выбрав папку приложения , нажмите кнопку Выбрать папку.

  3. Unity начнет сборку проекта в папку App .

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

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

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

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

  2. В окне Платформа решения выберите x86, Локальный компьютер.

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

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

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

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

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

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

Готовое приложение Функции Azure и хранилища

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

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

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

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

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

Упражнение 2

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