【问题标题】:Moving a cube with the Gear VR controller in Unity在 Unity 中使用 Gear VR 控制器移动立方体
【发布时间】:2017-09-30 13:27:17
【问题描述】:

我正在尝试使用 Gear VR 控制器和 Oculus SDK 制作一个 Gear VR 应用程序。 我让 GazePointerRing 与控制器预制件一起工作。我的应用程序中有一个标线可见,我可以使用 Gear VR 控制器四处移动。它检测我放置在场景中的立方体。 我现在要做的是将标线指向一个立方体并按住控制器上的一个按钮,这样立方体就会粘在我的控制器模型上并且可以四处移动,直到我松开按钮。我一直在 OVR Physics Raycaster 脚本中搜索如何调用光线投射命中并将其输入到 if 语句中的按钮命令中。但我找不到一种方法来调用物体击中的光线投射。 这是 OVR Physics Raycaster 脚本中的 Oculus 代码:

using System.Collections.Generic;

namespace UnityEngine.EventSystems
{
    /// <summary>
    /// Simple event system using physics raycasts.
    /// </summary>
    [RequireComponent(typeof(OVRCameraRig))]
    public class OVRPhysicsRaycaster : BaseRaycaster
    {
        /// <summary>
        /// Const to use for clarity when no event mask is set
        /// </summary>
        protected const int kNoEventMaskSet = -1;


    /// <summary>
    /// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
    /// </summary>
    [SerializeField]
    public LayerMask m_EventMask = kNoEventMaskSet;

    protected OVRPhysicsRaycaster()
    { }

    public override Camera eventCamera
    {
        get
        {
            return GetComponent<OVRCameraRig>().leftEyeCamera;
        }
    }

    /// <summary>
    /// Depth used to determine the order of event processing.
    /// </summary>
    public virtual int depth
    {
        get { return (eventCamera != null) ? (int)eventCamera.depth : 0xFFFFFF; }
    }

    /// <summary>
    /// Event mask used to determine which objects will receive events.
    /// </summary>
    public int finalEventMask
    {
        get { return (eventCamera != null) ? eventCamera.cullingMask & m_EventMask : kNoEventMaskSet; }
    }

    /// <summary>
    /// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
    /// </summary>
    public LayerMask eventMask
    {
        get { return m_EventMask; }
        set { m_EventMask = value; }
    }


    /// <summary>
    /// Perform a raycast using the worldSpaceRay in eventData.
    /// </summary>
    /// <param name="eventData"></param>
    /// <param name="resultAppendList"></param>
    public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
    {
        // This function is closely based on PhysicsRaycaster.Raycast

        if (eventCamera == null)
            return;

        OVRRayPointerEventData rayPointerEventData = eventData as OVRRayPointerEventData;
        if (rayPointerEventData == null)
            return;

        var ray = rayPointerEventData.worldSpaceRay;

        float dist = eventCamera.farClipPlane - eventCamera.nearClipPlane;

        var hits = Physics.RaycastAll(ray, dist, finalEventMask);

        if (hits.Length > 1)
            System.Array.Sort(hits, (r1, r2) => r1.distance.CompareTo(r2.distance));

        if (hits.Length != 0)
        {
            for (int b = 0, bmax = hits.Length; b < bmax; ++b)
            {
                var result = new RaycastResult
                {
                    gameObject = hits[b].collider.gameObject,
                    module = this,
                    distance = hits[b].distance,
                    index = resultAppendList.Count,
                    worldPosition = hits[0].point,
                    worldNormal = hits[0].normal,
                };
                resultAppendList.Add(result);
            }
        }
    }

