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
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.
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 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.
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 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. |