Térbeli leképezés a Unityben

A térbeli leképezés lehetővé teszi olyan háromszöghálók lekérését, amelyek a világ felszínét ábrázolják egy HoloLens körül. A felületi adatok elhelyezéshez, elzáródáshoz és helyiségelemzéshez is használhatók, így a Unity-projektek még nagyobb élményt kaphatnak.

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

  1. A MixedRealityToolkit térbeli leképezési összetevői kényelmes és gyors útvonalat biztosítanak a térbeli leképezés első lépésekhez
  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 biztosítanak

Ha térbeli leképezést használ az alkalmazásban, a SpatialPerception képességet be kell állítania 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 felhasználja a térbeli leképezési adatokat, engedélyezni kell a SpatialPerception képességet.

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

  1. A Unity-szerkesztőben nyissa meg a "Player Gépház" panelt (Edit Project Gépház > Player)
  2. A "Windows Áruház" lapon válassza a lehetőséget.
  3. Bontsa ki a "Publishing Gépház" (Közzétételi adatok közzététele) listában, és ellenőrizze a "SpatialPerception" képességet a "Capabilities" (Képességek) listában

Megjegyzés

Ha már exportálta a Unity-projektet egy Visual Studio-megoldásba, akkor vagy exportálnia kell egy új mappába, vagy manuálisan kell beállítania ezt a képességet az AppxManifestbena Visual Studio.

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

  1. A Visual Studio kattintson a jobb gombbal a Csomag.appxmanifest elemre a Megoldáskezelő és válassza a Kód megtekintése lehetőséget
  2. Keresse meg a TargetDeviceFamily értéket megszabaduló sort, és módosítsa a MaxVersionTested="10.0.10240.0" értéket MaxVersionTested="10.0.10586.0" névre
  3. Mentse a Package.appxmanifest gombra.

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

Tértudatos rendszer

A térbeli háló különböző megfigyelőinek beállításával kapcsolatos információkért az MRTK-ban a Térbeli tudatosság első lépések útmutatója nyújt tájékoztatást.

Az eszköz megfigyelőivel kapcsolatos információkért nézze meg a Háló megfigyelők konfigurálása eszközhöz útmutatót.

A jelenetekkel kapcsolatos információkért a megfigyelők megértéséről a Scene understanding Observer útmutatóban található.

Magasabb szintű hálóelemzés: Spatial Understanding

Figyelemfelhívás

A Spatial Understanding elavult a Scene Understanding (Jelenetértelmezés) érdekében.

A MixedRealityToolkit a Unity holografikus API-ira épített segédprogramkód-gyűjtemény a holografikus fejlesztéshez.

Spatial Understanding

A hologramok fizikai világba való elhelyezésekor gyakran célszerű túllépni a térbeli leképezés hálón és felületi síkon. Ha az elhelyezést eljárás szerint végezik, magasabb szintű környezetértelmezésre van szükség. Ehhez általában a padlóról, a felső határról és a falról kell döntéseket hozni. Lehetőség van továbbá az elhelyezési korlátozások alapján optimalizálni, hogy meghatározza a holografikus objektumokhoz legmegfelelőbb fizikai helyeket.

Young Conker és fragments fejlesztése során az Asobo Studióval egy helyiséget megoldó megoldás fejlesztésével szembesült ezzel a problémával. Ezek a játékok mind játékspecifikus igényeiknek 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 beágyazva lehetővé teszi, hogy gyorsan keressen üres helyeket a falon, objektumokat helyezzen a felső határra, azonosítsa az elhelyezhető karaktereket, és számtalan egyéb térértelmezítő lekérdezést.

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++ megoldó kódja egy UWP-dll-be van csomagolva, és elérhetővé lett téve a Unityben a MixedRealityToolkitben található előfab-csökkenéssel.

Modulok ismertetése

A modul három elsődleges felületet fed fel: az egyszerű felület- és térbeli lekérdezések topológiája, az objektumészlelés alakzata, valamint az objektumelhelyezés-megoldó az objektumkészletek korlátozásalapú elhelyezéséhez. Ezek mindegyikét az alábbiakban ismertetjük. A három elsődleges modulfelület mellett egy sugáröntési illesztő is használható a címkézett felülettípusok lekérésére, és egy egyéni vízmentes playspace mesh kimásolható.

Ray Casting

A helyiség vizsgálatának befejezése után belső címkéket hoznak létre az olyan felületekhez, mint a padló, a felső határ és a fal. A függvény egy sugarat vesz fel, és visszaadja, hogy a sugár ütközik-e egy ismert felülettel, és ha igen, a felülettel kapcsolatos információkat egy formájában PlayspaceRaycast adja RaycastResult vissza.

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 sugárképet a rendszer a playspace számított 8 cm-es kockás voxel ábrázolása szerint számítja ki. Minden voxel több felületi elemet tartalmaz feldolgozott topológiaadatokkal (más néven surfels-ekkel). A rendszer összehasonlítja az interkected voxel cellában található felületeket, és a legjobb egyezést használja a topológiainformációk ki keressenek. Ezek a topológiai adatok a "SurfaceTypes" felsorolás formájában visszaadott címkézést, valamint az ékes felület felületét is tartalmazják.