    /// <summary>
    ///  Perform a Spherecast using the worldSpaceRay in eventData.
    /// </summary>
    /// <param name="eventData"></param>
    /// <param name="resultAppendList"></param>
    /// <param name="radius">Radius of the sphere</param>
    public void Spherecast(PointerEventData eventData, List<RaycastResult> resultAppendList, float radius)
    {
        if (eventCamera == null)
            return;

        OVRRayPointerEventData rayPointerEventData = eventData as OVRRayPointerEventData;
        if (rayPointerEventData == null)
            return;

        var ray = rayPointerEventData.worldSpaceRay;

        float dist = eventCamera.farClipPlane - eventCamera.nearClipPlane;

        var hits = Physics.SphereCastAll(ray, radius, dist, finalEventMask);

        if (hits.Length > 1)
            System.Array.Sort(hits, (r1, r2) => r1.distance.CompareTo(r2.distance));

        if (hits.Length != 0)
        {
            for (int b = 0, bmax = hits.Length; b < bmax; ++b)
            {
                var result = new RaycastResult
                {
                    gameObject = hits[b].collider.gameObject,
                    module = this,
                    distance = hits[b].distance,
                    index = resultAppendList.Count,
                    worldPosition = hits[0].point,
                    worldNormal = hits[0].normal,
                };
                resultAppendList.Add(result);
            }
        }
    }
    /// <summary>
    /// Get screen position of this world position as seen by the event camera of this OVRPhysicsRaycaster
    /// </summary>
    /// <param name="worldPosition"></param>
    /// <returns></returns>
    public Vector2 GetScreenPos(Vector3 worldPosition)
    {
        // In future versions of Uinty RaycastResult will contain screenPosition so this will not be necessary
        return eventCamera.WorldToScreenPoint(worldPosition);
    }
}
}

【问题讨论】:

    标签: c# unity3d virtual-reality oculus gear-vr


    【解决方案1】:

    先决条件:确保您的场景中有 OVR 管理器,它是一个单例,是 GearVR 控制器(OVRInput 类)工作所必需的。

    我通常的方法是从控制器锚点位置向前投射光线并检查它是否击中所需的对象

    public class SampleScript : MonoBehaviour
    {
        public Transform anchorPos;
        public GameObject detectionLineObject; // a gameObject with a line renderer
    
        private RaycastHit _hitInfo;
        private LineRenderer _detectionLine;
    
        void Start()
        {
            GameObject line = Instantiate(detectionLineObject);
            _detectionLine = line.GetComponent<LineRenderer>();
        }
    
        void Update()
        {
            DetectionManager();
        }
    
        void DetectionManager()
        {
            // check if controller is actually connected
            if (!OVRInput.IsControllerConnected(OVRInput.Controller.RTrackedRemote) || !OVRInput.IsControllerConnected(OVRInput.Controller.LTrackedRemote))
            {
                return;
            }
            // launch a ray from the OVRCameraRig's Anchor Right
            if (Physics.Raycast(anchorPos.position, anchorPos.forward, out _hitInfo))
            {
                // set our line points
                _detectionLine.SetPosition(0, anchorPos.position);
                _detectionLine.SetPosition(1, _hitInfo.point);
    
                MyComponent target = _hitInfo.collider.gameObject.GetComponent<MyComponent>();
    
                if (target != null)
                {
                    // Do you stuff here
                    target.StartInteraction();
                }
            }
            else
            {
    
                // point our line to infinity
                _detectionLine.SetPosition(0, anchorPos.position);
                _detectionLine.SetPosition(1, anchorPos.forward * 500.0f);
            }
        }
    }
    

    【讨论】:

    • 我的场景中有 OVRManager。感谢您分享您的光线投射方法,它看起来很清晰。我想我可以进一步解决这个问题,现在我会尝试实现它。
    • 您好,关于您对光线投射脚本的处理方法,请再次提出几个问题。 1. 游戏对象检测线是您瞄准的控制器还是您想与之交互的游戏对象? 2、代码的目的是什么:MyComponent target = _hitInfo.collider.gameObject.GetComponent(); MyComponent 应该是什么?例如,通过指向一个立方体将它移动到不同的位置,MyComponent 应该是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多