Bagikan melalui


Kueri spasial

Kueri spasial adalah operasi yang dapat digunakan untuk menanyakan objek mana yang terletak di suatu area ke layanan penyajian jarak jauh. Kueri spasial sering digunakan untuk mengimplementasikan interaksi, seperti mencari tahu objek mana yang ditunjuk pengguna.

Semua kueri spasial dievaluasi di server. Oleh karena itu, kueri adalah operasi asinkron dan hasilnya tiba dengan penundaan yang tergantung pada latensi jaringan Anda.

Transmisi Sinar

Transmisi sinar adalah kueri spasial di mana runtime memeriksa objek mana yang bersinggungan dengan sinar, dimulai pada posisi tertentu dan menunjuk ke arah tertentu. Sebagai optimasi, jarak sinar maksimum juga diberikan, untuk tidak mencari benda yang terlalu jauh. Meskipun melakukan ratusan transmisi sinar setiap bingkai secara komputasi layak di sisi server, setiap kueri juga menghasilkan lalu lintas jaringan, sehingga jumlah kueri per bingkai harus disimpan serendah mungkin.

async void CastRay(RenderingSession session)
{
    // trace a line from the origin into the +z direction, over 10 units of distance.
    RayCast rayCast = new RayCast(new Double3(0, 0, 0), new Double3(0, 0, 1), 10);

    // only return the closest hit
    rayCast.HitCollection = HitCollectionPolicy.ClosestHit;

    RayCastQueryResult result = await session.Connection.RayCastQueryAsync(rayCast);
    RayCastHit[] hits = result.Hits;
    if (hits.Length > 0)
    {
        var hitObject = hits[0].HitObject;
        var hitPosition = hits[0].HitPosition;
        var hitNormal = hits[0].HitNormal;
        var hitType = hits[0].HitType;
        // do something with the hit information
    }
}
void CastRay(ApiHandle<RenderingSession> session)
{
    // trace a line from the origin into the +z direction, over 10 units of distance.
    RayCast rayCast;
    rayCast.StartPos = {0, 0, 0};
    rayCast.EndPos = {0, 0, 10};

    // only return the closest hit
    rayCast.HitCollection = HitCollectionPolicy::ClosestHit;

    session->Connection()->RayCastQueryAsync(rayCast, [](Status status, ApiHandle<RayCastQueryResult> result)
    {
        if (status == Status::OK)
        {
            std::vector<RayCastHit> hits;
            result->GetHits(hits);

            if (hits.size() > 0)
            {
                auto hitObject = hits[0].HitObject;
                auto hitPosition = hits[0].HitPosition;
                auto hitNormal = hits[0].HitNormal;
                auto hitType = hits[0].HitType;

                // do something with the hit information
            }
        }
    });
}

Ada tiga mode pengumpulan hit:

  • Closest: Dalam mode ini, hanya hit terdekat yang dilaporkan.
  • Any: Pilih mode ini saat yang ingin Anda ketahui adalah apakah sinar akan melakukan hit apa pun, tetapi tidak peduli apa itu hit. Kueri ini dapat jauh lebih murah untuk dievaluasi, tetapi juga hanya memiliki beberapa aplikasi.
  • All: Dalam mode ini, semua klik di sepanjang sinar dilaporkan, diurutkan berdasarkan jarak. Jangan gunakan mode ini kecuali Anda benar-benar membutuhkan lebih dari hit pertama. Batasi jumlah klik yang dilaporkan dengan opsi MaxHits tersebut.

Untuk mengecualikan objek secara selektif agar tidak dipertimbangkan untuk transmisi sinar, komponen HierarchicalStateOverrideComponent dapat digunakan.

Hasil hit

Hasil dari kueri transmisi sinar adalah serangkaian hit. Array kosong, jika tidak ada objek yang berupa hit.

Hit memiliki properti berikut:

  • HitEntity: Yang mana entitas adalah hit.
  • SubPartId: Yang mana submesh adalah hit dalam MeshComponent. Dapat digunakan untuk mengindeks ke dalam MeshComponent.UsedMaterials dan mencari materi pada saat itu.
  • HitPosition: Posisi ruang dunia tempat sinar memotong objek.
  • HitNormal: Permukaan ruang dunia normal jala pada posisi persimpangan.
  • DistanceToHit: Jarak dari posisi awal sinar ke hit.
  • HitType: Apa yang terkena sinar: TriangleFrontFace, TriangleBackFace atau Point. Secara default, ARR merender dua sisi sehingga segitiga yang dilihat pengguna tidak selalu menghadap ke depan. Jika Anda ingin membedakan antara TriangleFrontFace dan TriangleBackFace dalam kode Anda, pastikan model Anda ditulis dengan arah wajah yang benar terlebih dahulu.

Kueri spasial

Kueri spasial memungkinkan runtime untuk memeriksa MeshComponents mana yang bersinggungan dengan volume yang ditentukan pengguna. Pemeriksaan ini dilakukan karena pemeriksaan individu dilakukan berdasarkan batas setiap bagian jala di adegan, bukan berdasarkan segitiga individu. Sebagai pengoptimalan, jumlah maksimum komponen jala hit dapat disediakan.
Meskipun kueri seperti itu dapat dijalankan secara manual di sisi klien, untuk adegan besar dapat berupa pesanan besaran lebih cepat bagi server untuk menghitung ini.

Contoh kode berikut menunjukkan cara melakukan kueri terhadap kotak batas rata sumbu (AABB). Varian kueri juga memungkinkan volume kotak pembatas berorientasi (SpatialQueryObbAsync) dan volume bola (SpatialQuerySphereAsync).

async void QueryAABB(RenderingSession session)
{
    // Query all mesh components in a 2x2x2m cube.
    SpatialQueryAabb query = new SpatialQueryAabb();
    query.Bounds = new Microsoft.Azure.RemoteRendering.Bounds(new Double3(-1, -1, -1), new Double3(1, 1, 1));
    query.MaxResults = 100;

    SpatialQueryResult result = await session.Connection.SpatialQueryAabbAsync(query);
    foreach (MeshComponent meshComponent in result.Overlaps)
    {
        Entity owner = meshComponent.Owner;
        // do something with the hit MeshComponent / Entity
    }
}
void QueryAABB(ApiHandle<RenderingSession> session)
{
    // Query all mesh components in a 2x2x2m cube.
    SpatialQueryAabb query;
    query.Bounds.Min = {-1, -1, -1};
    query.Bounds.Max = {1, 1, 1};
    query.MaxResults = 100;

    session->Connection()->SpatialQueryAabbAsync(query, [](Status status, ApiHandle<SpatialQueryResult> result)
        {
            if (status == Status::OK)
            {
                std::vector<ApiHandle<MeshComponent>> overlaps;
                result->GetOverlaps(overlaps);

                for (ApiHandle<MeshComponent> meshComponent : overlaps)
                {
                    ApiHandle<Entity> owner = meshComponent->GetOwner();
                    // do something with the hit MeshComponent / Entity
                }
            }
        });
}

Dokumentasi API

Langkah berikutnya