Térbeli leképezés a Unityben

A térbeli leképezés lehetővé teszi a holoLens-eszköz körüli világfelületeket ábrázoló háromszöghálók lekérését. A felületi adatokat elhelyezésre, elzáródásra és helyiségelemzésre használhatja, hogy a Unity-projektek további mennyiségű bemerítést biztosítsanak.

A Unity teljes körű támogatást nyújt a térbeli leképezéshez, amelyet a fejlesztők a következő módokon érhetnek el:

  1. A MixedRealityToolkitben elérhető térbeli leképezési összetevők kényelmes és gyors utat biztosítanak a térbeli leképezés első lépéseihez
  2. Alacsonyabb szintű térbeli leképezési API-k, amelyek teljes körű vezérlést biztosítanak, és kifinomultabb alkalmazásspecifikus testreszabást tesznek lehetővé

Ahhoz, hogy térbeli leképezést használjon az alkalmazásban, be kell állítani a SpatialPerception képességet az AppxManifestben.

Eszköztámogatás

Szolgáltatás HoloLens (első generációs) HoloLens 2 Modern headsetek
Térbeli leképezés ✔️ ✔️

A SpatialPerception képesség beállítása

Ahhoz, hogy egy alkalmazás térbeli leképezési adatokat használhasson fel, engedélyezni kell a SpatialPerception képességet.

A SpatialPerception képesség engedélyezése:

  1. A Unity-szerkesztőben nyissa meg a "Lejátszó beállításai" panelt (Projektbeállítások > lejátszójának szerkesztése>)
  2. Kiválasztás a "Windows Áruház" lapon
  3. Bontsa ki a "Közzétételi beállítások" elemet, és ellenőrizze a "SpatialPerception" képességet a "Képességek" listában

Megjegyzés

Ha már exportálta a Unity-projektet egy Visual Studio-megoldásba, exportálnia kell egy új mappába, vagy manuálisan kell beállítania ezt a képességet a Visual Studióban található AppxManifestben.

A térbeli leképezéshez legalább 10.0.10586.0 MaxVersionTested szükséges:

  1. A Visual Studióban kattintson a jobb gombbal a Package.appxmanifest elemre a Megoldáskezelő, és válassza a Kód megtekintése lehetőséget.
  2. Keresse meg a TargetDeviceFamily értéket megjelölő sort, és módosítsa a MaxVersionTested="10.0.10240.0" értéket MaxVersionTested="10.0.10586.0" értékre.
  3. Mentse a Package.appxmanifest fájlt.

Leképezés hozzáadása a Unityben

Térbeli tudatossági rendszer

Az MRTK-ban tekintse meg a térbeli tudatosság első lépéseit ismertető útmutatót, amely a különböző térbeli hálós megfigyelők beállításával kapcsolatos információkat tartalmazza.

Az eszköz megfigyelőivel kapcsolatos információkért tekintse meg a Hálófigyelők konfigurálása eszközhöz című útmutatót.

A jelenetértelmező megfigyelőkkel kapcsolatos információkért tekintse meg a Jelenetértelmezés megfigyelői útmutatót.

Magasabb szintű hálóelemzés: Térbeli megértés

Figyelemfelhívás

A térbeli megértés elavult a Jelenetfelismerés mellett.

A MixedRealityToolkit a Unity holografikus API-jára épülő holografikus fejlesztésre szolgáló segédprogramkód gyűjteménye.

Térbeli megértés

Hologramok fizikai világban való elhelyezésekor gyakran kívánatos a térbeli leképezés háló- és felületsíkjain túlmenni. Ha az elhelyezést eljárási módon végzik el, kívánatos a környezettudatosság magasabb szintje. Ehhez általában döntéseket kell hozni arról, hogy mi a padló, a mennyezet és a falak. A holografikus objektumok legjobb fizikai helyének meghatározásához az elhelyezési korlátozások alapján is optimalizálhat.

A Young Conker és a Fragments fejlesztése során az Asobo Studios szembesült ezzel a problémával, és kifejlesztett egy szobamegoldót. Mindegyik játéknak játékspecifikus igényei voltak, de megosztották a térbeli megértés alapvető technológiáját. A HoloToolkit.SpatialUnderstanding kódtár ezt a technológiát foglalja magában, így gyorsan megtalálhatja a falak üres tereit, tárgyakat helyezhet a mennyezetre, azonosíthatja a karakter elhelyezését, és számos más térértelmezési lekérdezést is használhat.

