Rumslig mappning i Unity

Med rumslig mappning kan du hämta triangelnät som representerar ytorna i världen runt en HoloLens-enhet. Du kan använda ytdata för placering, ocklusion och rumsanalys för att ge Unity-projekten en extra dos nedsänkning.

Unity har fullt stöd för rumslig mappning, som exponeras för utvecklare på följande sätt:

  1. Komponenter för rumslig mappning som är tillgängliga i MixedRealityToolkit, vilket ger en praktisk och snabb väg för att komma igång med rumslig mappning
  2. API:er för rumslig mappning på lägre nivå, som ger fullständig kontroll och möjliggör mer avancerad programspecifik anpassning

Om du vill använda rumslig mappning i din app måste SpatialPerception-funktionen anges i din AppxManifest.

Stöd för enheter

Funktion HoloLens (första generationen) HoloLens 2 Integrerande headset
Rumslig mappning ✔️ ✔️

Ange SpatialPerception-funktionen

För att en app ska kunna använda rumsliga mappningsdata måste spatialperception-funktionen vara aktiverad.

Så här aktiverar du SpatialPerception-funktionen:

  1. I Unity-redigeraren öppnar du fönstret "Spelarinställningar" (Redigera > projektinställningar > spelare)
  2. Välj på fliken "Windows Store"
  3. Expandera "Publiceringsinställningar" och kontrollera funktionen "SpatialPerception" i listan "Funktioner"

Anteckning

Om du redan har exporterat Unity-projektet till en Visual Studio-lösning måste du antingen exportera till en ny mapp eller manuellt ange den här funktionen i AppxManifest i Visual Studio.

Rumslig mappning kräver också en MaxVersionTested på minst 10.0.10586.0:

  1. Högerklicka på Package.appxmanifest i Solution Explorer i Visual Studio och välj Visa kod
  2. Hitta raden som anger TargetDeviceFamily och ändra MaxVersionTested="10.0.10240.0" till MaxVersionTested="10.0.10586.0"
  3. Spara Package.appxmanifest.

Lägga till mappning i Unity

System för rumslig medvetenhet

I MRTK tittar du på guiden För att komma igång med rumslig medvetenhet för information om hur du konfigurerar olika spatiala nätobservatörer.

Information om observatörer på enheten finns i guiden Konfigurera nätobservatörer för enhet .

Information om observatörer för scentolkning finns i övervakningsguiden för scentolkning .

Nätanalys på högre nivå: Spatial Understanding

Varning

Spatial Understanding har blivit inaktuell till förmån för Scene Understanding.

MixedRealityToolkit är en samling verktygskod för holografisk utveckling som bygger på Unitys holografiska API:er.

Rumslig förståelse

När du placerar hologram i den fysiska världen är det ofta önskvärt att gå utöver den rumsliga mappningens nät- och ytplan. När placeringen görs procedurmässigt är en högre nivå av miljöförståldelse önskvärd. Detta kräver vanligtvis att fatta beslut om vad som är golv, tak och väggar. Du kan också optimera mot en uppsättning placeringsbegränsningar för att fastställa de bästa fysiska platserna för holografiska objekt.

Under utvecklingen av Young Conker och Fragments mötte Asobo Studios detta problem rakt på genom att utveckla en rumslösare. Vart och ett av dessa spel hade spelspecifika behov, men de delade grundläggande rumslig förståelseteknik. Biblioteket HoloToolkit.SpatialUnderstanding kapslar in den här tekniken, så att du snabbt kan hitta tomma utrymmen på väggarna, placera objekt i taket, identifiera placerade för tecken att sitta och en myriad av andra frågor om rumslig förståelse.

All källkod ingår, så att du kan anpassa den efter dina behov och dela dina förbättringar med communityn. Koden för C++-lösaren har omslutits till en UWP-dll och exponerats för Unity med en minskning av prefab som finns i MixedRealityToolkit.

Förstå moduler

Det finns tre primära gränssnitt som exponeras av modulen: topologi för enkla yt- och rumsfrågor, form för objektidentifiering och objektplaceringslösaren för begränsningsbaserad placering av objektuppsättningar. Var och en av dessa beskrivs nedan. Förutom de tre primära modulgränssnitten kan ett ray casting-gränssnitt användas för att hämta taggade yttyper och ett anpassat vattentätt spelområdesnät kan kopieras ut.

Ray Casting

När rumsgenomsökningen är klar genereras etiketter internt för ytor som golv, tak och väggar. Funktionen PlayspaceRaycast tar en stråle och returnerar om strålen kolliderar med en känd yta och i så fall information om den ytan i form av en 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;
};

Internt beräknas raycasten mot den beräknade voxelrepresentationen på 8 cm i kubik av spelytan. Varje voxel innehåller en uppsättning ytelement med bearbetade topologidata (till exempel surfels). De surfels som finns i den överlappande voxelcellen jämförs och den bästa matchningen används för att leta upp topologiinformationen. Dessa topologidata innehåller de etiketter som returneras i form av "SurfaceTypes"-uppräkningen, samt ytan på den överlappande ytan.

