Delen via


Ruimtelijke toewijzing in Unity

Met ruimtelijke toewijzing kunt u driehoeken ophalen die de oppervlakken in de wereld rond een HoloLens-apparaat vertegenwoordigen. U kunt oppervlaktegegevens gebruiken voor plaatsing, occlusie en ruimteanalyse om uw Unity-projecten een extra dosis onderdompeling te geven.

Unity biedt volledige ondersteuning voor ruimtelijke toewijzing, die op de volgende manieren beschikbaar is voor ontwikkelaars:

  1. Onderdelen voor ruimtelijke toewijzing die beschikbaar zijn in de MixedRealityToolkit, die een handig en snel pad bieden om aan de slag te gaan met ruimtelijke toewijzing
  2. API's voor ruimtelijke toewijzing op lager niveau, die volledige controle bieden en geavanceerdere toepassingsspecifieke aanpassingen mogelijk maken

Als u ruimtelijke toewijzing in uw app wilt gebruiken, moet de mogelijkheid SpatialPerception worden ingesteld in uw AppxManifest.

Ondersteuning voor apparaten

Functie HoloLens (eerste generatie) HoloLens 2 Insluitende headsets
Ruimtelijke toewijzing ✔️ ✔️

De mogelijkheid SpatialPerception instellen

Als een app ruimtelijke toewijzingsgegevens kan gebruiken, moet de mogelijkheid SpatialPerception zijn ingeschakeld.

De mogelijkheid SpatialPerception inschakelen:

  1. Open in de Unity Editor het deelvenster Spelerinstellingen (Project Settings > Player bewerken>)
  2. Selecteer op het tabblad Windows Store
  3. Vouw Publicatie-instellingen uit en controleer de mogelijkheid SpatialPerception in de lijst Mogelijkheden

Notitie

Als u uw Unity-project al hebt geëxporteerd naar een Visual Studio-oplossing, moet u exporteren naar een nieuwe map of deze mogelijkheid handmatig instellen in appxManifest in Visual Studio.

Voor ruimtelijke toewijzing is ook een MaxVersionTested van ten minste 10.0.10586.0 vereist:

  1. Klik in Visual Studio met de rechtermuisknop op Package.appxmanifest in Solution Explorer en selecteer Code weergeven
  2. Zoek de regel die TargetDeviceFamily opgeeft en wijzig MaxVersionTested="10.0.10240.0" in MaxVersionTested="10.0.10586.0"
  3. Sla het Package.appxmanifest op.

Toewijzing toevoegen in Unity

Ruimtelijk bewustzijnssysteem

In MRTK bekijkt u de introductiehandleiding voor ruimtelijk bewustzijn voor informatie over het instellen van verschillende ruimtelijke mesh-waarnemers.

Zie de handleiding Mesh-waarnemers configureren voor apparaatinformatie voor informatie over waarnemers op het apparaat .

Zie de gids voor waarnemers voor scènes voor informatie over waarnemers in scènes.

Mesh-analyse op hoger niveau: Ruimtelijk inzicht

Let op

Spatial Understanding is afgeschaft ten gunste van Scene Understanding.

De MixedRealityToolkit is een verzameling hulpprogrammacode voor holografische ontwikkeling die is gebouwd op de holografische API's van Unity.

Ruimtelijk inzicht

Bij het plaatsen van hologrammen in de fysieke wereld is het vaak wenselijk om verder te gaan dan de mesh- en oppervlaktevlakken van ruimtelijke toewijzingen. Wanneer de plaatsing procedureel wordt uitgevoerd, is een hoger niveau van milieukennis wenselijk. Hiervoor moeten meestal beslissingen worden genomen over wat vloer, plafond en muren zijn. U hebt ook de mogelijkheid om te optimaliseren op basis van een set plaatsingsbeperkingen om de beste fysieke locaties voor holografische objecten te bepalen.

Tijdens de ontwikkeling van Young Conker en Fragments stond Asobo Studios tegenover dit probleem door een kamerlosser te ontwikkelen. Elk van deze games had spelspecifieke behoeften, maar ze hebben kerntechnologie voor ruimtelijk begrip gedeeld. De HoloToolkit.SpatialUnderstanding-bibliotheek kapselt deze technologie in, zodat u snel lege ruimten op de wanden kunt vinden, objecten op het plafond kunt plaatsen, het teken kunt identificeren om te zitten en een groot aantal andere query's voor ruimtelijk begrip.

