Megosztás a következőn keresztül:


Esettanulmány – A HoloLens térbeli leképezési képességeinek bővítése

Az első alkalmazások Microsoft HoloLens való létrehozásakor kíváncsiak voltunk arra, hogy milyen messzire tudjuk leküldni a térbeli leképezés határait az eszközön. Jeff Evertt, a Microsoft Studios szoftvermérnöke azt ismerteti, hogyan fejlesztettek ki egy új technológiát, hogy jobban szabályozni kell a hologramok helyét a felhasználók valós környezetében.

Megjegyzés

HoloLens 2 implementál egy új Scene Understanding Runtime-ot, amely Mixed Reality fejlesztők számára egy strukturált, magas szintű környezetábrázolást biztosít, amelynek célja, hogy a környezettudatos alkalmazások fejlesztése intuitív legyen.

Videó megtekintése

A térbeli leképezésen túl

Miközben a Fragments és a Young Conker, a HoloLens két első játékán dolgoztunk, azt találtuk, hogy amikor a hologramok a fizikai világban történő elhelyezését végeztük, magasabb szintű megértésre volt szükségünk a felhasználó környezetével kapcsolatban. Minden játéknak saját elhelyezési igényei voltak: A Fragmentsben például meg akartuk különböztetni a különböző felületeket – például a padlót vagy az asztalt –, hogy nyomokat helyezzenek el a megfelelő helyeken. Azt is szerettük volna, hogy azonosítsuk azokat a felületeket, amelyeken életnagyságú holografikus karakterek ülhetnek, például egy kanapén vagy egy széken. A Young Conkerben azt akartuk, hogy Conker és ellenfelei emelt felületeket tudjanak használni egy játékos szobájában platformként.

Az Asobo Studios, a játékokkal foglalkozó fejlesztői partnerünk szembesült ezzel a problémával, és létrehozott egy technológiát, amely kibővíti a HoloLens térbeli leképezési képességeit. Ezzel elemezhetnénk egy játékos szobáját, és azonosíthatnánk az olyan felületeket, mint a falak, az asztalok, a székek és a padlók. Emellett lehetővé teszi számunkra, hogy a holografikus objektumok legjobb elhelyezésének meghatározására vonatkozó korlátozások alapján optimalizáljunk.

A térbeli megértési kód

Vettük Asobo eredeti kódját, és létrehoztunk egy könyvtárat, amely magában foglalja ezt a technológiát. A Microsoft és az Asobo már nyílt forráskódúvá tette ezt a kódot, és elérhetővé tette a MixedRealityToolkit webhelyen, hogy a saját projektjeiben használhassa. Az összes forráskódot tartalmazza, í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 csomagolták, és a Unity számára egy, a MixedRealityToolkitben található drop-in prefab előtaggal tették elérhetővé.

A Unity-minta számos hasznos lekérdezést tartalmaz, amelyek lehetővé teszik üres szóközök keresését a falakon, objektumok elhelyezését a mennyezeten vagy a padlón lévő nagy tereken, a karakterek ülendő helyeinek azonosítását és számos más térbeli megértési lekérdezést.

Bár a HoloLens által biztosított térbeli leképezési megoldás úgy lett kialakítva, hogy elég általános legyen a problématerek teljes skálájának igényeihez, a térbeli megértési modul két konkrét játék igényeinek kielégítésére lett létrehozva. Ennek megfelelően a megoldása egy adott folyamatra és feltételezésekre épül:

  • Rögzített méretű játéktér: A felhasználó az init-hívásban megadott maximális lejátszásitér-méretet adja meg.
  • Egyszeri vizsgálati folyamat: A folyamathoz diszkrét vizsgálati fázisra van szükség, amelyben a felhasználó végigjárja a folyamatot, meghatározva a játékteret. A lekérdezési függvények csak a vizsgálat befejezése után fognak működni.
  • 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 játéktérben, hatékonyan festve a területeket, amelyeket be kell vonni. A létrehozott 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 a hálók tessellációjának optimalizálása érdekében a fő- és altengely mentén.

Helyiségvizsgálati folyamat

A térbeli megértés modul betöltésekor az első teendő a tér beolvasása, így az összes használható felület – például a padló, a mennyezet és a falak – azonosíthatók és fel vannak címkézve. A vizsgálati folyamat során körülnéz a helyiségben, és "festi" azokat a területeket, amelyeket a vizsgálatnak tartalmaznia kell.