A program tartalmazza az összes forráskódot, így testre szabhatja az igényeinek megfelelően, és megoszthatja a fejlesztéseket a közösséggel. A C++ solver kódját egy UWP-dll-be burkolták, és elérhetővé tették a Unity számára a MixedRealityToolkit előtagjának egy csökkenésével.

A modulok ismertetése

A modul három elsődleges felületet fed le: az egyszerű felületi és térbeli lekérdezések topológiáját, az objektumészleléshez használható alakzatot, az objektumelhelyezési megoldás pedig az objektumkészletek kényszeralapú elhelyezését. Ezek mindegyikét az alábbiakban ismertetjük. A három elsődleges modulfelület mellett egy sugáröntvény interfész is használható a címkézett felülettípusok lekéréséhez, és egy egyéni, vízmentes játéktérháló is kimásolható.

Ray Casting

A szobavizsgálat befejezése után a címkék belsőleg jönnek létre olyan felületekhez, mint a padló, a mennyezet és a falak. A PlayspaceRaycast függvény egy sugarat vesz fel, és visszaadja, ha a sugár összeütközik egy ismert felülettel, és ha igen, akkor az adott felületre vonatkozó információk formájában 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;
};

Belsőleg a raycast számítása a játéktér számított 8 cm-nyi kockás voxel-reprezentációja alapján történik. Minden voxel feldolgozott topológiaadatokkal (más néven szörfösökkel) rendelkező felületelemeket tartalmaz. A metszett voxel cellában található surfeleket összehasonlítjuk, és a topológiai információk kereséséhez a legjobb egyezést használjuk. Ezek a topológiaadatok tartalmazzák a "SurfaceTypes" enumerálás formájában visszaadott címkézést, valamint az összekapcsolt felület felületét.

A Unity-mintában a kurzor minden egyes kerethez egy-egy sugarat vet. Először is, Unity ütközői ellen. Másodszor, a megértési modul világábrázolásával szemben. Végül pedig ismét a felhasználói felület elemeit. Ebben az alkalmazásban a felhasználói felület prioritást kap, a megértési eredmény, végül pedig a Unity ütközői. A SurfaceType a kurzor melletti szövegként jelenik meg.

A Surface-típus felirata a kurzor mellett van
A Surface-típus felirata a kurzor mellett van

Topológiai lekérdezések

A DLL-ben a topológiakezelő kezeli a környezet címkézését. Ahogy fentebb említettük, az adatok nagy része surfelsben van tárolva, amely egy voxel köteten belül található. A "PlaySpaceInfos" szerkezet emellett a játéktérrel kapcsolatos információk tárolására is használható, beleértve a világ igazítását (további részletek alább), a padlót és a mennyezet magasságát. A heurisztika a padló, a mennyezet és a falak meghatározására szolgál. Az 1 m2-nél nagyobb felületű legnagyobb és legkisebb vízszintes felület például padlónak számít.

Megjegyzés

Ebben a folyamatban a vizsgálati folyamat során a kamera elérési útja is használatos.

A Topológiakezelő által közzétett lekérdezések egy részhalmaza a dll-ben érhető el. A közzétett topológia-lekérdezések a következők.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

Mindegyik lekérdezés rendelkezik paraméterek készletével, amelyek a lekérdezés típusára vonatkoznak. A következő példában a felhasználó megadja a kívánt kötet minimális magasságát & szélességét, a padló feletti minimális elhelyezési magasságot és a kötet előtti minimális térközt. Minden mérés méterben van.

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)

Ezen lekérdezések mindegyike a "TopologyResult" struktúrák előre lefoglalt tömbjéből áll. A "locationCount" paraméter az átadott tömb hosszát adja meg. A visszatérési érték a visszaadott helyek számát jelenti. Ez a szám soha nem nagyobb, mint a locationCount paraméterben megadott érték.

A "TopologyResult" a visszaadott kötet középponti pozícióját, az irányt (azaz a normált) és a talált terület méretét tartalmazza.

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

Megjegyzés

A Unity-mintában ezek a lekérdezések a virtuális felhasználói felület paneljének egy gombjához vannak csatolva. A minta kemény kóddal kódozza az egyes lekérdezések paramétereit ésszerű értékekre. További példákért lásd: SpaceVisualizer.cs a mintakódban.