Alle broncode is opgenomen, zodat u deze aan uw behoeften kunt aanpassen en uw verbeteringen met de community kunt delen. De code voor de C++ oplosser is verpakt in een UWP-dll en blootgesteld aan Unity met een daling in prefab in de MixedRealityToolkit.

Informatie over modules

De module bevat drie primaire interfaces: topologie voor eenvoudige oppervlakte- en ruimtelijke query's, vorm voor objectdetectie en de oplosser voor objectplaatsing op basis van beperkingen voor plaatsing van objectsets. Deze methoden worden beide hieronder beschreven. Naast de drie primaire moduleinterfaces kan een ray casting-interface worden gebruikt om getagde oppervlaktetypen op te halen en kan een aangepaste waterdichte playspace mesh worden gekopieerd.

Ray Casting

Nadat de ruimtescan is voltooid, worden labels intern gegenereerd voor oppervlakken zoals de vloer, het plafond en de muren. De PlayspaceRaycast functie neemt een straal en retourneert als de straal botst met een bekend oppervlak en zo ja, informatie over dat oppervlak in de vorm van een 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;
};

Intern wordt de raycast berekend op basis van de berekende voxel-weergave van de playspace van 8 cm. Elke voxel bevat een set oppervlakte-elementen met verwerkte topologiegegevens (ook wel surfels genoemd). De surfels in de gekruiste voxelcel worden vergeleken en de beste overeenkomst die wordt gebruikt om de topologiegegevens op te zoeken. Deze topologiegegevens bevatten het label dat wordt geretourneerd in de vorm van de enum 'SurfaceTypes', evenals het oppervlak van het gekruiste oppervlak.

In het Unity-voorbeeld cast de cursor elk frame een ray. Ten eerste tegen unity's colliders. Ten tweede, tegen de wereldweergave van de understanding-module. En ten slotte, nogmaals UI-elementen. In deze toepassing krijgt de gebruikersinterface prioriteit, naast het begripsresultaat en ten slotte botst Unity. Het SurfaceType wordt gerapporteerd als tekst naast de cursor.

Surface-type wordt gelabeld naast de cursor
Surface-type wordt gelabeld naast de cursor

Topologiequery's

In het DLL-bestand verwerkt de topologiebeheerder het labelen van de omgeving. Zoals hierboven vermeld, worden veel van de gegevens opgeslagen in surfels, opgenomen in een voxel-volume. Daarnaast wordt de structuur 'PlaySpaceInfos' gebruikt om informatie over de playspace op te slaan, waaronder de werelduitlijning (meer informatie hieronder), vloer en plafondhoogte. Heuristiek wordt gebruikt voor het bepalen van vloer, plafond en muren. Het grootste en laagste horizontale oppervlak met een oppervlakte van meer dan 1 m2 wordt bijvoorbeeld beschouwd als de vloer.

Notitie

Het camerapad tijdens het scanproces wordt ook in dit proces gebruikt.

Een subset van de query's die door topologiebeheer worden weergegeven, worden weergegeven via het DLL-bestand. De weergegeven topologiequery's zijn als volgt.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

Elk van de query's heeft een set parameters, specifiek voor het querytype. In het volgende voorbeeld geeft de gebruiker de minimale hoogte en breedte van het gewenste volume, minimale plaatsingshoogte boven de vloer en de minimale afstand voor het volume op. Alle metingen zijn in meters.

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)

Elk van deze query's heeft een vooraf toegewezen matrix met structuren topologyResult. De parameter locationCount geeft de lengte van de doorgegeven matrix aan. De retourwaarde rapporteert het aantal geretourneerde locaties. Dit getal is nooit groter dan de parameter 'locationCount'.

De "TopologyResult" bevat de middenpositie van het geretourneerde volume, de richting van de richting (dat wil bijvoorbeeld normaal) en de afmetingen van de gevonden ruimte.

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

Notitie

In het Unity-voorbeeld wordt elk van deze query's gekoppeld aan een knop in het deelvenster virtuele gebruikersinterface. Het voorbeeld codeert de parameters voor elk van deze query's tot redelijke waarden. Zie SpaceVisualizer.cs in de voorbeeldcode voor meer voorbeelden.

Shapequery's

