Пример. Расширение возможностей пространственного сопоставления HoloLens

При создании первых приложений для Microsoft HoloLens мы хотели видеть, насколько далеко мы могли бы отправить границы пространственного сопоставления на устройстве. Джефф Эвертт ( Jeff Evertt), инженер по программному обеспечению в Microsoft Studios, объясняет, как была разработана новая технология, не требуя больше контроля над тем, как голограммы размещаются в реальной среде пользователя.

Примечание

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

Просмотреть видео

Вне пространственного сопоставления

Хотя мы работали над фрагментами и Young Conker, две из первых игр для HoloLens, мы обнаружили, что, когда мы делали процедурное размещение голограмм в физическом мире, нам нужен более высокий уровень понимания среды пользователя. Каждая игра имеет свои собственные потребности в размещении: в фрагментах, например, мы хотели бы иметь возможность различать различные поверхности , такие как пол или стол, чтобы разместить подсказки в соответствующих местах. Мы также хотели иметь возможность идентифицировать поверхности, на которых могут сидеть голографические персонажи размером жизни, например диван или стул. В Young Conker мы хотели, чтобы Конкер и его противники могли использовать поднятые поверхности в комнате игрока в качестве платформ.

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

Код пространственного распознавания

Мы взяли исходный код Asobo и создали библиотеку, которая инкапсулирует эту технологию. Корпорация Майкрософт и Asobo теперь имеют открытый исходный код и сделали его доступным в MixedRealityToolkit для использования в собственных проектах. Весь исходный код включен, что позволяет настроить его в соответствии с вашими потребностями и поделиться улучшениями с сообществом. Код решателя C++ был упакован в библиотеку DLL UWP и предоставлен Unity с префабом раскрывающегося списка, содержащегося в MixedRealityToolkit.

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

Хотя решение пространственного сопоставления, предоставляемое HoloLens, должно быть достаточно универсальным для удовлетворения потребностей всего гамма проблемных пространств, модуль пространственного понимания был создан для поддержки потребностей двух конкретных игр. Таким образом, его решение структурировано вокруг определенного процесса и набора предположений:

  • Фиксированное пространство воспроизведения: пользователь задает максимальный размер пространства воспроизведения в вызове инициализации.
  • Однократный процесс сканирования: для этого процесса требуется этап дискретного сканирования, в котором пользователь проходит, определяя пространство воспроизведения. Функции запросов не будут работать до завершения проверки.
  • Управляемое пользователем пространство воспроизведения "рисование": во время этапа сканирования пользователь перемещается и смотрит вокруг пространства воспроизведения, эффективно рисуя области, которые должны быть включены. Созданная сетка важна для предоставления отзывов пользователей на этом этапе.
  • Настройка дома или офиса в помещении: функции запросов разработаны вокруг плоских поверхностей и стен под прямым углом. Это мягкое ограничение. Однако на этапе сканирования выполняется анализ основной оси для оптимизации тесселяции сетки вдоль основной и дополнительной оси.

Процесс сканирования помещений

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

Сетка, наблюдаемая на этом этапе, является важной частью визуальной обратной связи, которая позволяет пользователям узнать, какие части комнаты сканируются. Библиотека DLL для модуля пространственного понимания внутренне хранит пространство воспроизведения в виде сетки объемных кубов размером 8 см. Во время начальной части сканирования выполняется анализ основного компонента для определения осей комнаты. Внутри системы он хранит пространство объемной оси, выровненное по этим осям. Сетка создается приблизительно каждую секунду путем извлечения isosurface из тома voxel.

Spatial mapping mesh in white and understanding playspace mesh in green

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

Включенный файл SpatialUnderstanding.cs управляет процессом этапа сканирования. Он вызывает следующие функции:

  • SpatialUnderstanding_Init: вызывается один раз в начале.
  • GeneratePlayspace_InitScan. Указывает, что этап сканирования должен начинаться.
  • GeneratePlayspace_UpdateScan_DynamicScan: вызывается каждый кадр для обновления процесса сканирования. Положение и ориентация камеры передаются и используются для процесса рисования пространства воспроизведения, как описано выше.
  • GeneratePlayspace_RequestFinish: вызывается для завершения пространства воспроизведения. При этом области "окрашены" на этапе сканирования будут использоваться для определения и блокировки пространства воспроизведения. Приложение может запрашивать статистику на этапе сканирования, а также запрашивать пользовательскую сетку для предоставления отзывов пользователей.
  • Import_UnderstandingMesh. Во время сканирования поведение SpatialUnderstandingCustomMesh , предоставляемое модулем и помещенное на предварительное представление, будет периодически запрашивать пользовательскую сетку, созданную процессом. Кроме того, это делается еще раз после завершения сканирования.

