Ruimtelijke toewijzing in Unity

Met ruimtelijke toewijzing kunt u driehoeksnetten 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 Immersive headsets
Ruimtelijke toewijzing ✔️ ✔️

De mogelijkheid SpatialPerception instellen

Om ervoor te zorgen dat 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' (Projectinstellingen > bewerken > Player)
  2. Selecteer op het tabblad Windows Store
  3. Vouw 'Publicatie-instellingen' uit en controleer de mogelijkheid 'SpatialPerception' in de lijst 'Capabilities'

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 het 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 de 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 package.appxmanifest op.

Toewijzing toevoegen in Unity

Ruimtelijk bewustzijnssysteem

Bekijk in MRTK de handleiding Aan de slag met ruimtelijk bewustzijn voor informatie over het instellen van verschillende ruimtelijke mesh-waarnemers.

Raadpleeg de handleiding Mesh-waarnemers configureren voor apparaten voor informatie over waarnemers op het apparaat.

Voor informatie over scènes die waarnemers begrijpen, raadpleegt u de waarnemershandleiding voor scènes .

Mesh-analyse op een hoger niveau: ruimtelijk inzicht

Waarschuwing

Spatial Understanding is afgeschaft ten gunste van Scene Understanding.

De MixedRealityToolkit is een verzameling hulpprogrammacode voor holografische ontwikkeling die is gebaseerd 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 kaarten. Wanneer plaatsing procedureel wordt uitgevoerd, is een hoger niveau van milieu-begrip wenselijk. Dit vereist meestal het nemen van beslissingen over wat vloer, plafond en wanden 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 werd Asobo Studios geconfronteerd met dit probleem door een room solver te ontwikkelen. Elk van deze games had spelspecifieke behoeften, maar ze deelden kerntechnologie voor ruimtelijk inzicht. De holoToolkit.SpatialUnderstanding-bibliotheek bevat deze technologie, zodat u snel lege ruimten op de wanden kunt vinden, objecten op het plafond kunt plaatsen, kunt identificeren waar het karakter moet zitten en talloze andere query's op ruimtelijk inzicht.

Alle broncode is opgenomen, zodat u deze kunt aanpassen aan uw behoeften en uw verbeteringen kunt delen met de community. 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

Er zijn drie primaire interfaces beschikbaar door de module: topologie voor eenvoudige oppervlak- en ruimtelijke query's, shape voor objectdetectie en de oplosser voor objectplaatsing voor het plaatsen van objectenets op basis van beperkingen. Deze methoden worden beide hieronder beschreven. Naast de drie primaire module-interfaces kan een ray casting-interface worden gebruikt om getagde oppervlaktetypen op te halen en kan een aangepast waterdicht playspace-mesh worden gekopieerd.

Ray Casting

Nadat de ruimtescan is voltooid, worden er intern labels gegenereerd voor oppervlakken zoals de vloer, het plafond en de wanden. 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 8-cm kubusvormige voxelweergave van de playspace. Elke voxel bevat een set oppervlakte-elementen met verwerkte topologiegegevens (ook wel surfels genoemd). De surfels in de gekruiste voxel-cel worden vergeleken en de beste overeenkomst wordt gebruikt om de topologiegegevens op te zoeken. Deze topologiegegevens bevatten de labeling die wordt geretourneerd in de vorm van de opsomming 'SurfaceTypes', evenals het oppervlak van het gekruiste oppervlak.

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

Surface-type is gelabeld naast de cursor
Surface-type is gelabeld naast de cursor

Topologiequery's

Binnen de DLL verwerkt de topologiebeheerder het labelen van de omgeving. Zoals hierboven vermeld, worden veel van de gegevens opgeslagen in surfels, die zich in een voxel-volume bevinden. Daarnaast wordt de structuur 'PlaySpaceInfos' gebruikt om informatie over de speelruimte op te slaan, waaronder de uitlijning van de wereld (meer informatie hierover hieronder), de vloer en de hoogte van het plafond. Heuristiek wordt gebruikt voor het bepalen van vloer, plafond en wanden. 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 gebruikt in dit proces.

Een subset van de query's die door topologiebeheer worden weergegeven, wordt weergegeven via de DLL. 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 die specifiek zijn voor het querytype. In het volgende voorbeeld geeft de gebruiker de minimale hoogte & breedte van het gewenste volume, de minimale plaatsingshoogte boven de vloer en de minimale ruimte vóór 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 maakt gebruik van een vooraf toegewezen matrix met 'TopologyResult'-structuren. De parameter locationCount geeft de lengte op van de doorgegeven matrix. De retourwaarde rapporteert het aantal geretourneerde locaties. Dit getal is nooit groter dan de doorgegeven parameter 'locationCount'.

