Compartilhar via


Mapeamento espacial no Unity

O mapeamento espacial permite recuperar malhas triangulares que representam as superfícies no mundo ao redor de um dispositivo HoloLens. Você pode usar dados de superfície para posicionamento, oclusão e análise de sala para dar aos seus projetos do Unity uma dose extra de imersão.

O Unity inclui suporte completo para mapeamento espacial, que é exposto aos desenvolvedores das seguintes maneiras:

  1. Componentes de mapeamento espacial disponíveis no MixedRealityToolkit, que fornecem um caminho conveniente e rápido para começar a usar o mapeamento espacial
  2. APIs de mapeamento espacial de nível inferior, que fornecem controle total e permitem uma personalização mais sofisticada específica do aplicativo

Para usar o mapeamento espacial em seu aplicativo, a funcionalidade SpatialPerception precisa ser definida em seu AppxManifest.

Suporte a dispositivos

Recurso HoloLens (primeira geração) HoloLens 2 Headsets imersivos
mapeamento espacial ✔️ ✔️

Configurando a funcionalidade SpatialPerception

Para que um aplicativo consuma dados de mapeamento espacial, a funcionalidade SpatialPerception deve ser habilitada.

Como habilitar o recurso SpatialPerception:

  1. No Editor do Unity, abra o painel "Configurações do Player" (Editar > Configurações > do Projeto do Player)
  2. Selecione na guia "Windows Store"
  3. Expanda "Configurações de publicação" e marque o recurso "SpatialPerception" na lista "Recursos"

Observação

Se você já tiver exportado seu projeto do Unity para uma solução do Visual Studio, precisará exportar para uma nova pasta ou definir manualmente essa funcionalidade no AppxManifest no Visual Studio.

O mapeamento espacial também requer um MaxVersionTested de pelo menos 10.0.10586.0:

  1. No Visual Studio, clique com o botão direito do mouse em Package.appxmanifest no Gerenciador de Soluções e selecione Exibir Código
  2. Localize a linha que especifica TargetDeviceFamily e altere MaxVersionTested="10.0.10240.0" para MaxVersionTested="10.0.10586.0"
  3. Salve o Package.appxmanifest.

Como adicionar mapeamento no Unity

Sistema de conscientização espacial

No MRTK, consulte o guia de introdução ao reconhecimento espacial para obter informações sobre como configurar vários observadores de malha espacial.

Para obter informações sobre observadores no dispositivo, consulte o guia Configurando observadores de malha para o dispositivo .

Para obter informações sobre observadores de compreensão de cena, consulte o Guia do observador de compreensão de cena.

Análise de malha de nível superior: Compreensão espacial

Cuidado

O Reconhecimento Espacial foi preterido em favor do Reconhecimento de Cena.

O MixedRealityToolkit é uma coleção de código utilitário para desenvolvimento holográfico criado nas APIs holográficas do Unity.

Compreensão espacial

Ao colocar hologramas no mundo físico, geralmente é desejável ir além da malha e dos planos de superfície do mapeamento espacial. Quando a colocação é feita processualmente, é desejável um nível mais alto de compreensão ambiental. Isso geralmente requer a tomada de decisões sobre o que é piso, teto e paredes. Você também tem a capacidade de otimizar em relação a um conjunto de restrições de posicionamento para determinar os melhores locais físicos para objetos holográficos.

Durante o desenvolvimento de Young Conker e Fragments, a Asobo Studios enfrentou esse problema de frente desenvolvendo um solucionador de sala. Cada um desses jogos tinha necessidades específicas do jogo, mas compartilhavam a tecnologia básica de compreensão espacial. A biblioteca HoloToolkit.SpatialUnderstanding encapsula essa tecnologia, permitindo que você encontre rapidamente espaços vazios nas paredes, coloque objetos no teto, identifique o local para o personagem sentar e uma infinidade de outras consultas de compreensão espacial.

Todo o código-fonte está incluído, permitindo que você o personalize de acordo com suas necessidades e compartilhe suas melhorias com a comunidade. O código para o solucionador C++ foi encapsulado em uma dll UWP e exposto ao Unity com uma queda no pré-fabricado contido no MixedRealityToolkit.

Entendendo os módulos

Há três interfaces principais expostas pelo módulo: topologia para consultas espaciais e de superfície simples, forma para detecção de objetos e o solucionador de posicionamento de objetos para posicionamento baseado em restrições de conjuntos de objetos. Veja a descrição das duas maneiras abaixo. Além das três interfaces de módulo primárias, uma interface de fundição de raios pode ser usada para recuperar tipos de superfície marcados e uma malha de espaço de jogo à prova d'água personalizada pode ser copiada.

Fundição de raios

Após a conclusão da verificação da sala, os rótulos são gerados internamente para superfícies como piso, teto e paredes. A PlayspaceRaycast função pega um raio e retorna se o raio colidir com uma superfície conhecida e, em caso afirmativo, informações sobre essa superfície na forma de um 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;
};

