You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已有桌面版拖拽代码,如何适配OVR Ray Interactable实现Canvas UI的VR拖拽?

Oculus VR场景下Canvas UI拖拽适配方案

核心问题分析

你的桌面端代码依赖鼠标输入和IPointerDown/UpHandler接口,但VR场景中控制器射线交互需要适配Meta的交互体系:

  • 需替换默认的StandaloneInputModule为VR专用输入模块
  • 不能再用Input.mousePosition,要通过控制器射线计算与Canvas的交点
  • 改用VR交互事件替代鼠标点击事件

适配代码(基于Meta Oculus Integration SDK)

using UnityEngine;
using Oculus.Interaction;

public class TestAsVR : MonoBehaviour
{
    private bool isDragging = false;
    private RectTransform rectTransform;
    private Canvas canvas;
    private Node node;
    private OVRRayInteractor rayInteractor;

    void Awake()
    {
        // 缓存组件避免重复调用GetComponent
        rectTransform = GetComponent<RectTransform>();
        canvas = GetComponentInParent<Canvas>();
        node = GetComponent<Node>();
        // 找到场景中的控制器射线交互器(可改为指定左右手)
        rayInteractor = FindObjectOfType<OVRRayInteractor>();

        // 绑定交互事件
        var interactable = GetComponent<OVRInteractable>();
        if (interactable != null)
        {
            interactable.WhenSelectEntered += OnDragStart;
            interactable.WhenSelectExited += OnDragEnd;
        }
    }

    private void OnDragStart(InteractorArgs args)
    {
        if (node.isHighlighting && gameObject.CompareTag("NodeUI"))
        {
            isDragging = true;
            node.isMoving = true;
        }
    }

    private void OnDragEnd(InteractorArgs args)
    {
        if (gameObject.CompareTag("NodeUI"))
        {
            isDragging = false;
            node.isMoving = false;

            // 更新子节点状态
            int childCount = rectTransform.childCount;
            int startIndex = Mathf.Max(0, childCount - 2);
            for (int i = startIndex; i < childCount; i++)
            {
                var point = rectTransform.GetChild(i).GetComponent<PointEventHandler>();
                if (point != null && point.isLinked)
                {
                    point.isMoved = false;
                }
            }
        }
    }

    void Update()
    {
        if (isDragging && rayInteractor != null)
        {
            // 获取射线与Canvas的交点
            if (rayInteractor.TryGetHitInfo(out RaycastHit hitInfo))
            {
                // 将世界坐标转换为Canvas本地锚点坐标
                Vector2 localPos;
                RectTransformUtility.ScreenPointToLocalPointInRectangle(
                    rectTransform.parent as RectTransform,
                    RectTransformUtility.WorldToScreenPoint(canvas.worldCamera, hitInfo.point),
                    canvas.worldCamera,
                    out localPos);

                rectTransform.anchoredPosition = localPos;

                // 更新子节点状态
                int childCount = rectTransform.childCount;
                int startIndex = Mathf.Max(0, childCount - 2);
                for (int i = startIndex; i < childCount; i++)
                {
                    var point = rectTransform.GetChild(i).GetComponent<PointEventHandler>();
                    if (point != null && point.isLinked)
                    {
                        point.isMoved = true;
                    }
                }
            }
        }
    }

    private void OnDestroy()
    {
        // 解绑事件避免内存泄漏
        var interactable = GetComponent<OVRInteractable>();
        if (interactable != null)
        {
            interactable.WhenSelectEntered -= OnDragStart;
            interactable.WhenSelectExited -= OnDragEnd;
        }
    }
}

必要场景设置

  1. Canvas配置

    • 将Canvas的渲染模式改为World Space,调整合适的大小和位置,确保控制器射线能照射到
    • 确认Canvas的World Camera设置为VR场景的主相机
  2. 交互组件配置

    • 给UI元素添加OVRInteractable组件,勾选"UI Interactable"选项
    • 给控制器添加OVRRayInteractor组件,开启射线可视化(Gizmos)便于调试
  3. EventSystem替换

    • 删除场景中EventSystem上的StandaloneInputModule,添加OVRInputModule(来自Oculus Integration包)

常见问题排查

  • 若射线无法命中UI:检查Canvas的碰撞体是否开启,射线交互器的交互层是否包含UI层
  • 若拖拽无反应:确认Node.isHighlighting逻辑在VR场景中正常触发(比如射线悬停时设置为true)
  • 若位置偏移:检查Canvas的锚点和 pivot 设置,确保坐标转换逻辑正确

内容的提问来源于stack exchange,提问作者YongseoKim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 13:17:46