Mapping spaziale in Unity

Il mapping spaziale consente di recuperare mesh di triangoli che rappresentano le superfici del mondo intorno a un dispositivo HoloLens. È possibile usare i dati di superficie per l'analisi di posizionamento, occlusione e sala per offrire ai progetti Unity una dose aggiuntiva di immersione.

Unity include il supporto completo per il mapping spaziale, esposto agli sviluppatori nei modi seguenti:

  1. Componenti di mapping spaziale disponibili in MixedRealityToolkit, che forniscono un percorso pratico e rapido per iniziare a usare il mapping spaziale
  2. API di mapping spaziale di livello inferiore, che forniscono il controllo completo e consentono una personalizzazione più sofisticata specifica dell'applicazione

Per usare il mapping spaziale nell'app, la funzionalità SpatialPerception deve essere impostata in AppxManifest.

Supporto di dispositivi

Funzionalità HoloLens (prima generazione) HoloLens 2 Visori VR immersive
Mapping spaziale ✔️

Impostazione della funzionalità SpatialPerception

Per consentire a un'app di utilizzare i dati di mapping spaziale, è necessario abilitare la funzionalità SpatialPerception.

Come abilitare la funzionalità SpatialPerception:

  1. Nell'editor di Unity aprire il riquadro "Impostazioni lettore" (Modifica > lettore impostazioni > progetto)
  2. Selezionare nella scheda "Windows Store"
  3. Espandere "Impostazioni di pubblicazione" e controllare la funzionalità "SpatialPerception" nell'elenco "Funzionalità"

Nota

Se il progetto Unity è già stato esportato in una soluzione di Visual Studio, sarà necessario esportare in una nuova cartella o impostare manualmente questa funzionalità in AppxManifest in Visual Studio.

Il mapping spaziale richiede anche un valore MaxVersionTested di almeno 10.0.10586.0:

  1. In Visual Studio fare clic con il pulsante destro del mouse su Package.appxmanifest nel Esplora soluzioni e scegliere Visualizza codice
  2. Trovare la riga che specifica TargetDeviceFamily e modificare MaxVersionTested="10.0.10240.0" in MaxVersionTested="10.0.10586.0"
  3. Salvare package.appxmanifest.

Come aggiungere il mapping in Unity

Sistema di consapevolezza spaziale

In MRTK, vedere la guida introduttiva alla consapevolezza spaziale per informazioni sulla configurazione di vari osservatori di mesh spaziali.

Per informazioni sugli osservatori sul dispositivo, vedere la guida Configurazione degli osservatori mesh per i dispositivi .

Per informazioni sugli osservatori di comprensione della scena, vedere la guida osservatore di comprensione della scena .

Analisi mesh di livello superiore: Spatial Understanding

Attenzione

Spatial Understanding è stato deprecato a favore di Scene Understanding.

MixedRealityToolkit è una raccolta di codice di utilità per lo sviluppo olografico basato sulle API olografiche di Unity.

Informazioni spaziali

Quando si posizionano gli ologrammi nel mondo fisico, spesso è consigliabile andare oltre i piani di mesh e superficie del mapping spaziale. Quando il posizionamento viene fatto in modo procedurale, è auspicabile un livello superiore di comprensione ambientale. Questo di solito richiede prendere decisioni su ciò che è pavimento, soffitto e pareti. È anche possibile ottimizzare in base a un set di vincoli di posizionamento per determinare le posizioni fisiche migliori per gli oggetti olografici.

Durante lo sviluppo di Young Conker e Fragments, Asobo Studios ha affrontato questo problema sviluppando un risolutore di sale. Ognuno di questi giochi aveva esigenze specifiche del gioco, ma condividevano la tecnologia di comprensione spaziale di base. La libreria HoloToolkit.SpatialUnderstanding incapsula questa tecnologia, consentendo di trovare rapidamente spazi vuoti sulle pareti, posizionare gli oggetti sul soffitto, identificare il carattere da sedersi e una miriade di altre query di comprensione spaziale.

