Pemetaan spasial di Unity

Pemetaan spasial memungkinkan Anda mengambil jala segitiga yang mewakili permukaan di dunia di sekitar perangkat HoloLens. Anda dapat menggunakan data permukaan untuk penempatan, oklusi, dan analisis ruangan untuk memberi proyek Unity Anda dosis perendaman tambahan.

Unity mencakup dukungan penuh untuk pemetaan spasial, yang diekspos ke pengembang dengan cara berikut:

  1. Komponen pemetaan spasial yang tersedia di MixedRealityToolkit, yang menyediakan jalur yang nyaman dan cepat untuk memulai pemetaan spasial
  2. API pemetaan spasial tingkat bawah, yang memberikan kontrol penuh dan memungkinkan penyesuaian khusus aplikasi yang lebih canggih

Untuk menggunakan pemetaan spasial di aplikasi Anda, kemampuan SpatialPerception perlu diatur di AppxManifest Anda.

Dukungan perangkat

Fitur HoloLens (generasi pertama) HoloLens 2 Headset imersif
Pemetaan spasial ✔️ ✔️

Mengatur kemampuan SpatialPerception

Agar aplikasi dapat menggunakan data pemetaan spasial, kemampuan SpatialPerception harus diaktifkan.

Cara mengaktifkan kemampuan SpatialPerception:

  1. Di Editor Unity, buka panel "Pengaturan Pemutar" (Edit > Pemutar Pengaturan > Proyek)
  2. Pilih pada tab "Bursa Windows"
  3. Perluas "Pengaturan Penerbitan" dan periksa kemampuan "SpatialPerception" di daftar "Kemampuan"

Catatan

Jika Anda telah mengekspor proyek Unity ke solusi Visual Studio, Anda harus mengekspor ke folder baru atau mengatur kemampuan ini secara manual di AppxManifest di Visual Studio.

Pemetaan spasial juga memerlukan MaxVersionTested setidaknya 10.0.10586.0:

  1. Di Visual Studio, klik kanan Package.appxmanifest di Penjelajah Solusi dan pilih Tampilkan Kode
  2. Temukan baris yang menentukan TargetDeviceFamily dan ubah MaxVersionTested="10.0.10240.0" ke MaxVersionTested="10.0.10586.0"
  3. Simpan Package.appxmanifest.

Cara menambahkan pemetaan di Unity

Sistem kesadaran spasial

Di MRTK, lihat panduan memulai kesadaran spasial untuk informasi tentang menyiapkan berbagai pengamat jala spasial.

Untuk informasi tentang pengamat perangkat, lihat Panduan mengonfigurasi pengamat jala untuk perangkat .

Untuk informasi tentang pengamat pemahaman adegan, lihat panduan pengamat pemahaman Adegan .

Analisis jala tingkat lebih tinggi: Pemahaman Spasial

Perhatian

Pemahaman Spasial tidak digunakan lagi demi Pemahaman Adegan.

MixedRealityToolkit adalah kumpulan kode utilitas untuk pengembangan holografik yang dibangun di atas API holografik Unity.

Pemahaman Spasial

Saat menempatkan hologram di dunia fisik, seringkali diinginkan untuk melampaui jala dan bidang permukaan pemetaan spasial. Ketika penempatan dilakukan secara prokurensial, tingkat pemahaman lingkungan yang lebih tinggi diinginkan. Ini biasanya membutuhkan pengambilan keputusan tentang apa itu lantai, langit-langit, dan dinding. Anda juga memiliki kemampuan untuk mengoptimalkan terhadap serangkaian batasan penempatan untuk menentukan lokasi fisik terbaik untuk objek holografik.

Selama pengembangan Conker Muda dan Fragmen, Asobo Studios menghadapi masalah ini dengan mengembangkan pemecah ruangan. Masing-masing game ini memiliki kebutuhan khusus game, tetapi mereka berbagi teknologi pemahaman spasial inti. Pustaka HoloToolkit.SpatialUnderstanding merangkum teknologi ini, memungkinkan Anda untuk dengan cepat menemukan ruang kosong di dinding, menempatkan objek di langit-langit, mengidentifikasi ditempatkan untuk karakter untuk duduk, dan segudang kueri pemahaman spasial lainnya.

