213. Ввод в смешанной реальности: контроллеры движений

Примечание

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

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

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

Темы, рассматриваемые в этом руководстве

MixedReality213 Topic1 MixedReality213 Topic2 MixedReality213 Topic3
Визуализация контроллера События ввода контроллера Пользовательский контроллер и пользовательский интерфейс
Узнайте, как отображать модели контроллеров движения в игровом режиме и среде выполнения Unity. Сведения о различных типах событий кнопок и их приложениях. Узнайте, как наложить элементы пользовательского интерфейса поверх контроллера или полностью настроить его.

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

Курс HoloLens Иммерсивные гарнитуры
213. Ввод в смешанной реальности: контроллеры движений ✔️

Прежде чем начать

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

Ознакомьтесь с контрольным списком установки иммерсивных гарнитур на этой странице.

Файлы проекта

Примечание

Если вы хотите просмотреть исходный код перед скачиванием, он доступен на сайте GitHub.

Настройка Unity

Задачи

  • Оптимизация Unity для разработки Windows Mixed Reality
  • Настройка камеры Смешанная реальность
  • Настраиваете среду.

Instructions

  • Запустите Unity.

  • Выберите Открыть.

  • Перейдите на рабочий стол и найдите папку MixedReality213-master, которая была ранее распакована.

  • Щелкните элемент Выбор папки.

  • Когда Unity завершит загрузку файлов проекта, вы сможете увидеть редактор Unity.

  • В Unity выберите Параметры сборки файлов>.

    MR213_BuildSettings

  • Выберите универсальная платформа Windows в списке Платформа и нажмите кнопку Переключить платформу.

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

  • Задайте для параметра Build Type (Тип сборки) значение D3D.

  • Установите для пакета SDK значение Latest Installed (Последняя установленная версия)

  • Проверка проектов Unity C#

    • Это позволяет изменять файлы скриптов в проекте Visual Studio без перестроения проекта Unity.
  • Щелкните Параметры проигрывателя.

  • На панели Инспектор прокрутите вниз.

  • В параметрах XR проверка поддерживается виртуальная реальность.

  • В разделе Пакеты SDK для виртуальной реальности выберите Windows Mixed Reality

    MR213_XRSettings

  • Закройте окно параметров сборки .

Структура проекта

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

Структура проекта

Завершенные сцены для справки

  • Две завершенные сцены Unity находятся в папке Scenes .
    • MixedReality213: завершенная сцена с одной кистью
    • MixedReality213Advanced: завершенная сцена для расширенного проектирования с помощью нескольких кистей

Настройка новой сцены для руководства

  • В Unity щелкните Файл > Создать сцену.

  • Удаление основной камеры и направленного света

  • На панели Проект найдите и перетащите следующие заготовки на панель Иерархия :

    • Assets/HoloToolkit/Input/Prefabs/MixedRealityCamera
    • Активы/AppPrefabs/Среда

    Камера и среда

  • В наборе средств Смешанная реальность Toolkit есть два заготовки камеры:

    • MixedRealityCamera.prefab: только камера
    • MixedRealityCameraParent.prefab: Камера + Телепортация + Граница
    • В этом руководстве мы будем использовать MixedRealityCamera без функции телепортации. Поэтому мы добавили простую заготовку Среды , которая содержит базовый пол, чтобы пользователь чувствовал себя заземленным.
    • Дополнительные сведения о телепортации с помощью MixedRealityCameraParent см. в статье Расширенный дизайн — телепортация и перемещение

Настройка Skybox

  • Щелкните Параметры освещения > окна>.

  • Щелкните круг в правой части поля Материал Skybox.

  • Введите "gray" и выберите SkyboxGray (Assets/AppPrefabs/Support/Materials/SkyboxGray.mat)

    Настройка skybox

  • Установите флажок Skybox для просмотра выделенного серого градиента skybox

    Переключатель скайбокс

  • Сцена с MixedRealityCamera, Environment и серым skybox будет выглядеть следующим образом.

    Среда MixedReality213

  • Щелкните Файл > Сохранить сцену как.

  • Сохраните сцену в папке Scenes с любым именем

