手部追踪

手部追踪示例

这个示例演示了如何启用手部追踪功能,如何使用SpacesHandTracking特性返回的数据,以及如何启用手部交互。要使用这个功能,必须在Snapdragon Spaces插件设置中启用,路径为:Project Settings > Snapdragon Spaces plugin.



警告!

请确保禁用OpenXRHandTracking插件,以防标准的手部追踪功能覆盖Spaces手部追踪。

图片6.png


示例工作原理

当打开示例后,用户将手放在头显相机的视野中时,手部追踪功能将启动。用户将看到每只手的网格模型。如果手部追踪被激活为输入模式,场景中的3D对象将变得可交互。根据选择的交互选项,场景中会生成不同的可交互对象。

 

下图展示了手部网格模型。


图片7.png

 

手部追踪

该示例使用了 BP_HandTrackingManager 蓝图资源(位于 SnapdragonSpacesSamples 内容 > SnapdragonSpaces > Samples > HandTracking > Placeable),用于控制场景中不同的交互选项,包括远程交互和近程交互。

 

要启用或禁用手部追踪,必须使用 Toggle Spaces Feature 方法,并选择手部追踪作为要启用的功能。通过这种方法,可以在项目的某些部分按需启用或停止手部追踪


图片8.png


手部网格的启用可以通过 Toggle AR Capture 方法,将捕获类型设置为 Hand Meshing 来实现,也可以通过 Toggle Spaces Feature 方法来启用。


警告!

在 Snapdragon Spaces 版本 0.12.1 之前,手部网格的启用是通过 Set Hand Mesh Status 实现的,网格的可见性通过 Get Hand Mesh Status 方法来检查状态进行管理。



两个手部以运动控制器的形式表示,数据可以通过 Get Motion Controller Data 方法来获取,从而访问手部关节的位置和旋转信息。

 

图片9.png

 

要获取手部关节的变换,可以使用 GetKeypointStateForAHand 函数。GetKeypointStateForAHand 函数的参数包括 EControllerHand 和 EHandKeypoint,其中 EControllerHand 指定手部(右手或左手),EHandKeypoint 指定关节。该函数会返回一个布尔值,表示是否找到该手部关节。

 

图片10.png


手部网格

BP_HandMeshingViewer,位于 SnapdragonSpacesSamples 内容 > SnapdragonSpaces > Samples > HandTracking > Placeable,绑定了来自 AR Trackable Notify 组件的事件,以响应 AR 可追踪几何体的变化,并用于渲染手部网格,它触发 On Add/Update Tracked Geometry 事件,并且由于不同类型的对象可以被注册为 UARTrackedGeometry,要验证追踪的几何体是否是手部网格,必须检查对象分类是否为 EARObjectClassification::HandMesh,如果手部追踪是输入模式,BP_HandMeshingViewer 会在 BP_HandTrackingControllerComponent 中生成,并作为手部网格的渲染器使用。

 

 图片11.png


可以使用 GetObjectClassification 函数来检查对象的分类。

 

图片12.png


警告!

在 Snapdragon Spaces 0.13.0 版本之前,BP_HandMeshingViewer 并不存在,这项功能在 BP_HandTrackingManager 中实现。在 Snapdragon Spaces 0.12.1 版本之前,渲染手部网格的方法是使用 HGestures Blueprint Library 中的 Render Hand Mesh,该方法在 Snapdragon Spaces 0.13.0 版本中已被弃用。

图片13.png



警告!

在蓝图节点中,Unreal Engine 会将参数作为返回值进行引用。必须同时传递手部网格表示的演员引用和顶点数量的变量,否则可能会创建多个Actor。

   


图片14.png


手势

 

图片15.png


WBP_HandTrackingSample(位于 SnapdragonSpacesSamples Content > SnapdragonSpaces > Samples > HandTracking > UI)曾用于在手部网格和手部关节可视化之间切换,并显示每帧识别的手势。为此,使用了 HGestures Blueprint Library 类中的函数,每一帧中都会检查双手是否被跟踪,以及正在执行的手势,这是通过使用 Get XRHand Gesture Data 和 Is Hand Tracked 方法完成的。

 

图片16.png


手势数据包括以下参数:

● Type: 枚举值,表示检测到的手势类型。可能的手势有:{UNKNOWN, OPEN_HAND, GRAB, PINCH, ERROR}

● GestureRatio: 浮点值,范围从 0 到 1,表示手势的执行程度。

● FlipRatio: 浮点值,范围从 -1 到 1,表示手势是从背面(-1)、正面(1)还是介于两者之间的位置检测到的。

下图展示了 UI 上显示的左手手势类型和比例的检测结果。

 

图片17.png

 

手势跟踪交互