Поток сканирования, управляемый поведением SpatialUnderstanding , вызывает InitScan, а затем UpdateScan каждый кадр. Когда запрос статистики сообщает о разумном охвате, пользователь может перезаставить запрос на вызов RequestFinish , чтобы указать конец этапа сканирования. UpdateScan продолжает вызываться до тех пор, пока не будет возвращено значение, указывающее, что библиотека DLL завершила обработку.

Запросы

После завершения проверки вы сможете получить доступ к трем разным типам запросов в интерфейсе:

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

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

Запросы топологии

В библиотеке DLL диспетчер топологии обрабатывает метки среды. Как упоминалось выше, большая часть данных хранится в серферах, которые содержатся в томе voxel. Кроме того, структура PlaySpaceInfos используется для хранения сведений о пространстве воспроизведения, включая выравнивание мира (дополнительные сведения об этом ниже), пол и высоту потолка.

Эвристика используется для определения пола, потолка и стен. Например, самая большая и самая низкая горизонтальная поверхность с площадью более 1 м2 считается полом. Обратите внимание, что путь камеры во время процесса сканирования также используется в этом процессе.

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

  • QueryTopology_FindPositionsOnWalls
  • QueryTopology_FindLargePositionsOnWalls
  • QueryTopology_FindLargestWall
  • QueryTopology_FindPositionsOnFloor
  • QueryTopology_FindLargestPositionsOnFloor
  • QueryTopology_FindPositionsSittable

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

EXTERN_C __declspec(dllexport) int QueryTopology_FindPositionsOnWalls(
          _In_ float minHeightOfWallSpace,
          _In_ float minWidthOfWallSpace,
          _In_ float minHeightAboveFloor,
          _In_ float minFacingClearance,
          _In_ int locationCount,
          _Inout_ Dll_Interface::TopologyResult* locationData)

Каждый из этих запросов принимает предварительно выделенный массив структур TopologyResult . Параметр locationCount указывает длину переданного массива. Возвращаемое значение сообщает количество возвращаемых расположений. Это число никогда не превышает переданный параметр locationCount .

TopologyResult содержит центральное положение возвращаемого тома, направление лицом (т. е. нормальным), а также размеры найденного пространства.

struct TopologyResult
     {
          DirectX::XMFLOAT3 position;
          DirectX::XMFLOAT3 normal;
          float width;
          float length;
     };

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

Запросы фигур

В библиотеке DLL анализатор фигур (ShapeAnalyzer_W) использует анализатор топологии для сопоставления с настраиваемыми фигурами, определенными пользователем. В примере Unity есть предопределенный набор фигур, отображаемых в меню запроса на вкладке фигуры.

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

Пример запроса, определенный в примере Unity (ShapeDefinition.cs), для объектов sittable выглядит следующим образом:

shapeComponents = new List<ShapeComponent>()
     {
          new ShapeComponent(
               new List<ShapeComponentConstraint>()
               {
                    ShapeComponentConstraint.Create_SurfaceHeight_Between(0.2f, 0.6f),
                    ShapeComponentConstraint.Create_SurfaceCount_Min(1),
                    ShapeComponentConstraint.Create_SurfaceArea_Min(0.035f),
               }),
     };
     AddShape("Sittable", shapeComponents);

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

В отличие от этого, фигура дивана имеет два компонента фигуры и четыре ограничения фигуры. Обратите внимание, что компоненты идентифицируются по их индексу в списке компонентов пользователя (0 и 1 в этом примере).

shapeConstraints = new List<ShapeConstraint>()
        {
              ShapeConstraint.Create_RectanglesSameLength(0, 1, 0.6f),
              ShapeConstraint.Create_RectanglesParallel(0, 1),
              ShapeConstraint.Create_RectanglesAligned(0, 1, 0.3f),
              ShapeConstraint.Create_AtBackOf(1, 0),
        };

Функции-оболочки предоставляются в модуле Unity для простого создания пользовательских определений фигур. Полный список ограничений компонентов и фигур можно найти в Файле SpatialUnderstandingDll.cs в структурах ShapeComponentConstraint и ShapeConstraint .

The blue rectangle highlights the results of the chair shape query.

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

Решатель размещения объектов

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

Запросы на размещение объектов состоят из трех частей: тип размещения с параметрами, списком правил и списком ограничений. Чтобы выполнить запрос, используйте следующий API:

public static int Solver_PlaceObject(
                [In] string objectName,
                [In] IntPtr placementDefinition,	// ObjectPlacementDefinition
                [In] int placementRuleCount,
                [In] IntPtr placementRules,     	// ObjectPlacementRule
                [In] int constraintCount,
                [In] IntPtr placementConstraints,	// ObjectPlacementConstraint
                [Out] IntPtr placementResult)