I Unity-exemplet kastar markören en stråle varje bildruta. Först mot Unitys kolliderare. För det andra, mot förståelsemodulens världsrepresentation. Och slutligen, återigen UI-element. I det här programmet får användargränssnittet prioritet, nästa förståelseresultat och slutligen Unitys kolliderare. SurfaceType rapporteras som text bredvid markören.

Yttyp är märkt bredvid markören
Yttyp är märkt bredvid markören

Topologifrågor

I DLL-filen hanterar topologihanteraren etikettering av miljön. Som nämnts ovan lagras mycket av data i surfels, som finns i en voxel-volym. Dessutom används "PlaySpaceInfos"-strukturen för att lagra information om spelytan, inklusive världsjusteringen (mer information om detta nedan), golv- och takhöjd. Heuristik används för att bestämma golv, tak och väggar. Till exempel anses den största och lägsta vågräta ytan med större än 1 m2 ytyta vara golvet.

Anteckning

Kamerasökvägen under genomsökningsprocessen används också i den här processen.

En delmängd av de frågor som exponeras av topologihanteraren exponeras via dll-filen. De exponerade topologifrågorna är följande.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

Var och en av frågorna har en uppsättning parametrar som är specifika för frågetypen. I följande exempel anger användaren den minsta höjden & bredden på önskad volym, minsta placeringshöjd över golvet och den minsta mängden utrymme framför volymen. Alla mått är i meter.

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)

Var och en av dessa frågor tar en förallokerad matris med "TopologyResult"-strukturer. Parametern "locationCount" anger längden på den skickade matrisen. Returvärdet rapporterar antalet returnerade platser. Det här talet är aldrig större än parametern som skickades i parametern "locationCount".

"TopologiResult" innehåller den returnerade volymens mittposition, den riktade riktningen (dvs. normal) och dimensionerna för det hittade utrymmet.

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

Anteckning

I Unity-exemplet är var och en av dessa frågor länkad till en knapp i den virtuella användargränssnittspanelen. Exemplet hårdkodar parametrarna för var och en av dessa frågor till rimliga värden. Fler exempel finns i SpaceVisualizer.cs i exempelkoden.

Formfrågor

I dll-filen använder formanalyseraren ("ShapeAnalyzer_W") topologianalysen för att matcha mot anpassade former som definieras av användaren. Unity-exemplet definierar en uppsättning former och exponerar resultaten via frågemenyn i appen på fliken Form. Avsikten är att användaren kan definiera sina egna objektformsfrågor och använda dem efter behov av sitt program.

Formanalysen fungerar endast på vågräta ytor. En soffa definieras till exempel av den platta sittytan och den platta toppen av soffans rygg. Formfrågan söker efter två ytor med en viss storlek, höjd och breddintervall, med de två ytorna justerade och anslutna. Med hjälp av API:ernas terminologi är soffsätet och bakdelen formkomponenter och justeringskraven är formkomponentbegränsningar.

En exempelfråga som definieras i Unity-exemplet (ShapeDefinition.cs) för "sittable"-objekt är följande.

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

Varje formfråga definieras av en uppsättning formkomponenter, var och en med en uppsättning komponentbegränsningar och en uppsättning formbegränsningar som visar beroenden mellan komponenterna. Det här exemplet innehåller tre begränsningar i en enskild komponentdefinition och inga formbegränsningar mellan komponenter (eftersom det bara finns en komponent).

Soffformen har däremot två formkomponenter och fyra formbegränsningar. Komponenter identifieras av deras index i användarens komponentlista (0 och 1 i det här exemplet).

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

Omslutningsfunktioner finns i Unity-modulen för att enkelt skapa anpassade formdefinitioner. Den fullständiga listan över komponent- och formbegränsningar finns i "SpatialUnderstandingDll.cs" i strukturerna "ShapeComponentConstraint" och "ShapeConstraint".

Rektangelformen finns på den här ytan
Rektangelformen finns på den här ytan

Objektplaceringslösare

Objektplaceringslösaren kan användas för att identifiera idealiska platser i det fysiska rummet för att placera dina objekt. Lösningslösaren hittar den plats som passar bäst beroende på objektregler och begränsningar. Dessutom bevaras objektfrågor tills objektet tas bort med "Solver_RemoveObject" eller "Solver_RemoveAllObjects"-anrop, vilket tillåter begränsad placering av flera objekt. Objektplaceringsfrågor består av tre delar: placeringstyp med parametrar, en lista över regler och en lista över begränsningar. Om du vill köra en fråga använder du följande 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)

