MRTK空间感知

本文详细解释了游戏开发中碰撞器与触发器的区别,物理特性的应用,以及运动跟踪技术如IO、VIO和回环检测在定位中的作用。还介绍了MRTK中的空间感知系统,包括网格数据操作、射线检测和摄像机碰撞检测的相关内容。
摘要由CSDN通过智能技术生成

碰撞器与触发器

问题来源:在游戏对象上添加碰撞(collider)组件,勾选is_tragger选项。

碰撞体:
物理特征:碰撞体发生碰撞时,会依据物理特性(材质,速度,质量,摩擦力)发生位移旋转等。
触发事件:发生时会触发如OnCollisionEnterOnCollisionExitOnCollisionStay的事件
事件响应:声明这样的类,编写内部行为,当事件发生时,会自动为对象调用该事件类。

触发器(勾选is_tragger)
物理特性:不再有了,这对一些射线的碰撞检测很有用
触发事件:OnTriggerEnterOnTriggerExitOnTriggerStay
事件响应:挂载的脚本组件内部声明事件类,触发该事件时,会自动调用方法
 

第六章 空间感知和映射

运动跟踪:定位与姿态估计原理

IO(惯性里程计):原理核心IMU传感器包括了两个运动传感器(加速度计+陀螺仪=加速度和角速度),对数据进行积分,实现物体的位置和姿态变化计算的方法,缺点是由于检测速度快,频率高,微小的误差在长时间跨度容易累计成大误差。所以常常与别的方法搭配使用。

VIO(视觉惯性里程计):计算机视觉_也是由于摄像机的运动前后对同一场景的图像存在视差,进行特征点匹配加对极几何运算,就能计算出不同时刻相机的位置和姿态。缺点是消耗计算资源,所以并不是每帧都执行,主要用来补充IO的累计误差。

回环检测:即便是io+vio的方式,在长距离的定位上也会出现定位误差。于是使用SLAM里面的一个重要概念,称为“”回环检测,在移动过程中,如果回到已经探索过的场景,会进行新旧场景数据匹配,来修正用户的位置信息误差。从而达到更精准的用户估计方式。

运跟注意事项:
1.其依赖于不间断的图像和传感器数据流,所以数据流中断会对运动跟踪造成影响,如遮挡相机
2.VIO依赖于采集图像质量,所以低质量图像会影响运动跟踪,如光照不足,纹理不丰富,模糊
3.VI和VIO数据不一致,电梯里看到的不变传感器数据变,波光粼粼的水面看到变传感器不变
4.tof相机是用的红外光,室外强太阳光可能会过滤掉信息,使得无法采集深度信息,影响构建环境

运动跟踪:系统状态识别与处理

包括状态识别和丢失处理


跟踪失败:MRTK会停止游戏更新循环,锁定全息影像,停止消息与事件分发。
呈现报错:可以在unity菜单中勾选设置,使得跟踪失败时自动显示定义好的图片通知玩家

空间系统:功能启用与配置

先在项目设置中启动功能

配置文件


 

空间系统:感知代码操作

1.拿到空间网格数据观察者-(因为配置文件中可能会有多个“空间网格观察者”)

#想拿到数据观察者 必通过<IMixedRealitySpatialAwarenessMeshObserver>重要接口 及其下面

#法1.直接调用服务下面的长泛型方法<x>()
var meshObserver=CoreServices.GetSpatialAwarenessSyetemDataProvider<重要接口>();

#法2.1从服务拿到系统 转换为A类接口 调用下面的短泛型方法<重要接口>()
var 系统=CoreServices.SpatialAwarenessSystem; 
var 入口= 系统 as IMixedRealityDataProviderAccess;
var meshObserver=入口.GetDataProvider<重要接口>();

#法2.2访问指定名称的网格观察者-调用下面的短泛型方法<x>(name)
var 系统=CoreServices.SpatialAwarenessSystem;
var 入口=spatialAwarenessService as IMixedRealityDataProviderAccess;
var 名称 = "Spatial Object Mesh Observer"
var meshObserver= 入口.GetDataProvider<重要接口>(名称)

CoreServices是MRTK中获取核心服务访问的静态类,这些服务就包括“输入系统 空间感知系统...”
GSASDP<x>()是类的一个泛型方法,用于获取空间感知系统中的某一特定数据提供者,由x指定。
IMixedRealitySpatialAwarenessMeshObserver是MRTK标准接口,定义了一些针对网格的方法。

接口:在面向对象编程中,除了类的概念,“接口”是一系列特定的“方法和属性”,但是并没有具体实现,任何类只要实现了接口中定义的所有方法,都可以认为该类实现了这个接口
泛型方法:xxx<T>(),T为类型参数,泛型方法具有处理多种不同类型数据的能力,以上述为例,系统中数据提供者可能有多个,它们定义的数据类型都不同,你难道要写多个方法来针对调用吗,只需要一个泛型方法GSASDP<>()传入类型参数T,它就知道处理谁了。