Эта функция принимает имя объекта, определение размещения и список правил и ограничений. Оболочки C# предоставляют вспомогательные функции для создания правил и ограничений. Определение размещения содержит тип запроса, то есть один из следующих:

public enum PlacementType
                {
                    Place_OnFloor,
                    Place_OnWall,
                    Place_OnCeiling,
                    Place_OnShape,
                    Place_OnEdge,
                    Place_OnFloorAndCeiling,
                    Place_RandomInAir,
                    Place_InMidAir,
                    Place_UnderFurnitureEdge,
                };

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

public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims)

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

public static ObjectPlacementRule Create_AwayFromPosition(
                    Vector3 position, float minDistance)
               public static ObjectPlacementConstraint Create_NearPoint(
                    Vector3 position, float minDistance = 0.0f, float maxDistance = 0.0f)

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

List<ObjectPlacementRule> rules = 
          new List<ObjectPlacementRule>() {
               ObjectPlacementRule.Create_AwayFromOtherObjects(1.0f),
          };

     List<ObjectPlacementConstraint> constraints = 
          new List<ObjectPlacementConstraint> {
               ObjectPlacementConstraint.Create_NearCenter(),
          };

     Solver_PlaceObject(
          “MyCustomObject”,
          new ObjectPlacementDefinition.Create_OnEdge(
          new Vector3(0.25f, 0.25f, 0.25f), 
          new Vector3(0.25f, 0.25f, 0.25f)),
          rules.Count,
          UnderstandingDLL.PinObject(rules.ToArray()),
          constraints.Count,
          UnderstandingDLL.PinObject(constraints.ToArray()),
          UnderstandingDLL.GetStaticObjectPlacementResultPtr());

В случае успешного выполнения возвращается структура ObjectPlacementResult , содержащая позицию размещения, измерения и ориентацию. Кроме того, размещение добавляется во внутренний список размещенных объектов DLL. Последующие запросы размещения будут учитывать этот объект. Файл LevelSolver.cs в примере Unity содержит дополнительные примеры запросов.

The blue boxes show the result from three Place On Floor queries with

Синие поля показывают результат из трех запросов Place On Floor с правилами "вдали от позиции камеры".

Советы

  • При решении задачи размещения нескольких объектов, необходимых для сценария уровня или приложения, сначала необходимо решить незаменимые и крупные объекты, чтобы максимально повысить вероятность обнаружения пространства.
  • Порядок размещения важен. Если не удается найти размещение объектов, попробуйте использовать менее ограниченные конфигурации. Наличие набора резервных конфигураций крайне важно для поддержки функциональных возможностей во многих конфигурациях помещений.

Луч литья

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

struct RaycastResult
     {
          enum SurfaceTypes
          {
               Invalid,	// No intersection
               Other,
               Floor,
               FloorLike,         // Not part of the floor topology, 
                                  //     but close to the floor and looks like the floor
               Platform,          // Horizontal platform between the ground and 
                                  //     the ceiling
               Ceiling,
               WallExternal,
               WallLike,          // Not part of the external wall surface, 
                                  //     but vertical surface that looks like a 
                                  //	wall structure
               };
               SurfaceTypes SurfaceType;
               float SurfaceArea;	// Zero if unknown 
                                        //	(i.e. if not part of the topology analysis)
               DirectX::XMFLOAT3 IntersectPoint;
               DirectX::XMFLOAT3 IntersectNormal;
     };

На внутреннем сервере raycast вычисляется по вычисляемой 8 см кубической воксел-представлению пространства воспроизведения. Каждый voxel содержит набор элементов поверхности с обработанными данными топологии (также называемыми серферами). Серферы, содержащиеся в пересекаемой ячейке voxel, сравниваются и лучшее совпадение, используемое для поиска сведений о топологии. Эти данные топологии содержат метки, возвращенные в виде перечисления SurfaceTypes , а также поверхности пересекаемой поверхности поверхности.

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

Raycast result reporting intersection with the floor.

Результат Raycast сообщает пересечение с полом.

Получите код

Код с открытым исходным кодом доступен в MixedRealityToolkit. Сообщите нам на форумах разработчиков HoloLens, если вы используете код в проекте. Мы не можем ждать, чтобы увидеть, что вы делаете с ним!

Об авторе

Jeff Evertt, Software Engineering Lead at Microsoft Джефф Эвертт является ведущим разработчиком программного обеспечения, который работал над HoloLens с первых дней, от инкубации до опыта разработки. Прежде чем HoloLens, он работал на Xbox Kinect и в индустрии игр на различных платформах и играх. Джефф страстно относится к робототехнике, графике и вещам с мигающими огнями, которые идут сигнал. Он любит изучать новые вещи и работать над программным обеспечением, оборудованием и особенно в пространстве, где два пересекаются.

См. также статью