Semua kode sumber disertakan, memungkinkan Anda untuk menyesuaikannya dengan kebutuhan Anda dan berbagi peningkatan Anda dengan komunitas. Kode untuk pemecah C++ telah dibungkus ke dalam dll UWP dan diekspos ke Unity dengan penurunan prefab yang terkandung dalam MixedRealityToolkit.

Memahami Modul

Ada tiga antarmuka utama yang diekspos oleh modul: topologi untuk permukaan sederhana dan kueri spasial, bentuk untuk deteksi objek, dan pemecah penempatan objek untuk penempatan set objek berbasis batasan. Masing-masing dijelaskan di bawah ini. Selain tiga antarmuka modul utama, antarmuka transmisi sinar dapat digunakan untuk mengambil jenis permukaan yang diberi tag dan jala ruang bermain kedap air kustom dapat disalin.

Transmisi Sinar

Setelah pemindaian ruangan selesai, label dihasilkan secara internal untuk permukaan seperti lantai, langit-langit, dan dinding. Fungsi mengambil PlayspaceRaycast sinar dan mengembalikan jika sinar bertabrakan dengan permukaan yang diketahui dan jika demikian, informasi tentang permukaan itu dalam bentuk 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;
};

Secara internal, raycast dihitung terhadap representasi voxel kubik 8 cm yang dihitung dari ruang bermain. Setiap voxel berisi sekumpulan elemen permukaan dengan data topologi yang diproses (alias surfel). Selancar yang terkandung dalam sel voxel berpotongan dibandingkan dan kecocokan terbaik yang digunakan untuk mencari informasi topologi. Data topologi ini berisi pelabelan yang dikembalikan dalam bentuk enum "SurfaceTypes", serta area permukaan permukaan bersinggungan.

Dalam sampel Unity, kursor mentransmisikan sinar setiap bingkai. Pertama, melawan tabrakan Unity. Kedua, terhadap representasi dunia modul pemahaman. Dan akhirnya, lagi elemen UI. Dalam aplikasi ini, UI mendapatkan prioritas, berikutnya hasil pemahaman, dan terakhir, collider Unity. SurfaceType dilaporkan sebagai teks di samping kursor.

Jenis permukaan diberi label di samping kursor
Jenis permukaan diberi label di samping kursor

Kueri Topologi

Dalam DLL, manajer topologi menangani pelabelan lingkungan. Seperti disebutkan di atas, sebagian besar data disimpan dalam surfel, yang terkandung dalam volume voxel. Selain itu, struktur "PlaySpaceInfos" digunakan untuk menyimpan informasi tentang ruang bermain, termasuk penyelarasan dunia (detail lebih lanjut tentang ini di bawah), lantai, dan tinggi langit-langit. Heuristik digunakan untuk menentukan lantai, langit-langit, dan dinding. Misalnya, permukaan horizontal terbesar dan terendah dengan area permukaan lebih besar dari 1-m2 dianggap sebagai lantai.

Catatan

Jalur kamera selama proses pemindaian juga digunakan dalam proses ini.

Subset kueri yang diekspos oleh manajer Topologi diekspos melalui dll. Kueri topologi yang diekspos adalah sebagai berikut.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

Setiap kueri memiliki sekumpulan parameter, khusus untuk jenis kueri. Dalam contoh berikut, pengguna menentukan tinggi minimum & lebar volume yang diinginkan, tinggi penempatan minimum di atas lantai, dan jumlah minimum clearance di depan volume. Semua pengukuran dalam meter.

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)

Masing-masing kueri ini mengambil array struktur "TopologyResult" yang telah dialokasikan sebelumnya. Parameter "locationCount" menentukan panjang array yang diteruskan. Nilai yang dikembalikan melaporkan jumlah lokasi yang dikembalikan. Jumlah ini tidak pernah lebih besar dari yang diteruskan dalam parameter "locationCount".

"TopologyResult" berisi posisi tengah volume yang dikembalikan, arah menghadap (yaitu normal), dan dimensi ruang yang ditemukan.

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

Catatan

Dalam sampel Unity, masing-masing kueri ini ditautkan ke tombol di panel antarmuka pengguna virtual. Sampel kode keras parameter untuk masing-masing kueri ini ke nilai yang wajar. Lihat SpaceVisualizer.cs dalam kode sampel untuk contoh selengkapnya.

Kueri Bentuk