Internamente, o raycast é calculado em relação à representação de voxel cúbico de 8 cm computada do espaço de jogo. Cada voxel contém um conjunto de elementos de superfície com dados de topologia processados (também conhecidos como surfels). Os surfels contidos na célula de voxel interceptada são comparados e a melhor correspondência é usada para pesquisar as informações de topologia. Esses dados de topologia contêm a rotulagem retornada na forma da enumeração "SurfaceTypes", bem como a área de superfície da superfície interseccionada.

No exemplo do Unity, o cursor converte um raio a cada quadro. Primeiro, contra os colisores da Unity. Em segundo lugar, contra a representação mundial do módulo de compreensão. E, finalmente, novamente elementos da interface do usuário. Neste aplicativo, a interface do usuário tem prioridade, em seguida, o resultado do entendimento e, por último, os colisores do Unity. O SurfaceType é relatado como texto ao lado do cursor.

O tipo de superfície é rotulado ao lado do cursor
O tipo de superfície é rotulado ao lado do cursor

Consultas de topologia

Dentro da DLL, o gerenciador de topologia lida com a rotulagem do ambiente. Como mencionado acima, muitos dos dados são armazenados em surfels, contidos em um volume de voxel. Além disso, a estrutura "PlaySpaceInfos" é usada para armazenar informações sobre o espaço de jogo, incluindo o alinhamento do mundo (mais detalhes sobre isso abaixo), piso e altura do teto. As heurísticas são usadas para determinar piso, teto e paredes. Por exemplo, a maior e mais baixa superfície horizontal com área de superfície superior a 1 m2 é considerada o piso.

Observação

O caminho da câmera durante o processo de digitalização também é usado neste processo.

Um subconjunto das consultas expostas pelo gerenciador de topologia é exposto por meio da dll. As consultas de topologia expostas são as seguintes.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

Cada uma das consultas tem um conjunto de parâmetros, específicos para o tipo de consulta. No exemplo a seguir, o usuário especifica a altura e a largura mínimas do volume desejado, a altura mínima de colocação acima do piso e a quantidade mínima de folga na frente do volume. Todas as medidas estão em metros.

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)

Cada uma dessas consultas usa uma matriz pré-alocada de estruturas "TopologyResult". O parâmetro "locationCount" especifica o comprimento da matriz passada. O valor retornado relata o número de locais retornados. Esse número nunca é maior que o parâmetro "locationCount" passado.

O "TopologyResult" contém a posição central do volume retornado, a direção voltada (ou seja, normal) e as dimensões do espaço encontrado.

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

Observação

No exemplo do Unity, cada uma dessas consultas é vinculada a um botão no painel da interface do usuário virtual. O exemplo codifica os parâmetros de cada uma dessas consultas para valores razoáveis. Consulte SpaceVisualizer.cs no código de exemplo para obter mais exemplos.

Consultas de forma

Na dll, o analisador de forma ("ShapeAnalyzer_W") usa o analisador de topologia para corresponder a formas personalizadas definidas pelo usuário. O exemplo do Unity define um conjunto de formas e expõe os resultados por meio do menu de consulta no aplicativo, na guia forma. A intenção é que o usuário possa definir suas próprias consultas de forma de objeto e usá-las, conforme necessário para sua aplicação.

A análise de forma funciona somente em superfícies horizontais. Um sofá, por exemplo, é definido pela superfície plana do assento e pela parte superior plana do encosto do sofá. A consulta de forma procura duas superfícies de um tamanho, altura e intervalo de aspectos específicos, com as duas superfícies alinhadas e conectadas. Usando a terminologia das APIs, o assento do sofá e a parte superior traseira são componentes de forma e os requisitos de alinhamento são restrições de componentes de forma.

Um exemplo de consulta definido no exemplo do Unity (ShapeDefinition.cs) para objetos "sentáveis" é o seguinte.

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);

Cada consulta de forma é definida por um conjunto de componentes de forma, cada um com um conjunto de restrições de componente e um conjunto de restrições de forma que listam dependências entre os componentes. Este exemplo inclui três restrições em uma única definição de componente e nenhuma restrição de forma entre componentes (já que há apenas um componente).

Em contraste, a forma do sofá tem dois componentes de forma e quatro restrições de forma. Os componentes são identificados por seu índice na lista de componentes do usuário (0 e 1 neste exemplo).

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),
};

As funções de wrapper são fornecidas no módulo Unity para facilitar a criação de definições de forma personalizadas. A lista completa de restrições de componente e forma pode ser encontrada em "SpatialUnderstandingDll.cs" nas estruturas "ShapeComponentConstraint" e "ShapeConstraint".

A forma retangular é encontrada nesta superfície
A forma retangular é encontrada nesta superfície

Solucionador de posicionamento de objetos

O solucionador de posicionamento de objetos pode ser usado para identificar locais ideais na sala física para colocar seus objetos. O solucionador encontrará o local mais adequado, considerando as regras e restrições do objeto. Além disso, as consultas de objeto persistem até que o objeto seja removido com chamadas "Solver_RemoveObject" ou "Solver_RemoveAllObjects", permitindo o posicionamento restrito de vários objetos. As consultas de posicionamento de objetos consistem em três partes: tipo de posicionamento com parâmetros, uma lista de regras e uma lista de restrições. Para executar uma consulta, use a API a seguir.

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)