Глава 1. Визуализация контроллера

Задачи

  • Узнайте, как отображать модели контроллера движения в игровом режиме Unity и во время выполнения.

Windows Mixed Reality предоставляет анимированную модель контроллера для визуализации контроллера. Существует несколько подходов к визуализации контроллера в приложении.

  • По умолчанию — использование контроллера по умолчанию без изменений
  • Гибридная среда — использование контроллера по умолчанию, но настройка некоторых его элементов или наложение компонентов пользовательского интерфейса
  • Замена — использование собственной настроенной трехмерной модели для контроллера

В этой главе мы рассмотрим примеры этих настроек контроллера.

Instructions

  • На панели Проект в поле поиска введите MotionControllers . Его также можно найти в разделе Assets/HoloToolkit/Input/Prefabs/.
  • Перетащите заготовку MotionControllers на панель Иерархия .
  • Щелкните заготовку MotionControllers на панели Иерархия .

Заготовка MotionControllers

Заготовка MotionControllers содержит скрипт MotionControllerVisualizer , который предоставляет слоты для альтернативных моделей контроллеров. Если вы назначите собственные трехмерные модели, такие как рука или меч, и проверка "Всегда использовать альтернативную левую или правую модель", вы увидите их вместо модели по умолчанию. Мы будем использовать этот слот в главе 4 для замены модели контроллера кистью.

MR213_ControllerVisualizer

Инструкции

  • На панели Инспектор дважды щелкните скрипт MotionControllerVisualizer , чтобы просмотреть код в Visual Studio.

Скрипт MotionControllerVisualizer

Классы MotionControllerVisualizer и MotionControllerInfo предоставляют средства для доступа к & изменения моделей контроллеров по умолчанию. MotionControllerVisualizer подписывается на событие InteractionSourceDetected в Unity и автоматически создает экземпляры моделей контроллеров при их обнаружении.

protected override void Awake()
{
    ...
    InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
    InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
    ...
}

Модели контроллеров доставляются в соответствии со спецификацией glTF. Этот формат был создан для предоставления общего формата, а также улучшения процесса передачи и распаковки трехмерных ресурсов. В этом случае необходимо извлечь и загрузить модели контроллера во время выполнения, так как мы хотим сделать взаимодействие с пользователем максимально простым, и это не гарантирует, какую версию контроллеров движения может использовать пользователь. В этом курсе с помощью Смешанная реальность Toolkit используется версия проекта UnityGLTF группы Khronos.

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

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

В некоторых сценариях вы найдете блоки кода с #if ! UNITY_EDITOR или UNITY_WSA. Эти блоки кода выполняются только в среде выполнения UWP при развертывании в Windows. Это связано с тем, что набор API, используемых редактором Unity и средой выполнения приложения UWP, отличается.

  • Сохраните сцену и нажмите кнопку воспроизведения .

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

MR213_Controller визуализация по умолчанию

Глава 2. Присоединение элементов пользовательского интерфейса к контроллеру

Задачи

  • Сведения об элементах контроллеров движения
  • Сведения о присоединении объектов к определенным частям контроллеров

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

Instructions

  • На панели Проект найдите скрипт MotionControllerInfo .
  • В результатах поиска дважды щелкните скрипт MotionControllerInfo , чтобы просмотреть код в Visual Studio.

Скрипт MotionControllerInfo

Первым шагом является выбор элемента контроллера, к которому требуется подключить пользовательский интерфейс. Эти элементы определяются в ControllerElementEnum в Файле MotionControllerInfo.cs.

MR213 MotionControllerElements

  • Дом
  • Menu
  • Понять
  • Стик
  • Select
  • Сенсорная панель
  • Положение указателя — этот элемент представляет кончик контроллера, указывающего направление вперед.