Tutto il codice sorgente è incluso, consentendo di personalizzarlo alle proprie esigenze e condividere i miglioramenti con la community. Il codice per il risolutore C++ è stato eseguito il wrapping in una dll UWP ed è stato esposto a Unity con un rilascio nel prefab contenuto all'interno di MixedRealityToolkit.

Informazioni sui moduli

Esistono tre interfacce primarie esposte dal modulo: topologia per query di superficie e spaziali semplici, forma per il rilevamento degli oggetti e risolutore di posizionamento degli oggetti per il posizionamento basato sui vincoli di set di oggetti. Ogni modalità è illustrata di seguito. Oltre alle tre interfacce del modulo primario, è possibile usare un'interfaccia di cast di raggi per recuperare i tipi di superficie contrassegnati e una mesh playspace a tenuta d'acqua personalizzata può essere copiata.

Ray Cast

Al termine dell'analisi della stanza, le etichette vengono generate internamente per superfici come il pavimento, il soffitto e le pareti. La PlayspaceRaycast funzione accetta un raggio e restituisce se il raggio si scontra con una superficie nota e, in tal caso, informazioni su tale superficie sotto forma di .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, il raycast viene calcolato in base alla rappresentazione voxel a cubo calcolata di 8 cm dello spazio di riproduzione. Ogni voxel contiene un set di elementi di superficie con dati di topologia elaborati (aka surfels). I surfels contenuti all'interno della cella voxel intersecata vengono confrontati e la corrispondenza migliore utilizzata per cercare le informazioni sulla topologia. Questi dati di topologia contengono l'etichettatura restituita sotto forma di enumerazione "SurfaceTypes", nonché l'area di superficie della superficie intersecata.

Nell'esempio unity il cursore esegue il cast di un raggio ogni fotogramma. Prima di tutto, contro i collider di Unity. In secondo luogo, rispetto alla rappresentazione mondiale del modulo di comprensione. Infine, ancora elementi dell'interfaccia utente. In questa applicazione l'interfaccia utente ottiene la priorità, successivamente il risultato di comprensione e infine i collider di Unity. SurfaceType viene segnalato come testo accanto al cursore.

Tipo di superficie etichettato accanto al cursore
Tipo di superficie etichettato accanto al cursore

Query di topologia

All'interno della DLL, gestione topologia gestisce l'etichettatura dell'ambiente. Come accennato in precedenza, gran parte dei dati viene archiviata all'interno di surfels, contenuta all'interno di un volume voxel. Inoltre, la struttura "PlaySpaceInfos" viene usata per archiviare informazioni sullo spazio playspace, tra cui l'allineamento del mondo (altri dettagli su questo sotto), il pavimento e l'altezza del soffitto. Le euristiche vengono usate per determinare il pavimento, il soffitto e le pareti. Ad esempio, la superficie orizzontale più grande e bassa con una superficie superiore a 1 m2 è considerata il pavimento.

Nota

Il percorso della fotocamera durante il processo di analisi viene usato anche in questo processo.

Un subset delle query esposte dalla gestione topologia viene esposto tramite la dll. Le query di topologia esposte sono le seguenti.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

Ognuna delle query ha un set di parametri, specifici del tipo di query. Nell'esempio seguente, l'utente specifica l'altezza minima & larghezza del volume desiderato, l'altezza minima di posizionamento sopra il pavimento e la quantità minima di spaziatura davanti al volume. Tutte le misurazioni sono in metri.

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)

Ognuna di queste query accetta una matrice pre-allocata di strutture "TopologyResult". Il parametro "locationCount" specifica la lunghezza della matrice passata. Il valore restituito segnala il numero di posizioni restituite. Questo numero non è mai maggiore del parametro "locationCount".

Il valore "TopologyResult" contiene la posizione centrale del volume restituito, la direzione di fronte (ad esempio normale) e le dimensioni dello spazio trovato.

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

Nota