Den här funktionen tar ett objektnamn, en placeringsdefinition och en lista över regler och begränsningar. C#-omslutningarna tillhandahåller bygghjälpfunktioner som gör det enkelt att bygga regler och begränsningar. Placeringsdefinitionen innehåller frågetypen – det vill: något av följande.

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

Var och en av placeringstyperna har en uppsättning parametrar som är unika för typen. Strukturen "ObjectPlacementDefinition" innehåller en uppsättning statiska hjälpfunktioner för att skapa dessa definitioner. Om du till exempel vill hitta en plats för att placera ett objekt på golvet kan du använda följande funktion. public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims) Utöver placeringstypen kan du ange en uppsättning regler och begränsningar. Regler kan inte brytas. Möjliga placeringsplatser som uppfyller typen och reglerna optimeras sedan mot begränsningsuppsättningen för att välja den optimala placeringsplatsen. Var och en av reglerna och begränsningarna kan skapas av de tillhandahållna statiska skapandefunktionerna. Ett exempel på en funktion för regel- och villkorskonstruktion finns nedan.

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

Nedanstående objektplaceringsfråga letar efter en plats för att placera en halv meter kub på kanten av en yta, bort från andra tidigare platsobjekt och nära mitten av rummet.

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

Om det lyckas returneras en "ObjectPlacementResult"-struktur som innehåller placeringspositionen, dimensionerna och orienteringen. Dessutom läggs placeringen till i dll-filens interna lista över placerade objekt. Efterföljande placeringsfrågor tar hänsyn till det här objektet. Filen "LevelSolver.cs" i Unity-exemplet innehåller fler exempelfrågor.

Resultat av objektplacering
Bild 3: De blå rutorna visar resultatet från tre platser i golvfrågor med undantag för kamerans placeringsregler

När du löser placeringsplatsen för flera objekt som krävs för ett nivå- eller programscenario löser du först oumbärliga och stora objekt för att maximera sannolikheten för att ett blanksteg kan hittas. Placeringsordningen är viktig. Om det inte går att hitta objektplaceringar kan du prova mindre begränsade konfigurationer. Det är viktigt att ha en uppsättning återställningskonfigurationer för att stödja funktioner i många rumskonfigurationer.

Rumsgenomsökningsprocess

Även om den rumsliga mappningslösningen som tillhandahålls av HoloLens är utformad för att vara tillräckligt generisk för att uppfylla behoven i hela skalan av problemutrymmen, skapades modulen spatial understanding för att stödja behoven i två specifika spel. Lösningen är strukturerad kring en specifik process och en uppsättning antaganden, som sammanfattas nedan.

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.

Användardriven spelyta "målning" – Under skanningsfasen rör sig användaren och tittar runt uppspelningstakten, effektivt måla områdena, som bör inkluderas. Det genererade nätet är viktigt för att ge användarfeedback under den här fasen. Inomhus hemma- eller kontorsinstallation – Frågefunktionerna är utformade runt plana ytor och väggar i rät vinkel. Detta är en mjuk begränsning. Under genomsökningsfasen slutförs dock en analys av primäraxeln för att optimera mesh-tessellationen längs huvudaxeln och mindre axeln. Den inkluderade Filen SpatialUnderstanding.cs hanterar genomsökningsfasen. Den anropar följande funktioner.

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.

Genomsökningsflödet, som drivs av beteendet "SpatialUnderstanding", anropar InitScan och sedan UpdateScan varje bildruta. När statistikfrågan rapporterar rimlig täckning kan användaren airtap anropa RequestFinish för att ange slutet på genomsökningsfasen. UpdateScan fortsätter att anropas tills dess returvärde anger att dll-filen har slutfört bearbetningen.

Förstå Mesh

Den förstånde dll-filen lagrar spelytan internt som ett rutnät med voxelkuber i 8 cm-storlek. Under den första delen av genomsökningen slutförs en primär komponentanalys för att fastställa rummets axlar. Internt lagrar den sitt voxelutrymme som är justerat till dessa axlar. Ett nät genereras ungefär varje sekund genom att isosurface extraheras från voxelvolymen.

Genererat nät som produceras från voxel-volymen
Genererat nät som produceras från voxel-volymen

Felsökning

  • Kontrollera att du har angett SpatialPerception-funktionen
  • När spårningen går förlorad tar nästa OnSurfaceChanged-händelse bort alla nät.

Rumslig mappning i Mixed Reality Toolkit

Mer information om hur du använder rumslig mappning med Mixed Reality Toolkit finns i avsnittet spatial medvetenhet i MRTK-dokumenten.

Nästa kontrollpunkt för utveckling

Om du följer unity-utvecklingsresan som vi har lagt fram är du mitt uppe i att utforska MRTK-kärnbyggstenarna. Härifrån kan du fortsätta till nästa byggblock:

Eller gå vidare till Mixed Reality plattformsfunktioner och API:er:

Du kan alltid gå tillbaka till unity-utvecklingskontrollpunkterna när som helst.

Se även