Di dll, penganalisis bentuk ("ShapeAnalyzer_W") menggunakan penganalisis topologi untuk mencocokkan dengan bentuk kustom yang ditentukan oleh pengguna. Sampel Unity menentukan sekumpulan bentuk dan mengekspos hasilnya melalui menu kueri dalam aplikasi, di dalam tab bentuk. Niatnya adalah bahwa pengguna dapat menentukan kueri bentuk objek mereka sendiri dan memanfaatkannya, sesuai kebutuhan oleh aplikasi mereka.

Analisis bentuk hanya berfungsi pada permukaan horizontal. Sofa, misalnya, didefinisikan oleh permukaan kursi datar dan bagian atas datar sofa belakang. Kueri bentuk mencari dua permukaan dengan ukuran, tinggi, dan rentang aspek tertentu, dengan dua permukaan selaras dan tersambung. Menggunakan terminologi API, kursi sofa dan bagian atas belakang adalah komponen bentuk dan persyaratan penyelarasan adalah batasan komponen bentuk.

Contoh kueri yang ditentukan dalam sampel Unity (ShapeDefinition.cs), untuk objek "sittable" adalah sebagai berikut.

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

Setiap kueri bentuk didefinisikan oleh sekumpulan komponen bentuk, masing-masing dengan sekumpulan batasan komponen dan sekumpulan batasan bentuk yang mencantumkan dependensi di antara komponen. Contoh ini mencakup tiga batasan dalam satu definisi komponen dan tidak ada batasan bentuk antar komponen (karena hanya ada satu komponen).

Sebaliknya, bentuk sofa memiliki dua komponen bentuk dan empat batasan bentuk. Komponen diidentifikasi oleh indeks mereka dalam daftar komponen pengguna (0 dan 1 dalam contoh ini).

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

Fungsi pembungkus disediakan dalam modul Unity untuk memudahkan pembuatan definisi bentuk kustom. Daftar lengkap batasan komponen dan bentuk dapat ditemukan di "SpatialUnderstandingDll.cs" dalam struktur "ShapeComponentConstraint" dan "ShapeConstraint".

Bentuk persegi panjang ditemukan di permukaan ini
Bentuk persegi panjang ditemukan di permukaan ini

Pemecah Penempatan Objek

Pemecah penempatan objek dapat digunakan untuk mengidentifikasi lokasi ideal di ruang fisik untuk menempatkan objek Anda. Pemecah akan menemukan lokasi yang paling cocok mengingat aturan dan batasan objek. Selain itu, kueri objek bertahan hingga objek dihapus dengan panggilan "Solver_RemoveObject" atau "Solver_RemoveAllObjects", memungkinkan penempatan multi-objek yang dibatasi. Kueri penempatan objek terdiri dari tiga bagian: jenis penempatan dengan parameter, daftar aturan, dan daftar batasan. Untuk menjalankan kueri, gunakan API berikut.

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)

Fungsi ini mengambil nama objek, definisi penempatan, dan daftar aturan dan batasan. Pembungkus C# menyediakan fungsi pembantu konstruksi untuk membuat konstruksi aturan dan batasan menjadi mudah. Definisi penempatan berisi jenis kueri – yaitu, salah satu hal berikut ini.

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

Masing-masing jenis penempatan memiliki sekumpulan parameter yang unik untuk jenis tersebut. Struktur "ObjectPlacementDefinition" berisi sekumpulan fungsi pembantu statis untuk membuat definisi ini. Misalnya, untuk menemukan tempat untuk meletakkan objek di lantai, Anda dapat menggunakan fungsi berikut. objectPlacementDefinition statis publik Create_OnFloor(Vector3 halfDims) Selain jenis penempatan, Anda dapat memberikan seperangkat aturan dan batasan. Aturan tidak dapat dilanggar. Kemungkinan lokasi penempatan yang memenuhi jenis dan aturan kemudian dioptimalkan terhadap serangkaian batasan untuk memilih lokasi penempatan yang optimal. Setiap aturan dan batasan dapat dibuat oleh fungsi pembuatan statis yang disediakan. Contoh aturan dan fungsi konstruksi batasan disediakan di bawah ini.

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

Kueri penempatan objek di bawah ini mencari tempat untuk meletakkan kubus setengah meter di tepi permukaan, jauh dari objek lain yang sebelumnya ditempatkan dan di dekat tengah ruangan.

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