Nell'esempio unity, ognuna di queste query viene collegata a un pulsante nel pannello dell'interfaccia utente virtuale. Il codice rigido di esempio codici i parametri per ognuna di queste query ai valori ragionevoli. Per altri esempi, vedere SpaceVisualizer.cs nel codice di esempio.

Query shape

Nella dll l'analizzatore forma ("ShapeAnalyzer_W") usa l'analizzatore della topologia per corrispondere a forme personalizzate definite dall'utente. L'esempio unity definisce un set di forme ed espone i risultati tramite il menu query in-app, all'interno della scheda forma. L'intenzione è che l'utente può definire le proprie query di forma oggetto e usarle, in base alle esigenze dell'applicazione.

L'analisi della forma funziona solo su superfici orizzontali. Un divano, ad esempio, è definito dall'area di seduta piatta e dalla parte superiore piatta del divano indietro. La query di forma cerca due superfici di una dimensione, un'altezza e un intervallo di aspetti specifici, con le due superfici allineate e connesse. Usando la terminologia delle API, il sedile del divano e la parte posteriore sono componenti della forma e i requisiti di allineamento sono vincoli dei componenti della forma.

Una query di esempio definita nell'esempio unity (ShapeDefinition.cs), per gli oggetti "sittable" è il seguente.

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

Ogni query di forma viene definita da un set di componenti di forma, ognuno con un set di vincoli di componente e un set di vincoli di forma che elencano le dipendenze tra i componenti. In questo esempio sono inclusi tre vincoli in una singola definizione del componente e non sono presenti vincoli di forma tra i componenti, come è presente un solo componente.

Al contrario, la forma del divano ha due componenti di forma e quattro vincoli di forma. I componenti vengono identificati dall'indice nell'elenco dei componenti dell'utente (0 e 1 in questo esempio).

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

Le funzioni wrapper vengono fornite nel modulo Unity per semplificare la creazione di definizioni di forme personalizzate. L'elenco completo dei vincoli di componente e forma è disponibile nelle strutture "SpatialUnderstandingDll.cs" all'interno delle strutture "ShapeComponentConstraint" e "ShapeConstraint".

La forma rettangolo viene trovata in questa superficie
La forma rettangolo viene trovata in questa superficie

Risolutore posizionamento oggetti

Il risolutore di posizionamento degli oggetti può essere usato per identificare le posizioni ideali nella stanza fisica per posizionare gli oggetti. Il risolutore troverà la posizione più adatta in base alle regole e ai vincoli dell'oggetto. Inoltre, le query sugli oggetti vengono mantenute finché l'oggetto non viene rimosso con chiamate "Solver_RemoveObject" o "Solver_RemoveAllObjects", consentendo il posizionamento a più oggetti vincolati. Le query di posizionamento degli oggetti sono costituite da tre parti: tipo di posizionamento con parametri, un elenco di regole e un elenco di vincoli. Per eseguire una query, usare l'API seguente.

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)

Questa funzione accetta un nome dell'oggetto, una definizione di posizionamento e un elenco di regole e vincoli. I wrapper C# offrono funzioni helper di costruzione per semplificare la costruzione di regole e vincoli. La definizione di posizionamento contiene il tipo di query, ovvero uno dei seguenti.

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

Ognuno dei tipi di posizionamento ha un set di parametri univoci per il tipo. La struttura "ObjectPlacementDefinition" contiene un set di funzioni helper statiche per la creazione di queste definizioni. Ad esempio, per trovare un posto per inserire un oggetto sul pavimento, è possibile usare la funzione seguente. public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims) Oltre al tipo di posizionamento, è possibile fornire un set di regole e vincoli. Non è possibile violare regole. Le possibili posizioni di posizionamento che soddisfano il tipo e le regole vengono quindi ottimizzate rispetto al set di vincoli per selezionare la posizione di posizionamento ottimale. Ognuna delle regole e dei vincoli può essere creata dalle funzioni di creazione statiche fornite. Di seguito è riportata una regola di esempio e una funzione di costruzione dei vincoli.

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