Alakzat-lekérdezések

A dll-ben az alakzatelemző ("ShapeAnalyzer_W") a topológiaelemzőt használja a felhasználó által definiált egyéni alakzatok egyeztetéséhez. A Unity-minta alakzatkészletet definiál, és az eredményeket az alkalmazáson belüli lekérdezési menüben teszi elérhetővé az alakzatok lapján. A cél az, hogy a felhasználó saját objektumalakzat-lekérdezéseket definiáljon, és azokat az alkalmazásának megfelelően használja.

Az alakzatelemzés csak vízszintes felületeken működik. A kanapét például a sík ülésfelület és a kanapé hátlapja határozza meg. Az alakzat lekérdezése két, adott méretű, magasságú és mérettartományú felületet keres, a két felület egymáshoz igazítva és csatlakoztatva van. Az API-k terminológiáját használva a kanapé ülése és a hátlap alakzatösszetevők, az igazítási követelmények pedig az alakzatösszetevők korlátozásai.

A Unity-mintában (ShapeDefinition.cs) definiált példalekérdezés a "sittable" objektumok esetében a következő.

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

Minden alakzat-lekérdezést alakzatösszetevők halmaza határoz meg, amelyek mindegyike összetevő-kényszerekkel és az összetevők közötti függőségeket felsoroló alakzatkényszerekkel rendelkezik. Ez a példa három kényszert tartalmaz egyetlen összetevő definíciójában, és nincsenek alakzatkényszerek az összetevők között (mivel csak egy összetevő van).

Ezzel szemben a kanapé alakzat két alakzatösszetevőt és négy alakzatkényszert tartalmaz. Az összetevőket az indexük azonosítja a felhasználó összetevőlistájában (ebben a példában 0 és 1).

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

A Burkoló függvények a Unity modulban érhetők el az egyéni alakzatdefiníciók egyszerű létrehozásához. Az összetevő- és alakzatkorlátozások teljes listája a "ShapeComponentConstraint" és a "ShapeConstraint" struktúrák "SpatialUnderstandingDll.cs" szakaszában található.

Téglalap alakzat található ezen a felületen
Téglalap alakzat található ezen a felületen

Objektumelhelyezési solver

Az objektumelhelyezési solver segítségével azonosíthatja a fizikai helyiségben az ideális helyeket az objektumok elhelyezéséhez. A solver az objektumszabályok és megkötések alapján a legmegfelelőbb helyet fogja megtalálni. Emellett az objektum lekérdezései mindaddig megmaradnak, amíg el nem távolítják az objektumot "Solver_RemoveObject" vagy "Solver_RemoveAllObjects" hívásokkal, ami lehetővé teszi a korlátozott többobjektumos elhelyezést. Az objektumelhelyezési lekérdezések három részből állnak: elhelyezés típusa paraméterekkel, szabályok listája és kényszerek listája. Lekérdezés futtatásához használja a következő API-t.

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)

Ez a függvény egy objektumnevet, egy elhelyezési definíciót, valamint egy szabály- és korlátozáslistát vesz fel. A C#-burkolók építési segédfunkciókkal könnyítik meg a szabály- és kényszerépítést. Az elhelyezési definíció tartalmazza a lekérdezés típusát, azaz az alábbiak egyikét.

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

Az elhelyezési típusok mindegyike egyedi paraméterkészlettel rendelkezik. Az "ObjectPlacementDefinition" struktúra statikus segédfüggvényeket tartalmaz a definíciók létrehozásához. Ha például meg szeretne találni egy helyet, ahol elhelyezhet egy objektumot a padlón, használhatja az alábbi függvényt. public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims) Az elhelyezési típuson kívül szabályokat és korlátozásokat is megadhat. A szabályok nem sérthetők meg. A típusnak és szabályoknak megfelelő lehetséges elhelyezési helyeket ezután a rendszer a korlátozások alapján optimalizálja az optimális elhelyezési hely kiválasztásához. Az egyes szabályokat és korlátozásokat a megadott statikus létrehozási függvények hozhatják létre. Alább egy példaszabályt és kényszerszerkezeti függvényt talál.

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

Az alábbi objektumelhelyezési lekérdezés egy olyan helyet keres, ahová egy félméteres kockát helyezhet a felület szélére, távol a többi korábban elhelyezett objektumtól és a szoba közepéhez.

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

