Unity Editor 有一个低级脚本参考 API 用于在项目环境中收集有关表面的信息。此低级脚本参考 API 可用于最大限度控制何时查询设备的表面更改,以及何时创建或更新相应的表面游戏对象。空间映射 (Spatial Mapping) 组件可用于快速设置并运行混合现实应用,而无需直接使用低级脚本参考 API。
有两个空间映射组件:空间映射渲染器 (Spatial Mapping Renderer) 和空间映射碰撞体 (Spatial Mapping Collider)。选择 Component > Add…__(或单击 Inspector 窗口中的 Add Component__)以显示 Add Component 菜单。空间映射组件位于 Add Component 菜单中的 AR 类别之下。
这些组件可以一起使用或独立使用。每个空间映射组件都使用自己的表面观察者 (surface observer) 来了解物理世界的变化。根据组件的配置方式,每个空间映射组件会定期查询系统,以了解物理空间中发生了哪些变化。当系统向组件通知有相关变化时,组件会确定对各种发生变化的表面进行烘焙的优先级。烘焙过程涉及生成网格过滤器 (Mesh Filter) 以及对应于物理表面的网格。__空间映射渲染器__和__空间映射碰撞体__组件以自己的特定方式使用此网格过滤器。
空间映射渲染器 (Spatial Mapping Renderer) 组件提供空间映射表面的可视化表示。这对于通过可视化方式调试表面并向环境添加视觉效果非常有用。
空间映射渲染器组件定期向系统查询物理空间变化。每次向该组件通知这些更改时,都会将返回的表面数据烘焙到游戏对象中。这些游戏对象包含网格过滤器和网格渲染器。渲染器组件会管理表面游戏对象的生命周期。也就是说,空间映射渲染器组件负责创建、更新和销毁表面游戏对象。
此组件提供了一种动态更改所有生成的表面上的材质的简便方法。附带两种材质类型:
遮挡材质 (Occlusion Material) 看起来是透明的但会隐藏全息图。例如,如果需要一个真实的桌子来隐藏位于其下方的游戏内全息对象,这可能会是一种有用的材质。
适用于所有组件表面的线框着色器。线框的颜色代表距离。以下是距离与颜色的对应关系。
0 到 1 米 = 黑色
1 到 2 米 = 红色
2 到 3 米 = 绿色
3 到 4 米 = 蓝色
4 到 5 米 = 黄色
5 到 6 米 = 青色
6 到 7 米 = 洋红色
7 到 8 米 = 栗色
8 到 9 米 = 蓝绿色
9 到 10 米 = 橙色
10 米或以上 = 白色
设置 | 属性 |
---|---|
Custom Render Setting | 从三个选项之中选择一项来渲染表面:__Occlusion Material__ - 一种透明材质,可将游戏对象隐藏在现实世界的表面之后。注意:此选项会启用所有表面的网格渲染器,并覆盖任何其他设置。Custom Material - 自定义的表面可视化材质。此选项用于调试、视觉效果或自定义的遮挡材质。此选项会启用所有表面的网格渲染器,并覆盖任何其他设置。None (Game Object) - 禁用分配给表面的所有网格渲染器。 |
Custom Material | 选择要用于渲染的材质。默认设置为内置的 SpatialMappingWireframe 材质。此处选择的选项是适用于 Custom Render Settings 的渲染材质。请注意,__Custom Render Settings__ 中的两个有效选项(__Occlusion Material__ 和 Custom Material__)都需要此处的 Custom Material__ 设置。 |
有关 General Settings 设置的信息,请参阅以下的 General Settings部分。
注意:
所有表面游戏对象都从 Custom Render Setting 中获取材质。如果更改 Custom Render Setting__,则所有表面游戏对象的渲染材质都会更改为 Custom Render Setting__ 中指定的材质。这样可减少绘制调用次数,进而提高渲染性能。使用共享材质还可以减少渲染过程使用的内存量。
将新材质指定给 Custom Material 设置时,表面游戏对象的表面材质不会自动更改。还必须将 Custom Render Setting 设置为 Custom Material 或 Occlusion Material 以将新材质应用于所有表面。
如果在运行时未分配 Custom Render Setting 中的 Occlusion Material 或 Custom Material 属性,则会使用渲染器 (Renderer) 组件将它们销毁。但是,不会使用该组件销毁在运行时分配的任何 Occlusion Material 或 __Custom Material__,因此需要手动分别销毁它们。
以下脚本示例演示了如何在运行时动态更改应用于所有表面游戏对象的材质。
SpatialMappingRenderer renderer = spatialMappingGameObject.AddComponent<SpatialMappingRenderer>();
renderer.customMaterial = new Material(Shader.Find("VR/SpatialMapping/Wireframe"));
renderer.currentRenderSetting = SpatialMappingRenderer.RenderSetting.CustomMaterial;
空间映射碰撞体 (Spatial Mapping Collider) 组件允许全息内容与物理表面进行交互。该组件可以创建、更新和销毁表面游戏对象。
该组件定期向系统查询物理世界中的表面更改。当系统报告有表面更改时,__空间映射碰撞体__组件会确定对每个报告的表面进行烘焙的先后时间。烘焙表面时会创建一个新的游戏对象,使其包含网格过滤器 (Mesh Filter) 和网格碰撞体 (Mesh Collider) 组件。一旦表面具有网格碰撞体,就可以将射线投射到表面并与之发生碰撞。
设置 | 属性 |
---|---|
Enable Collisions | 选中此框可启用表面网格碰撞体。 |
Mesh Layer | 设置所有表面网格碰撞体上的层 (Layer) 属性。请注意,需要为射线投射设置层 (Layers)。执行射线投射时,必须指明要根据哪些层来测试射线交点。默认情况下会将所有游戏对象分配到__默认 (Default)__ 层。但是,最好将游戏对象分配给特定的层。请参阅下文的性能优化。请参阅层页面和射线投射页面以了解更多信息。另请参阅下文的示例脚本:SpatialSurface 射线投射。 |
Physic Material | 指定要分配给网格碰撞体的__物理材质 (Physic Material)。默认设置为 None (Physic Material)。物理材质__指定其他刚体组件应如何与其交互。例如,可用一个表面来模拟冰面,因此对该表面上移动的对象施加较小的摩擦力。空间映射碰撞体组件将其__物理材质__应用于其表面游戏对象上的所有网格碰撞体。请参阅物理材质页面以了解更多信息。 |
有关 General Settings 设置的信息,请参阅以下的 General Settings部分。
以下示例演示了如何对 SpatialSurface 层上的游戏对象执行射线投射。
using UnityEngine;
using System.Collections;
public class CustomLayerCollision : MonoBehaviour
{
// 每帧调用一次 Update。
void Update()
{
//当用户按下鼠标左键时,
// 执行一次碰撞测试。可根据手势事件
// 触发 DetectCollisions。*
if(Input.GetMouseButtonDown(0))
{
DetectCollisions();
}
}
void DetectCollisions()
{
// 对空间表面或 UI 层上的所有游戏对象
// 进行射线投射。
int layerMask = 1 << LayerMask.NameToLayer("SpatialSurface");
// 我们使用 ScreenPointToRay 创建一条射线,
// 其原点是主摄像机的位置,方向是
// 从主摄像机的位置到鼠标在世界空间中的位置。
RaycastHit[] hits = Physics.RaycastAll(Camera.main.ScreenPointToRay(Input.mousePosition), float.MaxValue, layerMask);
if(hits.Length > 0)
{
foreach(RaycastHit hit in hits)
{
Debug.Log(string.Format("Hit Object **\"**{0}**\"** at position **\"**{1}**\"**", hit.collider.gameObject, hit.point));
}
}
else
{
Debug.Log("Nothing was hit.");
}
}
}
General Settings 的工作方式与 Spatial Mapping Renderer (Script) 和 Spatial Mapping Collider (Script) 组件相同。
设置 | 属性 |
---|---|
Surface Parent | 选择希望由空间映射组件生成的表面游戏对象继承自的__表面父级 (Surface Parent)__ 游戏对象。将此设置保留为 None (Game Object) 可自动生成表面父游戏对象。 |
Freeze Updates | 选中此复选框可停止组件向系统查询表面更改。注意:每个空间映射组件会定期向系统查询物理空间中的表面更改。查询和烘焙表面的过程存在内存、性能和功耗方面的成本。对于希望基本为静态的环境,可让用户在一段时间内观察环境而不进行更新。 |
Time Between Updates | 指定对物理空间中的表面更改进行查询的间隔时间(以十分之一秒为单位,如 3.7 或 4.6)。默认值为 2.5 秒。请注意,查询越频繁,内存、性能和功耗的成本就越高。 |
Removal Update Count | 指定在删除表面游戏对象之前的更新次数。在此上下文中,一次更新相当于一帧。默认为 10 次更新(帧)。注意:当系统通知组件表面游戏对象不再位于表面观察者的包围体中时,即从系统报告的规定区域中消失时,将开始进行删除更新倒计时。此处指定此事件之后在删除表面游戏对象之前应执行的更新(帧)数。 |
Level of Detail | 选择组件生成 Low、Medium 还是 High 质量的网格。默认值为 Medium。质量越高,碰撞体和渲染的准确度越高,质量越低,性能和功耗成本越低。请参阅下图了解三个 Level Of Detail 模式的示例。 |
Bounding Volume Type | 在此处选择包围体区域形状:__Sphere__ 或 Axis Aligned Box。默认设置为 Axis Aligned Box。注意:包围体是供系统报告物理表面更改的规定区域。 |
Size In Meters | 以米为单位设置包围体的大小。按半径配置 Sphere__;默认半径为 2 米。按面积配置 Axis Aligned Box__;默认值为 Vector3 (4,4,4) 或 4 立方米。注意:观察者的包围体是供系统报告物理表面更改的规定区域。 |
细节级别 (Level Of Detail)
切记,每个空间映射组件独立于其他空间映射组件。这意味着每个组件都维护自己的表面列表,即使多个组件识别到相同的表面也是如此。为了优化性能,请尝试限制所使用的空间映射组件的数量。
如果希望模拟中的环境在很大程度上为静态且不变(如棋盘游戏),可以根据需要预先扫描尽可能多的表面数据,然后将 Freeze Updates 属性设置为 false。这样可以略微提高性能并降低功耗。
移动空间映射组件会有少量性能成本。尽量避免移动具有空间映射组件的游戏对象。
在 Collider Settings > Level of Detail 中,使用 Low 设置。这样将在计算碰撞交点时提高性能并降低功耗。
空间映射网格碰撞体 (Spatial Mapping Mesh Collider) 的更新延迟比空间映射网格渲染器 (Spatial Mapping Mesh Renderer) 更短。这意味着碰撞体的更新速度比渲染器快。
在 Collider Settings > Mesh Layer 中,默认情况下,所有游戏对象都分配给__默认 (Default)__ 层。但是,最好将游戏对象分配给特定层:射线投射是一项高成本的计算,因此会导致性能降低。通过使用层,可以过滤要进行射线投射计算的游戏对象,从而可以优化性能。 如果__默认__层上没有很多复杂的网格,那么对碰撞进行射线投射测试不会产生很大的性能成本。但是,为了在进行碰撞时降低射线投射测试的复杂性,最好将游戏对象按层进行组织。