Пространственное сопоставление в Unity

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

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

  1. Компоненты пространственного сопоставления, доступные в MixedRealityToolkit, которые предоставляют удобный и быстрый путь для начала работы с пространственным сопоставлением.
  2. БОЛЕЕ низкоуровневые API пространственного сопоставления, которые обеспечивают полный контроль и обеспечивают более сложную настройку для конкретных приложений.

Чтобы использовать пространственное сопоставление в приложении, в AppxManifest необходимо задать возможность SpatialPerception.

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

Компонент HoloLens (1-го поколения) HoloLens 2 Иммерсивные гарнитуры
пространственное сопоставление ✔️ ✔️

Настройка возможности SpatialPerception

Чтобы приложение потребляло данные пространственного сопоставления, необходимо включить возможность SpatialPerception.

Как включить функцию SpatialPerception:

  1. В редакторе Unity откройте панель "Параметры проигрывателя" (Изменить > параметры > проекта проигрывателя)
  2. Выберите вкладку "Магазин Windows"
  3. Разверните узел "Параметры публикации" и проверка возможность SpatialPerception в списке "Возможности".

Примечание

Если вы уже экспортировали проект Unity в решение Visual Studio, необходимо либо экспортировать его в новую папку, либо вручную задать эту возможность в AppxManifest в Visual Studio.

Для пространственного сопоставления также требуется maxVersionTested не менее 10.0.10586.0:

  1. В Visual Studio щелкните правой кнопкой мыши Package.appxmanifest в Обозреватель решений и выберите Пункт Просмотреть код.
  2. Найдите строку, указывающую TargetDeviceFamily , и измените значение MaxVersionTested="10.0.10240.0" на MaxVersionTested="10.0.10586.0"
  3. Сохраните Package.appxmanifest.

Добавление сопоставления в Unity

Система отслеживания пространственного положения.

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

Сведения об наблюдателях на устройстве см. в руководстве Настройка наблюдателей сетки для устройства .

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

Анализ сетки более высокого уровня: распознавание пространственного пространства

Внимание!

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

MixedRealityToolkit — это набор служебного кода для голографической разработки, основанный на голографических API Unity.

Распознавание пространственного пространства

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

Во время разработки Young Conker и Fragments, Asobo Studios столкнулась с этой проблемой головой, разработав решатель комнаты. У каждой из этих игр были особые потребности, но в них были общие основные технологии пространственного понимания. Библиотека HoloToolkit.SpatialUnderstanding инкапсулирует эту технологию, позволяя быстро находить пустые пространства на стенах, размещать объекты на потолке, определять места для размещения символов и множество других запросов пространственного понимания.

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

Основные сведения о модулях

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

Приведение лучей

После завершения сканирования комнаты внутренние метки создаются для таких поверхностей, как пол, потолок и стены. Функция 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;
};

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

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

Тип Surface помечен рядом с курсором
Тип Surface помечен рядом с курсором

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

В библиотеке 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.

Фигура прямоугольника найдена на этой поверхности
Фигура прямоугольника найдена на этой поверхности

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

Решатель размещения объектов можно использовать для определения идеальных расположений в физической комнате для размещения объектов. Решатель найдет оптимальное расположение с учетом правил и ограничений объекта. Кроме того, запросы объектов сохраняются до тех пор, пока объект не будет удален с помощью вызовов "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 содержит дополнительные примеры запросов.

Результаты размещения объекта
Рис. 3. Синие рамки, как результат из трех мест на полу запросы с правилами положения камеры

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

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

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

Fixed size playspace – The user specifies the maximum playspace size in the init call.

One-time scan process –
    The process requires a discrete scanning phase where the user walks around,
    defining the playspace.
    Query functions will not function until after the scan has been finalized.

"Рисование" пространства воспроизведения, управляемого пользователем. На этапе сканирования пользователь перемещается и просматривает темп воспроизведения, эффективно рисуя области, которые должны быть включены. Созданная сетка важна для предоставления отзывов пользователей на этом этапе. Домашняя или офисная настройка в помещении — функции запросов разрабатываются вокруг плоских поверхностей и стен под прямым углом. Это мягкое ограничение. Однако на этапе сканирования выполняется анализ основной оси для оптимизации тесселяции сетки вдоль основной и вспомогательной осей. Включенный файл SpatialUnderstanding.cs управляет процессом этапа сканирования. Он вызывает следующие функции.

SpatialUnderstanding_Init – Called once at the start.

GeneratePlayspace_InitScan – Indicates that the scan phase should begin.

GeneratePlayspace_UpdateScan_DynamicScan –
    Called each frame to update the scanning process. The camera position and
    orientation is passed in and is used for the playspace painting process,
    described above.

GeneratePlayspace_RequestFinish –
    Called to finalize the playspace. This will use the areas “painted” during
    the scan phase to define and lock the playspace. The application can query
    statistics during the scanning phase as well as query the custom mesh for
    providing user feedback.

Import_UnderstandingMesh –
    During scanning, the “SpatialUnderstandingCustomMesh” behavior provided by
    the module and placed on the understanding prefab will periodically query the
    custom mesh generated by the process. In addition, this is done once more
    after scanning has been finalized.

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

Основные сведения о сетке

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

Созданная сетка, созданная из тома voxel
Созданная сетка, созданная из тома voxel

Устранение неполадок

  • Убедитесь, что задана возможность SpatialPerception .
  • При потере отслеживания следующее событие OnSurfaceChanged удалит все сетки.

Пространственное сопоставление в Смешанная реальность Toolkit

Дополнительные сведения об использовании пространственного сопоставления с Смешанная реальность Toolkit см. в разделе о пространственной осведомленности документации MRTK.

Следующий этап разработки

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

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

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

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