本节解释了使用手势跟踪交互所需的各种演员和组件。



警告!

手势跟踪交互不仅在手势跟踪示例中使用,还在项目中的所有示例中使用。这使得用户能够与支持手势跟踪的 UI 元素和 3D 元素进行交互。



Spaces 手势输入管理器

要使用手势跟踪交互,这个演员是最关键的。为了将手势跟踪设置为输入模式,需要将这个演员添加到场景中,建议使用“Spawn Actor of Class”节点来生成这个演员。

 

图片28.png

 

警告!

在将此演员添加到场景中或生成之前,请务必检查手势跟踪是否可用。

图片19.png


Spaces Hand Gesture Input Manager 演员负责实时监听手势,并通过委托报告基于这些手势的动作。它生成并拥有两个 ASpacesHandInteraction 类的演员,每只手一个,这些演员用于执行交互。以下是该类中可用的变量和函数:

 

变量

● FOnSpacesHandPinch OnSpacesHandPinchLeft 和 FOnSpacesHandPinch OnSpacesHandPinchRight:用于通知捏合手势状态的委托。

● FOnSpacesHandOpen OnSpacesHandOpenLeft 和 FOnSpacesHandOpen OnSpacesHandOpenRight:用于通知张开手势状态的委托。

● FOnSpacesHandGrab OnSpacesHandGrabLeft 和 FOnSpacesHandGrab OnSpacesHandGrabRight:用于通知抓取手势状态的委托。

● FOnSpacesHandInteractionStatusUpdated OnSpacesHandInteractionStatusUpdated:用于通知手部交互状态更新的委托,报告布尔值形式的状态。

● TSubclassOf<ASpacesHandInteraction> HandInteractionClass:用于生成手部交互演员的 Spaces Hand Interaction Actor 的子类。

● FVector LeftRayPositionOffset 和 FVector RightRayPositionOffset:两个手部交互演员的射线偏移量。

● float RayDistance:两个手部交互演员的射线距离。


函数

● ASpacesHandInteraction* GetHandLeftInteraction() const 和 ASpacesHandInteraction* GetHandRightInteraction() const:用于获取左手和右手的交互演员。

● void SetHandInteractionState(bool active):用于启用或禁用手部交互,该函数会影响整个手部交互系统。手部交互默认为禁用状态。

● void GetHandInteractionState() const:返回手部交互系统的状态。

 

图片20.png

 

空间手势交互

Spaces Hand Interaction 演员负责与关卡中不同的可手部交互元素进行交互,例如 3D 小部件和其他类型的演员。该演员支持远程手部交互(通过射线投射到场景元素上)和近程手部交互(当用手触摸可交互演员时激活)。Spaces Hand Interaction 演员会用从用户指定的手部开始的射线来表示。射线在使用近程交互时会变得不可见。射线有两种交互模式:激活(当射线投射到场景中的任何可手部交互演员上时)和未激活。射线的颜色和长度会根据这两种模式发生变化。要与 UI 进行交互,请使用远程交互和捏合手势。


图片21.png


图片22.png

 

Spaces Hand Interaction actor 可以通过以下变量和函数进行自定义:


变量

●  EControllerHand HandType:指定手是右手还是左手。

●  FVector RayPositionOffset:调整射线的位置,它是从肩部位置的偏移量。

● float RayDistance:射线投射的距离(单位为厘米)。

● float SnappingDistanceTolerance:在 Spaces Snapping Volume 组件上停止捕捉效果的距离。

● float DistalRayThresholdDistance:与聚焦的可交互对象的距离,这个距离决定了射线的可见性,从而切换近端和远端交互模式。

● float RayRepresentationLength:在使用远端交互且未击中任何可交互对象时射线的长度。

● UStaticMesh* RayMesh:用于视觉上表示手部射线的网格,这个网格将用于 Unreal Engine Spline Mesh 组件

●  UMaterialInterface* RayMaterial:射线网格的材质,需要与 Unreal Engine Spline Mesh 组件兼容

● FLinearColor HitRayColor:射线击中可交互对象时的颜色。

● FLinearColor NoHitRayColor:射线未击中可交互对象时的颜色。

● TSubclassOf<ASpacesHandJointCollider> HandJointColliderActorClass:用于近端交互的 ASpacesHandJointCollider 的子类。建议使用插件文件夹 SnapdragonSpaces > Content > HandTracking > Actors 中的 ASpacesHandJointCollider Blueprint 子类。


提示!

对于 Unreal Engine 的 Spline Mesh 组件,建议使用中间几何体足够丰富的网格,这样在有足够的样条点时可以实现弯曲效果。

要使材质与 Spline Mesh 组件兼容,请确保材质中的“用于样条网格”选项设置为启用(可以在 Details > Usage 中找到该选项)。

 

