Dela via


Rumsliga frågor

Rumsliga frågor är åtgärder där du kan fråga fjärrrenderingstjänsten vilka objekt som finns i ett område. Rumsliga frågor används ofta för att implementera interaktioner, till exempel att ta reda på vilket objekt en användare pekar på.

Alla rumsliga frågor utvärderas på servern. Därför är frågorna asynkrona åtgärder och resultaten kommer med en fördröjning som beror på nätverksfördröjningen.

Ray casts

En ray cast är en rumslig fråga där körningen kontrollerar vilka objekt som korsar en stråle, med början vid en viss position och pekar i en viss riktning. Som en optimering ges också ett maximalt strålavstånd för att inte söka efter objekt som är för långt borta. Även om det är beräkningsbart att göra hundratals ray casts varje bildruta på serversidan, genererar varje fråga också nätverkstrafik, så antalet frågor per bildruta bör hållas så lågt som möjligt.

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

Det finns tre lägen för träffsamling:

  • Closest: I det här läget rapporteras endast den närmaste träffen.
  • Any: Föredrar det här läget när allt du vill veta är om en stråle skulle träffa något, men bry dig inte om vad som träffades exakt. Den här frågan kan vara betydligt billigare att utvärdera, men har också bara några få program.
  • All: I det här läget rapporteras alla träffar längs strålen, sorterade efter avstånd. Använd inte det här läget om du inte behöver mer än den första träffen. Begränsa antalet rapporterade träffar med alternativet MaxHits .

Om du vill undanta objekt selektivt från att övervägas för ray casts kan komponenten HierarchicalStateOverrideComponent användas.

Träffresultat

Resultatet av en ray cast-fråga är en matris med träffar. Matrisen är tom om inget objekt har träffats.

En träff har följande egenskaper:

  • HitEntity: Vilken entitet som träffades.
  • SubPartId: Vilken submesh träffades i en MeshComponent. Kan användas för att indexera MeshComponent.UsedMaterials och leta upp materialet vid den tidpunkten.
  • HitPosition: Världsrymdspositionen där strålen korsar objektet.
  • HitNormal: Nätytans världsyta är normal vid skärningspunktens position.
  • DistanceToHit: Avståndet från strålens startposition till träffen.
  • HitType: Vad träffas av strålen: TriangleFrontFace, TriangleBackFace eller Point. Som standard renderas ARR dubbelsidigt så att trianglar som användaren ser inte nödvändigtvis är framåtriktade. Om du vill skilja mellan TriangleFrontFace och TriangleBackFace i koden måste du först se till att dina modeller har rätt ansiktsriktningar.

Rumsliga frågor

Med en rumslig fråga kan körningen kontrollera vilka MeshComponents som korsar en användardefinierad volym. Den här kontrollen är performant eftersom den enskilda kontrollen utförs baserat på varje nätdels gränser i scenen, inte på individuell triangelbasis. Som optimering kan ett maximalt antal träffnätkomponenter tillhandahållas.
En sådan fråga kan köras manuellt på klientsidan, men för stora scener kan det vara storleksordningar snabbare för servern att beräkna detta.

Följande exempelkod visar hur du gör frågor mot en axeljusterad avgränsningsruta (AABB). Varianter av frågan tillåter också orienterade avgränsningsboxvolymer (SpatialQueryObbAsync) och sfärvolymer (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
                }
            }
        });
}

API-dokumentation

Nästa steg