Инструкции

  • На панели Проект выполните поиск скрипта AttachToController .
  • В результатах поиска дважды щелкните скрипт AttachToController , чтобы просмотреть код в Visual Studio.

Скрипт AttachToController

Скрипт AttachToController предоставляет простой способ присоединения любых объектов к указанному контроллеру и элементу.

В AttachElementToController(),

  • Проверка сданности с помощью MotionControllerInfo.Handedness
  • Получение определенного элемента контроллера с помощью MotionControllerInfo.TryGetElement()
  • После получения преобразования элемента из модели контроллера родительский объект под ним и задайте для локального положения объекта & повороте значение нуля.
public MotionControllerInfo.ControllerElementEnum Element { get { return element; } }

private void AttachElementToController(MotionControllerInfo newController)
{
     if (!IsAttached && newController.Handedness == handedness)
     {
          if (!newController.TryGetElement(element, out elementTransform))
          {
               Debug.LogError("Unable to find element of type " + element + " under controller " + newController.ControllerParent.name + "; not attaching.");
               return;
          }

          controller = newController;

          SetChildrenActive(true);

          // Parent ourselves under the element and set our offsets
          transform.parent = elementTransform;
          transform.localPosition = positionOffset;
          transform.localEulerAngles = rotationOffset;
          if (setScaleOnAttach)
          {
               transform.localScale = scale;
          }

          // Announce that we're attached
          OnAttachToController();
          IsAttached = true;
     }
}

Самый простой способ использовать скрипт AttachToController — наследовать от него, как это было сделано в случае с ColorPickerWheel. Просто переопределите функции OnAttachToController и OnDetachFromController , чтобы выполнить настройку или разбивку при обнаружении или отключении контроллера.

Инструкции

  • На панели Проект введите в поле поиска ColorPickerWheel. Его также можно найти в разделе Активы/AppPrefabs/.
  • Перетащите заготовку ColorPickerWheel на панель Иерархия .
  • Щелкните заготовку ColorPickerWheel на панели Иерархия .
  • На панели Инспектор дважды щелкните Скрипт ColorPickerWheel , чтобы просмотреть код в Visual Studio.

Заготовка ColorPickerWheel

Скрипт ColorPickerWheel

Так как ColorPickerWheel наследует AttachToController, на панели Инспектор отображаются элементы Handedness и Element. Мы подключим пользовательский интерфейс к элементу Сенсорной панели на левом контроллере.

Скрипт ColorPickerWheel

ColorPickerWheel переопределяет OnAttachToController и OnDetachFromController , чтобы подписаться на событие ввода, которое будет использоваться в следующей главе для выбора цвета с помощью сенсорной панели.

public class ColorPickerWheel : AttachToController, IPointerTarget
{
    protected override void OnAttachToController()
    {
        // Subscribe to input now that we're parented under the controller
        InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
    }

    protected override void OnDetachFromController()
    {
        Visible = false;

        // Unsubscribe from input now that we've detached from the controller
        InteractionManager.InteractionSourceUpdated -= InteractionSourceUpdated;
    }
    ...
}
  • Сохраните сцену и нажмите кнопку воспроизведения .

Альтернативный метод присоединения объектов к контроллерам

Рекомендуется, чтобы скрипты наследовали от AttachToController и переопределили OnAttachToController. Однако это не всегда возможно. Альтернативой является использование его в качестве автономного компонента. Это может быть полезно, если требуется подключить существующую заготовку к контроллеру без рефакторинга скриптов. Перед выполнением любой настройки просто дождитесь, пока isAttached будет задано значение true. Самый простой способ сделать это — использовать сопрограмму для start.

private IEnumerator Start() {
    AttachToController attach = gameObject.GetComponent<AttachToController>();

    while (!attach.IsAttached) {
        yield return null;
    }

    // Perform setup here
}

Глава 3. Работа с вводом на сенсорной панели