Essa função usa um nome de objeto, uma definição de posicionamento e uma lista de regras e restrições. Os wrappers C# fornecem funções auxiliares de construção para facilitar a construção de regras e restrições. A definição de posicionamento contém o tipo de consulta – ou seja, um dos seguintes.

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

Cada um dos tipos de posicionamento tem um conjunto de parâmetros exclusivos para o tipo. A estrutura "ObjectPlacementDefinition" contém um conjunto de funções auxiliares estáticas para criar essas definições. Por exemplo, para encontrar um lugar para colocar um objeto no chão, você pode usar a seguinte função. public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims) Além do tipo de posicionamento, você pode fornecer um conjunto de regras e restrições. As regras não podem ser violadas. Os possíveis locais de posicionamento que atendem ao tipo e às regras são otimizados em relação ao conjunto de restrições para selecionar o local de posicionamento ideal. Cada uma das regras e restrições pode ser criada pelas funções de criação estática fornecidas. Um exemplo de regra e função de construção de restrição é fornecido abaixo.

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

A consulta de posicionamento de objeto abaixo está procurando um local para colocar um cubo de meio metro na borda de uma superfície, longe de outros objetos colocados anteriormente e perto do centro da sala.

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());

Se for bem-sucedido, uma estrutura "ObjectPlacementResult" contendo a posição, as dimensões e a orientação do posicionamento será retornada. Além disso, o posicionamento é adicionado à lista interna de objetos inseridos da dll. As consultas de posicionamento subsequentes levarão esse objeto em consideração. O arquivo "LevelSolver.cs" no exemplo do Unity contém mais consultas de exemplo.

Resultados da colocação do objeto
Figura 3: As caixas azuis mostram como o resultado de três consultas de lugar no chão com regras de posição longe da câmera

Ao resolver a localização de vários objetos necessários para um cenário de nível ou aplicação, primeiro resolva objetos grandes e indispensáveis para maximizar a probabilidade de que um espaço possa ser encontrado. A ordem de colocação é importante. Se os posicionamentos de objetos não puderem ser encontrados, tente configurações menos restritas. Ter um conjunto de configurações de fallback é fundamental para dar suporte à funcionalidade em muitas configurações de sala.

Processo de digitalização da sala

Embora a solução de mapeamento espacial fornecida pelo HoloLens tenha sido projetada para ser genérica o suficiente para atender às necessidades de toda a gama de espaços problemáticos, o módulo de compreensão espacial foi criado para dar suporte às necessidades de dois jogos específicos. Sua solução é estruturada em torno de um processo específico e conjunto de suposições, resumidas abaixo.

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.

"Pintura" do espaço de jogo orientado pelo usuário – Durante a fase de digitalização, o usuário se move e olha ao redor do ritmo de jogo, pintando efetivamente as áreas que devem ser incluídas. A malha gerada é importante para fornecer feedback do usuário durante esta fase. Configuração interna de casa ou escritório – As funções de consulta são projetadas em torno de superfícies planas e paredes em ângulos retos. Esta é uma limitação suave. No entanto, durante a fase de varredura, uma análise do eixo primário é concluída para otimizar a tesselação da malha ao longo dos eixos maior e menor. O arquivo SpatialUnderstanding.cs incluído gerencia o processo da fase de digitalização. Ele chama as funções a seguir.

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.

O fluxo de verificação, orientado pelo comportamento "SpatialUnderstanding", chama InitScan e, em seguida, UpdateScan cada quadro. Quando a consulta de estatísticas relata uma cobertura razoável, o usuário tem permissão para usar airtap para chamar RequestFinish para indicar o fim da fase de verificação. UpdateScan continua a ser chamado até que seu valor retornado indique que a dll concluiu o processamento.

Entendendo a malha

A dll de compreensão armazena internamente o espaço de jogo como uma grade de cubos de voxel de 8 cm. Durante a parte inicial da digitalização, uma análise de componente primário é concluída para determinar os eixos da sala. Internamente, ele armazena seu espaço de voxel alinhado a esses eixos. Uma malha é gerada aproximadamente a cada segundo, extraindo a isosuperfície do volume de voxel.

Malha gerada produzida a partir do volume de voxel
Malha gerada produzida a partir do volume de voxel

Solução de problemas

  • Verifique se você definiu a funcionalidade SpatialPerception
  • Quando o rastreamento for perdido, o próximo evento OnSurfaceChanged removerá todas as malhas.

Mapeamento espacial no Realidade Misturada Toolkit

Para obter mais informações sobre como usar o Mapeamento Espacial com o Realidade Misturada Toolkit, consulte a seção de reconhecimento espacial dos documentos do MRTK.

Próximo ponto de verificação de desenvolvimento

Se você estiver seguindo a jornada de desenvolvimento do Unity que apresentamos, estará explorando os principais blocos de construção do MRTK. Deste ponto, você pode prosseguir para o próximo bloco de construção:

Ou vá diretamente para as funcionalidades e APIs da plataforma de Realidade Misturada:

Você sempre pode voltar para os pontos de verificação de desenvolvimento do Unity a qualquer momento.

Confira também