1.前言
求解器是有助于根据预定义算法计算对象位置和方向的组件。 示例:将对象放置在与用户注视视线相交的表面。
求解器系统确定性地定义这些转换计算的运算顺序,因为没有可靠的方法向 Unity 指定组件的更新顺序。
求解器提供一系列行为,以将对象附加到其他对象或系统。 另一个示例是一个尾随对象,该对象悬停在用户前面(基于摄像机)。 求解器还可以附加到控制器和对象,使对象尾随控制器。 所有求解器都可以安全地堆叠,例如尾随行为加表面磁性加动量。
2.求解器的使用
- 求解器系统由三类脚本组成:
- Solver:抽象基类,所有求解器都派生自该类。 它提供状态跟踪、平滑参数和实现、自动求解器系统集成和更新顺序。
- SolverHandler:设置跟踪的参照对象(例如:主摄像头转换、手部射线等),处理求解器组件收集以及按正确顺序执行更新。
- 第三个类别是求解器本身。 以下求解器提供基本行为的构建基块:
求解器类型 | 描述 |
Orbital | 锁定到指定位置并偏离参照对象 |
ConstantViewSize | 应缩放以保持相对于参照对象视图不变的大小 |
RadialVie | 使对象保持在参照对象的视锥投射范围内。 |
ConstantViewSize | 应缩放以保持相对于参照对象视图不变的大小 |
Follow | 使对象保持在参照对象的一组用户定义边界内。 |
InBetween | 使对象保持在两个跟踪对象之间。 |
SurfaceMagnetism | 将射线投射到世界中的表面上,并使对象对齐到该表面。 |
DirectionalIndicator | 确定作为方向指示器的对象的位置和方向。 从 SolverHandler 跟踪目标的参照点来看,此指示器将面向提供的 DirectionalTarget。 |
Momentum | 应用加速/速度/摩擦来模拟由其他求解器/组件移动的对象的动量和弹性。 |
HandConstraint | 约束对象,使其在 GameObject 不会与手部交叉的区域跟随手部。 对手部约束的交互式内容(如菜单等)很有用。此求解器旨在与 XRNode 一起使用。 |
HandConstraintPalmUp: | 派生自 HandConstraint,但包含用于测试手部在激活前是否手掌面向用户的逻辑。 此求解器只能与 XRNode 控制器一起使用,如果与其他控制器类型一起使用,此求解器的行为类似于基类。 |
Overlap | 与跟踪的对象重叠。 |
3.更改跟踪参照
- SolverHandler组件的“TrackedTargetType”属性定义所有求解器将用于计算其算法的参考点。 例如,具有简单SurfaceMagnetism组件的Head值类型将产生从头部开始,沿着用户凝视方向发射出去的射线,用于求解射线到达的表面。TrackedTargetType属性的可能值包括:
- Head:参照点是主摄像头的转换
- ControllerRay:参考点是控制器上指向射线方向的 LinePointer 转换(即运动控制器或手操控制器上的指针原点), 使用 TrackedHandedness 属性选择惯用手偏好(即左手和/或右手)
- HandJoint:参照点是特定手部关节的转换,使用 TrackedHandedness 属性选择惯用手偏好(即左手和/或右手),使用 TrackedHandJoint 属性确定要利用的联接转换。
- CustomOverride:参照点来自于已分配的 TransformOverride。
4.创建新的求解器
- 所有求解器都必须继承自抽象基类 Solver。 求解器扩展的主要要求涉及重写 SolverUpdate 方法。 在此方法中,开发人员应将继承的 GoalPosition、GoalRotation 和 GoalScale 属性更新为所需值。 此外,将 SolverHandler.TransformTarget 用作使用者所需的参考系十分有益。
- 下面提供的代码提供了名为 InFront 的新求解器组件的示例,该组件将附加对象放在 SolverHandler.TransformTarget 前面 2 米处。 如果使用者将 SolverHandler.TrackedTargetType 设置为 Head,则 SolverHandler.TransformTarget 将是相机转换,因此该求解器会在每一帧将附加的 GameObject 放在用户凝视的前面的 2 米处。
public class InFront : Solver { public override void SolverUpdate() { if (SolverHandler != null && SolverHandler.TransformTarget != null) { var target = SolverHandler.TransformTarget; GoalPosition = target.position + target.forward * 2.0f; } } }
5.求解器属性
每个求解器组件都有一组核心属性,这些属性是相同的,用于控制求解器行为。
如果启用了“Smoothing”,则求解器将随着时间的推移,将 GameObject 的转换逐渐更新为计算值。 每个转换组件的“LerpTime”属性确定了此更改的速度。 例如,MoveLerpTime 值越高,帧之间的移动增量就会越慢。
如果启用了 MaintainScale,求解器将利用 GameObject 的默认局部缩放。
5.1.Orbital
- Orbital 类是一个尾随组件,其行为类似于太阳系中的行星。 此求解器将确保附加的 GameObject 围绕着跟踪转换旋转。 因此,如果 SolverHandler 的“Tracked Target Type”设置为 Head,则 GameObject 将按照所应用的固定偏移量,围绕用户的头部旋转。
- 可以修改此固定偏移量,以使菜单或其他场景组件保持在眼睛或腰部的高度,围绕在用户周围。 这可以通过更改“Local Offset(局部偏移量)”和“World Offset(全局偏移量)”属性完成。 “Orientation Type(方向类型)”属性确定应用于对象的旋转,例如,对象应始终保持原始旋转,或者总是面向摄像头,或者面向驱动其位置的转换。
5.2.RadialView
- RadialView 是另一个尾随组件,用于使 GameObject 的特定部分保持在用户视野的圆锥体内。
“Min和Max View Degrees”属性决定了 GameObject 必须始终在视线范围内的部分的面积。
“Min和Max Distance”属性决定了 GameObject 应该与用户保持多远距离。 例如,如果“Min Distance”为 1 米,走向 GameObject 会将 GameObject 推开,以确保它永远不会距离用户短于 1 米。
通常,RadialView 与设置为 Head 的“TrackedTargetType(跟踪目标类型)”一起使用,这样组件就会跟随用户凝视。 但是,此组件可以发挥作用,以保持在任何跟踪目标类型的“视线”范围内。
5.3.Follow
- Follow 类将元素定位在跟踪目标的前面,相对于其局部前向轴。 该元素可以是松散约束型(也称为“尾随”),这可以确保在跟踪目标移动到用户定义的边界之外之前它不会跟随。
它的工作方式类似于 RadialView 求解器,但具有更多控制,可以管理“Max View Horizontal和Vertical Degrees(最大水平和垂直视场角度)”,此外还有用于更改对象“方向”的机制
5.4.InBetween
- InBetween 类使附加的 GameObject 保持在两个转换之间。 这两个转换终结点由 GameObject 自己的 SolverHandler“TrackedTargetType(跟踪目标类型)”和 InBetween 组件的“第二个跟踪目标类型”属性定义。 通常,这两个类型都将设置为 CustomOverride,产生的 SolverHandler.TransformOverride 和 InBetween.SecondTransformOverride 值将设置为两个跟踪的终结点。
在运行时,InBetween 组件将基于“第二个跟踪目标类型”和“第二个转换覆盖”属性再创建一个 SolverHandler 组件。
PartwayOffset 定义将在直线上两个转换之间的哪个位置放置对象,0.5 表示中间,1.0 表示第一个转换,0.0 表示第二个转换。
5.5.SurfaceMagnetism
- SurfaceMagnetism 的工作方式是对一组表面的 LayerMask 执行光线投射,并将 GameObject 放置在接触点。“Surface Ray Offset(表面垂直偏移)”按照设定好的距离表面的距离(米),沿着表面上击中点处的法线方向放置 GameObject。相反,“Surface Ray Offset(表面射线偏移)”按照设定好的距离表面的距离(米),沿着所执行光线投射的相反方向放置 GameObject。 因此,如果光线投射是用户凝视的方向,则 GameObject 将沿直线从表面上的击中点向摄像头靠近。
- “Oriention Mode(方向模式)”确定相对于表面上的法线应用的旋转类型。
- None(无) - 不应用旋转
- Tracked Target(跟踪目标) - 对象将面向驱动光线投射的跟踪转换
- Surface Normal(表面法线) - 对象将基于表面上的击中点对齐
- Blended(混合) - 对象将基于表面上的击中点对齐,并且面向跟踪转换。
- 要强制关联的 GameObject 在除“None”以外的任何模式下都保持垂直,请启用“Keep Orientation Vertical(使方向保持垂直)”。
5.6 Overlap
- Overlap是一个简单的求解器,它将使对象的转换保持与转换目标相同的位置和旋转SolverHandler’s。
5.7 SurfaceMagnetism
- 将 SurfaceMagnetism 组件添加到 GameObject 时,必须考虑 GameObject 及其子代的层(如果任何子代有碰撞器)。 该组件的工作方式是执行各种光线投射,以确定哪些表面可以“吸附”光线。 假设求解器 GameObject 在 SurfaceMagnetism 的 MagneticSurfaces 属性所列的其中一个层上有碰撞器。 在这种情况下,光线投射很可能会击中自己,导致 GameObject 附加到其自己的碰撞器点。 这种异常行为是可以避免的,方法是将主 GameObject 和所有子代设置为“忽略光线投射”层或相应地修改 MagneticSurfaces LayerMask 数组。
- 相反,SurfaceMagnetism GameObject 不会与 MagneticSurfaces 属性中未列出的层上的表面发生碰撞。 建议将所有需要的表面放在专用层(即图面)上,并将 MagneticSurfaces 属性设置为仅此层。 使用“默认”或“全部”可能会导致 UI 组件或光标影响求解器。
- 最后,SurfaceMagnetism 光线投射将忽略 MaxRaycastDistance 属性设置,而不是表面。
5.8 DirectionalIndicator
- DirectionalIndicator 类是一个尾随组件,它可以根据空间中指定点的方向调整自身方向。 最常用于 SolverHandler 的“跟踪目标类型”设置为 Head 的情况。 这样,具有 DirectionalIndicator 求解器的 UX 组件将指引用户看空间中的指定点。 此点由 Directional Target 属性确定。
- 如果用户可以查看方向目标,或在SolverHandler中设置了任何参照帧,则该求解器将禁用它下面的所有Renderer组件。 如果不可查看,则该指示器上将启用所有内容。随着用户逐渐靠近以在他们的 FOV 中捕捉“Direction Target(方向目标)”,指示器的大小将缩小。
- Min Indicator Scale(最小指示器比例) - 指示器对象的最小比例
- Max Indicator Scale(最大指示器比例) - 指示器对象的最大比例
- Visibility Scale Factor(可见性比例因子) - 用于增加或减少 FOV 的乘数,用于确定“方向目标”点是否可见
- View Offset(视角偏移) - 从参考系(可能是相机)的角度来看,该属性定义对象在指示器方向上距视区中心多远。
5.9 HandConstraint 和 HandConstraintPalmUp 的手部菜单
- HandConstraint 行为提供了一个求解器,该求解器将跟踪对象约束在确保可显示手部约束内容(如手部 UI、菜单等)的区域内。安全区域是指不会与手部相交的区域。 还包含了一个名为 HandConstraintPalmUp 的 HandConstraint 派生类,用于演示手掌朝向用户时激活求解器的常见行为。