Ruimtelijke query's

Ruimtelijke query's zijn bewerkingen waarmee u de remote rendering-service kunt vragen welke objecten zich in een gebied bevinden. Ruimtelijke query's worden vaak gebruikt voor het implementeren van interacties, zoals het bepalen naar welk object een gebruiker verwijst.

Alle ruimtelijke query's worden op de server geëvalueerd. De query's zijn daarom asynchrone bewerkingen en resultaten komen binnen met een vertraging die afhankelijk is van de netwerklatentie.

Ray casts

Een raycast is een ruimtelijke query waarbij de runtime controleert welke objecten een ray snijden, beginnend bij een bepaalde positie en in een bepaalde richting wijzen. Als optimalisatie wordt ook een maximale straalafstand gegeven, om niet te zoeken naar objecten die te ver weg zijn. Hoewel het uitvoeren van honderden raycasts elk frame rekenbaar is aan de serverzijde, genereert elke query ook netwerkverkeer, dus het aantal query's per frame moet zo laag mogelijk worden gehouden.

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

Er zijn drie hitverzamelingsmodi:

  • Closest: In deze modus wordt alleen de dichtstbijzijnde hit gerapporteerd.
  • Any: Geef de voorkeur aan deze modus als alles wat je wilt weten is of een ray iets zou raken, maar het niet uitmaakt wat er precies is geraakt. Deze query kan aanzienlijk goedkoper zijn om te evalueren, maar heeft ook maar weinig toepassingen.
  • All: In deze modus worden alle hits langs de ray gerapporteerd, gesorteerd op afstand. Gebruik deze modus alleen als u meer nodig hebt dan de eerste hit. Beperk het aantal gerapporteerde treffers met de MaxHits optie.

Als u objecten selectief wilt uitsluiten van het overwegen van raycasts, kan het component HierarchicalStateOverrideComponent worden gebruikt.

Resultaat hit

Het resultaat van een raycast-query is een matrix met treffers. De matrix is leeg als er geen object is geraakt.

Een treffer heeft de volgende eigenschappen:

  • HitEntity: Welke entiteit is geraakt.
  • SubPartId: Welke submesh werd geraakt in een MeshComponent. Kan worden gebruikt om het materiaal op dat moment te indexeren MeshComponent.UsedMaterials en op te zoeken.
  • HitPosition: De ruimtepositie van de wereld waar de straal het object doorkruiste.
  • HitNormal: Het ruimteoppervlak van de wereld normaal van de mesh op de positie van het snijpunt.
  • DistanceToHit: De afstand van de ray-beginpositie tot de hit.
  • HitType: Wat wordt geraakt door de ray: TriangleFrontFace, of PointTriangleBackFace . Standaard wordt ARR dubbelzijdig weergegeven, zodat de driehoeken die de gebruiker ziet niet noodzakelijkerwijs naar voren gericht zijn. Als u onderscheid wilt maken tussen TriangleFrontFace en TriangleBackFace in uw code, moet u ervoor zorgen dat uw modellen eerst met de juiste gezichtsrichtingen zijn geschreven.

Ruimtelijke query's

Met een ruimtelijke query kan de runtime controleren welke MeshComponents elkaar kruisen met een door de gebruiker gedefinieerd volume. Deze controle wordt uitgevoerd omdat de afzonderlijke controle wordt uitgevoerd op basis van de grenzen van elk mesh-onderdeel in de scène, niet op basis van een afzonderlijke driehoek. Als optimalisatie kan een maximum aantal hit mesh-onderdelen worden geleverd.
Hoewel een dergelijke query handmatig aan de clientzijde kan worden uitgevoerd, kan het voor grote scènes sneller worden uitgevoerd voor de server om dit te berekenen.

In de volgende voorbeeldcode ziet u hoe u query's uitvoert op een uitgelijnd begrenzingsvak (AABB). Varianten van de query maken ook georiënteerde begrenzingsvakvolumes (SpatialQueryObbAsync) en bolvolumes (SpatialQuerySphereAsync) mogelijk.

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

API-documentatie

Volgende stappen