Dela via


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 dina Unity-projekt en extra dos av 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 finns i MixedRealityToolkit, vilket ger en bekväm och snabb väg för att komma igång med spatial 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 Uppslukande headset
Rumslig mappning ✔️ ✔️

Ange spatialperception-funktionen

För att en app ska kunna använda spatial 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"

Kommentar

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.

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

  1. Högerklicka på Package.appxmanifest i Istraživač rešenja 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 scentolkningsobservatörer 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 placering 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 Fragment stod Asobo Studios inför 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 karaktär att sitta och en mängd 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.

Strålegjutning

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 voxel-representationen på 8 cm i kubik av spelytan. Varje voxel innehåller en uppsättning ytelement med bearbetade topologidata (även kallade surfels). De surfels som finns i den korsande voxelcellen jämförs och den bästa matchningen används för att leta upp topologiinformationen. Dessa topologidata innehåller etiketterna som returneras i form av "SurfaceTypes"-uppräkningen, samt ytan på den korsande 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 användargränssnittselement. 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 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 strukturen "PlaySpaceInfos" 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 yta vara golvet.

Kommentar

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 och bredden på önskad volym, minsta placeringshöjd ovanför golvet och den minsta mängden frigång framför volymen. Alla mått är i mätare.

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 "TopologiResult"-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 den som skickades i parametern "locationCount".

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

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

Kommentar

I Unity-exemplet länkas var och en av dessa frågor 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. Se SpaceVisualizer.cs i exempelkoden för fler exempel.

Formfrågor

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

Formanalysen fungerar endast på vågräta ytor. En soffa, till exempel, definieras av den platta sätesytan och den platta toppen av soffan tillbaka. Formfrågan söker efter två ytor med en specifik storlek, höjd och aspektintervall, med de två ytorna justerade och anslutna. Med api:ernas terminologi är soffsätet och ryggstödet 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).

Däremot har soffformen 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

Problem med objektplacering

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 med tanke 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#-omslutningen tillhandahåller bygghjälpfunktioner för att göra regel- och begränsningskonstruktionen enkel. Placeringsdefinitionen innehåller frågetypen – dvs. 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 där ett objekt ska placeras 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 uppsättningen med begränsningar för att välja den optimala placeringsplatsen. Var och en av reglerna och begränsningarna kan skapas av de tillhandahållna statiska skapandefunktionerna. Nedan visas en exempelregel och begränsningskonstruktionsfunktion.

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 hur resultatet från tre platser på golvfrågor med undantag för kamerapositionsregler

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 utrymme kan hittas. Placeringsordning är viktigt. Om det inte går att hitta objektplaceringar kan du prova mindre begränsade konfigurationer. Att ha en uppsättning återställningskonfigurationer är avgörande för att stödja funktioner i många rumskonfigurationer.

Rumsgenomsökningsprocess

Medan 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 hos 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 genomsökningsfasen rör sig användaren och tittar runt uppspelningstakten och målar effektivt områdena, som bör ingå. 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 primär axelanalys för att optimera mesh-tessellationen längs större och mindre axel. Den inkluderade SpatialUnderstanding.cs-filen hanterar genomsökningsprocessen. 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 får användaren airtap för att 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

Förståelsedllen lagrar spelytan internt som ett rutnät med voxelkuber med 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 efter 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

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

Spatial mappning i Mixed Reality Toolkit

Mer information om hur du använder spatial mappning med Mixed Reality Toolkit finns i avsnittet rumslig 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ärnbyggnadsblocken. Härifrån kan du fortsätta till nästa byggblock:

Eller hoppa till funktioner och API:er för Mixed Reality-plattformen:

Du kan alltid gå tillbaka till Unity-utvecklingspunkterna när som helst.

Se även