Az ebben a fázisban látott háló fontos vizuális visszajelzés, amely tájékoztatja a felhasználókat arról, hogy a helyiség mely részeit ellenőrzik. A térbeli megértési modul DLL-je belsőleg tárolja a játékteret 8 cm méretű voxel kockák rácsaként. A vizsgálat kezdeti részében egy elsődleges összetevő elemzése fejeződik be 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 isosurface voxel kötetből való kinyerésével.

Térbeli leképezési háló fehérben és a játéktér hálója zöld színnel

Térbeli leképezési háló fehérben és a játéktér hálója zöld színnel

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: Először egyszer hívjuk meg.
  • GeneratePlayspace_InitScan: Azt jelzi, hogy a vizsgálati fázisnak el kell kezdődnie.
  • GeneratePlayspace_UpdateScan_DynamicScan: Meghívta az egyes kereteket a vizsgálati folyamat frissítéséhez. A kamera helyzete és tájolása átadva, és a játéktér festési folyamatához használatos, a fent leírt módon.
  • GeneratePlayspace_RequestFinish: A játéktér véglegesítéséhez hívva. Ez a vizsgálati fázisban a "festett" területeket fogja használni a játéktér definiálásához és zárolásához. Az alkalmazás lekérdezheti a statisztikát a vizsgálati fázisban, valamint lekérdezheti az egyéni hálót a felhasználói visszajelzések biztosításához.
  • Import_UnderstandingMesh: A vizsgálat során a modul által biztosított SpatialUnderstandingCustomMesh viselkedés, amely a megértési előlapra kerül, rendszeres időközönként lekérdezi a folyamat által létrehozott egyéni hálót. A vizsgálat véglegesítése után ez még egyszer megtörténik.

A SpatialUnderstanding viselkedés által hajtott vizsgálati folyamat meghívja az InitScant, majd az egyes kereteket frissíti . Amikor a statisztikai lekérdezés ésszerű lefedettséget jelez, a felhasználó a RequestFinish hívásával jelezheti a vizsgálati fázis végét. Az UpdateScan hívása addig folytatódik, amíg a visszaadott érték azt nem jelzi, hogy a DLL befejezte a feldolgozást.

A lekérdezések

A vizsgálat befejezése után három különböző típusú lekérdezés érhető el a felületen:

  • Topológia-lekérdezések: Ezek gyors lekérdezések, amelyek a beolvasott helyiség topológiáján alapulnak.
  • Alakzat-lekérdezések: Ezek a topológiai lekérdezések eredményei alapján keresnek olyan vízszintes felületeket, amelyek megfelelnek az Ön által definiált egyéni alakzatoknak.
  • Objektumelhelyezési lekérdezések: Ezek összetettebb lekérdezések, amelyek az objektumra vonatkozó szabályok és korlátozások alapján megtalálják a legmegfelelőbb helyet.

A három elsődleges lekérdezés mellett van egy raycasting felület is, amellyel lekérhetők a címkézett felülettípusok, és kimásolható egy egyéni vízmentes helyiségháló.

Topológia 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, amelyek egy voxel köteten belül találhatók. 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 heurisztikusok a padló, a mennyezet és a falak meghatározására szolgálnak. Az 1 m2-nél nagyobb felületű legnagyobb és legalacsonyabb vízszintes felület például a padló. Vegye figyelembe, hogy a vizsgálati folyamat során a kamera elérési útja is használatos ebben a folyamatban.

A Topológia-kezelő által közzétett lekérdezések egy részhalmaza a DLL-ben lesz közzétéve. 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

Az egyes lekérdezések paraméterkészlete a lekérdezés típusára jellemző. 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 szabad helyet. Minden mérés mérőben 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)

Ezek a lekérdezések a TopologyResult struktúrák előre lefoglalt tömbjéhez tartoznak. 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 az átadott locationCount paraméter.

A TopologyResult tartalmazza a visszaadott kötet középső pozícióját, az irányt (azaz a normált) és a talált tér méreteit.

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

Vegye figyelembe, hogy 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 mintául szolgáló kemény kód az egyes lekérdezések paramétereit ésszerű értékekre kódozza. 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ővel egyezik a felhasználó által definiált egyéni alakzatokkal. A Unity-minta egy előre definiált alakzatkészlettel rendelkezik, amely a lekérdezés menüjében, az alakzatok lapján látható.