De "TopologyResult" bevat de middenpositie van het geretourneerde volume, de richting (dat wil zeggen 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 is elk van deze query's gekoppeld aan een knop in het deelvenster van de virtuele gebruikersinterface. Het voorbeeld codeert de parameters voor elk van deze query's naar redelijke waarden. Zie SpaceVisualizer.cs in de voorbeeldcode voor meer voorbeelden.

Shapequery's

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

De shapeanalyse werkt alleen op horizontale oppervlakken. Een bank wordt bijvoorbeeld gedefinieerd door het platte zitvlak en de platte bovenkant van de bank. Met de shapequery wordt gezocht naar twee oppervlakken met een specifieke grootte, hoogte en hoogtebereik, waarbij de twee oppervlakken zijn uitgelijnd en verbonden. Volgens de API-terminologie zijn de bankzitting en de rugleuning onderdelen van de vorm en zijn de uitlijningsvereisten beperkingen van 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 onderdeelbeperkingen en een set shapebeperkingen die afhankelijkheden tussen de onderdelen weergeeft. Dit voorbeeld bevat drie beperkingen in één onderdeeldefinitie en geen vormbeperkingen tussen onderdelen (omdat er slechts één onderdeel is).

De divanshape heeft daarentegen twee shapeonderdelen en vier shapebeperkingen. 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, zodat u eenvoudig aangepaste shapedefinities kunt maken. De volledige lijst met beperkingen voor onderdelen en vormen vindt u in SpatialUnderstandingDll.cs in 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 de plaatsing van meerdere objecten beperkt is. Plaatsingsquery's voor objecten bestaan uit drie delen: 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 constructie van regels en beperkingen eenvoudig te maken. De plaatsingsdefinitie bevat het querytype. Dit is een van de volgende.

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 zoeken om een object op de vloer te plaatsen, kunt u de volgende functie gebruiken. public static 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 met de opgegeven functies voor het maken van statische bestanden. Hieronder ziet u een voorbeeld van de constructiefunctie voor regels en 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 op de rand van een oppervlak te plaatsen, weg van andere objecten die eerder zijn geplaatst 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 'ObjectPlacementResult'-structuur met de positie, afmetingen en afdrukstand geretourneerd. Bovendien wordt de plaatsing toegevoegd aan de interne lijst met geplaatste objecten van de DLL. Volgende plaatsingsquery's houden rekening 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 is van drie plaats op vloerquery's met niet-camerapositieregels

Bij het oplossen van de plaatsingslocatie van meerdere objecten die vereist zijn voor een niveau of toepassingsscenario, lost u eerst onmisbare 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 de functionaliteit in veel ruimteconfiguraties.

Scanproces voor ruimten

Hoewel de oplossing voor ruimtelijke toewijzing die door de HoloLens wordt geleverd, algemeen genoeg is om te voldoen aan de behoeften van het hele scala aan probleemruimten, is de module voor ruimtelijk inzicht gebouwd om de behoeften van twee specifieke games te ondersteunen. De oplossing is gestructureerd rond een specifiek proces en een set veronderstellingen, hieronder samengevat.

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 "schilderen" - Tijdens de scanfase beweegt de gebruiker en kijkt rond het speeltempo, effectief schilderen van de gebieden, die moeten worden opgenomen. Het gegenereerde mesh is belangrijk om gebruikersfeedback te geven tijdens deze fase. Binnenhuis- of kantoorconfiguratie: de queryfuncties zijn ontworpen rond platte oppervlakken en wanden met rechte hoeken. Dit is een zachte beperking. Tijdens de scanfase wordt echter een analyse van de primaire as voltooid om de mesh-vlaklijn langs de primaire en secundaire as te optimaliseren. Het opgenomen bestand SpatialUnderstanding.cs beheert het proces van de scanfase. De volgende functies worden aangeroepen.

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, die wordt aangestuurd door het gedrag 'SpatialUnderstanding' roept InitScan aan en vervolgens UpdateScan elk frame. Wanneer de statistiekenquery een redelijke dekking rapporteert, mag de gebruiker airtap aanroepen om RequestFinish aan te roepen om het einde van de scanfase aan te geven. UpdateScan blijft aangeroepen totdat de retourwaarde aangeeft dat de dll-verwerking is voltooid.

Informatie over Mesh

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

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

Problemen oplossen

  • Zorg ervoor dat u de mogelijkheid SpatialPerception hebt ingesteld
  • Wanneer de tracering verloren gaat, verwijdert de volgende OnSurfaceChanged-gebeurtenis alle meshes.

Ruimtelijke toewijzing in Mixed Reality Toolkit

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

Controlepunt volgende ontwikkeling

Als u het Unity-ontwikkelingstraject volgt dat we hebben uitgetekend, bent u bezig met het verkennen van de basisbouwstenen van MRTK. Vanaf hier kunt u doorgaan naar de volgende bouwsteen:

Of ga naar Mixed Reality platformmogelijkheden en API's:

U kunt altijd op elk gewenst moment teruggaan naar de controlepunten voor Unity-ontwikkeling .

Zie ook