Задачи

  • Узнайте, как получить события входных данных сенсорной панели
  • Узнайте, как использовать сведения о положении оси сенсорной панели для работы с приложением

Instructions

  • На панели Иерархия щелкните ColorPickerWheel.
  • На панели Инспектор в разделе Аниматор дважды щелкните ColorPickerWheelController.
  • Откроется вкладка "Аниматор "

Отображение или скрытие пользовательского интерфейса с контроллером анимации Unity

Чтобы отобразить и скрыть пользовательский интерфейс ColorPickerWheel с анимацией , мы используем систему анимации Unity. Установка свойства Visible ColorPickerWheel в значение true или false триггеры Показать и Скрыть триггеры анимации. Параметры Show и Hide определяются в контроллере анимации ColorPickerWheelController .

Контроллер анимации Unity

Инструкции

  • На панели Иерархия выберите Заготовка ColorPickerWheel .
  • На панели Инспектор дважды щелкните скрипт ColorPickerWheel , чтобы просмотреть код в Visual Studio.

Скрипт ColorPickerWheel

ColorPickerWheel подписывается на событие InteractionSourceUpdated в Unity для прослушивания событий сенсорной панели.

В InteractionSourceUpdated() скрипт сначала проверяет, что он:

  • на самом деле является событием сенсорной панели (obj.state.touchpadTouched)
  • происходит из левого контроллера (obj.state.source.рукой)

Если оба значения имеют значение true, положение сенсорной панели (obj.state.touchpadPosition) назначается selectorPosition.

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness && obj.state.touchpadTouched)
    {
        Visible = true;
        selectorPosition = obj.state.touchpadPosition;
    }
}

В Update()на основе видимого свойства он активирует триггеры анимации Show и Hide в компоненте аниматора выбора цвета.

if (visible != visibleLastFrame)
{
    if (visible)
    {
        animator.SetTrigger("Show");
    }
    else
    {
        animator.SetTrigger("Hide");
    }
}

В Update()selectorPosition используется для отвода луча на сетчатом коллайде цветового круга, который возвращает положение УФ. Затем эту позицию можно использовать для поиска координаты пикселя и значения цвета текстуры цветового колесика. Это значение доступно для других скриптов с помощью свойства SelectedColor .

Цветопередачи колесика

...
    // Clamp selector position to a radius of 1
    Vector3 localPosition = new Vector3(selectorPosition.x * inputScale, 0.15f, selectorPosition.y * inputScale);
    if (localPosition.magnitude > 1)
    {
        localPosition = localPosition.normalized;
    }
    selectorTransform.localPosition = localPosition;

    // Raycast the wheel mesh and get its UV coordinates
    Vector3 raycastStart = selectorTransform.position + selectorTransform.up * 0.15f;
    RaycastHit hit;
    Debug.DrawLine(raycastStart, raycastStart - (selectorTransform.up * 0.25f));

    if (Physics.Raycast(raycastStart, -selectorTransform.up, out hit, 0.25f, 1 << colorWheelObject.layer, QueryTriggerInteraction.Ignore))
    {
        // Get pixel from the color wheel texture using UV coordinates
        Vector2 uv = hit.textureCoord;
        int pixelX = Mathf.FloorToInt(colorWheelTexture.width * uv.x);
        int pixelY = Mathf.FloorToInt(colorWheelTexture.height * uv.y);
        selectedColor = colorWheelTexture.GetPixel(pixelX, pixelY);
        selectedColor.a = 1f;
    }
    // Set the selector's color and blend it with white to make it visible on top of the wheel
    selectorRenderer.material.color = Color.Lerp (selectedColor, Color.white, 0.5f);
}

Глава 4. Переопределение модели контроллера

Задачи

  • Узнайте, как переопределить модель контроллера с помощью пользовательской трехмерной модели.

MR213_BrushToolOverride