2.使用空间网格观察者来 开启/暂停 空间网格数据获取

#使用空间网格观察者来 开启/暂停 空间网格数据获取
#接法1-处理第1个空间网格观察者
观察者.Suspend();
观察者.Resume();
观察者.ClearObservations();

#接法2-处理指定的空间网格观察者
系统.ResumeObserver<x>(name);
系统.SuspendObserver<x>(name);
系统.ClearObservations<x>(name);

#接法2-处理所有的空间网格观察者
系统.ResumeObservers();
系统.SuspendObservers();
系统.ClearObservations();

3.网格数据获取

为了方便操作和语义区分,MRTK并不会把所有的表面点转换为几何网格,而是会按照一定的规则和语义划分到不同的几何网格,每个几何网格都有唯一的ID标识。

#用网格观察者查看所有网格
foreach (SpatialAwarenessMeshObject meshObject in observer.Meshes.Values)
{
    Mesh mesh = meshObject.Filter.mesh
}

observer.Meshes.values observer为网格数据观察者 .Meshes是网格字典 .values是网格游戏对象
.Filter.mesh .filter 是网格游戏对象的组件 用来访问网格的顶点,三角形等信息

4.控制网格数据的显隐
实际上就是控制网格数据观察者的配置文件中display option选项为visible/None/Occlusion

#设置网格数据观察者的可视性
数据观察者.DisplayOption=SpatialAwarenessMeshDisplayOptions.Visible
数据观察者.DisplayOption=SpatialAwarenessMeshDisplayOptions.None
数据观察者.DisplayOption=SpatialAwarenessMeshDisplayOptions.Occlusion

5.动态的开启或关闭整个感知系统

if(needDisable)
{
    CoreServices.SpatialAwarenessSystem.Disable();
}
else
{
    CoreServices.SpatialAwarenessSystem.Enable();
}

开发测试:便捷性开发方法

1.用现成的3d网格数据做测试开发
2.用扫描数据做测试开发

射线检测:获取物理层掩码

为了加速射线检测,我们只对目标层进行检测,所以需要目标物理层的掩码作为参数传给检测方法

//获取场景几何网格所在层掩码 以便 设置射线检测的物理层 来加速射线检测
private static int mPhysicsLayer = 0;
private static int GetSpatialMeshMask()
{
    if (mPhysicsLayer == 0)
    {
        var spatialMappingConfig = CoreServices.SpatialAwarenessSystem.ConfigurationProfile as MixedRealitySpatialAwarenessSystemProfile;
		//CoreServices.SpatialAwarenessSystem.ConfigurationProfile 拿到“服务.空间感知系统.配置文件”
		//as MixedRealitySpatialAwarenessSystemProfile 用as转换符将配置文件转换为xxx配置 转换成功就返回该类型对象 失败返回null
        if (spatialMappingConfig != null)
        {
            foreach (var config in spatialMappingConfig.ObserverConfigurations)//遍历系统配置文件下面的所有观察者配置
            {
                var observerProfile = config.ObserverProfile as MixedRealitySpatialAwarenessMeshObserverProfile;//当前观察者配置文件转换为xx类型配置
                if (observerProfile != null)
                {
                    mPhysicsLayer |= (1 << observerProfile.MeshPhysicsLayer);
					//获取当前观察者配置下面的"网格物理层"并将1位向左移这么多位
                }
            }
        }
    }
    return mPhysicsLayer;
}

射线检测:摄像机射线碰撞点

获取从主摄像机的位置向前方投射一个射线,并检查这个射线是否与某个物体(在特定的空间网格内)相交。如果相交,则返回碰撞点的位置;否则返回null

#6-12 获取摄像机发出的射线与网格的碰撞点
public static Vector3? GetPositionOnSpatialMap(float maxDistance = 10)
{
    RaycastHit hitInfo;
    var cameraTransform = Camera.main.transform;
    if (UnityEngine.Physics.Raycast(cameraTransform.position, cameraTransform.forward, out hitInfo, maxDistance, GetSpatialMeshMask()))
    {
        return hitInfo.point;
    }
    return null;
}

Vector3? 方法返回类型 指定该方法返回三维向量或者null
RaycastHIT hitInfp 结构体类型变量 存下了碰撞点的信息
Camera.main.transform 获取摄像机位置组件
UnityEngine.Physics.Raycast 核心方法 给出起点/方向/距离/层掩码 自动检测碰撞并保存信息
return hitInfo.point  返回碰撞点(三维向量)
 

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值