Jika berhasil, struktur "ObjectPlacementResult" yang berisi posisi penempatan, dimensi, dan orientasi dikembalikan. Selain itu, penempatan ditambahkan ke daftar internal dll dari objek yang ditempatkan. Kueri penempatan berikutnya akan mempertimbangkan objek ini. File "LevelSolver.cs" dalam sampel Unity berisi lebih banyak contoh kueri.

Hasil penempatan objek
Gambar 3: Kotak biru mengelompokkan hasil dari tiga tempat pada kueri lantai dengan jauh dari aturan posisi kamera

Saat memecahkan lokasi penempatan beberapa objek yang diperlukan untuk skenario tingkat atau aplikasi, pertama-tama selesaikan objek yang sangat diperlukan dan besar untuk memaksimalkan probabilitas bahwa ruang dapat ditemukan. Urutan penempatan penting. Jika penempatan objek tidak dapat ditemukan, coba konfigurasi yang kurang dibatasi. Memiliki serangkaian konfigurasi fallback sangat penting untuk mendukung fungsionalitas di banyak konfigurasi ruangan.

Proses Pemindaian Ruangan

Sementara solusi pemetaan spasial yang disediakan oleh HoloLens dirancang cukup generik untuk memenuhi kebutuhan seluruh gamut ruang masalah, modul pemahaman spasial dibangun untuk mendukung kebutuhan dua game tertentu. Solusinya disusun di sekitar proses dan serangkaian asumsi tertentu, dirangkum di bawah ini.

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.

"Lukisan" ruang bermain yang digerakkan pengguna – Selama fase pemindaian, pengguna bergerak dan melihat-lihat kecepatan pemutaran, secara efektif melukis area, yang harus disertakan. Jala yang dihasilkan penting untuk memberikan umpan balik pengguna selama fase ini. Penyiapan rumah atau kantor dalam ruangan – Fungsi kueri dirancang di sekitar permukaan datar dan dinding di sudut kanan. Ini adalah batasan lunak. Namun, selama fase pemindaian, analisis sumbu utama selesai untuk mengoptimalkan tessellasi jala di sepanjang sumbu utama dan minor. File SpatialUnderstanding.cs yang disertakan mengelola proses fase pemindaian. Ini memanggil fungsi berikut.

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.

Alur pemindaian, yang didorong oleh perilaku "SpatialUnderstanding" memanggil InitScan, lalu UpdateScan setiap bingkai. Ketika kueri statistik melaporkan cakupan yang wajar, pengguna diizinkan untuk melakukan airtap untuk memanggil RequestFinish untuk menunjukkan akhir fase pemindaian. UpdateScan terus dipanggil sampai nilai pengembaliannya menunjukkan bahwa dll telah selesai diproses.

Memahami Mesh

Dll pemahaman secara internal menyimpan ruang bermain sebagai kisi kubus voxel berukuran 8 cm. Selama bagian awal pemindaian, analisis komponen utama selesai untuk menentukan sumbu ruangan. Secara internal, ia menyimpan ruang voxelnya yang selaras dengan sumbu ini. Jala dihasilkan kira-kira setiap detik dengan mengekstrak isosurface dari volume voxel.

Jala yang dihasilkan dihasilkan dari volume voxel
Jala yang dihasilkan dihasilkan dari volume voxel

Pemecahan Masalah

  • Pastikan Anda telah mengatur kemampuan SpatialPerception
  • Saat pelacakan hilang, peristiwa OnSurfaceChanged berikutnya akan menghapus semua jala.

Pemetaan Spasial di toolkit Mixed Reality

Untuk informasi selengkapnya tentang menggunakan Pemetaan Spasial dengan Mixed Reality Toolkit, lihat bagian kesadaran spasial dokumen MRTK.

Titik Pemeriksaan Pengembangan Berikutnya

Jika Anda mengikuti perjalanan pengembangan Unity yang telah kami susun, Anda berada di tengah-tengah menjelajahi blok penyusun inti MRTK. Dari sini, Anda dapat melanjutkan ke blok penyusun berikutnya:

Atau lompat ke kemampuan platform dan API Mixed Reality:

Anda selalu dapat kembali ke titik pemeriksaan pengembangan Unity kapan saja.

Lihat juga