Instructions

  • Щелкните MotionControllers на панели Иерархия .
  • Щелкните круг в правой части поля Альтернативный правый контроллер .
  • Введите BrushController и выберите заготовку из результата. Его можно найти в разделе Assets/AppPrefabs/BrushController.
  • Проверка постоянного использования альтернативной правой модели

MR213_BrushToolOverrideSlot

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

  • На панели Проект введите BrushController и перетащите заготовку BrushController на панель Иерархия .

MR213_BrushTool_Prefab2

Компонент Tip можно найти в BrushController. Мы будем использовать его преобразование для начала и остановки рисования линий.

  • Удалите BrushController из панели Иерархия .
  • Сохраните сцену и нажмите кнопку воспроизведения . Вы увидите, что модель кисти заменила правый контроллер движения.

Глава 5. Рисование с помощью входных данных Select

Задачи

  • Узнайте, как использовать событие кнопки Select для запуска и остановки рисования линии

Instructions

  • Найдите заготовку BrushController на панели Проект .
  • На панели Инспектор дважды щелкните BrushController Script, чтобы просмотреть код в Visual Studio.

Скрипт BrushController

BrushController подписывается на события InteractionSourcePressed и InteractionSourceReleased в InteractionManager. При активации события InteractionSourcePressed свойство Draw кисти имеет значение true; При активации события InteractionSourceReleased свойство Draw кисти имеет значение false.

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = true;
    }
}

private void InteractionSourceReleased(InteractionSourceReleasedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = false;
    }
}

Хотя для draw задано значение true, кисть будет создавать точки в экземпляре Unity LineRenderer. Ссылка на эту заготовку хранится в поле "Заготовка росчерка " кисти.

private IEnumerator DrawOverTime()
{
    // Get the position of the tip
    Vector3 lastPointPosition = tip.position;

    ...

    // Create a new brush stroke
    GameObject newStroke = Instantiate(strokePrefab);
    LineRenderer line = newStroke.GetComponent<LineRenderer>();
    newStroke.transform.position = startPosition;
    line.SetPosition(0, tip.position);
    float initialWidth = line.widthMultiplier;

    // Generate points in an instantiated Unity LineRenderer
    while (draw)
    {
        // Move the last point to the draw point position
        line.SetPosition(line.positionCount - 1, tip.position);
        line.material.color = colorPicker.SelectedColor;
        brushRenderer.material.color = colorPicker.SelectedColor;
        lastPointAddedTime = Time.unscaledTime;
        // Adjust the width between 1x and 2x width based on strength of trigger pull
        line.widthMultiplier = Mathf.Lerp(initialWidth, initialWidth * 2, width);

        if (Vector3.Distance(lastPointPosition, tip.position) > minPositionDelta || Time.unscaledTime > lastPointAddedTime + maxTimeDelta)
        {
            // Spawn a new point
            lastPointAddedTime = Time.unscaledTime;
            lastPointPosition = tip.position;
            line.positionCount += 1;
            line.SetPosition(line.positionCount - 1, lastPointPosition);
        }
        yield return null;
    }
}

Чтобы использовать текущий выбранный цвет из пользовательского интерфейса колесика выбора цвета, BrushController должен иметь ссылку на объект ColorPickerWheel . Так как заготовка BrushController создается во время выполнения в качестве замены контроллера, все ссылки на объекты в сцене должны быть заданы во время выполнения. В этом случае мы используем GameObject.FindObjectOfType для поиска ColorPickerWheel:

private void OnEnable()
{
    // Locate the ColorPickerWheel
    colorPicker = FindObjectOfType<ColorPickerWheel>();

    // Assign currently selected color to the brush’s material color
    brushRenderer.material.color = colorPicker.SelectedColor;
    ...
}
  • Сохраните сцену и нажмите кнопку воспроизведения . Вы сможете рисовать линии и рисовать с помощью кнопки выбора на контроллере справа.

Глава 6. Нерестирование объектов с помощью входных данных Select

Задачи

  • Узнайте, как использовать события ввода кнопки Выбора и Захвата
  • Узнайте, как создавать экземпляры объектов