In het dll-bestand gebruikt de shape analyzer ('ShapeAnalyzer_W') de topologieanalyse om overeen te komen met aangepaste shapes die door de gebruiker zijn gedefinieerd. In het Unity-voorbeeld wordt een set shapes gedefinieerd en worden de resultaten weergegeven via het querymenu in de app, op het tabblad Shape. De bedoeling is dat de gebruiker zijn eigen objectshapequery's kan definiëren en deze, indien nodig, kan gebruiken door de toepassing.

De shapeanalyse werkt alleen op horizontale oppervlakken. Een bank wordt bijvoorbeeld gedefinieerd door het vlakke zitvlak en de platte bovenkant van de bank terug. De shapequery zoekt naar twee oppervlakken van een specifieke grootte, hoogte en hoogtebereik, waarbij de twee oppervlakken zijn uitgelijnd en verbonden. Met behulp van de API-terminologie zijn de bankstoel en de achterkant onderdelen van de shape en zijn de uitlijningsvereisten beperkingen voor shapeonderdelen.

Een voorbeeldquery die is gedefinieerd in het Unity-voorbeeld (ShapeDefinition.cs), voor 'sittable'-objecten is als volgt.

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

Elke shapequery wordt gedefinieerd door een set shapeonderdelen, elk met een set componentbeperkingen en een set shapebeperkingen die afhankelijkheden tussen de onderdelen weergeeft. Dit voorbeeld bevat drie beperkingen in één onderdeeldefinitie en geen shapebeperkingen tussen onderdelen (omdat er slechts één onderdeel is).

De bankshape heeft daarentegen twee shapeonderdelen en vier vormbeperkingen. Onderdelen worden geïdentificeerd door hun index in de lijst met onderdelen van de gebruiker (0 en 1 in dit voorbeeld).

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

Wrapper-functies zijn beschikbaar in de Unity-module voor het eenvoudig maken van aangepaste shapedefinities. De volledige lijst met component- en shapebeperkingen vindt u in 'SpatialUnderstandingDll.cs' binnen de structuren ShapeComponentConstraint en ShapeConstraint.

Rechthoekshape is te vinden op dit oppervlak
Rechthoekshape is te vinden op dit oppervlak

Oplosser voor objectplaatsing

De oplosser voor objectplaatsing kan worden gebruikt om ideale locaties in de fysieke ruimte te identificeren om uw objecten te plaatsen. De oplosser vindt de best passende locatie op basis van de objectregels en -beperkingen. Bovendien blijven objectquery's behouden totdat het object wordt verwijderd met aanroepen 'Solver_RemoveObject' of 'Solver_RemoveAllObjects', waardoor beperkte plaatsing van meerdere objecten mogelijk is. Objectenplaatsingsquery's bestaan uit drie onderdelen: plaatsingstype met parameters, een lijst met regels en een lijst met beperkingen. Gebruik de volgende API om een query uit te voeren.

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)

Deze functie gebruikt een objectnaam, plaatsingsdefinitie en een lijst met regels en beperkingen. De C#-wrappers bieden bouwhulpfuncties om de bouw van regels en beperkingen eenvoudig te maken. De plaatsingsdefinitie bevat het querytype: een van de volgende opties.

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

Elk van de plaatsingstypen heeft een set parameters die uniek zijn voor het type. De structuur ObjectPlacementDefinition bevat een set statische helperfuncties voor het maken van deze definities. Als u bijvoorbeeld een plaats wilt vinden om een object op de vloer te plaatsen, kunt u de volgende functie gebruiken. openbare statische ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims) Naast het plaatsingstype kunt u een set regels en beperkingen opgeven. Regels kunnen niet worden geschonden. Mogelijke plaatsingslocaties die voldoen aan het type en de regels, worden vervolgens geoptimaliseerd op basis van de set beperkingen om de optimale plaatsingslocatie te selecteren. Elk van de regels en beperkingen kan worden gemaakt door de opgegeven statische aanmaakfuncties. Hieronder vindt u een voorbeeld van een regel en een bouwfunctie voor beperkingen.

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

De onderstaande objectplaatsingsquery is op zoek naar een plek om een kubus van een halve meter aan de rand van een oppervlak te plaatsen, weg van andere eerder geplaatste objecten en in de buurt van het midden van de ruimte.

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

