4.SDK常用组件
此章节将详细介绍SDK常用的组件,如果您是初学者,建议您对照SDK中的demo场景,一一检查如下组件的设置以及说明。
如果您已经有相关开发经验,您可以在此章节中查找每个组件设置项的详细说明。
下面内容主要介绍组件的常规使用方法,没有写明具体API,如果您需要调用具体的API,可以查看 API文档
4.1 基础组件
SDK基础组件是指封装在 RhinoX-Unity.dll 中的组件 ,主要包括以下几种类型 :
ARCamera, TrackableIdentity, DynamicTarget, GroundPlane, RxController, RxInput, RxButtonEventTrigger, RxEventSystem, RxInputModule.
1.ARCamera
ARCamera介绍
ARCamera 代表头显。 用于控制和头显相关的功能, 包括位置跟踪,双目渲染。
创建方式: 在 Hierarchy 对象列表中使用右键弹出菜单创建 ARCamera ,如果场景里面已经有其他Camera,需要将其删除:
创建完成后,ARCamera会自动生成在父对象 ARCameraRig下面,且ARCamera对象上会自动挂载ARCamera Script, ARCamera的相关配置都是通过此脚本控制。
注解
开发者不应该改变 ARCamera 和 ARCameraRig 的层级结构。 并且不应该移动 ARCamera 的位置。 如果需要改变 ARCamera 的起始位置,请移动 ARCameraRig 而不是 ARCamera.
在应用启动以后, ARCamera的实时位置代表了用户的头部位置。
ARCamera 的配置界面:
ARCamera属性
这里主要介绍GUI界面上的设置,以及您可能需要用到的一些API,详细API以及用法您可以查看 ARCameraAPI
TrackPosition : 是否随着用户的头部运动而更新位置。
TrackRotation : 是否随着用户的头部运动而更新朝向。
Tracking Profile : 挂载设置好的Tracking Profile,不能为空, 具体见下节 Tracking Profile 对象介绍。
Enable Reticle: 是否启动头瞄模式。 头瞄模式下, 用户通过瞄准准星以及头显上的 OK 键对UI进行交互。
Reticle Image : 头瞄准星的纹理贴图。
Reticle Interact Mask : 头瞄交互的对象层级。需要被头瞄交互的模型的Layer需要被包含在此层级里面,此处可选择多个层级。
SetObjecTrackingProfile(ObjectTrackingProfile newProfile): 使用此方法在运行时加载新的 ObjectTrackingProfile, 以此实现动态替换跟踪物体。 如果传入参数为Null,则此方法会清空当前已经加载的跟踪物体库。
LoadTrackingFile(string jsonFilePath): 使用此方法加载任意路径的跟踪数据文件,例如从互联网上下载保存到sdcard上的文件。
RecenterTracking(): 对ARCamera 做归中操作,调用后, ARCamera 的transform 的local position 和 local rotation 都会归零。
静态事件 : OnCreateStereoCameras : ARCamera在启动以后,会自动在transform层级下创建左右双目Camera, 如果要实现后处理特效, 需要通过 OnCreateStereoCameras 事件添加后处理组件.
代码示例: 在 ARCamera.OnCreateStereoCameras 添加后处理组件, (完整代码: https://gitee.com/PolyEngine_Ent/rhino-x-rendering-demo)
void Awake()
{
//在 ARCamera.OnCreateStereoCameras 事件中,添加后处理脚本:
//这个事件在Unity编辑器上不会触发,只有在RhinoX设备上运行的时候才会触发.
ARCamera.OnCreateStereoCameras += ARCamera_OnCreateStereoCameras;
}
private void ARCamera_OnCreateStereoCameras(Camera left, Camera right)
{
//创建左右眼上的后期效果:
if (!isEffectScriptCreated)
{
leftEffectFx = left.gameObject.AddComponent<Bloom>();//添加Bloom后效组件
rightEffectFx = right.gameObject.AddComponent<Bloom>();//添加Bloom后效组件
}
}
代码示例: 等待 ARCamera 启动完成
private IEnumerator Start()
{
if (Application.platform == RuntimePlatform.Android)
{
while (ARCamera.Instance == null || ARCamera.Instance.IsARBegan == false) //等待 ARCamera 启动完成.
{
yield return null;
}
Debug.Log("ARCamera is started");//此时,定位系统和渲染系统都已经启动。
}
}
//从 v1.5 开始 , 可以通过 ARCamera.OnRhinoXSDKInitialized 事件获取 ARCamera 启动完成事件。
ARCamera.OnRhinoXSDKInitialized += ()=> {
Debug.Log("ARCamera is started");//此时,定位系统和渲染系统都已经启动。
};
2.Tracking Profile
Tracking Profile主要是用来定义ARCamera需要跟踪的定位信标的配置组件,通常默认的Tracking Profile配置为可识别Beacon。 如果需要识别其他定位信标,需要新建Tracking Profile,并添加对应标定文件。
按照如下图路创建Tracking Profile
默认创建的Tracking Profile如下图,勾选了Track Beacons,表示此文件默认支持跟踪Beacon1,2,3。如果您只需要跟踪Beacon 则可以不用做任何修改,直接使用默认配置,将他挂载在ARCamera上即可
如果您已经购买了我们的其他定位信标,如地灯,或者侧发光灯等等,您需要勾选Additive Tracking,然后添加需要跟踪信标的 标定文件
标定文件和标定数据 : 在 Assets/Plugins/Android/assets 下的json文件称为标定文件, dat 文件称为标定数据,两者均为 标准文件,不可修改。
json 文件定义了marker的ID和尺寸, 和引用的标定数据。
{
"CARD_SINGLE":
{
"CalibFile": "CARD-500-40.dat",
"Markers": [2, 6, 8, 11, 12, 13, 15, 16, 18, 19, 21, 22, 23, 24, 26, 64],
"MarkersSize": [0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04]
}
}
如果要实现对其他定位信标的跟踪,则需要添加额外的跟踪文件,只需要勾选 Additive tracking 选项,并将对应的 Json 文件拖动到GUI的添加区域上即可,如下图所示。
注解
不需要添加额外的跟踪数据文件来跟踪控制器, 控制器跟踪文件是内置的。
如果没有对应定位信标的标定文件,请联系技术支持人员。
警告
被Tracking Profile引用的Json文件必须放置在 Assets/Plugins/Android/assets 目录下。
3.TrackableIdentity
Trackable identity 组件定义跟踪定位信标 的 ID 信息。 Dynamic Target 和 Ground Plane 都需要 Trackable identity 组件,创建时会自动添加在他们上面。
Target 字段 定义定位信标的id , 内置了 Beacon 01/02/03 和 left / right 控制器的ID。除此之外的其他定位信标需要选择Custom, 通过Custom ID来设置定位信标的ID。
OnVisibilityChanged 事件 当定位信标出现/消失在跟踪区域的时候, 触发此事件。可以通过此事件触发定位信标跟踪或者消失 后的行为。
Tracking Log 如果为true,则在logcat中打印跟踪数据。
trackableIdentity.OnVisibilityChange.AddListener(
(bool visible) => Debug.LogFormat("Marker becomes visible: {0}", visible));
4.Dynamic Target
Dynamic Target 组件定义跟踪定位信标的跟踪行为:当定位信标进入Camera的跟踪区域时,Dynamic Target 对象会实时 更新他相对于 ARCamera 的Transform值。
手柄就是最典型的DynamicTarget对象,如果您需要跟踪的定位信标的使用方式与手柄类似,例如拿着一个定位信标在空间 中随意的移动,那么建议您将其创建为DynamicTarget对象。
注解
如果要让某一个模型跟随Dynamic Target对象移动,那么你需要将此模型添加在DynamicTarget下面,与其绑定在一起。 这也是他与接下来要讲的 Ground Plane 的根本区别,GroundPlane是控制整个场景的位置,不是某一个模型。
YawOnly:如果为true, 则Dynamic Target只更新transform 的Yaw轴朝向。 此模式适用于假设定位信标永远水平放置的情况。
Lost Tracking Behaviour: 如果是 Stay,当定位信标丢失跟踪的时候,会停留在最后一次出现的世界空间位置。 如果是 Follow,当定位信标丢失跟踪的时候,会停留在最后一次相对于头部空间的位置,并一直跟随头部运动。这个模式适用于代表用户的双手的控制器跟踪, 在丢失跟踪的情况下, 还可以使用陀螺仪控制其朝向。
DebugView:如果为true,渲染一个Gizmos。在调试阶段不确定是否跟踪到定位信标的情况下,可以勾选此设置。
5.Ground Plane
GroundPlane 如其名字所示,他的功能是做为世界坐标的中心点,实际应用中的作用是用来定位虚拟场景的原点位置。 GroundPlane有 Wall 和 Ground 两种模式。通常我们将作为GroundPlane的定位信标平放在地上使用,即使用Ground模式
如果您需要将作为GroundPlane的定位信标贴在墙上或者竖直立着使用,则需要将其设置为Wall模式,前面提到的DynamicTarget因为 可以在空间中随意移动,所以没有这两种模式之分。
注解
由于GroundPlane的特殊作用,他只在Yaw方向上可以改变场景的朝向,在其他方向旋转不会生效
如果作为Ground模式使用,则只在贴着地面旋转时才改变场景的朝向,沿着其他方向不改变
如果作为Wall模式使用,则只在贴着墙面旋转时才改变场景的朝向,沿着其他方向不改变
Beacon就是最典型的GroundPlane,如果您需要跟踪的定位信标的使用方式与Beacon类似,则将其设置为GroundPlane对象
注解
GroundPlane的作用是控制整个场景的原点位置,只需要将他创建在工程的根目录下即可,不需要将任何模型或者场景绑定在他下面。
RecenterMode : 默认是Automate , 当作为Ground Plane的定位信标进入跟踪区域,并且满足跟踪配置的时候, 自动矫正头部位置。 如果是 Scripting, 代表开发者要自行控制矫正头部的时机, 可以调用静态方法 GroundPlane.ForceRecenter() 来实现程序化的头部矫正功能。
Placement : 定义定位信标的放置方式是水平还是竖直,设置为Wall模式时,定位信标可以贴在墙上(竖直放置)使用。
DecoupleVIO : 当GroundPlane矫正头部位置的时候,停用MR头显的VIO跟踪系统。这是只有进阶开发者才需要用到的功能。
Recenter Condition 参数配置说明:
UseBestConfidence : 只采用最高跟踪置信度时的数据来矫正头部的位置, 如果勾选此选项,会降低头部矫正的频率,提高矫正的精度。建议大部分开发者不要勾选此选项。
MinTrackAngle : 定位信标最小可跟踪角度。当定位信标和跟踪相机的夹角小于这个角度的时候, 不使用定位信标数据,即小于这个角度时 定位信标不起作用。建议保留默认值: 28˚
MinTrackDistance 和 MaxTrackDistance : 定位信标可跟踪距离范围。对于随箱Beacon,跟踪范围建议设置为0-1.5米. 如果使用主动 发光定位信标, 跟踪距离范围建议设置为 0 - 5米。
MaxRecenterAngularVelocity : 当用户的头部在快速转动,并且转动角速度大于此配置值的时候,不予矫正头部位置,因为可能造成用户晕眩。
MinTrackedConfidence : 最小跟踪置信度,当跟踪数据置信度小于这个值的时候, 不予矫正。建议保留默认值: 0.85
注解
置信度可以简单理解为跟踪数据的可信度,置信度越大,跟踪数据越稳定,但是会相应减小跟踪范围。置信度越小则更容易出现跟踪 抖动,但是可以包含更大的跟踪范围。
Min Error Head Distance 和 Min Error Head Diff Angle : 控制GroundPlane 归中时候的允许误差。当位置偏差超过这个值时 才会对头显进行校正,如果小于这个值,即使发生了偏移,也不会进行校正
注解
如果这两个数值太小, GroundPlane 会频繁归中ARCamera造成用户视觉上的瞬移感。
如果这两个数值太大, GroundPlane就会失去归中的功能。
对于Beacon我们建议用户保留默认的数值设置 :
MinTracked Distance = 0;
Max Tracked Distance = 1.5;
Head Error Distance = 0.12;
Head Error Diff Angle = 15;
对于主动发光板,建议采用如下数值:
MinTracked Distance = 0;
Max Tracked Distance = 5;
Head Error Distance = 0.2;
Head Error Diff Angle = 20;
OnFirstRecenter 事件 : 当GroundPlane对象第一次矫正用户头部的时候触发。 开发者可以使用此事件来实现“进入AR世界”的触发机制。
6.RxController
此组件代表控制器
Index: 定义控制器的类型,包括左右手柄以及预留的ID Preserve03, 04。
MinTrackConfidenceUse 和 Min Track Confidence Recenter IMU : 代表控制器的最小可跟踪置信度。一般不需要自定义, 保留默认值。
Tracking Mode : 跟踪模式, 默认是6DOF跟踪, 如果是3DOF跟踪模式, 则只保留陀螺仪跟踪朝向,不采纳位置跟踪。
注解
在只需要使用3dof数据,且对数据稳定性要求较高时可使用此模式,例如使用虚拟键盘输入时。
ConnectionEvent : 控制器连接事件,控制器连接或者断开时上报。用户可以使用此事件,控制手柄模型的显示/隐藏的功能。
Raycasting 相关设置: 如果Physics-Raycasting 打开, 则RhinoX事件系统会每帧发射Raycasting实现物理检测。射线的起点是 RaycastOrigin 字段指向的 Transform。
Raycast Culling Mask 定义交互对象的层级。需要被交互的模型的Layer层级,必须包含在此层级里面才可以被控制器射线交互。
RaycastDistance : 交互射线的长度。
RenderRay : 是否渲染交互射线的 LineRenderer。
RayRenderer : 交互射线 LineRenderer。
Ray Hit Point : 交互射线的焦点。此对象应该是一个场景对象而不是一个资源引用。可以为空。
DebugMode : 如果为true,在logcat中打印按键和跟踪数据。
注解
当控制器和头显建立连接之后,SDK会自动设置RxController上的TrackableIdentity组件的Marker ID。
8.RxInput 静态类
RxInput 静态类提供轮询式查询按键事件。 和 RxButtonEventTrigger 的响应式事件机制形成互补。
查询双击按键代码示例:
private void Update()
{
if(RXInput.IsButton(RhinoXButton.ControllerTrigger, ControllerIndex.Controller_Right_Controller))
{
Debug.Log("User is pressing button : trigger"); //用户一直按着右手控制器的trigger按键,每帧触发。
}
if (RXInput.IsButtonTap(RhinoXButton.ControllerTrigger, ControllerIndex.Controller_Right_Controller))
{
Debug.Log("User clicks button : trigger"); //用户点击右手控制器的trigger按键, 只会在点击的时候触发一次。
}
if (RXInput.IsButtonLongHeldDown(RhinoXButton.ControllerTrigger, ControllerIndex.Controller_Right_Controller))
{
Debug.Log("User long hold button : trigger"); //用户长按右手控制器的trigger按键, 只会在松开按键之前触发一次。长按时间配置见 ProjectSetting/RhinoX Setting
}
}
9.事件系统
事件系统组件包括:RxEventSystem、RxInputModule
这是RhinoX 的事件系统中枢组件。场景中必须存在这两个组件才能确保 RxController 的raycast射线可以和 Unity 的事件系统交互, RxController, RxInput 等交互组件才可以正常工作。
RxEventSystem 和 RxInputModule是重要的功能性接口方法, 它们的职责主要是事件调度,将RhinoX的事件和Unity的事件系统联动起来。
代码示例: 使用 unity event system 和 RxController 的射线系统交互:
using UnityEngine.EventSystems;
public class RecordButton : MonoBehaviour, IPointerEnterHandler //当射线接触到某个可交互层级的物体时候, 该物体上的script会接收到 OnPointerEnter 事件
{
public RXController leftController, rightController;
void IPointerDownHandler.OnPointerEnter (PointerEventData eventData) {
var raycasterTransform = eventData.pointerCurrentRaycast.module.transform;
bool isRaycastFromLeftHand = raycasterTransform.IsChildOf(leftController.transform);//是否被左手控制器射线命中
bool isRaycastFromRightHand = raycasterTransform.IsChildOf(rightController.transform); //是否被右手控制器射线命中
Debug.LogFormat ("Is raycast hit by right hand : {0} , is raycast hit by left hand: {1}", isRaycastFromRightHand, isRaycastFromLeftHand);
}
}
public class RecordButton : MonoBehaviour, IPointerExitHandler //当射线离开某个可交互层级的物体时候, 该物体上的script会接收到 OnPointerExit 事件
{
public RXController leftController, rightController;
void IPointerDownHandler.OnPointerExit (PointerEventData eventData) {
var raycasterTransform = eventData.pointerCurrentRaycast.module.transform;
bool isRaycastFromLeftHand = raycasterTransform.IsChildOf(leftController.transform);//是否被左手控制器射线命中
bool isRaycastFromRightHand = raycasterTransform.IsChildOf(rightController.transform); //是否被右手控制器射线命中
Debug.LogFormat ("Is raycast exit by right hand : {0} , is raycast exit by left hand: {1}", isRaycastFromRightHand, isRaycastFromLeftHand);
}
}
public class RecordButton : MonoBehaviour, IPointerClickHandler //当射线停留在某个可交互层级的物体时候,用户按下trigger键, 该物体上的script会接收到 OnPointerClick 事件
{
public RXController leftController, rightController;
void IPointerDownHandler.OnPointerClick (PointerEventData eventData) {
var raycasterTransform = eventData.pointerCurrentRaycast.module.transform;
bool isRaycastFromLeftHand = raycasterTransform.IsChildOf(leftController.transform);//是否被左手控制器射线命中
bool isRaycastFromRightHand = raycasterTransform.IsChildOf(rightController.transform); //是否被右手控制器射线命中
Debug.LogFormat ("Is raycast click by right hand : {0} , is raycast click by left hand: {1}", isRaycastFromRightHand, isRaycastFromLeftHand);
}
}
上面的内容主要是给大家介绍各组件的功能以及使用场景,具体需要调用的API,大家可以参考 API文档
4.2 交互组件
这里我们主要提供几种MR交互种最常用的几种交互功能组件
他们包括 : Touchable(触碰) / Grabable(抓取) / Throwable(抛掷) / Outline(勾边) / PlayerHand(用户的虚拟手部动画控制) / FrontDocker (UI 锚定眼前位置)。
交互组件是应用层脚本, 设计初衷是实现虚拟对象的物理交互功能,例如抓取物体, 抛掷物体等。
注解
交互组件是开源的C#代码, 放在在 SDK 的 OpenSource 目录中, 开发者可以按照自己的需求改动代码。
如何创建可交互的对象?
因为这些交互组件都是已脚本的形式提供给大家,如果您需要创建一个可交互的对象,您只需要在该对象的Inspector下面添加 对应的脚本即可。
1.Touchable & Touchable Unity Event
Touchable 代表一个可以被触摸的物体。 触摸是通过物理射线(也就是RxController上的raycaster)与 被交互模型上的碰撞体接触实现。所以 touchable 物体上需要有处于可交互层级的collider。
Touchable Unity Event 则将触碰的事件以GUI的形式展示出来,开发者可以调用这些事件实现需要的功能。
LongTouchTime : 触发长时间触碰事件 / OnLongTouch() 的时间预值。
LongTouchTrigger : 触发OnLongTouch()事件的控制机制, 是否可以反复多次触发。如果为Once,则在射线进入-离开这个交互周期内, 只触发一次。
2.Grabable & Grabable Unity Event
Grabable 代表一个物体可以被抓取的行为。
Grabable Unity Event 将 Grabable 的事件以GUI的形式展示出来,开发者可以调用这些事件实现需要的功能。
OnGrabBegin:当抓取发生的时候触发
OnGrabUpdate:正在抓取的过程中, 每帧触发一次
OnGrabEnd: 当抓取结束的时候触发
GUI功能定义如下:
TriggerAction : 定义用户抓取物体的触发方式。
Button Down and Up - 在按下按键的时候抓取, 在松开按键的时候释放物体。
Touch - 在触碰到物体的时候自动抓取。在按下按键的时候释放物体。
ButtonClick - 在第一次点按(也就是按下-松开)的时候抓取,在第二次点按的时候释放。
AnchorTransform : 抓取锚点, 必须是 Grabable的子对象,此Transform定义当抓取的时候, grabable物件与手部对齐的位置锚点。
Tween To Player Hand 是否在抓取的时候, 控制Grabable 对象飞到用户的虚拟手上。
Tween Duration 如果Tween To Player Hand为true,控制飞到用户手上的时间长度。
Align Mode 控制物体被抓取的时候, 如何处理其朝向。 如果为 Full Align , 则朝向会和抓取锚点的朝向一致。 如果为 Dont Align ,则保持抓取前的朝向。
CanBeGrabByOtherHand 是否可以在被一只手抓取的时候,被另一只手交换抓取。
3.Throwable & Throwable Unity Event
Throwable 代表一个物体可以被抓取后抛出的行为。 Throwable 组件依赖于 Grabable和Rigidbody, 基于Unity的物理系统实现。
Throwable Unity Event 将 Throwable 的事件以GUI的形式暴露给开发者 : OnThrown 事件,当物体被抛出的时候触发。
- Throwable Behaviour Type 定义抛掷的行为模式。
Throw away: 是默认的模式,模拟用户抛掷物体的行为。
Eject: 是模拟射箭的模式, 用户不需要挥舞手部运动, 只需要按下按键,Throwable物体就会像箭一样发射。
UseGravity 定义当发射之后,是否对Rigidbody应用重力。
Eject Force 当 Throwable Behaviour Type 为 Eject 的时候有效, 定义发射的力度。
Disallow Grabable After Thrown 如果为true,当物体被抛掷之后, 禁用Grabable 组件。使用此功能模拟一些抛掷之后过一会就自动消失的,一次性的小物体,例如飞镖,小石块等。
Rigidbody 绑定的Rigidbody对象。
Speed Max 对抛掷之后限制的最大速度,使用此字段避免用户用力过大造成物体飞出太远的问题。
Multiplier 用户抛掷力的系数。
4.FrontDocker
FrontDocker 组件用于将Canvas锚定在用户眼前,如果您需要将某个UI固定在用户视野前方,跟随头显的转到而移动,您可以使用此组件。 您可以使用此组件强制某个UI一直显示在眼前,或者控制头显转动导致某个UI消失在视野之后,将UI再次自动定位到用户眼前。
Z Depth UI与Camera的距离
Force EveryFrame 是否每帧更新位置。 如果为true, 则Canvas会一直锚定在用户眼前。
Angle Diff Error 当Force EveryFrame为false时,控制头部偏转一定的角度后,UI才重新锚定到用户眼前。
Dock Delay UI被重新锚定到眼前的延时。
Dock DampTime UI被重新锚定到眼前过程发生的时长。
Follow With Pitch 是否会随着用户俯仰角度的变化而变化。
Position Offset 在最终锚点上的位置偏移。