Instructions

  • На панели Проект в поле поиска введите ObjectSpawner . Вы также можете найти его в разделе Активы/AppPrefabs/

  • Перетащите заготовку ObjectSpawner на панель Иерархия .

  • Щелкните ObjectSpawner на панели Иерархия .

  • ObjectSpawner имеет поле с именем Источник цвета.

  • С панели Иерархия перетащите ссылку ColorPickerWheel в это поле.

    Инспектор spawner объекта

  • Щелкните заготовку ObjectSpawner на панели Иерархия .

  • На панели Inspector (Инспектор ) дважды щелкните ObjectSpawner Script (Скрипт ObjectSpawner ), чтобы просмотреть код в Visual Studio.

Скрипт ObjectSpawner

ObjectSpawner создает экземпляры примитивной сетки (куба, сферы, цилиндра) в пространстве. При обнаружении InteractionSourcePressed проверяется возможность передачи и событие InteractionSourcePressType.Grasp или InteractionSourcePressType.Select .

Для события Захват увеличивается индекс текущего типа сетки (сфера, куб, цилиндр).

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    // Check handedness, see if it is left controller
    if (obj.state.source.handedness == handedness)
    {
        switch (obj.pressType)
        {
            // If it is Select button event, spawn object
            case InteractionSourcePressType.Select:
                if (state == StateEnum.Idle)
                {
                    // We've pressed the grasp - enter spawning state
                    state = StateEnum.Spawning;
                    SpawnObject();
                }
                break;

            // If it is Grasp button event
            case InteractionSourcePressType.Grasp:

                // Increment the index of current mesh type (sphere, cube, cylinder)
                meshIndex++;
                if (meshIndex >= NumAvailableMeshes)
                {
                    meshIndex = 0;
                }
                break;

            default:
                break;
        }
    }
}

Для события Select в SpawnObject() создается экземпляр нового объекта, который не является родительским и освобождается в мире.

private void SpawnObject()
{
    // Instantiate the spawned object
    GameObject newObject = Instantiate(displayObject.gameObject, spawnParent);
    // Detach the newly spawned object
    newObject.transform.parent = null;
    // Reset the scale transform to 1
    scaleParent.localScale = Vector3.one;
    // Set its material color so its material gets instantiated
    newObject.GetComponent<Renderer>().material.color = colorSource.SelectedColor;
}

ObjectSpawner использует ColorPickerWheel для задания цвета материала отображаемого объекта. Порождаемые объекты получают экземпляр этого материала, чтобы они сохранили свой цвет.

  • Сохраните сцену и нажмите кнопку воспроизведения .

Вы сможете изменять объекты с помощью кнопки Захват и создавать объекты с помощью кнопки Выбрать.

Создание и развертывание приложения на портале Смешанная реальность

  • В Unity выберите Параметры сборки файлов>.
  • Щелкните Добавить открытые сцены , чтобы добавить текущую сцену в сцены в сборке.
  • Щелкните Построить.
  • Создайте новую папку с именем App.
  • Щелкните папку App одним щелчком.
  • Щелкните элемент Выбор папки.
  • По завершении работы Unity появится окно проводник.
  • Откройте папку Приложение .
  • Дважды щелкните файл решения Visual Studio YourSceneName.sln .
  • С помощью верхней панели инструментов в Visual Studio измените целевой объект с Отладка на Выпуск и с ARM на X64.
  • Щелкните стрелку раскрывающегося списка рядом с кнопкой Устройство и выберите Локальный компьютер.
  • Щелкните Отладка —> запуск без отладки в меню или нажмите клавиши CTRL+F5.

Теперь приложение создано и установлено на портале Смешанная реальность. Его можно запустить снова с помощью меню "Пуск" на портале Смешанная реальность.

Расширенный дизайн — инструменты кисти с радиальным макетом

MixedReality213 Main