函数

●  FTransform GetGrabPointTransform() const:返回抓取点的变换。对于远端交互,将返回射线的端点;对于近端交互,将返回手部的变换。

●  FTransform GetOffsetTransform() const:返回可交互对象与抓取变换之间的偏移变换。

●  void SetHandInteractionState(bool active):启用或禁用此演员的交互状态。

 

图片23.png

 

Spaces手部交互

将此组件添加到参与物将使其可以与手部交互兼容,可以通过捏合和抓取手势来抓取带有此组件的参与物,在远端交互模式下,仅支持平移操作;在近端交互模式下,支持平移、旋转和缩放操作,其中缩放需要使用双手完成,可以调整以下变量来自定义其行为。


变量

●  float LerpFactor:调节演员的平移和旋转速度。

●  float ScaleLerpFactor:调节演员的缩放速度。

●  float MinimumScaleFactor:演员可以应用的最小缩放因子。

●  float MaximumScaleFactor:演员可以应用的最大缩放因子。

●  bool bApplyTranslation:指示是否对演员进行平移。

●  bool bApplyRotation:指示是否对演员进行旋转。

●  bool bApplyScale:指示是否对演员进行缩放。

●  FOnSpacesHandInteractableStateChanged OnSpacesHandInteractableStateChanged:委托/分发器,用于传达手部交互在演员上的状态,使用 ESpacesHandInteractableState 枚举返回状态(有关此枚举的使用方法,请参见下面的代码示例)。


图片24.png

 

此组件的一个使用示例是 BP_SpacesHandInteractableCube 蓝图演员,位于插件文件夹 SnapdragonSpacesSamples Content > SnapdragonSpaces > Samples > HandTracking > Placeable > InteractableObjects 中。

 

图片25.png

 

空间捕捉

Spaces Snapping Volume 组件继承自 Unreal Engine 的 Box Component,它主要用于将 SpacesHandInteraction 演员的射线端点捕捉到另一个演员的指定位置。这对于交互式 3D 小部件(如按钮、复选框或滑块)特别有用,但也适用于任何类型的 3D 演员。该组件可以添加到演员中,并需要手动放置在所需位置,例如在 3D 小部件的按钮上,如下图所示。

 

图片26.png


警告!

在将此组件用于 UI 时,必须遵循以下指南:

● 盒子的定位和大小必须与 3D 小部件组件的形状一致,否则可能会出现不期望的效果,例如射线投射到 3D 小部件演员之外时出现闪烁。

● 组件的 X 轴方向必须与 3D 小部件组件的方向对齐,以确保能正确与小部件组件进行交互。

   

要自定义此组件的行为,可以使用不同的变量和函数。

 

变量

● bool bSnap:决定组件是否用于捕捉。如果不启用捕捉,组件仍可以用于其他用途,例如 3D 小部件的滑块,在这种情况下,虽然无法将射线的端点捕捉到滑块手柄上,但仍然需要可视化手部射线以提升用户体验。

● bool bIsUI:当组件用于 3D 小部件 UI 组件的交互时,必须启用此选项。对于其他演员,可以禁用此选项。

● bool bIsDisabled:决定组件的碰撞是否从一开始就处于激活状态,默认情况下为 false。

 

函数

● void SetCollisionDisabledState(bool disabled):设置 bIsDisabled 的值。

● void UpdateCollisionStatus(bool active):更新组件的碰撞状态。如果 bIsDisabled 为 true,无论函数的输入值如何,碰撞都会被禁用。

 

空间远端交互盒

BP_SpacesDistalInteractionBox 允许通过远端交互来旋转和缩放参与物,要使用它,必须将其作为子参与物组件添加到要操作的参与物中。可以在 SnapdragonSpaces Content > Hand Tracking > Actors 下找到 BP_SpacesDistalInteractionBox。有关如何将 BP_SpacesDistalInteractionBox 添加到另一个演员的示例,请查看 BP_PandaInteractable ,位于 SnapdragonSpacesSamples Content > Snapdragon Spaces > Samples > HandTracking > Placeable > InteractableObjects 中。远端交互箱由多个 Spaces Distal Manipulator Actor 实例组成,每个实例被称为“操作点”。Spaces Distal Manipulator Actor 有两种类型:Spaces Distal Scale Point 和 Spaces Distal Rotation Point。不同的操作点在箱体中的位置不同,具有不同的行为,位于箱体边缘的操作点用于调整演员的缩放,其余操作点用于执行不同的旋转操作,具体旋转轴(X、Y 或 Z 平面)取决于操作点在箱体中的位置。请使用捏合手势与交互箱进行交互。

 

图片27.png