A Unity-mintában a kurzor minden egyes képkockát átképez. Először is, a Unity ütköztetői ellen. Másodszor, az understanding modul világi ábrázolása ellen. Végül ismét a felhasználói felület elemeit. Ebben az alkalmazásban a felhasználói felület kap prioritást, a következő a megértés eredménye, és végül a Unity ütköztetői. A SurfaceType szövegként lesz jelentve a kurzor mellett.

A felülettípus a kurzor mellett van megcímkézve
A felülettípus a kurzor mellett van megcímkézve

Topológialekérdezések

A DLL-ben a topológiakezelő kezeli a környezet címkézését. Ahogy korábban említettük, az adatok nagy része egy voxel kötetben található hullámzókban van tárolva. Emellett a "PlaySpaceInfos" struktúra a playspace-ről tárol információkat, beleértve a világ igazítását (további részletek alább), a padló és a felső határ magasságát. A heurisztika a padló, a felső határ és a fal meghatározására használható. A legnagyobb és legkisebb vízszintes, 1 m2-esnél nagyobb felület például padlónak számít.

Megjegyzés

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

A Topology Manager által elérhetővétett lekérdezések egy része a dll-fájlon keresztül lesz elérhető. Az elérhető topológialekérdezések a következők.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

Minden lekérdezés rendelkezik paraméterkészletekkel, amelyek a lekérdezés típusától függően vannak megszabadva. A következő példában a felhasználó megadja a kívánt kötet minimális magasságát, a padló fölötti elhelyezési magasságot és a kötet előtt található minimális & magasságot. 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 mindegyikéhez egy előre lefoglalt "TopologyResult" struktúratömb szükséges. A "locationCount" paraméter határozza meg a tömbben átadott hosszát. A visszaadott é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 normál) és a megtalált tér dimenzióit tartalmazza.

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

Megjegyzés

A Unity-mintában ezek a lekérdezések mind egy gombra vannak csatolva a virtuális felhasználói felület panelén. A minta az egyes lekérdezések paramétereit ésszerű értékekre kódértéket ad vissza. További példákat a mintakód SpaceVisualizer.cs fájlban talál.

Alakzatlekérdezések

A dll-ben az alakzatelemző ("ShapeAnalyzer_W") a topológiaelemzőt használja a felhasználó által meghatározott egyéni alakzatokhoz való illeszkedéshez. A Unity-minta alakzatkészletet definiál, és az eredményeket az alkalmazáson belüli lekérdezési menüben, az alakzat lapon teszi elérhetővé. A cél az, hogy a felhasználó saját objektumalak-lekérdezéseket határozzon meg, és szükség szerint használja ezeket az alkalmazáshoz.

Az alakzatelemzés csak vízszintes felületeken működik. A heverőt például a lapos helyfelület és a háta lapos teteje határozza meg. Az alakzatlekérdezés két meghatározott méretű, magasságú és oldaltartományú felületet keres, a két felületet igazítva és csatlakoztatva. Az API-k terminológiáját használva a hemzszse-hely és a háttere alakzatösszetevők, az igazítási követelmények pedig az alakzatösszetevőkre vonatkozó megkötések.

A Unity-mintában (ShapeDefinition.cs) definiált példalekérdezés a "sittable" objektumokhoz 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);

Az alakzatlekérdezéseket alakzatösszetevők halmaza határozza meg, amelyek mind összetevő-korlátozásokkal és az összetevők közötti függőségeket felsoroló alakzatkorlátozásokkal vannak meghatározva. Ez a példa három korlátozást tartalmaz egyetlen összetevő definíciójában, és nincsenek alakzatkorlátozások az összetevők között (mivel csak egy összetevő van).

Ezzel szemben a couch alakzat két alakzatösszetevővel és négy alakzatkorlátozásokkal rendelkezik. Az összetevőket az indexük azonosítja a felhasználó összetevő-listájában (ebben a példában a 0 és az 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 biztosítanak egyéni alakzatdefiníciók egyszerű létrehozását. Az összetevő- és alakzatkorlátozások teljes listája a "SpatialUnderstandingDll.cs" fájlban található a "ShapeComponentConstraint" és a "ShapeConstraint" struktúrákban.

Ezen a felületen téglalap alakú alakzat található
Ezen a felületen téglalap alakú alakzat található

Objektumelhelyezés-megoldó

Az objektumelhelyezés-megoldó segítségével azonosíthatók az objektumok elhelyezésére ideális helyek a fizikai helyiségben. A megoldó megkeresi a legmegfelelőbb helyet az objektumszabályok és megkötések alapján. Emellett az objektumlekérdezések mindaddig megmaradnak, amíg az objektumot "Solver_RemoveObject" vagy "Solver_RemoveAllObjects" hívásokkal eltávolítják, ami lehetővé teszi a korlátozott többobjektumos elhelyezést. Az objektumok elhelyezésére vonatkozó lekérdezések három részből állnak: elhelyezési típus paraméterekkel, szabályok listájával és megkötések listájával. 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 a szabályok és megkötések listáját veszi fel. A C#-burkolók az építés segítő függvényei segítségével megkönnyítik a szabályok és a megkötések szerkezetét. 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,
};

