你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
空间查询
空间查询是一种操作,可用来询问远程渲染服务哪些对象位于一个区域中。 空间查询经常用于实现交互,如确定用户正在指向哪个对象。
所有空间查询都是在服务器上进行计算。 因此,查询是异步操作,结果会得到延迟,具体取决于网络延迟。
光线投射
光线转换是空间查询,运行时检查对象与光线相交、从给定位置开始并指向特定方向。 作为一种优化,还给出了最长光线距离,以免搜索太远的对象。 尽管在服务器端执行数百个光线转换在计算上是可行的,但每个查询也会生成网络流量,因此每个帧的查询数应尽可能低。
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
}
}
});
}
有三种命中收集模式:
Closest
: 在此模式下,只报告最近的命中。Any
: 当你想要知道 的是光线是否会 击中任何东西时,首选此模式,但并不关心所击中的内容。 此查询的计算成本可能会大大降低,但几乎没有应用程序。All
: 在此模式下,将报告沿光线的所有命中,按距离排序。 除非确实除了第一次命中还需要更多命中,否则请不要使用这种模式。 使用MaxHits
选项可以限制报告的命中数。
若要有选择性地从光线投射的目标对象范围内排除对象,可以使用 HierarchicalStateOverrideComponent 组件。
命中结果
光线投射查询的结果是命中数组。 如果未命中任何对象,数组就是空的。
命中有以下属性:
HitEntity
: 命中了哪个 实体 。SubPartId
:在 MeshComponent 中命中了哪个子消息。 可用于索引到MeshComponent.UsedMaterials
,并查找此时的材料。HitPosition
: 光线与对象相交的世界空间位置。HitNormal
: 网格在交集位置处的世界空间表面法线。DistanceToHit
: 从光线起始位置到命中距离。HitType
: 光线击中的内容:TriangleFrontFace
或TriangleBackFace
Point
。 默认情况下, ARR 呈现双面 ,以便用户看到的三角形不一定是正面的。 如果要区分TriangleFrontFace
和TriangleBackFace
代码,请首先确保使用正确的人脸方向创作模型。
空间查询
空间查询允许运行时检查哪些 MeshComponent 与用户定义的卷相交。 此检查是高性能的,因为单个检查基于场景中每个网格部件的边界执行,而不是基于单个三角形。 作为优化,可以提供最大的命中网格组件数。
虽然此类查询可以在客户端手动运行,但对于大型场景,服务器计算此查询的速度可能更快。
以下示例代码演示如何针对轴对齐边界框(AABB)执行查询。 查询的变体还允许面向边界框卷(SpatialQueryObbAsync
)和球体卷(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 文档
- C# RenderingConnection.RayCastQueryAsync()
- C# 呈现连接。SpatialQueryAabbAsync()
- C# 呈现连接。SpatialQuerySphereAsync()
- C# 呈现连接。SpatialQueryObbAsync()
- C++ RenderingConnection::RayCastQueryAsync()
- C++ 呈现连接ion::SpatialQueryAabbAsync()
- C++ 呈现连接ion::SpatialQuerySphereAsync()
- C++ 呈现连接ion::SpatialQueryObbAsync()