В этой главе вы узнаете, как заменить модель контроллера движения по умолчанию пользовательской коллекцией инструментов кистей. Для справки вы можете найти завершенную сцену MixedReality213Advanced в папке Scenes .

Instructions

  • На панели Проект в поле поиска введите BrushSelector . Вы также можете найти его в разделе Активы/AppPrefabs/

  • Перетащите заготовку BrushSelector на панель Иерархия .

  • Для организации создайте пустой GameObject с именем Brushes.

  • Перетащите следующие заготовки с панели Проект в кисти

    • Assets/AppPrefabs/BrushFat
    • Assets/AppPrefabs/BrushThin
    • Assets/AppPrefabs/Eraser
    • Assets/AppPrefabs/MarkerFat
    • Assets/AppPrefabs/MarkerThin
    • Assets/AppPrefabs/Pencil

    Кисти

  • Щелкните Заготовка MotionControllers на панели Иерархия .

  • На панели Инспектор снимите флажок Всегда использовать альтернативную правую модель в визуализаторе контроллера движения.

  • На панели Иерархия щелкните BrushSelector.

  • BrushSelector содержит поле с именем ColorPicker

  • Из панели Иерархия перетащите ColorPickerWheel в поле ColorPicker на панели Инспектор .

    Назначение ColorPickerWheel для селектора кисти

  • На панели Иерархия в разделе Заготовка BrushSelector выберите объект Menu .

  • На панели Инспектор в компоненте LineObjectCollection откройте раскрывающийся список Массив объектов . Вы увидите 6 пустых слотов.

  • На панели Иерархия перетащите каждый из заготовок под gameObject Brushes в эти слоты в любом порядке. (Убедитесь, что вы перетаскиваете заготовки из сцены, а не заготовки в папке проекта.)

Селектор кисти

Заготовка BrushSelector

Так как BrushSelector наследует AttachToController, в нем отображаются параметры Handedness и Element на панели Инспектор . Мы выбрали правое и указывающее положение , чтобы прикрепить инструменты кисти к контроллеру правой руки с направлением вперед.

BrushSelector использует две служебные программы:

  • Эллипс: используется для создания точек в пространстве вдоль фигуры эллипса.
  • LineObjectCollection: распределяет объекты с помощью точек, созданных любым классом Line (например, Ellipse). Это то, что мы будем использовать для размещения кистей вдоль фигуры Эллипса.

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

Скрипт LineObjectCollection

LineObjectCollection имеет элементы управления размером, положением и поворотом объектов, распределенных вдоль его линии. Это полезно для создания радиальных меню, таких как селектор кисти. Чтобы создать внешний вид кистей, которые масштабируются с нуля по мере приближения к выбранной позиции центра, кривая ObjectScale достигает пиков в центре и сужается по краям.

Скрипт BrushSelector

В случае BrushSelector мы решили использовать процедурную анимацию. Во-первых, модели кистей распределяются многоточием с помощью скрипта LineObjectCollection . Затем каждая кисть отвечает за сохранение своего положения в руке пользователя на основе его значения DisplayMode , которое изменяется в зависимости от выбора. Мы выбрали процедурный подход из-за высокой вероятности прерывания переходов положения кисти при выборе пользователем кистей. Анимация Mecanim может корректно обрабатывать прерывания, но она, как правило, сложнее, чем простая операция Lerp.

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

Визуализация ввода на сенсорной панели

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

protected override void OnAttachToController()
{
    // Turn off the default controller's renderers
    controller.SetRenderersVisible(false);

    // Get the touchpad and assign our custom material to it
    Transform touchpad;
    if (controller.TryGetElement(MotionControllerInfo.ControllerElementEnum.Touchpad, out touchpad))
    {
        touchpadRenderer = touchpad.GetComponentInChildren<MeshRenderer>();
        originalTouchpadMaterial = touchpadRenderer.material;
        touchpadRenderer.material = touchpadMaterial;
        touchpadRenderer.enabled = true;
    }

    // Subscribe to input now that we're parented under the controller
    InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
}