La query di posizionamento dell'oggetto seguente cerca un posto per inserire un cubo di mezzo metro sul bordo di una superficie, lontano da altri oggetti posto in precedenza e vicino al centro della stanza.

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 ha esito positivo, viene restituita una struttura "ObjectPlacementResult" contenente la posizione di posizionamento, le dimensioni e l'orientamento. Inoltre, il posizionamento viene aggiunto all'elenco interno della dll degli oggetti inseriti. Le query di posizionamento successive tengono conto di questo oggetto. Il file "LevelSolver.cs" nell'esempio unity contiene più query di esempio.

Risultati del posizionamento dell'oggetto
Figura 3: Le caselle blu come il risultato da tre posizioni sulle query sul piano con le regole di posizione della fotocamera

Quando si risolve la posizione di posizionamento di più oggetti necessari per uno scenario di livello o applicazione, risolvere prima oggetti indispensabile e di grandi dimensioni per massimizzare la probabilità che sia possibile trovare uno spazio. L'ordine di posizionamento è importante. Se non è possibile trovare i posizionamenti degli oggetti, provare configurazioni meno vincolate. La presenza di un set di configurazioni di fallback è fondamentale per supportare le funzionalità in molte configurazioni della sala.

Processo di analisi della stanza

Mentre la soluzione di mapping spaziale fornita da HoloLens è progettata per essere abbastanza generica per soddisfare le esigenze dell'intera gamma di spazi problemi, il modulo di comprensione spaziale è stato creato per supportare le esigenze di due giochi specifici. La soluzione è strutturata intorno a un processo specifico e a un set di presupposti, riepilogati di seguito.

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.

Playspace guidato dall'utente : durante la fase di analisi, l'utente si sposta e guarda intorno al ritmo dei giochi, disegnare in modo efficace le aree, che devono essere incluse. La mesh generata è importante per fornire commenti e suggerimenti degli utenti durante questa fase. Installazione interna o ufficio: le funzioni di query sono progettate intorno alle superfici flat e alle pareti ad angolo destro. Si tratta di una limitazione temporanea. Tuttavia, durante la fase di analisi, viene completata un'analisi dell'asse primario per ottimizzare la tessellazione mesh lungo l'asse principale e secondario. Il file SpatialUnderstanding.cs incluso gestisce il processo di analisi. Chiama le funzioni seguenti.

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.

Il flusso di analisi, basato sul comportamento "SpatialUnderstanding" chiama InitScan, quindi UpdateScan ogni frame. Quando la query statistiche segnala una copertura ragionevole, l'utente può chiamare RequestFinish per indicare la fine della fase di analisi. UpdateScan continua a essere chiamato fino a quando il valore restituito indica che la dll ha completato l'elaborazione.

Informazioni sulla mesh

La dll di comprensione archivia internamente lo spazio di riproduzione come griglia di 8 cubi voxel di dimensioni pari a 8 cm. Durante la parte iniziale dell'analisi, viene completata un'analisi dei componenti primaria per determinare gli assi della stanza. Internamente, archivia lo spazio voxel allineato a questi assi. Una mesh viene generata approssimativamente ogni secondo estraendo l'isosurface dal volume voxel.

Mesh generata dal volume voxel
Mesh generata dal volume voxel

Risoluzione dei problemi

  • Assicurarsi di aver impostato la funzionalità SpatialPerception
  • Quando il rilevamento viene perso, l'evento OnSurfaceChanged successivo rimuoverà tutte le mesh.

Mapping spaziale in Realtà mista Toolkit

Per altre informazioni sull'uso del mapping spaziale con Realtà mista Toolkit, vedere la sezione relativa alla consapevolezza spaziale della documentazione di MRTK.

Successivo checkpoint di sviluppo

Se si sta seguendo il percorso di sviluppo di Unity, si è in corso l'esplorazione dei blocchi predefiniti principali di MRTK. Da qui, è possibile passare al blocco predefinito successivo:

In alternativa, passare alle API e alle funzionalità della piattaforma di realtà mista:

È sempre possibile tornare ai checkpoint per lo sviluppo con Unity in qualsiasi momento.

Vedere anche