Ha sikerült, a rendszer egy "ObjectPlacementResult" struktúrát ad vissza, amely tartalmazza az elhelyezési pozíciót, a dimenziókat és a tájolást. Emellett az elhelyezés hozzá lesz adva a DLL elhelyezett objektumok belső listájához. A későbbi elhelyezési lekérdezések figyelembe veszik ezt az objektumot. A Unity-minta LevelSolver.cs fájlja további példalekérdezéseket tartalmaz.

Objektumelhelyezés eredménye
3. ábra: A kék dobozok, hogy az eredmény három helyről a padlón lekérdezések távol kamera helyzet szabályokat

Ha egy szinthez vagy alkalmazáshoz szükséges több objektum elhelyezésére van szükség, először oldja meg a nélkülözhetetlen és nagy méretű objektumokat annak érdekében, hogy a lehető legnagyobb valószínűséggel találjon helyet. Az elhelyezési sorrend fontos. Ha nem találhatók objektumelhelyezések, próbálkozzon kevésbé korlátozott konfigurációkkal. A tartalék konfigurációk készlete kritikus fontosságú a funkciók számos helyiségkonfigurációban való támogatásához.

Helyiségvizsgálati folyamat

Bár a HoloLens által biztosított térbeli leképezési megoldás úgy lett kialakítva, hogy elég általános legyen ahhoz, hogy megfeleljen a problématerek teljes skálájának igényeinek, a térbeli megértési modul két konkrét játék igényeinek kielégítésére készült. A megoldás egy adott folyamatra és feltételezésekre épül, az alábbiakban összefoglalva.

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.

Felhasználó által vezérelt játéktér "festés" – A vizsgálati fázisban a felhasználó mozog, és körülnéz a lejátszások tempójában, hatékonyan festve a területeket, amelyeket bele kell foglalni. A generált háló fontos, hogy felhasználói visszajelzést adjon ebben a fázisban. Beltéri otthoni vagy irodai beállítás – A lekérdezési függvények sík felületek és falak köré vannak tervezve, derékszögben. Ez egy enyhe korlátozás. A vizsgálati fázis során azonban az elsődleges tengely elemzése befejeződött, hogy optimalizálja a hálók tessellációját a fő- és altengely mentén. A mellékelt SpatialUnderstanding.cs fájl kezeli a vizsgálati fázis folyamatát. A következő függvényeket hívja meg.

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.

A "SpatialUnderstanding" viselkedés által vezérelt vizsgálati folyamat meghívja az InitScant, majd az UpdateScan minden keretet. Amikor a statisztikai lekérdezés ésszerű lefedettséget jelent, a felhasználónak lehetősége van arra, hogy a RequestFinish hívásával jelezze a vizsgálati fázis végét. Az UpdateScan hívása addig folytatódik, amíg a visszatérési értéke azt nem jelzi, hogy a DLL befejezte a feldolgozást.

A Mesh ismertetése

A értelmező DLL belsőleg tárolja a játékteret 8 cm méretű voxel kockák rácsaként. A vizsgálat kezdeti szakaszában egy elsődleges összetevő-elemzést végezünk a helyiség tengelyeinek meghatározásához. Belsőleg ezekhez a tengelyekhez igazítva tárolja a voxel térközét. A háló körülbelül másodpercenként jön létre az izosurface a voxel kötetből való kinyerésével.

A voxel kötetből előállított háló
A voxel kötetből előállított háló

Hibaelhárítás

  • Győződjön meg arról, hogy beállította a SpatialPerception képességet
  • Ha a nyomon követés elveszik, a következő OnSurfaceChanged esemény eltávolítja az összes hálót.

Térbeli leképezés az Mixed Reality Toolkitben

A térbeli leképezés Mixed Reality Toolkittel való használatáról az MRTK dokumentációjának térbeli tudatosságról szóló szakaszában talál további információt.

Következő fejlesztési ellenőrzőpont

Ha követi a Unity által meghatározott fejlesztési folyamatot, akkor az MRTK alapvető építőelemeinek felfedezése közben jár. Innen továbbléphet a következő építőelemre:

Vagy ugorjon Mixed Reality platform képességeire és API-ira:

Bármikor visszatérhet a Unity fejlesztési ellenőrzőpontjaihoz .

Lásd még