private void Update()
{
    ...
    // Update our touchpad material
    Color glowColor = touchpadColor.Evaluate((Time.unscaledTime - touchpadTouchTime) / touchpadGlowLossTime);
    touchpadMaterial.SetColor("_EmissionColor", glowColor);
    touchpadMaterial.SetColor("_Color", glowColor);
    ...
}

Выбор инструмента "Кисть" с вводом на сенсорной панели

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

Толщина штриха с помощью selectPressedAmount

Вместо события InteractionSourcePressType.Select в InteractionSourcePressed() можно получить аналоговое значение нажатой суммы с помощью selectPressedAmount. Это значение можно получить в разделе InteractionSourceUpdated().

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness)
    {
        if (obj.state.touchpadPressed)
        {
            // Check which side we clicked
            if (obj.state.touchpadPosition.x < 0)
            {
                currentAction = SwipeEnum.Left;
            }
            else
            {
                currentAction = SwipeEnum.Right;
            }

            // Ping the touchpad material so it gets bright
            touchpadTouchTime = Time.unscaledTime;
        }

        if (activeBrush != null)
        {
            // If the pressed amount is greater than our threshold, draw
            if (obj.state.selectPressedAmount >= selectPressedDrawThreshold)
            {
                activeBrush.Draw = true;
                activeBrush.Width = ProcessSelectPressedAmount(obj.state.selectPressedAmount);
            }
            else
            {
                // Otherwise, stop drawing
                activeBrush.Draw = false;
                selectPressedSmooth = 0f;
            }
        }
    }
}

Скрипт ластика

Ластик — это особый тип кисти, который переопределяет базовую функцию DrawOverTime(). Хотя значение Draw имеет значение true, ластик проверяет, пересекается ли его кончик с существующими штрихами кисти. Если это так, они добавляются в очередь для сжатия и удаления.

Расширенный дизайн — телепортация и перемещение

Если вы хотите разрешить пользователю перемещаться по сцене с помощью телепортации с помощью отпечатка, используйте MixedRealityCameraParent вместо MixedRealityCamera. Также необходимо добавить InputManager и DefaultCursor. Так как MixedRealityCameraParent уже включает в себя MotionControllers и Boundary в качестве дочерних компонентов, следует удалить существующие элементы MotionControllers и заготовкуСреды .

Instructions

  • На панели Иерархия удалите MixedRealityCamera, Environment и MotionControllers.

  • На панели Проект найдите и перетащите следующие заготовки на панель Иерархия :

    • Assets/AppPrefabs/Input/Prefabs/MixedRealityCameraParent
    • Assets/AppPrefabs/Input/Prefabs/InputManager
    • Assets/AppPrefabs/Input/Prefabs/Cursor/DefaultCursor

    Родитель камеры Смешанная реальность

  • На панели Иерархия щелкните Диспетчер входных данных.

  • На панели Инспектор прокрутите вниз до раздела Простой селектор с одним указателем .

  • Из панели Иерархия перетащите DefaultCursor в поле Курсор .

    Назначение DefaultCursor

  • Сохраните сцену и нажмите кнопку воспроизведения . Вы сможете использовать стик для поворота влево/вправо или телепорта.

Конец

И это конец этого учебника! Вы узнали:

  • Как работать с моделями контроллера движения в игровом режиме и среде выполнения Unity.
  • Использование различных типов событий кнопки и их приложений.
  • Сведения о наложении элементов пользовательского интерфейса на контроллер или его полной настройке.

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

Завершенные сцены

  • На панели Проект Unity щелкните папку Сцены .
  • Вы найдете две сцены Unity MixedReality213 и MixedReality213Дополнительно.
    • MixedReality213: завершенная сцена с одной кистью
    • MixedReality213Advanced: завершенная сцена с несколькими кистью с примером нажатия кнопки выбора

См. также раздел