Vegye figyelembe, hogy 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 kanapé hátlapjának teteje alakzatösszetevők, az igazítási követelmények pedig az alakzatösszetevőkre vonatkozó korlátozások.

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 alakzatkényszerekkel rendelkezik, amelyek felsorolják az összetevők közötti függőségeket. Ez a példa három kényszert tartalmaz egyetlen összetevő-definíció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. Vegye figyelembe, hogy 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 fájljában található.

A kék téglalap kiemeli a székalakzat lekérdezésének eredményeit.

A kék téglalap kiemeli a székalakzat lekérdezésének eredményeit.

Objektumelhelyezési megoldás

Az objektumelhelyezési lekérdezések a fizikai helyiség ideális helyeinek azonosítására használhatók az objektumok elhelyezéséhez. A solver megtalálja az objektumszabályok és megkötések alapján a legjobban illeszkedő helyet. Ezenkívül az objektum-lekérdezések mindaddig megmaradnak, amíg el nem távolítják az objektumot Solver_RemoveObject vagy Solver_RemoveAllObjects hívásokkal, ami korlátozott többobjektumos elhelyezést tesz lehetővé.

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 az objektum nevét, az elhelyezés definícióját, valamint a szabályok és korlátozások listáját veszi fel. A C#-burkolók építési segédfüggvényeket biztosítanak a szabály- és kényszerépítés megkönnyítése érdekében. 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 a következő 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 helyek ezután a kényszerek alapján vannak optimalizálva 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. Az alábbiakban egy példaszabályt és kényszerkiépítési 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 sikeres, a rendszer visszaad egy ObjectPlacementResult szerkezetet, amely tartalmazza az elhelyezési pozíciót, a dimenziókat és a tájolást. Emellett az elhelyezést hozzáadja a DLL az 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.

A kék mezők három,

A kék mezők három, "a kamera helyzetétől távol" szabályokkal rendelkező place on floor lekérdezés eredményét jelenítik meg.

Tippek:

  • Egy szinthez vagy alkalmazásforgatókönyvhez szükséges több objektum elhelyezési helyének megoldásakor először oldja meg a nélkülözhetetlen és nagy méretű objektumokat, hogy a lehető legnagyobb valószínűséggel találjon helyet.
  • Az elhelyezési sorrend fontos. Ha az objektumelhelyezések nem találhatók, 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.

Ray casting

A három elsődleges lekérdezésen kívül egy ray casting 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ó másolható ki A helyiség vizsgálata és véglegesíté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, a felületre vonatkozó információk RaycastResult formájában.

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

A raycast belső számítása a játéktér számított 8 cm-es kockás voxel-ábrázolása alapján történik. Minden voxel több felületi elemet tartalmaz feldolgozott topológiai adatokkal (más néven surfelekkel). A metszetbe ágyazott voxel cellában található surfeleket összehasonlítjuk, és a topológia adatainak 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 a metszett felület felületét.

A Unity-mintában a kurzor minden képkockán egy sugarat vet. Először is, a Unity ütközői ellen; másodszor, a megértési modul világábrázolása ellen; és végül a felhasználói felület elemein. Ebben az alkalmazásban a felhasználói felület prioritást kap, majd a megértési eredményt, végül pedig a Unity ütközőit. A SurfaceType szövegként jelenik meg a kurzor mellett.

Raycast eredményjelentési metszet a padlóval.

Raycast eredményjelentési metszet a padlóval.

A kód letöltése

A nyílt forráskódú kód a MixedRealityToolkitban érhető el. Ha a kódot egy projektben használja, ossza meg velünk a HoloLens fejlesztői fórumain . Alig várjuk, hogy lássuk, mit csinálsz vele!

A szerző ismertetése

Jeff Evertt, a Microsoft szoftvermérnöki vezetője Jeff Evertt egy szoftvermérnöki vezető, aki a holoLens-en dolgozott a korai idők óta, az inkubációtól a fejlesztésig. HoloLens előtt az Xbox Kinecten és a játékiparban dolgozott számos platformon és játékon. Jeff szenvedélyesen foglalkozik a robotikával, a grafikával és a villogó fényekkel, amelyek sípoló fényekkel vannak elsüllyedve. Szívesen tanul új dolgokat, és szoftveren, hardveren dolgozik, és különösen abban a térben, ahol a két elem metszik egymást.

Lásd még