碰撞器与触发器
问题来源:在游戏对象上添加碰撞(collider)组件,勾选is_tragger选项。
碰撞体:
物理特征:碰撞体发生碰撞时,会依据物理特性(材质,速度,质量,摩擦力)发生位移旋转等。
触发事件:发生时会触发如OnCollisionEnter
、OnCollisionExit
和OnCollisionStay
的事件
事件响应:声明这样的类,编写内部行为,当事件发生时,会自动为对象调用该事件类。
触发器(勾选is_tragger)
物理特性:不再有了,这对一些射线的碰撞检测很有用
触发事件:OnTriggerEnter
、OnTriggerExit
和OnTriggerStay
事件响应:挂载的脚本组件内部声明事件类,触发该事件时,会自动调用方法
第六章 空间感知和映射
运动跟踪:定位与姿态估计原理
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 返回碰撞点(三维向量)