Sdílet prostřednictvím


Prostorové dotazy

Prostorové dotazy jsou operace, se kterými můžete požádat službu vzdáleného vykreslování, které objekty se nacházejí v oblasti. Prostorové dotazy se často používají k implementaci interakcí, jako je například zjištění objektu, na který uživatel odkazuje.

Všechny prostorové dotazy se vyhodnocují na serveru. Dotazy jsou tedy asynchronní operace a výsledky přicházejí se zpožděním, které závisí na latenci vaší sítě.

Paprskové přetypování

Paprskové přetypování je prostorový dotaz, ve kterém modul runtime kontroluje, které objekty protínají paprsky, počínaje danou polohou a ukazují na určitý směr. Při optimalizaci je také uvedena maximální vzdálenost paprsku, aby se nehledaly objekty, které jsou příliš daleko. I když je provádění stovek paprskových přetypování každého rámce výpočetně proveditelné na straně serveru, každý dotaz také generuje síťový provoz, takže počet dotazů na rámec by měl být co nejnižší.

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

Existují tři režimy shromažďování přístupů:

  • Closest: V tomto režimu se hlásí pouze nejbližší přístup.
  • Any: Upřednostňujte tento režim, když chcete vědět , jestli by paprsek trefil cokoliv, ale nezajímá vás, co přesně udeřilo. Tento dotaz může být výrazně levnější k vyhodnocení, ale má pouze několik aplikací.
  • All: V tomto režimu jsou všechny hity podél paprsku hlášeny, seřazené podle vzdálenosti. Nepoužívejte tento režim, pokud opravdu nepotřebujete více než první hit. Omezte počet hlášených přístupů pomocí MaxHits možnosti.

Chcete-li vyloučit objekty selektivně z zvažování pro ray casts, lze použít HierarchicalStateOverrideComponent komponenta.

Výsledek dosažení

Výsledkem dotazu na přetypování paprsku je pole hitů. Pole je prázdné, pokud nebyl nalezen žádný objekt.

Přístup má následující vlastnosti:

  • HitEntity: Na kterou entitu jste narazili.
  • SubPartId: Která submesh byla zasažena v meshcomponentu. Lze použít k indexování MeshComponent.UsedMaterials a vyhledání materiálu v tomto okamžiku.
  • HitPosition: Pozice ve světě, kde paprsek protínal objekt.
  • HitNormal: Povrch vesmíru na světě normální síť v pozici průsečíku.
  • DistanceToHit: Vzdálenost od počáteční pozice paprsku k hitu.
  • HitType: Co je zasaženo paprskem: TriangleFrontFace, TriangleBackFace nebo Point. Ve výchozím nastavení se funkce ARR vykreslí oboustranně, takže trojúhelníky, které uživatel vidí, nemusí být nutně přední. Pokud chcete rozlišovat mezi TriangleFrontFace kódem a TriangleBackFace v kódu, nejprve se ujistěte, že vaše modely jsou vytvořené správnými pokyny pro rozpoznávání tváře.

Prostorové dotazy

Prostorový dotaz umožňuje modulu runtime zkontrolovat, který meshComponents protíná s uživatelem definovaným svazkem. Tato kontrola se provádí, protože jednotlivá kontrola se provádí na základě hranic jednotlivých částí sítě ve scéně, ne na individuálním trojúhelníku. Jako optimalizaci je možné poskytnout maximální počet komponent sítě hitů.
I když se takový dotaz dá spustit ručně na straně klienta, pro velké scény to může být řádově rychlejší, aby server mohl tuto funkci vypočítat.

Následující příklad kódu ukazuje, jak provádět dotazy na osu zarovnané ohraničující pole (AABB). Varianty dotazu také umožňují orientované ohraničující svazky rámečku (SpatialQueryObbAsync) a svazky sphere (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
                }
            }
        });
}

Dokumentace k rozhraní API

Další kroky