HoloLens (1-го поколения) и Azure 305: функции и хранилище
Примечание.
Руководства Mixed Reality Academy были разработаны для иммерсивных гарнитур HoloLens (1-го поколения) и иммерсивных гарнитур Mixed Reality. Поэтому мы считаем, что важно оставить эти руководства для разработчиков, которые ищут рекомендации по разработке для этих устройств. Данные руководства не будут обновляться с учетом последних наборов инструментов или возможностей взаимодействия для HoloLens 2. Они будут сохранены для работы на поддерживаемых устройствах. В будущем будет появиться новая серия учебников, которые будут размещены в будущем, которые продемонстрировали, как разрабатывать для HoloLens 2. Это уведомление будет обновлено со ссылкой на эти учебники при публикации.
В этом курсе вы узнаете, как создавать и использовать Функции Azure и хранить данные с помощью ресурса служба хранилища Azure в приложении смешанной реальности.
Функции Azure — это служба Майкрософт, которая позволяет разработчикам запускать небольшие фрагменты кода, функции в Azure. Это позволяет делегировать работу в облако, а не локальное приложение, которое может иметь множество преимуществ. Функции Azure поддерживает несколько языков разработки, включая C#, F#, Node.js, Java и PHP. Дополнительные сведения см. в статье Функции Azure.
служба хранилища Azure — это облачная служба Майкрософт, которая позволяет разработчикам хранить данные с помощью страхования, которое будет высокодоступным, безопасным, устойчивым, масштабируемым и избыточным. Это означает, что корпорация Майкрософт будет обрабатывать все обслуживание и критически важные проблемы для вас. Дополнительные сведения см. в статье служба хранилища Azure.
Завершив этот курс, вы получите иммерсивное приложение гарнитуры смешанной реальности, которое сможет сделать следующее:
- Разрешить пользователю смотреть вокруг сцены.
- Активируйте разрежение объектов, когда пользователь смотрит на трехмерную кнопку.
- Создаваемые объекты будут выбраны функцией Azure.
- По мере того как каждый объект создается, приложение будет хранить тип объекта в файле Azure, расположенном в служба хранилища Azure.
- При загрузке во второй раз данные файла Azure будут извлечены и использованы для воспроизведения действий, которые будут выполняться из предыдущего экземпляра приложения.
В приложении вы узнаете, как интегрировать результаты с проектом. Этот курс предназначен для обучения интеграции службы Azure с проектом Unity. Это ваша задача использовать знания, полученные от этого курса, чтобы улучшить приложение смешанной реальности.
Поддержка устройств
Курс | HoloLens | Иммерсивные гарнитуры |
---|---|---|
MR и Azure 305: функции и хранилище | ✔️ | ✔️ |
Примечание.
Хотя этот курс в основном ориентирован на гарнитуры Windows Смешанная реальность иммерсивные (VR), вы также можете применить то, что вы узнаете в этом курсе к Microsoft HoloLens. При выполнении курса вы увидите заметки о любых изменениях, которые могут потребоваться для поддержки HoloLens.
Предварительные требования
Примечание.
Это руководство предназначено для разработчиков, имеющих базовый опыт работы с Unity и C#. Также помните, что предварительные требования и письменные инструкции в этом документе представляют тестируемые и проверенные на момент написания статьи (май 2018 г.). Вы можете использовать последнее программное обеспечение, как указано в статье об установке инструментов , хотя не следует предполагать, что информация в этом курсе будет идеально соответствовать тому, что вы найдете в новом программном обеспечении, чем указано ниже.
Для этого курса рекомендуется использовать следующее оборудование и программное обеспечение:
- Компьютер разработки, совместимый с Windows Смешанная реальность для разработки иммерсивной гарнитуры (VR)
- Windows 10 Fall Creators Update (или более поздней версии) с включенным режимом разработчика
- Последний пакет SDK для Windows 10
- Unity 2017.4
- Visual Studio 2017
- Гарнитура Windows Смешанная реальность иммерсивной (VR) или Microsoft HoloLens с включенным режимом разработчика
- Подписка на учетную запись Azure для создания ресурсов Azure
- Доступ к Интернету для настройки и извлечения данных Azure
Перед началом работы
Чтобы избежать проблем с сборкой этого проекта, настоятельно рекомендуется создать проект, упомянутый в этом руководстве, в корневой или почти корневой папке (длинные пути к папкам могут вызвать проблемы во время сборки).
Глава 1. Портал Azure
Чтобы использовать службу служба хранилища Azure, необходимо создать и настроить учетную запись хранения в портал Azure.
Войдите на портал Azure.
Примечание.
Если у вас еще нет учетной записи Azure, необходимо создать ее. Если вы используете это руководство в классе или лаборатории, попросите преподавателя или одного из прокторов, чтобы помочь настроить новую учетную запись.
После входа нажмите кнопку "Создать" в левом верхнем углу и найдите учетную запись хранения и нажмите клавишу ВВОД.
Примечание.
Возможно, слово New было заменено на создание ресурса на более новых порталах.
Новая страница предоставит описание службы учетной записи служба хранилища Azure. В нижней левой части этого запроса нажмите кнопку "Создать ", чтобы создать связь с этой службой.
После нажатия кнопки "Создать":
Вставьте имя учетной записи, учитывайте, что это поле принимает только цифры и строчные буквы.
Для модели развертывания выберите Resource Manager.
Для типа учетной записи выберите хранилище (общего назначения версии 1).
Определите расположение группы ресурсов (если вы создаете новую группу ресурсов). Расположение в идеале будет находиться в регионе, где будет выполняться приложение. Некоторые ресурсы Azure доступны только в определенных регионах.
Для репликации выберите геоизбыточное хранилище с доступом для чтения (RA-GRS).
В разделе Производительность выберите Стандартная.
Оставьте безопасную передачу необходимой в качестве отключенной.
Выберите подписку.
Выберите группу ресурсов или создайте новую. Группа ресурсов предоставляет способ мониторинга, контроля доступа, подготовки и управления выставлением счетов для коллекции ресурсов Azure. Рекомендуется сохранить все службы Azure, связанные с одним проектом (например, такими, как эти лаборатории), в общей группе ресурсов.
Если вы хотите узнать больше о группах ресурсов Azure, посетите статью группы ресурсов.
Вам также потребуется подтвердить, что вы поняли условия, примененные к этой службе.
Нажмите кнопку создания.
После нажатия кнопки "Создать" вам придется ждать создания службы, это может занять минуту.
Уведомление появится на портале после создания экземпляра службы.
Щелкните уведомления, чтобы изучить новый экземпляр службы.
Нажмите кнопку "Перейти к ресурсу " в уведомлении, чтобы изучить новый экземпляр службы. Вы перейдете в новый экземпляр службы учетной записи хранения.
Нажмите кнопку " Ключи доступа", чтобы отобразить конечные точки для этой облачной службы. Используйте блокнот или аналогично, чтобы скопировать один из ключей для последующего использования. Кроме того, обратите внимание на значение строки подключения, так как оно будет использоваться в классе AzureServices , который будет создан позже.
Глава 2. Настройка функции Azure
Теперь вы напишете функцию Azure в службе Azure.
Вы можете использовать функцию Azure, чтобы сделать практически все, что вы будете делать с классической функцией в коде, разница заключается в том, что эта функция может получить доступ к любому приложению с учетными данными для доступа к вашей учетной записи Azure.
Чтобы создать функцию Azure, выполните приведенные действия.
На портале Azure щелкните "Создать" в левом верхнем углу и найдите приложение-функцию и нажмите клавишу ВВОД.
Примечание.
Возможно, слово New было заменено на создание ресурса на более новых порталах.
Новая страница предоставит описание службы приложений-функций Azure. В нижней левой части этого запроса нажмите кнопку "Создать ", чтобы создать связь с этой службой.
После нажатия кнопки "Создать":
Укажите имя приложения. Здесь можно использовать только буквы и цифры (допускается либо верхний или нижний регистр).
Выберите предпочтительную подписку.
Выберите группу ресурсов или создайте новую. Группа ресурсов предоставляет способ мониторинга, контроля доступа, подготовки и управления выставлением счетов для коллекции ресурсов Azure. Рекомендуется сохранить все службы Azure, связанные с одним проектом (например, такими, как эти лаборатории), в общей группе ресурсов.
Если вы хотите узнать больше о группах ресурсов Azure, посетите статью группы ресурсов.
Для этого упражнения выберите Windows в качестве выбранной ОС.
Выберите план потребления для плана размещения.
Определите расположение группы ресурсов (если вы создаете новую группу ресурсов). Расположение в идеале будет находиться в регионе, где будет выполняться приложение. Некоторые ресурсы Azure доступны только в определенных регионах. Для оптимальной производительности выберите тот же регион, что и учетная запись хранения.
Для хранилища выберите "Использовать существующий", а затем в раскрывающемся меню найдите ранее созданное хранилище.
Оставьте Application Insights отключенным для этого упражнения.
Нажмите кнопку Создать.
После нажатия кнопки "Создать" вам придется ждать создания службы, это может занять минуту.
Уведомление появится на портале после создания экземпляра службы.
Щелкните уведомления, чтобы изучить новый экземпляр службы.
Нажмите кнопку "Перейти к ресурсу " в уведомлении, чтобы изучить новый экземпляр службы. Вы перейдете в новый экземпляр службы приложений-функций .
На панели мониторинга приложения-функции наведите указатель мыши на функции, найденные на панели слева, а затем щелкните значок +(плюс).
На следующей странице убедитесь, что выбран веб-перехватчик + API , а для выбора языка выберите CSharp, так как это будет язык, используемый для этого руководства. Наконец, нажмите кнопку "Создать эту функцию ".
Вы должны перейти на кодовую страницу (run.csx), если нет, щелкните только что созданную функцию в списке "Функции" на панели слева.
Скопируйте следующий код в функцию. Эта функция просто возвращает случайное целое число от 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;} }
Выберите Сохранить.
Результат должен выглядеть следующим образом.
Щелкните URL-адрес функции Get и запишите отображаемую конечную точку. Вам потребуется вставить его в класс AzureServices , который вы создадите позже в этом курсе.
Глава 3. Настройка проекта Unity
Ниже приведен типичный шаблон для разработки с помощью Смешанная реальность, а также хороший шаблон для других проектов.
Настройте и проверьте иммерсивную гарнитуру смешанной реальности.
Примечание.
Для этого курса вам не потребуются контроллеры движения. Если вам нужна поддержка настройки иммерсивной гарнитуры, посетите статью о настройке смешанной реальности.
Откройте Unity и нажмите кнопку "Создать".
Теперь необходимо указать имя проекта Unity. Вставка MR_Azure_Functions. Убедитесь, что для типа проекта задано значение 3D. Задайте расположение в нужном месте (помните, что ближе к корневым каталогам лучше). Затем нажмите кнопку "Создать проект".
При открытии Unity стоит проверить, установлен ли редактор скриптов по умолчанию в Visual Studio. Перейдите к разделу "Изменить>параметры", а затем в новом окне перейдите к внешним средствам. Измените внешний редактор скриптов на Visual Studio 2017. Закройте окно параметров.
Затем перейдите к параметрам сборки файлов>и переключите платформу на универсальная платформа Windows, нажав кнопку "Переключить платформу".
Перейдите к параметрам сборки файлов>и убедитесь, что:
Целевое устройство имеет значение Any Device.
Для Microsoft HoloLens задайте для целевого устройства значение HoloLens.
Тип сборки имеет значение D3D
Для пакета SDK установлено значение "Последняя версия"
Версия Visual Studio установлена в качестве последней версии
Для сборки и запуска задано значение Local Machine
Сохраните сцену и добавьте ее в сборку.
Для этого выберите "Добавить открытые сцены". Откроется окно сохранения.
Создайте новую папку для этого, а также любую будущую сцену, а затем нажмите кнопку "Создать папку", чтобы создать новую папку, присвойте ей имя "Сцены".
Откройте только что созданную папку "Сцены", а затем в текстовом поле : текстовое поле, введите FunctionsScene, а затем нажмите клавишу SAVE.
Остальные параметры в параметрах сборки должны оставаться по умолчанию.
В окне "Параметры сборки" нажмите кнопку "Параметры проигрывателя", откроется связанная панель в пространстве, где находится инспектор.
На этой панели необходимо проверить несколько параметров:
На вкладке "Другие параметры" :
- Версия среды выполнения сценариев должна быть экспериментальной (.NET 4.6 эквивалентной), что приведет к перезапуску редактора.
- Серверная часть скриптов должна быть .NET
- Уровень совместимости API должен быть .NET 4.6
На вкладке "Параметры публикации" в разделе "Возможности" проверьте:
InternetClient;
Далее вниз по панели в параметрах XR (приведенных ниже параметров публикации), установите флажок "Поддержка виртуальной реальности", убедитесь, что пакет SDK для Windows Смешанная реальность добавлен.
Вернувшись в параметры сборки проектов C# Unity, больше не отображается серым цветом. Установите флажок рядом с этим.
Закройте окно Build Settings (Параметры сборки).
Сохраните сцену и проект (ФАЙЛ>СОХРАНИТЬ СЦЕНУ или ФАЙЛ>СОХРАНИТЬ ПРОЕКТ).
Глава 4. Настройка основной камеры
Внимание
Если вы хотите пропустить компоненты настройки Unity этого курса и перейти прямо в код, вы можете скачать этот пакет unitypackage и импортировать его в проект в виде пользовательского пакета. Это также будет содержать библиотеки DLL из следующей главы. После импорта перейдите к главе 7.
На панели иерархии вы найдете объект с именем Main Camera, этот объект представляет вашу "головную" точку зрения после того, как вы "внутри" приложения.
На панели мониторинга Unity перед вами выберите главную камеру GameObject. Вы заметите, что панель инспектора (обычно найдена справа, в панели мониторинга) отобразит различные компоненты этого GameObject, с преобразованием вверху, а затем камерой и некоторыми другими компонентами. Вам потребуется сбросить преобразование основной камеры, поэтому он правильно расположен.
Для этого выберите значок Шестеренки рядом с компонентом преобразования камеры и нажмите кнопку "Сброс".
Затем обновите компонент преобразования , чтобы выглядеть следующим образом:
Преобразование — положение
X | Y | Z |
---|---|---|
0 | 1 | 0 |
Преобразование — поворот
X | Y | Z |
---|---|---|
0 | 0 | 0 |
Преобразование — масштабирование
X | Y | Z |
---|---|---|
1 | 1 | 1 |
Глава 5. Настройка сцены Unity
Щелкните правой кнопкой мыши пустую область панели иерархии в разделе трехмерный объект, добавьте плоскость.
Выбрав объект "Плоскость", измените следующие параметры на панели инспектора:
Преобразование — положение
X | Y | Z |
---|---|---|
0 | 0 | 4 |
Преобразование — масштабирование
X | Y | Z |
---|---|---|
10 | 1 | 10 |
Щелкните правой кнопкой мыши пустую область панели иерархии в разделе трехмерный объект, добавьте куб.
Переименуйте куб в GazeButton (с выбранным кубом нажмите клавишу F2).
Измените следующие параметры для позиции преобразования в панели инспектора:
X Y Z 0 3 5 Нажмите кнопку раскрывающегося списка тегов и нажмите кнопку "Добавить тег", чтобы открыть область "Теги и слои".
Нажмите кнопку +(плюс) и в поле "Имя нового тега", введите GazeButton и нажмите клавишу SAVE.
Щелкните объект GazeButton на панели иерархии и на панели инспектора назначьте только что созданный тег GazeButton.
Щелкните правой кнопкой мыши объект GazeButton на панели иерархии и добавьте пустой gameObject (который будет добавлен в качестве дочернего объекта).
Выберите новый объект и переименуйте его ShapeSpawnPoint.
Измените следующие параметры для позиции преобразования в панели инспектора:
X Y Z 0 -1 0
Затем вы создадите трехмерный текстовый объект для предоставления отзывов о состоянии службы Azure.
Щелкните правой кнопкой мыши элемент GazeButton на панели иерархии и добавьте трехмерный объект 3D>Text в качестве дочернего объекта.
Переименуйте трехмерный текстовый объект в AzureStatusText.
Измените положение преобразования объекта AzureStatusText следующим образом:
X Y Z 0 0 –0,6 Измените масштаб преобразования объекта AzureStatusText следующим образом: | X | Y | Z | :---: | :---: | :---: | | 0.1 | 0.1 | 0.1 | 0.1 |
Примечание.
Не беспокойтесь, если он, как представляется, отключен, так как это будет исправлено при обновлении следующего компонента сетки текста.
Измените компонент сетки текста следующим образом:
Совет
Выбранный цвет здесь шестнадцатеричный: 00000FF, хотя вы можете выбрать свой собственный, просто убедитесь, что он доступен для чтения.
Структура панели иерархии должна выглядеть следующим образом:
Теперь сцена должна выглядеть следующим образом:
Глава 6. Импорт служба хранилища Azure для Unity
Вы будете использовать служба хранилища Azure для Unity (который сам использует пакет SDK для .Net для Azure). Дополнительные сведения об этом см. в статье служба хранилища Azure для Unity.
В настоящее время в Unity существует известная проблема, которая требует перенастройки подключаемых модулей после импорта. Эти действия (4 – 7 в этом разделе) больше не потребуются после устранения ошибки.
Чтобы импортировать пакет SDK в собственный проект, убедитесь, что вы скачали последнюю версию unitypackage из GitHub. После этого выполните следующее:
Добавьте файл unitypackage в Unity с помощью> параметра меню "Импорт>пользовательского пакета ресурсов".
Во всплывающем окне импорта пакета Unity можно выбрать все в разделе "Хранилище подключаемых модулей>". Снимите флажок все остальное, так как для этого курса не требуется.
Нажмите кнопку "Импорт", чтобы добавить элементы в проект.
Перейдите в папку хранилища в разделе "Подключаемые модули" в представлении проекта и выберите только следующие подключаемые модули:
Microsoft.Data.Edm
Microsoft.Data.OData
Microsoft.WindowsAzure.Storage
Newtonsoft.Json
System.Spatial
Выбрав эти определенные подключаемые модули, снимите флажок "Любая платформа" и снимите флажок WSAPlayer и нажмите кнопку "Применить".
Примечание.
Мы помечаем эти конкретные подключаемые модули только в редакторе Unity. Это связано с тем, что в папке WSA существуют разные версии одинаковых подключаемых модулей, которые будут использоваться после экспорта проекта из Unity.
В папке подключаемого модуля хранилища выберите только:
Microsoft.Data.Services.Client
Установите флажок "Не обрабатывать" в разделе "Параметры платформы" и нажмите кнопку "Применить".
Примечание.
Мы помечаем этот подключаемый модуль "Не обрабатывать", так как исправление сборки Unity имеет трудности при обработке этого подключаемого модуля. Подключаемый модуль по-прежнему будет работать, даже если он не обработан.
Глава 7. Создание класса AzureServices
Первый класс, который вы собираетесь создать, — это класс AzureServices .
Класс AzureServices будет отвечать за:
Хранение учетных данных учетной записи Azure.
Вызов функции приложение Azure.
Отправка и скачивание файла данных в облачном хранилище Azure.
Чтобы создать этот класс, выполните указанные ниже действия.
Щелкните правой кнопкой мыши папку ресурса , расположенную на панели проекта, создайте>папку. Назовите скрипты папок.
Дважды щелкните только что созданную папку, чтобы открыть ее.
Щелкните правой кнопкой мыши в папке скрипт >C#. Вызовите скрипт AzureServices.
Дважды щелкните новый класс AzureServices, чтобы открыть его с помощью Visual Studio.
Добавьте следующие пространства имен в верхнюю часть AzureServices:
using System; using System.Threading.Tasks; using UnityEngine; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.File; using System.IO; using System.Net;
Добавьте следующие поля Инспектора в класс 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;
Затем добавьте следующие переменные-члены в класс 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.
Теперь необходимо добавить код для методов 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() в следующей главе.
Удалите метод Update(), так как этот класс не будет использовать его.
Сохраните изменения в Visual Studio и вернитесь в Unity.
Щелкните и перетащите класс AzureServices из папки "Скрипты" в объект Main Camera на панели иерархии.
Выберите основную камеру, а затем захватите дочерний объект AzureStatusText под объектом GazeButton и поместите его в поле целевого объекта AzureStatusText в инспекторе, чтобы указать ссылку на скрипт AzureServices.
Глава 8. Создание класса ShapeFactory
Следующий скрипт для создания — это класс ShapeFactory . Роль этого класса заключается в создании новой фигуры при запросе и сохранении журнала фигур, созданных в списке журналов фигур. Каждый раз при создании фигуры список журналов фигур обновляется в классе AzureService, а затем хранится в служба хранилища Azure. При запуске приложения, если сохраненный файл найден в служба хранилища Azure, список журналов фигур извлекается и воспроизводимся, при этом объект 3D Text предоставляет, является ли созданная фигура из хранилища или новая.
Чтобы создать этот класс, выполните указанные ниже действия.
Перейдите в папку "Скрипты", созданную ранее.
Щелкните правой кнопкой мыши в папке скрипт >C#. Вызовите скрипт ShapeFactory.
Дважды щелкните новый скрипт ShapeFactory, чтобы открыть его с помощью Visual Studio.
Убедитесь, что класс ShapeFactory включает следующие пространства имен:
using System.Collections.Generic; using UnityEngine;
Добавьте приведенные ниже переменные в класс 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>(); }
Метод 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); } }
Не забудьте сохранить изменения в Visual Studio, прежде чем вернуться в Unity.
Вернитесь в редактор Unity, щелкните и перетащите класс ShapeFactory из папки "Скрипты " в объект Main Camera на панели иерархии.
При выборе основной камеры вы заметите, что компонент скрипта ShapeFactory отсутствует ссылка spawn Point . Чтобы исправить его, перетащите объект ShapeSpawnPoint из панели иерархии в целевой объект ссылки Spawn Point .
Глава 9. Создание класса Gaze
Последний скрипт, который необходимо создать, — это класс Gaze .
Этот класс отвечает за создание Raycast , который будет проецирован с основной камеры, чтобы определить, какой объект смотрит пользователь. В этом случае raycast потребуется определить, смотрит ли пользователь на объект GazeButton в сцене и активирует поведение.
Чтобы создать этот класс, выполните указанные ниже действия.
Перейдите в папку "Скрипты", созданную ранее.
Щелкните правой кнопкой мыши панель проекта и создайте>скрипт C#. Вызовите скрипт Gaze.
Дважды щелкните новый скрипт Gaze , чтобы открыть его с помощью Visual Studio.
Убедитесь, что в верхней части скрипта включено следующее пространство имен:
using UnityEngine;
Затем добавьте следующие переменные в класс 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;
Внимание
Некоторые из этих переменных смогут изменяться в редакторе.
Теперь необходимо добавить код для методов 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(); }
Добавьте следующий код, который создаст объект курсора на начальном этапе вместе с методом 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(); } }
Затем добавьте метод 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(); } } } }
Наконец, добавьте метод 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; } } }
Сохраните изменения в Visual Studio перед возвращением в Unity.
Щелкните и перетащите класс Gaze из папки "Скрипты" в объект Main Camera на панели иерархии.
Глава 10. Завершение класса AzureServices
С помощью других сценариев теперь можно завершить класс AzureServices . Это будет достигнуто с помощью следующего:
Добавление нового метода с именем 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(); } }
Следующий фрагмент кода находится в методе 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(); }
Заполните код метода 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(); }
Добавьте метод для создания строки, сцепляя целые числа, хранящиеся в списке журналов фигур, и сохраняя его в файле служба хранилища 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); }
Добавьте метод, чтобы получить текст, хранящийся в файле, расположенном в файле служба хранилища Azure, и десериализировать его в список.
После завершения этого процесса метод повторно включает взгляд, чтобы пользователь мог добавить в сцену дополнительные фигуры.
///<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!"; }
Сохраните изменения в Visual Studio перед возвращением в Unity.
Глава 11. Создание решения UWP
Чтобы начать процесс сборки, выполните следующие действия.
Перейдите к параметрам сборки файлов>.
Нажмите кнопку " Создать". Unity запустит окно проводник, в котором необходимо создать, а затем выбрать папку для сборки приложения. Создайте папку и присвойте ей имя приложения. Затем с выбранной папкой приложения нажмите клавишу SELECT FOLDER.
Unity начнет создание проекта в папку приложения .
После завершения сборки Unity (может потребоваться некоторое время), откроется окно проводник в расположении сборки (проверьте панель задач, так как она может не всегда отображаться над окнами, но уведомит вас о добавлении нового окна).
Глава 12. Развертывание приложения
Чтобы развернуть приложение, выполните приведенные действия.
Перейдите в папку приложения , созданную в последней главе. Вы увидите файл с именем приложения с расширением ".sln", которое необходимо дважды щелкнуть, чтобы открыть его в Visual Studio.
На платформе решения выберите x86, Локальный компьютер.
В разделе "Конфигурация решения" выберите "Отладка".
Для Microsoft HoloLens это может быть проще установить на удаленный компьютер, чтобы вы не были подключены к компьютеру. Однако вам также потребуется выполнить следующие действия:
- Ознакомься с IP-адресом HoloLens, который можно найти в> разделе "Параметры сети" и "Расширенные параметры Интернета>Wi-Fi>".IPv4 — это адрес, который следует использовать.
- Убедитесь, что режим разработчика включен; в разделе "Параметры>обновления" и "Безопасность>для разработчиков".
Перейдите в меню "Сборка" и щелкните "Развернуть решение ", чтобы загрузить неопубликованное приложение на компьютер.
Теперь приложение должно отображаться в списке установленных приложений, готовых к запуску и тестированию!
Готовое приложение Функции Azure и хранилища
Поздравляем, вы создали приложение смешанной реальности, которое использует как Функции Azure, так и службы служба хранилища Azure. Ваше приложение сможет использовать сохраненные данные и предоставить действие на основе данных.
Дополнительные упражнения
Упражнение 1
Создайте вторую точку и запишите, из которой был создан объект. При загрузке файла данных воспроизводимые фигуры, которые создаются из исходного расположения.
Упражнение 2
Создайте способ перезапуска приложения, а не повторно открывать его каждый раз. Загрузка сцен является хорошим местом для начала. После этого создайте способ очистки сохраненного списка в служба хранилища Azure, чтобы его можно было легко сбросить из приложения.