很久之前写过一篇关于 VRTK 多 Canvas 画布重叠手柄射线穿透问题的文章,当时才疏学浅,没有找到解决方案。最近虽然不干 VR 了,但偶然研究了下,找到了比较完美的解决方案。

起因

起因请看这篇文章: VRTK重叠Canvas上UIPointer射线穿透的问题(Unity VR)

解决方法

以下 1、2 两点必须同时修改,非二选一。

步骤1:修改 VRTK_UIGraphicRaycaster

VRTK_UIGraphicRaycaster脚本第 59 行,找到如下一行:

//梓喵出没
eventData.pointerCurrentRaycast = nearestRaycast.Value;

将本行注释掉:

//梓喵出没
//eventData.pointerCurrentRaycast = nearestRaycast.Value;

注释的目的是让射线投射从本地零点开始,这一行就是造成“近在咫尺的 UI 选不到,射线穿透到背后很远的 UI 上”的原因。

关于Raycast方法如何被调用的问题,有兴趣的可以翻 UGUI 关于 GraphicRaycaster 与 EventSystem 的源码。

步骤2:修改 VRTK_VRInputModule 自定义排序

修改 1 中内容后,使用EventSystem.RaycastAll即可以获取到射线路径上所有的 UI 元素,如果不修改 1 中内容,则会导致获取不全。

由于 EventSystem.RaycastAll 返回结果的排序与我们预期有差别,因此需要手动排序。在VRTK_VRInputModule脚本的第 56 行,即 eventSystem.RaycastAll的后面,追加如下内容:

raycasts.Sort((res1, res2) =>{
    if (Mathf.Abs(res1.distance - res2.distance) < 0.001)
    {
        return res2.depth.CompareTo(res1.depth);
    }
    return res1.distance.CompareTo(res2.distance);
});
if (raycasts.Count > 0)
{
    pointer.pointerEventData.pointerCurrentRaycast = raycasts[0];
}

距离差小于 0.001 后按 depth 排序的目的是为了避免距离计算中的精度问题。当 A B两个元素重叠时,有可能上一帧计算的距离值 A 比 B 小,在这一帧距离值就变成了 B 比 A 小(float),如果顺序乱跳,后面强行设置pointerCurrentRaycast时就可能出现悬浮点在 A B 间不停切换的现象。

引用资料

该修复方法来自于 GitHub finartist。

  1. [代码]【GitHub】finartist issues/1846
梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/7509.html
欢迎加入梓喵出没博客交流群:313732000

我来吐槽

*

*