Als dit lukt, wordt een structuur 'ObjectPlacementResult' met de plaatsingspositie, dimensies en afdrukstand geretourneerd. Daarnaast wordt de plaatsing toegevoegd aan de interne lijst met geplaatste objecten van het DLL-bestand. Bij volgende plaatsingsquery's wordt rekening gehouden met dit object. Het bestand LevelSolver.cs in het Unity-voorbeeld bevat meer voorbeeldquery's.

Resultaten van objectplaatsing
Afbeelding 3: De blauwe vakken hoe het resultaat van drie plaatsen op vloerquery's met afstand van camerapositieregels

Bij het oplossen van de plaatsingslocatie van meerdere objecten die zijn vereist voor een niveau- of toepassingsscenario, lost u eerst onmisbaar en grote objecten op om de kans te maximaliseren dat een ruimte kan worden gevonden. Plaatsingsvolgorde is belangrijk. Als objectplaatsingen niet kunnen worden gevonden, probeert u minder beperkte configuraties. Het hebben van een set terugvalconfiguraties is essentieel voor het ondersteunen van functionaliteit in veel ruimteconfiguraties.

Proces voor het scannen van ruimten

Hoewel de oplossing voor ruimtelijke toewijzing die door de HoloLens wordt geboden, algemeen genoeg is om te voldoen aan de behoeften van de gehele ruimteruimte, is de module voor ruimtelijk begrip gebouwd ter ondersteuning van de behoeften van twee specifieke games. De oplossing is gestructureerd rond een specifiek proces en een reeks veronderstellingen, samengevat hieronder.

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.

Door de gebruiker gestuurde playspace 'schilderij': tijdens de scanfase beweegt de gebruiker zich en kijkt hij rond het afspeeltempo, waarbij de gebieden effectief worden geschilderd, die moeten worden opgenomen. De gegenereerde mesh is belangrijk om tijdens deze fase gebruikersfeedback te geven. Binnen huis- of kantoorinstellingen – De queryfuncties zijn ontworpen rond vlakke oppervlakken en muren in rechte hoeken. Dit is een zachte beperking. Tijdens de scanfase wordt echter een analyse van de primaire as voltooid om de mesh-tessellation langs de primaire en secundaire as te optimaliseren. Het opgenomen SpatialUnderstanding.cs-bestand beheert het scanfaseproces. De volgende functies worden aanroepen.

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.

De scanstroom, aangestuurd door het gedrag 'SpatialUnderstanding', roept InitScan aan en vervolgens UpdateScan elk frame. Wanneer de statistiekenquery redelijke dekking rapporteert, mag de gebruiker airtap aanroepen van RequestFinish om het einde van de scanfase aan te geven. UpdateScan wordt nog steeds aangeroepen totdat de retourwaarde aangeeft dat het dll-bestand de verwerking heeft voltooid.

Informatie over Mesh

De understanding dll slaat de playspace intern op als een raster van 8 cm grote voxel kubussen. Tijdens het eerste deel van het scannen wordt een analyse van het primaire onderdeel voltooid om de assen van de ruimte te bepalen. Intern wordt de voxel-ruimte opgeslagen die is uitgelijnd op deze assen. Er wordt ongeveer elke seconde een mesh gegenereerd door het isooppervlak uit het voxel-volume te extraheren.

Gegenereerde mesh geproduceerd op basis van het voxel-volume
Gegenereerde mesh geproduceerd op basis van het voxel-volume

Probleemoplossing

  • Zorg ervoor dat u de mogelijkheid SpatialPerception hebt ingesteld
  • Wanneer het bijhouden is verbroken, worden met de volgende onSurfaceChanged-gebeurtenis alle meshes verwijderd.

Ruimtelijke toewijzing in Mixed Reality Toolkit

Zie de sectie ruimtelijk bewustzijn van de MRTK-documenten voor meer informatie over het gebruik van Spatial Mapping met Mixed Reality Toolkit.

Volgend controlepunt voor ontwikkeling

Als u het Unity-ontwikkeltraject volgt dat we hebben opgesteld, bevindt u zich midden in het verkennen van de bouwstenen van de MRTK-kern. Vanaf hier kunt u doorgaan naar de volgende bouwsteen:

Of ga naar de mogelijkheden en API's van het Mixed Reality-platform:

U kunt altijd op elk gewenst moment teruggaan naar de Unity-ontwikkelingscontrolepunten .

Zie ook