手部追踪示例
这个示例演示了如何启用手部追踪功能,如何使用SpacesHandTracking特性返回的数据,以及如何启用手部交互。要使用这个功能,必须在Snapdragon Spaces插件设置中启用,路径为:Project Settings > Snapdragon Spaces plugin.
警告! 请确保禁用OpenXRHandTracking插件,以防标准的手部追踪功能覆盖Spaces手部追踪。 |
示例工作原理
当打开示例后,用户将手放在头显相机的视野中时,手部追踪功能将启动。用户将看到每只手的网格模型。如果手部追踪被激活为输入模式,场景中的3D对象将变得可交互。根据选择的交互选项,场景中会生成不同的可交互对象。
下图展示了手部网格模型。
手部追踪
该示例使用了 BP_HandTrackingManager 蓝图资源(位于 SnapdragonSpacesSamples 内容 > SnapdragonSpaces > Samples > HandTracking > Placeable),用于控制场景中不同的交互选项,包括远程交互和近程交互。
要启用或禁用手部追踪,必须使用 Toggle Spaces Feature 方法,并选择手部追踪作为要启用的功能。通过这种方法,可以在项目的某些部分按需启用或停止手部追踪。
手部网格的启用可以通过 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 方法来获取,从而访问手部关节的位置和旋转信息。
要获取手部关节的变换,可以使用 GetKeypointStateForAHand 函数。GetKeypointStateForAHand 函数的参数包括 EControllerHand 和 EHandKeypoint,其中 EControllerHand 指定手部(右手或左手),EHandKeypoint 指定关节。该函数会返回一个布尔值,表示是否找到该手部关节。
手部网格
BP_HandMeshingViewer,位于 SnapdragonSpacesSamples 内容 > SnapdragonSpaces > Samples > HandTracking > Placeable,绑定了来自 AR Trackable Notify 组件的事件,以响应 AR 可追踪几何体的变化,并用于渲染手部网格,它触发 On Add/Update Tracked Geometry 事件,并且由于不同类型的对象可以被注册为 UARTrackedGeometry,要验证追踪的几何体是否是手部网格,必须检查对象分类是否为 EARObjectClassification::HandMesh,如果手部追踪是输入模式,BP_HandMeshingViewer 会在 BP_HandTrackingControllerComponent 中生成,并作为手部网格的渲染器使用。
可以使用 GetObjectClassification 函数来检查对象的分类。
警告! 在 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 版本中已被弃用。 |
警告! 在蓝图节点中,Unreal Engine 会将参数作为返回值进行引用。必须同时传递手部网格表示的演员引用和顶点数量的变量,否则可能会创建多个Actor。 |
手势
WBP_HandTrackingSample(位于 SnapdragonSpacesSamples Content > SnapdragonSpaces > Samples > HandTracking > UI)曾用于在手部网格和手部关节可视化之间切换,并显示每帧识别的手势。为此,使用了 HGestures Blueprint Library 类中的函数,每一帧中都会检查双手是否被跟踪,以及正在执行的手势,这是通过使用 Get XRHand Gesture Data 和 Is Hand Tracked 方法完成的。
手势数据包括以下参数:
● Type: 枚举值,表示检测到的手势类型。可能的手势有:{UNKNOWN, OPEN_HAND, GRAB, PINCH, ERROR}
● GestureRatio: 浮点值,范围从 0 到 1,表示手势的执行程度。
● FlipRatio: 浮点值,范围从 -1 到 1,表示手势是从背面(-1)、正面(1)还是介于两者之间的位置检测到的。
下图展示了 UI 上显示的左手手势类型和比例的检测结果。
手势跟踪交互
本节解释了使用手势跟踪交互所需的各种演员和组件。
警告! 手势跟踪交互不仅在手势跟踪示例中使用,还在项目中的所有示例中使用。这使得用户能够与支持手势跟踪的 UI 元素和 3D 元素进行交互。 |
Spaces 手势输入管理器
要使用手势跟踪交互,这个演员是最关键的。为了将手势跟踪设置为输入模式,需要将这个演员添加到场景中,建议使用“Spawn Actor of Class”节点来生成这个演员。
警告! 在将此演员添加到场景中或生成之前,请务必检查手势跟踪是否可用。 |
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:返回手部交互系统的状态。
空间手势交互
Spaces Hand Interaction 演员负责与关卡中不同的可手部交互元素进行交互,例如 3D 小部件和其他类型的演员。该演员支持远程手部交互(通过射线投射到场景元素上)和近程手部交互(当用手触摸可交互演员时激活)。Spaces Hand Interaction 演员会用从用户指定的手部开始的射线来表示。射线在使用近程交互时会变得不可见。射线有两种交互模式:激活(当射线投射到场景中的任何可手部交互演员上时)和未激活。射线的颜色和长度会根据这两种模式发生变化。要与 UI 进行交互,请使用远程交互和捏合手势。
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):启用或禁用此演员的交互状态。
Spaces手部交互
将此组件添加到参与物将使其可以与手部交互兼容,可以通过捏合和抓取手势来抓取带有此组件的参与物,在远端交互模式下,仅支持平移操作;在近端交互模式下,支持平移、旋转和缩放操作,其中缩放需要使用双手完成,可以调整以下变量来自定义其行为。
变量
● float LerpFactor:调节演员的平移和旋转速度。
● float ScaleLerpFactor:调节演员的缩放速度。
● float MinimumScaleFactor:演员可以应用的最小缩放因子。
● float MaximumScaleFactor:演员可以应用的最大缩放因子。
● bool bApplyTranslation:指示是否对演员进行平移。
● bool bApplyRotation:指示是否对演员进行旋转。
● bool bApplyScale:指示是否对演员进行缩放。
● FOnSpacesHandInteractableStateChanged OnSpacesHandInteractableStateChanged:委托/分发器,用于传达手部交互在演员上的状态,使用 ESpacesHandInteractableState 枚举返回状态(有关此枚举的使用方法,请参见下面的代码示例)。
此组件的一个使用示例是 BP_SpacesHandInteractableCube 蓝图演员,位于插件文件夹 SnapdragonSpacesSamples Content > SnapdragonSpaces > Samples > HandTracking > Placeable > InteractableObjects 中。
空间捕捉
Spaces Snapping Volume 组件继承自 Unreal Engine 的 Box Component,它主要用于将 SpacesHandInteraction 演员的射线端点捕捉到另一个演员的指定位置。这对于交互式 3D 小部件(如按钮、复选框或滑块)特别有用,但也适用于任何类型的 3D 演员。该组件可以添加到演员中,并需要手动放置在所需位置,例如在 3D 小部件的按钮上,如下图所示。
警告! 在将此组件用于 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 平面)取决于操作点在箱体中的位置。请使用捏合手势与交互箱进行交互。