Minden elhelyezési típushoz egyedi paraméterkészletek vannak beállítva. Az "ObjectPlacementDefinition" struktúra statikus segítő függvények készletét tartalmazza ezen definíciók létrehozásához. Ha például keres egy helyet, ahol egy objektumot a padlóra lehet tenni, használhatja a következő függvényt. public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims) Az elhelyezés típusa mellett szabályokat és korlátozásokat is meghatározhat. A szabályokat nem lehet megsérteni. 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ényekkel lehet létrehozni. Alább egy példát mutatunk be a szabályra és a megkötési konstrukcióra.

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, ahol egy félmérőkocka a felület szélére kerül, más korábban elhelyezési objektumoktól távol, a helyiség közepéhez közel.

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

Sikeres művelet esetén a rendszer az elhelyezési pozíciót, dimenziókat és tájolást tartalmazó "ObjectPlacementResult" struktúrát ad vissza. Emellett az elhelyezés hozzáadódik a dll belső listájához, amely az elhelyezett objektumokat tartalmazza. A további elhelyezési lekérdezések ezt az objektumot veszik figyelembe. A Unity-mintában található "LevelSolver.cs" fájl további példalekérdezéseket tartalmaz.

Objektumelhelyezés eredményei
3. ábra: A kék négyzetek azt ékeik, hogy a kamerapozíció szabályaitól távolodó, a padlóra kerülő három helytől származó lekérdezések eredménye

Ha egy szinthez vagy alkalmazási forgatókönyvhöz szükséges több objektum elhelyezését oldja meg, először oldja meg a tárgyakat és a nagy méretű objektumokat, hogy maximális valószínűséggel találjon helyet. Az elhelyezés sorrendje fontos. Ha nem található objektumelhelyezés, próbálkozzon kevésbé korlátozott konfigurációval. A tartalék konfigurációk készlete kritikus fontosságú a funkciók támogatásában számos helyiségkonfigurációban.

Helyiség vizsgálatának folyamata

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ája igényeinek, a térbeli megértés modult úgy alakítottuk ki, hogy két adott játék igényeit támogassa. A megoldása egy adott folyamat és feltételezések halmaza köré é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 playspace "festmény" – A vizsgálat során a felhasználó mozog, és a játék tempóját nézve gyakorlatilag lefesti a területeket, amelyeket bele kell foglalni. A létrehozott háló fontos, hogy felhasználói visszajelzést nyújtson ebben a fázisban. Beltéri otthoni vagy irodai környezet – A lekérdezési funkciók a sima felületek és a megfelelő szögben található fal köré vannak tervezve. Ez egy soft korlátozás. A vizsgálat fázisában azonban befejeződött az elsődleges tengelyelemzés, hogy optimalizálja a hálószellációt a fő- és altengely mentén. A beolvasható SpatialUnderstanding.cs fájl kezeli a beolvasási 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 ellenőrzési folyamat az InitScan, majd az UpdateScan minden keretet átvizsgál. Ha a statisztikai lekérdezés ésszerű lefedettséget jelez, a felhasználó airtap használatával hívhatja meg a RequestFinish (Kérelem vége) adatokat, jelezve a vizsgálat fázisának végét. Az UpdateScan függvény addig lesz hívva, amíg a visszatérési értéke azt nem jelzi, hogy a dll feldolgozása befejeződött.

A Mesh ismertetése

A understanding dll belsőleg egy 8 cm méretű voxelkockarácsként tárolja a playspace-t. A vizsgálat kezdeti részében egy elsődleges összetevő-elemzésnek kell befejeződni a helyiség tengelyének meghatározásához. Belsőleg ezekhez a tengelyekhez igazítva tárolja a voxeles teret. A háló körülbelül másodpercenként jön létre az isosurface a voxel kötetből való kinyerével.

A voxelkötetből létrehozott háló
A voxelkötetből létrehozott háló

Hibaelhárítás

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

Térbeli leképezés Mixed Reality eszközkészletben

A térbeli leképezés a Mixed Reality eszközkészlettel való használatával kapcsolatos további információkért tekintse meg az MRTK-dokumentumok térbeli tudatosságról című szakaszát.

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

Ha az eddig kifektetett Unity-fejlesztési utat követi, akkor az MRTK alapvető építőelemei vizsgálatának közepén van. Innen folytathatja a következő építőelemre:

Vagy ugorjon a Mixed Reality képességekre és API-kra:

Bármikor visszamehet a Unity fejlesztési ellenőrzőpontjaiba.

Lásd még