diff --git a/Assets/OVRInputSelection/InputSystem/HandsManager.cs b/Assets/OVRInputSelection/InputSystem/HandsManager.cs new file mode 100644 index 0000000..424bfdb --- /dev/null +++ b/Assets/OVRInputSelection/InputSystem/HandsManager.cs @@ -0,0 +1,372 @@ +/************************************************************************************ + +Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved. + +See SampleFramework license.txt for license terms. Unless required by applicable law +or agreed to in writing, the sample code is provided “AS IS” WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the license for specific +language governing permissions and limitations under the license. + +************************************************************************************/ + +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Assertions; + +namespace ControllerSelection +{ + public class HandsManager : MonoBehaviour + { + private const string SKELETON_VISUALIZER_NAME = "SkeletonRenderer"; + + [SerializeField] GameObject _leftHand = null; + [SerializeField] GameObject _rightHand = null; + + public HandsVisualMode VisualMode = HandsVisualMode.Mesh; + private OVRHand[] _hand = new OVRHand[(int)OVRHand.Hand.HandRight + 1]; + private OVRSkeleton[] _handSkeleton = new OVRSkeleton[(int)OVRHand.Hand.HandRight + 1]; + private OVRSkeletonRenderer[] _handSkeletonRenderer = new OVRSkeletonRenderer[(int)OVRHand.Hand.HandRight + 1]; + private OVRMesh[] _handMesh = new OVRMesh[(int)OVRHand.Hand.HandRight + 1]; + private OVRMeshRenderer[] _handMeshRenderer = new OVRMeshRenderer[(int)OVRHand.Hand.HandRight + 1]; + private SkinnedMeshRenderer _leftMeshRenderer = null; + private SkinnedMeshRenderer _rightMeshRenderer = null; + private GameObject _leftSkeletonVisual = null; + private GameObject _rightSkeletonVisual = null; + private float _currentHandAlpha = 1.0f; + private int HandAlphaId = Shader.PropertyToID("_HandAlpha"); + private PinchMode[] _pinchModeLeft = new PinchMode[(int)OVRHand.HandFinger.Max]; + private PinchMode[] _pinchModeRight = new PinchMode[(int)OVRHand.HandFinger.Max]; + private PinchMode[] _lastPinchModeLeft = new PinchMode[(int)OVRHand.HandFinger.Max]; + private PinchMode[] _lastPinchModeRight = new PinchMode[(int)OVRHand.HandFinger.Max]; + + // Pinch strength to be considered a pinch + static readonly float PinchMaxStrength = 0.9f; + + public enum HandsVisualMode + { + Mesh = 0, Skeleton = 1, Both = 2 + } + + public enum PinchMode + { + Pinched = 0, NotPinched = 1 + } + + public OVRHand RightHand + { + get + { + return _hand[(int)OVRHand.Hand.HandRight]; + } + private set + { + _hand[(int)OVRHand.Hand.HandRight] = value; + } + } + + public OVRSkeleton RightHandSkeleton + { + get + { + return _handSkeleton[(int)OVRHand.Hand.HandRight]; + } + private set + { + _handSkeleton[(int)OVRHand.Hand.HandRight] = value; + } + } + + public OVRSkeletonRenderer RightHandSkeletonRenderer + { + get + { + return _handSkeletonRenderer[(int)OVRHand.Hand.HandRight]; + } + private set + { + _handSkeletonRenderer[(int)OVRHand.Hand.HandRight] = value; + } + } + + public OVRMesh RightHandMesh + { + get + { + return _handMesh[(int)OVRHand.Hand.HandRight]; + } + private set + { + _handMesh[(int)OVRHand.Hand.HandRight] = value; + } + } + + public OVRMeshRenderer RightHandMeshRenderer + { + get + { + return _handMeshRenderer[(int)OVRHand.Hand.HandRight]; + } + private set + { + _handMeshRenderer[(int)OVRHand.Hand.HandRight] = value; + } + } + + public OVRHand LeftHand + { + get + { + return _hand[(int)OVRHand.Hand.HandLeft]; + } + private set + { + _hand[(int)OVRHand.Hand.HandLeft] = value; + } + } + + public OVRSkeleton LeftHandSkeleton + { + get + { + return _handSkeleton[(int)OVRHand.Hand.HandLeft]; + } + private set + { + _handSkeleton[(int)OVRHand.Hand.HandLeft] = value; + } + } + + public OVRSkeletonRenderer LeftHandSkeletonRenderer + { + get + { + return _handSkeletonRenderer[(int)OVRHand.Hand.HandLeft]; + } + private set + { + _handSkeletonRenderer[(int)OVRHand.Hand.HandLeft] = value; + } + } + + public OVRMesh LeftHandMesh + { + get + { + return _handMesh[(int)OVRHand.Hand.HandLeft]; + } + private set + { + _handMesh[(int)OVRHand.Hand.HandLeft] = value; + } + } + + public OVRMeshRenderer LeftHandMeshRenderer + { + get + { + return _handMeshRenderer[(int)OVRHand.Hand.HandLeft]; + } + private set + { + _handMeshRenderer[(int)OVRHand.Hand.HandLeft] = value; + } + } + + public static HandsManager Instance { get; private set; } + + private void Awake() + { + if (Instance && Instance != this) + { + Destroy(this); + return; + } + Instance = this; + + Assert.IsNotNull(_leftHand); + Assert.IsNotNull(_rightHand); + + LeftHand = _leftHand.GetComponent(); + LeftHandSkeleton = _leftHand.GetComponent(); + LeftHandSkeletonRenderer = _leftHand.GetComponent(); + LeftHandMesh = _leftHand.GetComponent(); + LeftHandMeshRenderer = _leftHand.GetComponent(); + + RightHand = _rightHand.GetComponent(); + RightHandSkeleton = _rightHand.GetComponent(); + RightHandSkeletonRenderer = _rightHand.GetComponent(); + RightHandMesh = _rightHand.GetComponent(); + RightHandMeshRenderer = _rightHand.GetComponent(); + _leftMeshRenderer = LeftHand.GetComponent(); + _rightMeshRenderer = RightHand.GetComponent(); + StartCoroutine(FindSkeletonVisualGameObjects()); + } + + private void Update() + { + switch (VisualMode) + { + case HandsVisualMode.Mesh: + case HandsVisualMode.Skeleton: + _currentHandAlpha = 1.0f; + break; + case HandsVisualMode.Both: + _currentHandAlpha = 0.6f; + break; + default: + _currentHandAlpha = 1.0f; + break; + } + _rightMeshRenderer.sharedMaterial.SetFloat(HandAlphaId, _currentHandAlpha); + _leftMeshRenderer.sharedMaterial.SetFloat(HandAlphaId, _currentHandAlpha); + + UpdateFingerPinching(LeftHand, _pinchModeLeft, _lastPinchModeLeft); + UpdateFingerPinching(RightHand, _pinchModeRight, _lastPinchModeRight); + } + + private IEnumerator FindSkeletonVisualGameObjects() + { + while (!_leftSkeletonVisual || !_rightSkeletonVisual) + { + if (!_leftSkeletonVisual) + { + Transform leftSkeletonVisualTransform = LeftHand.transform.Find(SKELETON_VISUALIZER_NAME); + if (leftSkeletonVisualTransform) + { + _leftSkeletonVisual = leftSkeletonVisualTransform.gameObject; + } + } + + if (!_rightSkeletonVisual) + { + Transform rightSkeletonVisualTransform = RightHand.transform.Find(SKELETON_VISUALIZER_NAME); + if (rightSkeletonVisualTransform) + { + _rightSkeletonVisual = rightSkeletonVisualTransform.gameObject; + } + } + yield return null; + } + SetToCurrentVisualMode(); + } + + public void SwitchVisualization() + { + if (!_leftSkeletonVisual || !_rightSkeletonVisual) + { + return; + } + VisualMode = (HandsVisualMode)(((int)VisualMode + 1) % ((int)HandsVisualMode.Both + 1)); + SetToCurrentVisualMode(); + } + + private void SetToCurrentVisualMode() + { + switch (VisualMode) + { + case HandsVisualMode.Mesh: + RightHandMeshRenderer.enabled = true; + _rightMeshRenderer.enabled = true; + _rightSkeletonVisual.gameObject.SetActive(false); + LeftHandMeshRenderer.enabled = true; + _leftMeshRenderer.enabled = true; + _leftSkeletonVisual.gameObject.SetActive(false); + break; + case HandsVisualMode.Skeleton: + RightHandMeshRenderer.enabled = false; + _rightMeshRenderer.enabled = false; + _rightSkeletonVisual.gameObject.SetActive(true); + LeftHandMeshRenderer.enabled = false; + _leftMeshRenderer.enabled = false; + _leftSkeletonVisual.gameObject.SetActive(true); + break; + case HandsVisualMode.Both: + RightHandMeshRenderer.enabled = true; + _rightMeshRenderer.enabled = true; + _rightSkeletonVisual.gameObject.SetActive(true); + LeftHandMeshRenderer.enabled = true; + _leftMeshRenderer.enabled = true; + _leftSkeletonVisual.gameObject.SetActive(true); + break; + default: + break; + } + } + + public static List GetCapsulesPerBone(OVRSkeleton skeleton, OVRSkeleton.BoneId boneId) + { + List boneCapsules = new List(); + var capsules = skeleton.Capsules; + for (int i = 0; i < capsules.Count; ++i) + { + if (capsules[i].BoneIndex == (short)boneId) + { + boneCapsules.Add(capsules[i]); + } + } + return boneCapsules; + } + + public PinchMode GetLeftPinchMode(OVRHand.HandFinger finger) + { + return _pinchModeLeft[(int)finger]; + } + + public PinchMode GetRightPinchMode(OVRHand.HandFinger finger) + { + return _pinchModeRight[(int)finger]; + } + + public PinchMode GetLastLeftPinchMode(OVRHand.HandFinger finger) + { + return _lastPinchModeLeft[(int)finger]; + } + + public PinchMode GetLastRightPinchMode(OVRHand.HandFinger finger) + { + return _lastPinchModeRight[(int)finger]; + } + + public bool IsInitialized() + { + return LeftHandSkeleton && LeftHandSkeleton.IsInitialized && + RightHandSkeleton && RightHandSkeleton.IsInitialized && + LeftHandMesh && LeftHandMesh.IsInitialized && + RightHandMesh && RightHandMesh.IsInitialized; + } + + static private bool IsFingerPinched(OVRHand hand, OVRHand.HandFinger finger) + { + return hand.GetFingerConfidence(finger) == OVRHand.TrackingConfidence.High && hand.GetFingerIsPinching(finger) && hand.GetFingerPinchStrength(finger) >= PinchMaxStrength; + } + + /// + /// Enumerates all fingers and updates pinching status. Also tracks last pinch status. + /// + /// + /// + /// + private void UpdateFingerPinching(OVRHand hand, PinchMode[] pinchModes, PinchMode[] lastPinchModes) + { + for (int i = 0; i < pinchModes.Length; i++) + { + lastPinchModes[i] = pinchModes[i]; + pinchModes[i] = PinchMode.NotPinched; + } + + var isReliable = hand.IsTracked && hand.HandConfidence == OVRHand.TrackingConfidence.High; + if (!isReliable) + { + return; + } + + pinchModes[(int)OVRHand.HandFinger.Thumb] = IsFingerPinched(hand, OVRHand.HandFinger.Thumb) ? PinchMode.Pinched : PinchMode.NotPinched; + pinchModes[(int)OVRHand.HandFinger.Index] = IsFingerPinched(hand, OVRHand.HandFinger.Index) ? PinchMode.Pinched : PinchMode.NotPinched; + pinchModes[(int)OVRHand.HandFinger.Middle] = IsFingerPinched(hand, OVRHand.HandFinger.Middle) ? PinchMode.Pinched : PinchMode.NotPinched; + pinchModes[(int)OVRHand.HandFinger.Ring] = IsFingerPinched(hand, OVRHand.HandFinger.Ring) ? PinchMode.Pinched : PinchMode.NotPinched; + pinchModes[(int)OVRHand.HandFinger.Pinky] = IsFingerPinched(hand, OVRHand.HandFinger.Pinky) ? PinchMode.Pinched : PinchMode.NotPinched; + } + } +} diff --git a/Assets/OVRInputSelection/InputSystem/HandsManager.cs.meta b/Assets/OVRInputSelection/InputSystem/HandsManager.cs.meta new file mode 100644 index 0000000..d8d3a04 --- /dev/null +++ b/Assets/OVRInputSelection/InputSystem/HandsManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 355b24382fa1a9c4f8b72fd2095581f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/OVRInputSelection/InputSystem/OVRInputHelpers.cs b/Assets/OVRInputSelection/InputSystem/OVRInputHelpers.cs index 5df66b4..21f1c96 100644 --- a/Assets/OVRInputSelection/InputSystem/OVRInputHelpers.cs +++ b/Assets/OVRInputSelection/InputSystem/OVRInputHelpers.cs @@ -19,37 +19,137 @@ limitations under the License. ************************************************************************************/ +using System.Collections.Specialized; +using System.Runtime.InteropServices; using UnityEngine; -namespace ControllerSelection { - public class OVRInputHelpers { - // Given a controller and tracking spcae, return the ray that controller uses. +namespace ControllerSelection +{ + public class OVRInputHelpers + { + public enum HandFilter + { + None = 0, + Left = 1, + Right = 2, + Both = Left | Right + } + + /// + /// Indicates whether hand started pinching in this frame + /// + /// + /// + /// + public static bool IsFingerStartPinching(OVRInput.Controller activeController, OVRHand.HandFinger finger) + { + bool isLeftHand = (activeController & OVRInput.Controller.LHand) == OVRInput.Controller.LHand; + var curPinch = isLeftHand ? HandsManager.Instance.GetLeftPinchMode(finger) : HandsManager.Instance.GetRightPinchMode(finger); + var lastPinch = isLeftHand ? HandsManager.Instance.GetLastLeftPinchMode(finger) : HandsManager.Instance.GetLastRightPinchMode(finger); + + return (lastPinch == HandsManager.PinchMode.NotPinched && curPinch == HandsManager.PinchMode.Pinched); + } + + /// + /// Indicates whether hand stopped pinching in this frame + /// + /// + /// + /// + public static bool IsFingerStopPinching(OVRInput.Controller activeController, OVRHand.HandFinger finger) + { + bool isLeftHand = (activeController & OVRInput.Controller.LHand) == OVRInput.Controller.LHand; + var curPinch = isLeftHand ? HandsManager.Instance.GetLeftPinchMode(finger) : HandsManager.Instance.GetRightPinchMode(finger); + var lastPinch = isLeftHand ? HandsManager.Instance.GetLastLeftPinchMode(finger) : HandsManager.Instance.GetLastRightPinchMode(finger); + + return (lastPinch == HandsManager.PinchMode.Pinched && curPinch == HandsManager.PinchMode.NotPinched); + } + + /// + /// Indicates whether hand is pinching + /// + /// + /// + /// + public static bool IsFingerPinching(OVRInput.Controller activeController, OVRHand.HandFinger finger) + { + bool isLeftHand = (activeController & OVRInput.Controller.LHand) == OVRInput.Controller.LHand; + var curPinch = isLeftHand ? HandsManager.Instance.GetLeftPinchMode(finger) : HandsManager.Instance.GetRightPinchMode(finger); + return (curPinch == HandsManager.PinchMode.Pinched); + } + + /// + /// Returns hand orientation + /// + /// + /// + /// + /// + public static bool GetHandOrientation(OVRInput.Controller activeController, out Quaternion orientation, out Vector3 position) + { + orientation = default(Quaternion); + position = default(Vector3); + + if ((activeController & OVRInput.Controller.Hands) == OVRInput.Controller.None) + { + return false; + } + + if (!HandsManager.Instance || !HandsManager.Instance.IsInitialized()) + { + return false; + } + + var hand = (activeController & OVRInput.Controller.RHand) == OVRInput.Controller.RHand ? HandsManager.Instance.RightHand : HandsManager.Instance.LeftHand; + var isReliable = hand.IsTracked && hand.HandConfidence == OVRHand.TrackingConfidence.High; + if (!isReliable || !hand.IsPointerPoseValid) + { + return false; + } + + var pointer = hand.PointerPose; + + orientation = pointer.rotation; + position = pointer.position; + + return true; + } + + // Given a controller and tracking space, return the ray that controller uses. // Will fall back to center eye or camera on Gear if no controller is present. - public static Ray GetSelectionRay(OVRInput.Controller activeController, Transform trackingSpace) { - if (trackingSpace != null && activeController != OVRInput.Controller.None) { - Quaternion orientation = OVRInput.GetLocalControllerRotation(activeController); - Vector3 localStartPoint = OVRInput.GetLocalControllerPosition(activeController); + public static bool GetSelectionRay(OVRInput.Controller activeController, Transform trackingSpace, out Ray ray) + { + ray = default(Ray); + if (trackingSpace != null && activeController != OVRInput.Controller.None) + { + Quaternion orientation = default(Quaternion); + Vector3 localStartPoint = default(Vector3); + + if ((activeController & OVRInput.Controller.Hands) != OVRInput.Controller.None) + { + if (!GetHandOrientation(activeController, out orientation, out localStartPoint)) + { + return false; + } + } + else + { + orientation = OVRInput.GetLocalControllerRotation(activeController); + localStartPoint = OVRInput.GetLocalControllerPosition(activeController); + } Matrix4x4 localToWorld = trackingSpace.localToWorldMatrix; Vector3 worldStartPoint = localToWorld.MultiplyPoint(localStartPoint); Vector3 worldOrientation = localToWorld.MultiplyVector(orientation * Vector3.forward); - return new Ray(worldStartPoint, worldOrientation); + ray = new Ray(worldStartPoint, worldOrientation); + return true; } - Transform cameraTransform = Camera.main.transform; - - if (OVRManager.instance != null) { - OVRCameraRig cameraRig = OVRManager.instance.GetComponent(); - if (cameraRig != null) { - cameraTransform = cameraRig.centerEyeAnchor; - } - } - - return new Ray(cameraTransform.position, cameraTransform.forward); + return false; } - // Search the scene to find a tracking spce. This method can be expensive! Try to avoid it if possible. + // Search the scene to find a tracking space. This method can be expensive! Try to avoid it if possible. public static Transform FindTrackingSpace() { // There should be an OVRManager in the scene if (OVRManager.instance != null) { @@ -82,39 +182,53 @@ namespace ControllerSelection { return null; } - // Find the current active controller, based on last time a certain button was hit. Needs to know the previous active controller. - public static OVRInput.Controller GetControllerForButton(OVRInput.Button joyPadClickButton, OVRInput.Controller oldController) { + /// + /// Returns connected controllers + /// + /// + /// + public static OVRInput.Controller GetConnectedControllers(HandFilter filter = HandFilter.Both) + { OVRInput.Controller controller = OVRInput.GetConnectedControllers(); - if ((controller & OVRInput.Controller.RTouch) == OVRInput.Controller.RTouch) { - if (OVRInput.Get(joyPadClickButton, OVRInput.Controller.RTouch) || oldController == OVRInput.Controller.None) { - return OVRInput.Controller.RTouch; + if (((filter & HandFilter.Right) == HandFilter.Right) && (controller & OVRInput.Controller.RTouch) == OVRInput.Controller.RTouch) + { + return OVRInput.Controller.RTouch; + } + + if (((filter & HandFilter.Left) == HandFilter.Left) && (controller & OVRInput.Controller.LTouch) == OVRInput.Controller.LTouch) + { + return OVRInput.Controller.LTouch; + } + + if (((filter & HandFilter.Right) == HandFilter.Right) && (controller & OVRInput.Controller.RTrackedRemote) == OVRInput.Controller.RTrackedRemote) + { + return OVRInput.Controller.RTrackedRemote; + } + + if (((filter & HandFilter.Left) == HandFilter.Left) && (controller & OVRInput.Controller.LTrackedRemote) == OVRInput.Controller.LTrackedRemote) + { + return OVRInput.Controller.LTrackedRemote; + } + + controller = OVRInput.Controller.None; + if (OVRPlugin.GetHandTrackingEnabled()) + { + if ((filter & HandFilter.Both) == HandFilter.Both) + { + return OVRInput.Controller.Hands; + } + else if ((filter & HandFilter.Right) == HandFilter.Right) + { + return OVRInput.Controller.RHand; + } + else + { + return OVRInput.Controller.LHand; } } - if ((controller & OVRInput.Controller.LTouch) == OVRInput.Controller.LTouch) { - if (OVRInput.Get(joyPadClickButton, OVRInput.Controller.LTouch) || oldController == OVRInput.Controller.None) { - return OVRInput.Controller.LTouch; - } - } - - if ((controller & OVRInput.Controller.RTrackedRemote) == OVRInput.Controller.RTrackedRemote) { - if (OVRInput.Get(joyPadClickButton, OVRInput.Controller.RTrackedRemote) || oldController == OVRInput.Controller.None) { - return OVRInput.Controller.RTrackedRemote; - } - } - - if ((controller & OVRInput.Controller.LTrackedRemote) == OVRInput.Controller.LTrackedRemote) { - if (OVRInput.Get(joyPadClickButton, OVRInput.Controller.LTrackedRemote) || oldController == OVRInput.Controller.None) { - return OVRInput.Controller.LTrackedRemote; - } - } - - if ((controller & oldController) != oldController) { - return OVRInput.Controller.None; - } - - return oldController; + return OVRInput.Controller.None; } - } + } } \ No newline at end of file diff --git a/Assets/OVRInputSelection/InputSystem/OVRInputModule.cs b/Assets/OVRInputSelection/InputSystem/OVRInputModule.cs index 0a5c2b4..5bed765 100644 --- a/Assets/OVRInputSelection/InputSystem/OVRInputModule.cs +++ b/Assets/OVRInputSelection/InputSystem/OVRInputModule.cs @@ -28,7 +28,14 @@ namespace ControllerSelection { public class OVRInputModule : UnityEngine.EventSystems.PointerInputModule { - protected override void Awake() { + public enum Hand + { + None, + Left = OVRInputHelpers.HandFilter.Left, + Right = OVRInputHelpers.HandFilter.Right + } + + protected override void Awake() { base.Awake(); if (trackingSpace == null) { Debug.LogWarning ("OVRInputModule did not have a tracking space set. Looking for one"); @@ -65,6 +72,9 @@ namespace ControllerSelection [Tooltip("Primary selection button")] public OVRInput.Button joyPadClickButton = OVRInput.Button.PrimaryIndexTrigger; + [Tooltip("Primary hand pinch finger")] + public OVRHand.HandFinger pinchFinger = OVRHand.HandFinger.Index; + [Header("Physics")] [Tooltip("Perform an sphere cast to determine correct depth for gaze pointer")] public bool performSphereCastForGazepointer; @@ -87,8 +97,7 @@ namespace ControllerSelection [Tooltip("Distance scrolled when swipe scroll occurs")] public float swipeScrollScale = 4f; - - [HideInInspector] + [HideInInspector] public OVRInput.Controller activeController = OVRInput.Controller.None; public delegate void RayHitDelegate(Vector3 hitPosition, Vector3 hitNormal); @@ -101,13 +110,15 @@ namespace ControllerSelection #endregion // The raycaster that gets to do pointer interaction (e.g. with a mouse), gaze interaction always works - // private OVRRaycaster _activeGraphicRaycaster; [NonSerialized] public OVRRaycaster activeGraphicRaycaster; [Header("Dragging")] [Tooltip("Minimum pointer movement in degrees to start dragging")] public float angleDragThreshold = 1; + [Tooltip("Suppress click while dragging")] + public bool suppressClickOnDrag = true; + // The following region contains code exactly the same as the implementation // of StandaloneInputModule. It is copied here rather than inheriting from StandaloneInputModule // because most of StandaloneInputModule is private so it isn't possible to easily derive from. @@ -120,8 +131,8 @@ namespace ControllerSelection // ProcessMouseEvent // UseMouse #region StandaloneInputModule code - - private float m_NextAction; + + private float m_NextAction; private Vector2 m_LastMousePosition; private Vector2 m_MousePosition; @@ -218,8 +229,6 @@ namespace ControllerSelection public override void UpdateModule() { - activeController = OVRInputHelpers.GetControllerForButton (OVRInput.Button.PrimaryIndexTrigger, activeController); - m_LastMousePosition = m_MousePosition; m_MousePosition = Input.mousePosition; } @@ -243,6 +252,7 @@ namespace ControllerSelection shouldActivate |= !Mathf.Approximately(Input.GetAxisRaw(m_VerticalAxis), 0.0f); shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f; shouldActivate |= Input.GetMouseButtonDown(0); + return shouldActivate; } @@ -265,8 +275,6 @@ namespace ControllerSelection ClearSelection(); } - - /// /// Process submit keys. /// @@ -337,10 +345,6 @@ namespace ControllerSelection return axisEventData.used; } - - - - private bool SendUpdateEventToSelectedObject() { if (eventSystem.currentSelectedGameObject == null) @@ -380,8 +384,6 @@ namespace ControllerSelection if (newPressed == null) newPressed = UnityEngine.EventSystems.ExecuteEvents.GetEventHandler(currentOverGo); - // Debug.Log("Pressed: " + newPressed); - float time = Time.unscaledTime; if (newPressed == pointerEvent.lastPress) @@ -408,22 +410,25 @@ namespace ControllerSelection pointerEvent.pointerDrag = UnityEngine.EventSystems.ExecuteEvents.GetEventHandler(currentOverGo); if (pointerEvent.pointerDrag != null) + { UnityEngine.EventSystems.ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, UnityEngine.EventSystems.ExecuteEvents.initializePotentialDrag); + } } // PointerUp notification if (data.ReleasedThisFrame()) { - // Debug.Log("Executing pressup on: " + pointer.pointerPress); UnityEngine.EventSystems.ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, UnityEngine.EventSystems.ExecuteEvents.pointerUpHandler); - // Debug.Log("KeyCode: " + pointer.eventData.keyCode); - // see if we mouse up on the same element that we clicked on... var pointerUpHandler = UnityEngine.EventSystems.ExecuteEvents.GetEventHandler(currentOverGo); + // Determine if we're dragging and if we want to suppress click while dragging + var isDragging = pointerEvent.pointerDrag != null && pointerEvent.dragging; + var suppressClick = suppressClickOnDrag && isDragging; + // PointerClick and Drop events - if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick) + if (!suppressClick && pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick) { UnityEngine.EventSystems.ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, UnityEngine.EventSystems.ExecuteEvents.pointerClickHandler); } @@ -436,8 +441,10 @@ namespace ControllerSelection pointerEvent.pointerPress = null; pointerEvent.rawPointerPress = null; - if (pointerEvent.pointerDrag != null && pointerEvent.dragging) + if (isDragging) + { UnityEngine.EventSystems.ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, UnityEngine.EventSystems.ExecuteEvents.endDragHandler); + } pointerEvent.dragging = false; pointerEvent.pointerDrag = null; @@ -506,10 +513,8 @@ namespace ControllerSelection SendSubmitEventToSelectedObject(); } - ProcessMouseEvent(GetGazePointerData()); -#if !UNITY_ANDROID - ProcessMouseEvent(GetCanvasPointerData()); -#endif + ProcessMouseEvent(GetGazePointerData(true)); + ProcessMouseEvent(GetGazePointerData(false)); } /// /// Decide if mouse events need to be processed this frame. Same as StandloneInputModule except @@ -560,19 +565,20 @@ namespace ControllerSelection #region PointerEventData pool // Pool for OVRRayPointerEventData for ray based pointers - protected Dictionary m_VRRayPointerData = new Dictionary(); + protected Dictionary m_VRRayPointerDataLeft = new Dictionary(); + protected Dictionary m_VRRayPointerDataRight = new Dictionary(); - - protected bool GetPointerData(int id, out OVRRayPointerEventData data, bool create) + protected bool GetPointerData(int id, out OVRRayPointerEventData data, bool create, bool isLeft) { - if (!m_VRRayPointerData.TryGetValue(id, out data) && create) + var rayPointerData = isLeft ? m_VRRayPointerDataLeft : m_VRRayPointerDataRight; + if (!rayPointerData.TryGetValue(id, out data) && create) { data = new OVRRayPointerEventData(eventSystem) { pointerId = id, }; - m_VRRayPointerData.Add(id, data); + rayPointerData.Add(id, data); return true; } return false; @@ -590,7 +596,12 @@ namespace ControllerSelection // clear all selection HandlePointerExitAndEnter(pointer, null); } - foreach (var pointer in m_VRRayPointerData.Values) + foreach (var pointer in m_VRRayPointerDataLeft.Values) + { + // clear all selection + HandlePointerExitAndEnter(pointer, null); + } + foreach (var pointer in m_VRRayPointerDataRight.Values) { // clear all selection HandlePointerExitAndEnter(pointer, null); @@ -614,26 +625,28 @@ namespace ControllerSelection return Vector3.Cross(LeftEdge, BottomEdge).normalized; } - private readonly MouseState m_MouseState = new MouseState(); - // Overridden so that we can process the two types of pointer separately + private readonly MouseState m_MouseStateLeft = new MouseState(); + private readonly MouseState m_MouseStateRight = new MouseState(); + // Overridden so that we can process the two types of pointer separately // The following 2 functions are equivalent to PointerInputModule.GetMousePointerEventData but are customized to // get data for ray pointers and canvas mouse pointers. - + /// /// State for a pointer controlled by a world space ray. E.g. gaze pointer /// /// - protected MouseState GetGazePointerData() + protected MouseState GetGazePointerData(bool isLeft) { // Get the OVRRayPointerEventData reference OVRRayPointerEventData leftData; - GetPointerData(kMouseLeftId, out leftData, true ); + GetPointerData(kMouseLeftId, out leftData, true, isLeft); leftData.Reset(); - - leftData.worldSpaceRay = OVRInputHelpers.GetSelectionRay(activeController, trackingSpace); + leftData.worldSpaceRay = default(Ray); + var activeController = OVRInputHelpers.GetConnectedControllers(isLeft ? OVRInputHelpers.HandFilter.Left : OVRInputHelpers.HandFilter.Right); + bool gotRay = OVRInputHelpers.GetSelectionRay(activeController, trackingSpace, out leftData.worldSpaceRay); leftData.scrollDelta = GetExtraScrollDelta(); //Populate some default values @@ -654,7 +667,6 @@ namespace ControllerSelection // space position for the camera attached to this raycaster for compatability leftData.position = ovrRaycaster.GetScreenPosition(raycast); - // Find the world position and normal the Graphic the ray intersected RectTransform graphicRect = raycast.gameObject.GetComponent(); if (graphicRect != null) @@ -682,75 +694,21 @@ namespace ControllerSelection // copy the apropriate data into right and middle slots OVRRayPointerEventData rightData; - GetPointerData(kMouseRightId, out rightData, true ); + GetPointerData(kMouseRightId, out rightData, true, isLeft); CopyFromTo(leftData, rightData); rightData.button = UnityEngine.EventSystems.PointerEventData.InputButton.Right; OVRRayPointerEventData middleData; - GetPointerData(kMouseMiddleId, out middleData, true ); + GetPointerData(kMouseMiddleId, out middleData, true, isLeft); CopyFromTo(leftData, middleData); middleData.button = UnityEngine.EventSystems.PointerEventData.InputButton.Middle; + var mouseState = isLeft ? m_MouseStateLeft : m_MouseStateRight; - m_MouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Left, GetGazeButtonState(), leftData); - m_MouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Right, UnityEngine.EventSystems.PointerEventData.FramePressState.NotChanged, rightData); - m_MouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Middle, UnityEngine.EventSystems.PointerEventData.FramePressState.NotChanged, middleData); - return m_MouseState; - } - - /// - /// Get state for pointer which is a pointer moving in world space across the surface of a world space canvas. - /// - /// - protected MouseState GetCanvasPointerData() - { - // Get the OVRRayPointerEventData reference - UnityEngine.EventSystems.PointerEventData leftData; - GetPointerData(kMouseLeftId, out leftData, true ); - leftData.Reset(); - - // Setup default values here. Set position to zero because we don't actually know the pointer - // positions. Each canvas knows the position of its canvas pointer. - leftData.position = Vector2.zero; - leftData.scrollDelta = Input.mouseScrollDelta; - leftData.button = UnityEngine.EventSystems.PointerEventData.InputButton.Left; - - if (activeGraphicRaycaster) - { - // Let the active raycaster find intersections on its canvas - activeGraphicRaycaster.RaycastPointer(leftData, m_RaycastResultCache); - var raycast = FindFirstRaycast(m_RaycastResultCache); - leftData.pointerCurrentRaycast = raycast; - m_RaycastResultCache.Clear(); - - OVRRaycaster ovrRaycaster = raycast.module as OVRRaycaster; - if (ovrRaycaster) // raycast may not actually contain a result - { - // The Unity UI system expects event data to have a screen position - // so even though this raycast came from a world space ray we must get a screen - // space position for the camera attached to this raycaster for compatability - Vector2 position = ovrRaycaster.GetScreenPosition(raycast); - - leftData.delta = position - leftData.position; - leftData.position = position; - } - } - - // copy the apropriate data into right and middle slots - UnityEngine.EventSystems.PointerEventData rightData; - GetPointerData(kMouseRightId, out rightData, true ); - CopyFromTo(leftData, rightData); - rightData.button = UnityEngine.EventSystems.PointerEventData.InputButton.Right; - - UnityEngine.EventSystems.PointerEventData middleData; - GetPointerData(kMouseMiddleId, out middleData, true ); - CopyFromTo(leftData, middleData); - middleData.button = UnityEngine.EventSystems.PointerEventData.InputButton.Middle; - - m_MouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Left, StateForMouseButton(0), leftData); - m_MouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Right, StateForMouseButton(1), rightData); - m_MouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData); - return m_MouseState; + mouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Left, GetGazeButtonState(activeController), leftData); + mouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Right, UnityEngine.EventSystems.PointerEventData.FramePressState.NotChanged, rightData); + mouseState.SetButtonState(UnityEngine.EventSystems.PointerEventData.InputButton.Middle, UnityEngine.EventSystems.PointerEventData.FramePressState.NotChanged, middleData); + return mouseState; } /// @@ -840,16 +798,27 @@ namespace ControllerSelection /// Get state of button corresponding to gaze pointer /// /// - protected UnityEngine.EventSystems.PointerEventData.FramePressState GetGazeButtonState() + protected UnityEngine.EventSystems.PointerEventData.FramePressState GetGazeButtonState(OVRInput.Controller activeController) { var pressed = false; var released = false; if (activeController != OVRInput.Controller.None) { - pressed = OVRInput.GetDown(joyPadClickButton, activeController); - released = OVRInput.GetUp(joyPadClickButton, activeController); + if ((activeController & OVRInput.Controller.Touch) != OVRInput.Controller.None) + { + // Handle touch controllers + pressed = OVRInput.GetDown(joyPadClickButton, activeController); + released = OVRInput.GetUp(joyPadClickButton, activeController); + } + else if ((activeController & OVRInput.Controller.Hands) != OVRInput.Controller.None && + OVRPlugin.GetHandTrackingEnabled() && null != HandsManager.Instance && HandsManager.Instance.IsInitialized()) + { + pressed = OVRInputHelpers.IsFingerStartPinching(activeController, pinchFinger); + released = OVRInputHelpers.IsFingerStopPinching(activeController, pinchFinger); + } } - else { + else + { pressed = OVRInput.GetDown(joyPadClickButton); released = OVRInput.GetUp(joyPadClickButton); } @@ -860,16 +829,13 @@ namespace ControllerSelection #endif if (pressed && released) { - //Debug.Log ("pressed & released"); return UnityEngine.EventSystems.PointerEventData.FramePressState.PressedAndReleased; } if (pressed) { - //Debug.Log ("pressed"); - return UnityEngine.EventSystems.PointerEventData.FramePressState.Pressed; + return UnityEngine.EventSystems.PointerEventData.FramePressState.Pressed; } if (released) { - //Debug.Log ("released"); - return UnityEngine.EventSystems.PointerEventData.FramePressState.Released; + return UnityEngine.EventSystems.PointerEventData.FramePressState.Released; } return UnityEngine.EventSystems.PointerEventData.FramePressState.NotChanged; diff --git a/Assets/OVRInputSelection/InputSystem/OVRPointerVisualizer.cs b/Assets/OVRInputSelection/InputSystem/OVRPointerVisualizer.cs index 277a262..ecf1062 100644 --- a/Assets/OVRInputSelection/InputSystem/OVRPointerVisualizer.cs +++ b/Assets/OVRInputSelection/InputSystem/OVRPointerVisualizer.cs @@ -23,7 +23,15 @@ using UnityEngine.SceneManagement; namespace ControllerSelection { - public class OVRPointerVisualizer : MonoBehaviour { + public class OVRPointerVisualizer : MonoBehaviour + { + public enum Hand + { + None, + Left = OVRInputHelpers.HandFilter.Left, + Right = OVRInputHelpers.HandFilter.Right + } + [Header("(Optional) Tracking space")] [Tooltip("Tracking space of the OVRCameraRig.\nIf tracking space is not set, the scene will be searched.\nThis search is expensive.")] public Transform trackingSpace = null; @@ -38,36 +46,42 @@ namespace ControllerSelection { public float gazeDrawDistance = 3; [Tooltip("Show gaze pointer as ray pointer.")] public bool showRayPointer = true; + [Tooltip("Left or Right hand / controller")] + public Hand handType = Hand.None; // Start ray draw distance private const float StartRayDrawDistance = 0.032f; - [HideInInspector] - public OVRInput.Controller activeController = OVRInput.Controller.None; - - void Awake() { - if (trackingSpace == null) { + void Awake() + { + if (trackingSpace == null) + { Debug.LogWarning("OVRPointerVisualizer did not have a tracking space set. Looking for one"); trackingSpace = OVRInputHelpers.FindTrackingSpace(); } } - void OnEnable() { + void OnEnable() + { SceneManager.sceneLoaded += OnSceneLoaded; } - void OnDisable() { + void OnDisable() + { SceneManager.sceneLoaded -= OnSceneLoaded; } - void OnSceneLoaded(Scene scene, LoadSceneMode mode) { - if (trackingSpace == null) { + void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + if (trackingSpace == null) + { Debug.LogWarning("OVRPointerVisualizer did not have a tracking space set. Looking for one"); trackingSpace = OVRInputHelpers.FindTrackingSpace(); } } - public void SetPointer(Ray ray) { + void SetPointer(Ray ray) + { float hitRayDrawDistance = rayDrawDistance; RaycastHit hit; if (Physics.Raycast(ray, out hit)) @@ -75,40 +89,54 @@ namespace ControllerSelection { hitRayDrawDistance = hit.distance; } - if (linePointer != null) { + if (linePointer != null) + { linePointer.SetPosition(0, ray.origin + ray.direction * StartRayDrawDistance); linePointer.SetPosition(1, ray.origin + ray.direction * hitRayDrawDistance); } - if (gazePointer != null) { + if (gazePointer != null) + { gazePointer.position = ray.origin + ray.direction * (showRayPointer ? hitRayDrawDistance : gazeDrawDistance); } } - public void SetPointerVisibility() { - if (trackingSpace != null && activeController != OVRInput.Controller.None) { - if (linePointer != null) { + void SetPointerVisibility(bool show) + { + if (show) { + if (linePointer != null) + { linePointer.enabled = true; } - if (gazePointer != null) { + if (gazePointer != null) + { gazePointer.gameObject.SetActive(showRayPointer ? true : false); } } else { - if (linePointer != null) { + if (linePointer != null) + { linePointer.enabled = false; } - if (gazePointer != null) { + if (gazePointer != null) + { gazePointer.gameObject.SetActive(showRayPointer ? false : true); } } } - void Update() { - activeController = OVRInputHelpers.GetControllerForButton(OVRInput.Button.PrimaryIndexTrigger, activeController); - Ray selectionRay = OVRInputHelpers.GetSelectionRay(activeController, trackingSpace); - SetPointerVisibility(); - SetPointer(selectionRay); + void Update() + { + var activeController = OVRInputHelpers.GetConnectedControllers((OVRInputHelpers.HandFilter)handType); + + Ray selectionRay; + bool gotRay = OVRInputHelpers.GetSelectionRay(activeController, trackingSpace, out selectionRay); + SetPointerVisibility(gotRay && trackingSpace != null && activeController != OVRInput.Controller.None); + + if (gotRay) + { + SetPointer(selectionRay); + } } } } \ No newline at end of file diff --git a/Assets/OVRInputSelection/InputSystem/OVRRawRaycaster.cs b/Assets/OVRInputSelection/InputSystem/OVRRawRaycaster.cs index d74556f..3ac4e2c 100644 --- a/Assets/OVRInputSelection/InputSystem/OVRRawRaycaster.cs +++ b/Assets/OVRInputSelection/InputSystem/OVRRawRaycaster.cs @@ -19,12 +19,25 @@ limitations under the License. ************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Security.Permissions; using UnityEngine; using UnityEngine.Events; +using UnityEngine.EventSystems; using UnityEngine.SceneManagement; -namespace ControllerSelection { - public class OVRRawRaycaster : MonoBehaviour { +namespace ControllerSelection +{ + public class OVRRawRaycaster : MonoBehaviour, IBeginDragHandler, IEndDragHandler + { + public enum Hand + { + None, + Left = OVRInputHelpers.HandFilter.Left, + Right = OVRInputHelpers.HandFilter.Right + } + [System.Serializable] public class HoverCallback : UnityEvent { } [System.Serializable] @@ -34,7 +47,6 @@ namespace ControllerSelection { [Tooltip("Tracking space of the OVRCameraRig.\nIf tracking space is not set, the scene will be searched.\nThis search is expensive.")] public Transform trackingSpace = null; - [Header("Selection")] [Tooltip("Primary selection button")] public OVRInput.Button primaryButton = OVRInput.Button.PrimaryIndexTrigger; @@ -42,6 +54,12 @@ namespace ControllerSelection { public OVRInput.Button secondaryButton = OVRInput.Button.PrimaryTouchpad; [Tooltip("Tertiary selection button")] public OVRInput.Button tertiaryButton = OVRInput.Button.One; + [Tooltip("Primary pinch finger")] + public OVRHand.HandFinger primaryPinchFinger = OVRHand.HandFinger.Index; + [Tooltip("Secondary pinch finger")] + public OVRHand.HandFinger secondaryPinchFinger = OVRHand.HandFinger.Middle; + [Tooltip("Tertiary pinch finger")] + public OVRHand.HandFinger tertiaryPinchFinger = OVRHand.HandFinger.Ring; [Tooltip("Layers to exclude from raycast")] public LayerMask excludeLayers; [Tooltip("Maximum raycast distance")] @@ -58,137 +76,338 @@ namespace ControllerSelection { public OVRRawRaycaster.SelectionCallback onTertiarySelect; //protected Ray pointer; - protected Transform lastHit = null; - protected Transform triggerDown = null; - protected Transform padDown = null; - protected Transform tertiaryDown = null; + protected Transform lastHitLeft = null; + protected Transform lastHitRight = null; + protected Transform lastButtonHitLeft = null; + protected Transform lastButtonHitRight = null; + protected Transform triggerButtonDownLeft = null; + protected Transform triggerButtonDownRight = null; + protected Transform padButtonDownLeft = null; + protected Transform padButtonDownRight = null; + protected Transform tertiaryButtonDownLeft = null; + protected Transform tertiaryButtonDownRight = null; + protected Transform triggerFingerDownLeft = null; + protected Transform triggerFingerDownRight = null; + protected Transform padFingerDownLeft = null; + protected Transform padFingerDownRight = null; + protected Transform tertiaryFingerDownLeft = null; + protected Transform tertiaryFingerDownRight = null; - [HideInInspector] - public OVRInput.Controller activeController = OVRInput.Controller.None; + // Hover actions + [Flags] + enum HoverAction + { + None = 0, + Exit = 1, + Enter = 2, + Stay = 4, + Hover = 8 + } - void Awake() { - if (trackingSpace == null) { + // Map of transform to hover actions. We allocate this once & reuse to avoid memory allocations in Update(). + Dictionary _actions = new Dictionary(4); + + // Whether we're dragging + bool _isDragging = false; + + void Awake() + { + if (trackingSpace == null) + { Debug.LogWarning("OVRRawRaycaster did not have a tracking space set. Looking for one"); trackingSpace = OVRInputHelpers.FindTrackingSpace(); } } - void OnEnable() { + void OnEnable() + { SceneManager.sceneLoaded += OnSceneLoaded; } - void OnDisable() { + void OnDisable() + { SceneManager.sceneLoaded -= OnSceneLoaded; } - void OnSceneLoaded(Scene scene, LoadSceneMode mode) { - if (trackingSpace == null) { + void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + if (trackingSpace == null) + { Debug.LogWarning("OVRRawRaycaster did not have a tracking space set. Looking for one"); trackingSpace = OVRInputHelpers.FindTrackingSpace(); } } - void Update() { - activeController = OVRInputHelpers.GetControllerForButton(OVRInput.Button.PrimaryIndexTrigger, activeController); - Ray pointer = OVRInputHelpers.GetSelectionRay(activeController, trackingSpace); + public void OnBeginDrag(PointerEventData eventData) + { + _isDragging = true; + } - RaycastHit hit; // Was anything hit? - if (Physics.Raycast(pointer, out hit, raycastDistance, ~excludeLayers)) { - if (lastHit != null && lastHit != hit.transform) { - if (onHoverExit != null) { - onHoverExit.Invoke(lastHit); - } - lastHit = null; - } + public void OnEndDrag(PointerEventData eventData) + { + _isDragging = false; + } - if (lastHit == null) { - if (onHoverEnter != null) { - onHoverEnter.Invoke(hit.transform); - } - } - - if (onHover != null) { - onHover.Invoke(hit.transform); - } - - lastHit = hit.transform; - - // Handle selection callbacks. An object is selected if the button selecting it was - // pressed AND released while hovering over the object. - if (activeController != OVRInput.Controller.None) { - if (OVRInput.GetDown(tertiaryButton, activeController)) + static void ProcessHit(Dictionary actions, bool isHit, Transform hit, ref Transform lastHit) + { + if (isHit) + { + if (lastHit != null) + { + if (lastHit != hit) { - tertiaryDown = lastHit; + // We move out of the last hit, so action is Exit + actions[lastHit] |= HoverAction.Exit; + lastHit = null; } - else if (OVRInput.GetUp(tertiaryButton, activeController)) + else { - if (tertiaryDown != null && tertiaryDown == lastHit) - { - if (onTertiarySelect != null) - { - onTertiarySelect.Invoke(tertiaryDown); - } - } - } - if (!OVRInput.Get(tertiaryButton, activeController)) - { - tertiaryDown = null; + // We have not moved from last hit, so action is Stay + actions[lastHit] |= HoverAction.Stay; } + } - if (OVRInput.GetDown(secondaryButton, activeController)) { - padDown = lastHit; - } - else if (OVRInput.GetUp(secondaryButton, activeController)) { - if (padDown != null && padDown == lastHit) { - if (onSecondarySelect != null) { - onSecondarySelect.Invoke(padDown); - } - } - } - if (!OVRInput.Get(secondaryButton, activeController)) { - padDown = null; - } + if (lastHit == null) + { + // We moved into a new hit, so action is Enter + actions[hit] |= HoverAction.Enter; + } - if (OVRInput.GetDown(primaryButton, activeController)) { - triggerDown = lastHit; - } - else if (OVRInput.GetUp(primaryButton, activeController)) { - if (triggerDown != null && triggerDown == lastHit) { - if (onPrimarySelect != null) { - onPrimarySelect.Invoke(triggerDown); - } - } - } - if (!OVRInput.Get(primaryButton, activeController)) { - triggerDown = null; - } - } -#if UNITY_ANDROID && !UNITY_EDITOR - // Gaze pointer fallback - else { - if (Input.GetMouseButtonDown(0) ) { - triggerDown = lastHit; - } - else if (Input.GetMouseButtonUp(0) ) { - if (triggerDown != null && triggerDown == lastHit) { - if (onPrimarySelect != null) { - onPrimarySelect.Invoke(triggerDown); - } - } - } - if (!Input.GetMouseButton(0)) { - triggerDown = null; - } + // We hit something, so action is hover + actions[hit] |= HoverAction.Hover; + lastHit = hit; } -#endif - } - // Nothing was hit, handle exit callback - else if (lastHit != null) { - if (onHoverExit != null) { - onHoverExit.Invoke(lastHit); - } + else if (lastHit != null) + { + // Nothing was hit, handle exit callback + actions[lastHit] |= HoverAction.Exit; lastHit = null; } } + + void ProcessButtonPresses(OVRInput.Controller activeController, bool isLeft, Transform lastHit, + ref Transform triggerDown, ref Transform padDown, ref Transform tertiaryDown) + { + // Handle selection callbacks. An object is selected if the button selecting it was + // pressed AND released while hovering over the object. + if (isLeft && (activeController & OVRInput.Controller.LTouch) != OVRInput.Controller.LTouch || + !isLeft && (activeController & OVRInput.Controller.RTouch) != OVRInput.Controller.RTouch) + { + return; + } + + if (OVRInput.GetDown(tertiaryButton, activeController)) + { + tertiaryDown = lastHit; + } + else if (OVRInput.GetUp(tertiaryButton, activeController)) + { + if (tertiaryDown != null && tertiaryDown == lastHit) + { + if (onTertiarySelect != null) + { + onTertiarySelect.Invoke(tertiaryDown); + } + } + } + if (!OVRInput.Get(tertiaryButton, activeController)) + { + tertiaryDown = null; + } + + if (OVRInput.GetDown(secondaryButton, activeController)) + { + padDown = lastHit; + } + else if (OVRInput.GetUp(secondaryButton, activeController)) + { + if (padDown != null && padDown == lastHit) + { + if (onSecondarySelect != null) + { + onSecondarySelect.Invoke(padDown); + } + } + } + if (!OVRInput.Get(secondaryButton, activeController)) + { + padDown = null; + } + + if (OVRInput.GetDown(primaryButton, activeController)) + { + triggerDown = lastHit; + } + else if (OVRInput.GetUp(primaryButton, activeController)) + { + if (triggerDown != null && triggerDown == lastHit) + { + if (onPrimarySelect != null) + { + onPrimarySelect.Invoke(triggerDown); + } + } + } + if (!OVRInput.Get(primaryButton, activeController)) + { + triggerDown = null; + } + } + + void ProcessHandPinch(OVRInput.Controller activeController, Transform lastHit, + ref Transform triggerDown, ref Transform padDown, ref Transform tertiaryDown) + { + // Handle selection callbacks. An object is selected if the button selecting it was + // pressed AND released while hovering over the object. + if ((activeController & OVRInput.Controller.Hands) == OVRInput.Controller.None) + { + return; + } + + if (!OVRPlugin.GetHandTrackingEnabled() || !HandsManager.Instance || !HandsManager.Instance.IsInitialized()) + { + return; + } + + if (OVRInputHelpers.IsFingerStartPinching(activeController, tertiaryPinchFinger)) + { + tertiaryDown = lastHit; + } + else if (OVRInputHelpers.IsFingerStopPinching(activeController, tertiaryPinchFinger)) + { + if (tertiaryDown != null && tertiaryDown == lastHit) + { + if (onTertiarySelect != null) + { + onTertiarySelect.Invoke(tertiaryDown); + } + } + } + else if (!OVRInputHelpers.IsFingerPinching(activeController, tertiaryPinchFinger)) + { + tertiaryDown = null; + } + + if (OVRInputHelpers.IsFingerStartPinching(activeController, secondaryPinchFinger)) + { + padDown = lastHit; + } + else if (OVRInputHelpers.IsFingerStopPinching(activeController, secondaryPinchFinger)) + { + if (padDown != null && padDown == lastHit) + { + if (onSecondarySelect != null) + { + onSecondarySelect.Invoke(padDown); + } + } + } + else if (!OVRInputHelpers.IsFingerPinching(activeController, secondaryPinchFinger)) + { + padDown = null; + } + + if (OVRInputHelpers.IsFingerStartPinching(activeController, primaryPinchFinger)) + { + triggerDown = lastHit; + } + else if (OVRInputHelpers.IsFingerStopPinching(activeController, primaryPinchFinger)) + { + if (triggerDown != null && triggerDown == lastHit) + { + if (onPrimarySelect != null) + { + onPrimarySelect.Invoke(triggerDown); + } + } + } + else if (!OVRInputHelpers.IsFingerPinching(activeController, primaryPinchFinger)) + { + triggerDown = null; + } + } + + void Update() + { + Ray pointerLeft; + Ray pointerRight; + + // Get left & right rays + var activeControllerLeft = OVRInputHelpers.GetConnectedControllers(OVRInputHelpers.HandFilter.Left); + var activeControllerRight = OVRInputHelpers.GetConnectedControllers(OVRInputHelpers.HandFilter.Right); + + bool gotRayLeft = OVRInputHelpers.GetSelectionRay(activeControllerLeft, trackingSpace, out pointerLeft); + bool gotRayRight = OVRInputHelpers.GetSelectionRay(activeControllerRight, trackingSpace, out pointerRight); + + // Cast the rays + RaycastHit hitLeft = default(RaycastHit); + RaycastHit hitRight = default(RaycastHit); + bool isHitLeft = gotRayLeft && Physics.Raycast(pointerLeft, out hitLeft, raycastDistance, ~excludeLayers); + bool isHitRight = gotRayRight && Physics.Raycast(pointerRight, out hitRight, raycastDistance, ~excludeLayers); + + // Process the hits + _actions.Clear(); + + if (lastHitLeft != null) + { + _actions[lastHitLeft] = HoverAction.None; + } + + if (lastHitRight != null) + { + _actions[lastHitRight] = HoverAction.None; + } + + if (isHitLeft) + { + _actions[hitLeft.transform] = HoverAction.None; + } + + if (isHitRight) + { + _actions[hitRight.transform] = HoverAction.None; + } + + ProcessHit(_actions, isHitLeft, hitLeft.transform, ref lastHitLeft); + ProcessHit(_actions, isHitRight, hitRight.transform, ref lastHitRight); + + // Perform the actions + foreach (KeyValuePair kvp in _actions) + { + // Only perform enter / exit actions if we are not staying on existing transform + // and if we're not both entering & exiting + if ((kvp.Value & HoverAction.Stay) == HoverAction.None && + (kvp.Value & (HoverAction.Enter | HoverAction.Exit)) != (HoverAction.Enter | HoverAction.Exit)) + { + if ((kvp.Value & HoverAction.Enter) != HoverAction.None && onHoverEnter != null) + { + onHoverEnter.Invoke(kvp.Key); + } + + if ((kvp.Value & HoverAction.Exit) != HoverAction.None && onHoverExit != null) + { + onHoverExit.Invoke(kvp.Key); + } + } + + if ((kvp.Value & HoverAction.Hover) != HoverAction.None && onHover != null) + { + // Hovering over transform + onHover.Invoke(kvp.Key); + } + } + + if (isHitLeft && !_isDragging) + { + ProcessButtonPresses(activeControllerLeft, true, lastHitLeft, ref triggerButtonDownLeft, ref padButtonDownLeft, ref tertiaryButtonDownLeft); + ProcessHandPinch(activeControllerLeft, lastHitLeft, ref triggerFingerDownLeft, ref padFingerDownLeft, ref tertiaryFingerDownLeft); + } + + if (isHitRight && !_isDragging) + { + ProcessButtonPresses(activeControllerRight, false, lastHitRight, ref triggerButtonDownRight, ref padButtonDownRight, ref tertiaryButtonDownRight); + ProcessHandPinch(activeControllerRight, lastHitRight, ref triggerFingerDownRight, ref padFingerDownRight, ref tertiaryFingerDownRight); + } + } } } \ No newline at end of file diff --git a/Assets/Resources/OVRPlatformToolSettings.asset b/Assets/Resources/OVRPlatformToolSettings.asset new file mode 100644 index 0000000..4f00931 --- /dev/null +++ b/Assets/Resources/OVRPlatformToolSettings.asset @@ -0,0 +1,23 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cd7bb81df5b74b34dadbf531f381a26b, type: 3} + m_Name: OVRPlatformToolSettings + m_EditorClassIdentifier: + riftRedistPackages: [] + languagePackDirectory: + assetConfigs: + - configList: [] + - configList: [] + - configList: [] + targetPlatform: 3 + runOvrLint: 1 + skipUnneededShaders: 0 diff --git a/Assets/Resources/OVRPlatformToolSettings.asset.meta b/Assets/Resources/OVRPlatformToolSettings.asset.meta new file mode 100644 index 0000000..68fa8d8 --- /dev/null +++ b/Assets/Resources/OVRPlatformToolSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b2c42866fbc7af0418cde247e0c7e807 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/QuestAppLauncher.unity b/Assets/Scenes/QuestAppLauncher.unity index 956ae0c..58965b5 100644 --- a/Assets/Scenes/QuestAppLauncher.unity +++ b/Assets/Scenes/QuestAppLauncher.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.017265823, g: 0.037191074, b: 0.035541035, a: 1} + m_IndirectSpecularColor: {r: 0.0013205316, g: 0.0028316353, b: 0.002707446, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -520,10 +520,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 472cd28b041d447a4b0f2b5c603034aa, type: 3} m_Name: m_EditorClassIdentifier: - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} primaryButton: 8192 secondaryButton: 0 tertiaryButton: 0 + primaryPinchFinger: 1 + secondaryPinchFinger: 2 + tertiaryPinchFinger: 3 excludeLayers: serializedVersion: 2 m_Bits: 0 @@ -579,7 +582,6 @@ MonoBehaviour: onTertiarySelect: m_PersistentCalls: m_Calls: [] - activeController: 0 --- !u!65 &49821818 BoxCollider: m_ObjectHideFlags: 0 @@ -1738,12 +1740,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 147802644} m_CullTransparentMesh: 0 ---- !u!1 &154827158 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 159718, guid: 126d619cf4daa52469682f85c1378b4a, - type: 3} - m_PrefabInstance: {fileID: 1811954864} - m_PrefabAsset: {fileID: 0} --- !u!1001 &174121771 PrefabInstance: m_ObjectHideFlags: 0 @@ -5707,10 +5703,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 472cd28b041d447a4b0f2b5c603034aa, type: 3} m_Name: m_EditorClassIdentifier: - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} primaryButton: 8192 secondaryButton: 10 tertiaryButton: 5 + primaryPinchFinger: 1 + secondaryPinchFinger: 2 + tertiaryPinchFinger: 3 excludeLayers: serializedVersion: 2 m_Bits: 0 @@ -5762,33 +5761,10 @@ MonoBehaviour: m_CallState: 2 onSecondarySelect: m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 686608804} - m_MethodName: OnSelectedPressedBorY - m_Mode: 0 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 + m_Calls: [] onTertiarySelect: m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 686608804} - m_MethodName: OnSelectedPressedAorX - m_Mode: 0 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 - activeController: 0 + m_Calls: [] --- !u!114 &686608804 MonoBehaviour: m_ObjectHideFlags: 0 @@ -6700,6 +6676,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 91f098ea5c7fe084c8f890ad453a103c, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!1 &798664536 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 1870938896605422, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + m_PrefabInstance: {fileID: 1020758336} + m_PrefabAsset: {fileID: 0} --- !u!1 &821577071 GameObject: m_ObjectHideFlags: 0 @@ -6789,6 +6771,85 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 821577071} m_CullTransparentMesh: 0 +--- !u!1 &831075830 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 831075831} + - component: {fileID: 831075833} + - component: {fileID: 831075832} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &831075831 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 831075830} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 3} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 1086705927} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &831075832 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 831075830} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 02f4d91e963f1e74d8bee0002c24efe7, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &831075833 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 831075830} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} --- !u!4 &850048949 stripped Transform: m_CorrespondingSourceObject: {fileID: 482130, guid: 126d619cf4daa52469682f85c1378b4a, @@ -6959,7 +7020,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: content: {fileID: 2026974424} - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} --- !u!114 &870628892 MonoBehaviour: m_ObjectHideFlags: 0 @@ -7331,12 +7392,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 874387363} m_CullTransparentMesh: 0 ---- !u!4 &881994610 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 459718, guid: 126d619cf4daa52469682f85c1378b4a, - type: 3} - m_PrefabInstance: {fileID: 1811954864} - m_PrefabAsset: {fileID: 0} --- !u!1 &883330323 GameObject: m_ObjectHideFlags: 0 @@ -7906,8 +7961,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b4a9c50de96f6d04386957f4741ac65c, type: 3} m_Name: m_EditorClassIdentifier: - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} joyPadClickButton: 8192 + pinchFinger: 1 performSphereCastForGazepointer: 0 matchNormalOnPhysicsColliders: 0 useLeftStickScroll: 1 @@ -7916,13 +7972,14 @@ MonoBehaviour: minSwipeMovement: 0 swipeScrollScale: 4 activeController: 0 - angleDragThreshold: 1 + angleDragThreshold: 3 + suppressClickOnDrag: 1 m_HorizontalAxis: Horizontal m_VerticalAxis: Vertical m_SubmitButton: Submit m_CancelButton: Cancel m_InputActionsPerSecond: 10 - m_AllowActivationOnMobileDevice: 0 + m_AllowActivationOnMobileDevice: 1 --- !u!114 &985952873 MonoBehaviour: m_ObjectHideFlags: 0 @@ -8183,6 +8240,93 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1004538039} m_CullTransparentMesh: 0 +--- !u!1001 &1020758336 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 850048949} + m_Modifications: + - target: {fileID: 1870938896605422, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_Name + value: OVRHandPrefab + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 114252240061623322, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _systemGestureMaterial + value: + objectReference: {fileID: 2100000, guid: 135e7828c00a165428394051b63e55aa, type: 2} + - target: {fileID: 114392993255165844, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: m_Enabled + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 114392993255165844, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _skeletonMaterial + value: + objectReference: {fileID: 2100000, guid: 5eec8807c5526ce4396daa4d3d31259a, type: 2} + - target: {fileID: 114392993255165844, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _systemGestureMaterial + value: + objectReference: {fileID: 2100000, guid: 205613560f9b94149817adcb207284ca, type: 2} + - target: {fileID: 114567484643301796, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _enablePhysicsCapsules + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 137619227449585070, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 0df12b5511b088d4c85a129ef70af305, type: 2} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 835e735ca71bf78459fb2cababd74112, type: 3} --- !u!1 &1026875225 GameObject: m_ObjectHideFlags: 0 @@ -8618,7 +8762,7 @@ GameObject: - component: {fileID: 1086705926} - component: {fileID: 1086705925} m_Layer: 0 - m_Name: SelectionVisualizer + m_Name: LeftSelectionVisualizer m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -8734,12 +8878,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 12283131fa5724f44b343883ae474072, type: 3} m_Name: m_EditorClassIdentifier: - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} linePointer: {fileID: 1086705925} - gazePointer: {fileID: 2108958131} + gazePointer: {fileID: 831075831} rayDrawDistance: 500 gazeDrawDistance: 3 showRayPointer: 1 + handType: 1 activeController: 0 --- !u!4 &1086705927 Transform: @@ -8748,13 +8893,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1086705924} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: - - {fileID: 2108958131} - m_Father: {fileID: 0} - m_RootOrder: 7 + - {fileID: 831075831} + m_Father: {fileID: 1507746428} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1090603839 GameObject: @@ -9705,6 +9850,114 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1148345054} m_CullTransparentMesh: 0 +--- !u!1001 &1157065265 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1192133537} + m_Modifications: + - target: {fileID: 1870938896605422, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_Name + value: OVRHandPrefab + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4453513310108136, guid: 835e735ca71bf78459fb2cababd74112, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 114252240061623322, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _systemGestureMaterial + value: + objectReference: {fileID: 2100000, guid: 135e7828c00a165428394051b63e55aa, type: 2} + - target: {fileID: 114392993255165844, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: m_Enabled + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 114392993255165844, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _skeletonMaterial + value: + objectReference: {fileID: 2100000, guid: 5eec8807c5526ce4396daa4d3d31259a, type: 2} + - target: {fileID: 114392993255165844, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _systemGestureMaterial + value: + objectReference: {fileID: 2100000, guid: 205613560f9b94149817adcb207284ca, type: 2} + - target: {fileID: 114428879332287356, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: HandType + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 114567484643301796, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _enablePhysicsCapsules + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 114567484643301796, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _skeletonType + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 114925265787909616, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: _meshType + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 137619227449585070, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 0df12b5511b088d4c85a129ef70af305, type: 2} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 835e735ca71bf78459fb2cababd74112, type: 3} +--- !u!1 &1157065266 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 1870938896605422, guid: 835e735ca71bf78459fb2cababd74112, + type: 3} + m_PrefabInstance: {fileID: 1157065265} + m_PrefabAsset: {fileID: 0} --- !u!1 &1157126547 GameObject: m_ObjectHideFlags: 0 @@ -13289,6 +13542,38 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_IsOn: 0 +--- !u!1 &1507746427 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1507746428} + m_Layer: 0 + m_Name: SelectionVisualizers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1507746428 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1507746427} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1086705927} + - {fileID: 1759377395} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1508111132 GameObject: m_ObjectHideFlags: 0 @@ -14078,7 +14363,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: content: {fileID: 627993405} - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} --- !u!114 &1585122607 MonoBehaviour: m_ObjectHideFlags: 0 @@ -14523,7 +14808,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: content: {fileID: 858538435} - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} --- !u!1 &1623456991 GameObject: m_ObjectHideFlags: 0 @@ -15298,6 +15583,157 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1748840623} m_CullTransparentMesh: 0 +--- !u!1 &1759377394 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1759377395} + - component: {fileID: 1759377397} + - component: {fileID: 1759377396} + m_Layer: 0 + m_Name: RightSelectionVisualizer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1759377395 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1759377394} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2108958131} + m_Father: {fileID: 1507746428} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!120 &1759377396 +LineRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1759377394} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 0} + - {fileID: 2100000, guid: 02f4d91e963f1e74d8bee0002c24efe7, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Positions: + - {x: 0, y: 0, z: 0} + - {x: 0, y: 0, z: 1} + m_Parameters: + serializedVersion: 3 + widthMultiplier: 0.005 + widthCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + colorGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + numCornerVertices: 0 + numCapVertices: 0 + alignment: 0 + textureMode: 0 + shadowBias: 0 + generateLightingData: 0 + m_UseWorldSpace: 1 + m_Loop: 0 +--- !u!114 &1759377397 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1759377394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 12283131fa5724f44b343883ae474072, type: 3} + m_Name: + m_EditorClassIdentifier: + trackingSpace: {fileID: 1811954865} + linePointer: {fileID: 1759377396} + gazePointer: {fileID: 2108958131} + rayDrawDistance: 500 + gazeDrawDistance: 3 + showRayPointer: 1 + handType: 2 + activeController: 0 --- !u!1 &1764737580 GameObject: m_ObjectHideFlags: 0 @@ -16285,6 +16721,18 @@ PrefabInstance: m_RemovedComponents: - {fileID: 114473266101150724, guid: 126d619cf4daa52469682f85c1378b4a, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 126d619cf4daa52469682f85c1378b4a, type: 3} +--- !u!4 &1811954865 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 459718, guid: 126d619cf4daa52469682f85c1378b4a, + type: 3} + m_PrefabInstance: {fileID: 1811954864} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1811954866 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 159718, guid: 126d619cf4daa52469682f85c1378b4a, + type: 3} + m_PrefabInstance: {fileID: 1811954864} + m_PrefabAsset: {fileID: 0} --- !u!1 &1815300719 GameObject: m_ObjectHideFlags: 0 @@ -16802,7 +17250,7 @@ MonoBehaviour: rightTabContainerContent: {fileID: 2026974423} renamePanelContainer: {fileID: 686608799} scrollRenameContainer: {fileID: 1045416981} - trackingSpace: {fileID: 154827158} + trackingSpace: {fileID: 1811954866} downloadStatusIndicator: {fileID: 788846829} prefabCell: {fileID: 4824380111246446992, guid: 8767e935b90413e48ae368ff87547352, type: 3} @@ -16997,6 +17445,52 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1875820932} m_Mesh: {fileID: 4300000, guid: 32fbc8bcebb64584da5868aeeb086cda, type: 3} +--- !u!1 &1876783794 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1876783795} + - component: {fileID: 1876783796} + m_Layer: 0 + m_Name: HandsManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1876783795 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1876783794} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1876783796 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1876783794} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 355b24382fa1a9c4f8b72fd2095581f7, type: 3} + m_Name: + m_EditorClassIdentifier: + _leftHand: {fileID: 798664536} + _rightHand: {fileID: 1157065266} + VisualMode: 0 --- !u!1 &1890535731 GameObject: m_ObjectHideFlags: 0 @@ -17535,10 +18029,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 472cd28b041d447a4b0f2b5c603034aa, type: 3} m_Name: m_EditorClassIdentifier: - trackingSpace: {fileID: 881994610} + trackingSpace: {fileID: 1811954865} primaryButton: 8192 secondaryButton: 10 tertiaryButton: 5 + primaryPinchFinger: 1 + secondaryPinchFinger: 3 + tertiaryPinchFinger: 4 excludeLayers: serializedVersion: 2 m_Bits: 0 @@ -17616,7 +18113,6 @@ MonoBehaviour: m_StringArgument: m_BoolArgument: 0 m_CallState: 2 - activeController: 0 --- !u!114 &1950750525 MonoBehaviour: m_ObjectHideFlags: 0 @@ -20083,11 +20579,11 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2108958130} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 3} m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} m_Children: [] - m_Father: {fileID: 1086705927} + m_Father: {fileID: 1759377395} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!23 &2108958132 diff --git a/Assets/Scripts/DownloadHandlerFileWithProgress.cs b/Assets/Scripts/DownloadHandlerFileWithProgress.cs index eca978a..6cc1d7a 100644 --- a/Assets/Scripts/DownloadHandlerFileWithProgress.cs +++ b/Assets/Scripts/DownloadHandlerFileWithProgress.cs @@ -58,6 +58,7 @@ namespace QuestAppLauncher return contentLength <= 0 ? 0 : Mathf.Clamp01((float)this.received / (float)contentLength); } + [Obsolete] protected override void ReceiveContentLength(int contentLength) { this.contentLength = contentLength; diff --git a/Assets/Scripts/DownloadStatusIndicator.cs b/Assets/Scripts/DownloadStatusIndicator.cs index 1141776..7cb9aa8 100644 --- a/Assets/Scripts/DownloadStatusIndicator.cs +++ b/Assets/Scripts/DownloadStatusIndicator.cs @@ -38,7 +38,7 @@ namespace QuestAppLauncher private readonly object stateLock = new object(); // State information - private string name; + private string fileName; private float progress; private string errorMessage; @@ -64,10 +64,10 @@ namespace QuestAppLauncher switch (this.state) { case State.DownloadStart: - this.textGui.text = string.Format("Downloading {0}", this.name); + this.textGui.text = string.Format("Downloading {0}", this.fileName); break; case State.DownloadFinish: - this.textGui.text = string.Format("Downloading {0} [100%]", this.name); + this.textGui.text = string.Format("Downloading {0} [100%]", this.fileName); break; case State.Checking: this.textGui.text = string.Format("Checking for updates"); @@ -100,7 +100,7 @@ namespace QuestAppLauncher this.textGui.text = this.errorMessage; break; case State.DownloadProgress: - this.textGui.text = string.Format("Downloading {0} [{1:0}%]", this.name, this.progress * 100); + this.textGui.text = string.Format("Downloading {0} [{1:0}%]", this.fileName, this.progress * 100); this.state = State.DownloadProgressUpdated; break; } @@ -114,11 +114,11 @@ namespace QuestAppLauncher } } - public void OnDownloadStart(string name) + public void OnDownloadStart(string fileName) { lock (this.stateLock) { - this.name = name; + this.fileName = fileName; this.state = State.DownloadStart; } } diff --git a/Assets/Scripts/ScrollRectColliderMask.cs b/Assets/Scripts/ScrollRectColliderMask.cs index 3eb51a0..93f9738 100644 --- a/Assets/Scripts/ScrollRectColliderMask.cs +++ b/Assets/Scripts/ScrollRectColliderMask.cs @@ -16,9 +16,6 @@ public class ScrollRectColliderMask : MonoBehaviour // Whether the pointer is within bounds of the scroll rect private bool isInBounds = true; - private bool isInitialized = false; - - private OVRInput.Controller activeController = OVRInput.Controller.None; // Start is called before the first frame update void Start() @@ -29,11 +26,17 @@ public class ScrollRectColliderMask : MonoBehaviour // Update is called once per frame void Update() { - this.activeController = OVRInputHelpers.GetControllerForButton(OVRInput.Button.PrimaryIndexTrigger, this.activeController); - Ray pointer = OVRInputHelpers.GetSelectionRay(this.activeController, this.trackingSpace); + var activeControllerLeft = OVRInputHelpers.GetConnectedControllers(OVRInputHelpers.HandFilter.Left); + Ray pointerLeft; + bool gotRayLeft = OVRInputHelpers.GetSelectionRay(activeControllerLeft, this.trackingSpace, out pointerLeft); - RaycastHit hit; - if (this.boxCollider.Raycast(pointer, out hit, 500)) + var activeControllerRight = OVRInputHelpers.GetConnectedControllers(OVRInputHelpers.HandFilter.Right); + Ray pointerRight; + bool gotRayRight = OVRInputHelpers.GetSelectionRay(activeControllerRight, this.trackingSpace, out pointerRight); + + RaycastHit hitLeft; + RaycastHit hitRight; + if (gotRayLeft && this.boxCollider.Raycast(pointerLeft, out hitLeft, 500) || gotRayRight && this.boxCollider.Raycast(pointerRight, out hitRight, 500)) { // We got a hit in the scroll view. Check if we're already within the bounds - if so, do nothing. if (!isInBounds) diff --git a/Assets/Scripts/ScrollRectOverride.cs b/Assets/Scripts/ScrollRectOverride.cs index be35277..130769a 100644 --- a/Assets/Scripts/ScrollRectOverride.cs +++ b/Assets/Scripts/ScrollRectOverride.cs @@ -3,10 +3,11 @@ using System.Collections; using UnityEngine.UI; using UnityEngine.EventSystems; using ControllerSelection; +using System.ComponentModel; namespace QuestAppLauncher { - public class ScrollRectOverride : ScrollRect, IMoveHandler, IPointerClickHandler, IScrollHandler + public class ScrollRectOverride : ScrollRect, IMoveHandler, IPointerClickHandler, IScrollHandler, IDragHandler { // Scrolling speed multiplier private const float SpeedMultiplier = 15f; @@ -33,12 +34,25 @@ namespace QuestAppLauncher // Whether the pointer is within bounds of the scroll rect private bool isInBounds = false; - private OVRInput.Controller activeController = OVRInput.Controller.None; + // Parent OVRRawRayCaster + private OVRRawRaycaster parentRawRaycaster = null; void Start() { this.cellHeight = this.transform.GetComponentInChildren().cellSize.y; this.boxCollider = GetComponent(); + + // Find parent OVRRawRayCaster + Transform t = this.gameObject.transform; + while (t.parent != null) + { + parentRawRaycaster = t.parent.GetComponent(); + if (parentRawRaycaster != null) + { + break; + } + t = t.parent.transform; + } } void Update() @@ -53,11 +67,17 @@ namespace QuestAppLauncher // colliders, which will behave as expected. // If we do not get a hit, it means that we're outside the scroll view - so we disable all the children // box colliders, which addresses the issue above. - this.activeController = OVRInputHelpers.GetControllerForButton(OVRInput.Button.PrimaryIndexTrigger, this.activeController); - Ray pointer = OVRInputHelpers.GetSelectionRay(this.activeController, this.trackingSpace); + var activeControllerLeft = OVRInputHelpers.GetConnectedControllers(OVRInputHelpers.HandFilter.Left); + Ray pointerLeft; + bool gotRayLeft = OVRInputHelpers.GetSelectionRay(activeControllerLeft, this.trackingSpace, out pointerLeft); - RaycastHit hit; - if (this.boxCollider.Raycast(pointer, out hit, 500)) + var activeControllerRight = OVRInputHelpers.GetConnectedControllers(OVRInputHelpers.HandFilter.Right); + Ray pointerRight; + bool gotRayRight = OVRInputHelpers.GetSelectionRay(activeControllerRight, this.trackingSpace, out pointerRight); + + RaycastHit hitLeft; + RaycastHit hitRight; + if (gotRayLeft && this.boxCollider.Raycast(pointerLeft, out hitLeft, 500) || gotRayRight && this.boxCollider.Raycast(pointerRight, out hitRight, 500)) { // We got a hit in the scroll view. Check if we're already within the bounds - if so, do nothing. if (!isInBounds) @@ -146,6 +166,32 @@ namespace QuestAppLauncher public override void OnBeginDrag(PointerEventData eventData) { + // Only handle dragging if hands are active. Use thumbstick on controllers. + if (!OVRPlugin.GetHandTrackingEnabled()) + { + return; + } + + if (null != parentRawRaycaster) + { + parentRawRaycaster.OnBeginDrag(eventData); + } + base.OnBeginDrag(eventData); + } + + public override void OnEndDrag(PointerEventData eventData) + { + // Only handle dragging if hands are active. Use thumbstick on controllers. + if (!OVRPlugin.GetHandTrackingEnabled()) + { + return; + } + + if (null != parentRawRaycaster) + { + parentRawRaycaster.OnEndDrag(eventData); + } + base.OnEndDrag(eventData); } void IMoveHandler.OnMove(AxisEventData e) @@ -154,6 +200,7 @@ namespace QuestAppLauncher void IScrollHandler.OnScroll(PointerEventData eventData) { + base.OnScroll(eventData); } void OnMouseDrag() diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index d593089..4fab503 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -12,7 +12,7 @@ PlayerSettings: targetDevice: 2 useOnDemandResources: 0 accelerometerFrequency: 60 - companyName: DefaultCompany + companyName: AAA productName: Quest App Launcher defaultCursor: {fileID: 0} cursorHotspot: {x: 0, y: 0} @@ -47,7 +47,7 @@ PlayerSettings: defaultScreenWidthWeb: 960 defaultScreenHeightWeb: 600 m_StereoRenderingPath: 1 - m_ActiveColorSpace: 0 + m_ActiveColorSpace: 1 m_MTRendering: 1 m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 @@ -119,8 +119,10 @@ PlayerSettings: 16:10: 1 16:9: 1 Others: 1 - bundleVersion: 0.10.3 - preloadedAssets: [] + bundleVersion: 0.11 + preloadedAssets: + - {fileID: -8332471933877474197, guid: 2be630b98a6f0a248ac3849f76251ed9, type: 2} + - {fileID: 11400000, guid: 497e8cda6e724d341b6eeb4df763826d, type: 2} metroInputSource: 0 wsaTransparentSwapchain: 0 m_HolographicPauseOnTrackingLoss: 1 @@ -167,7 +169,7 @@ PlayerSettings: Standalone: com.DefaultCompany.QuestAppLauncher buildNumber: {} AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 21 + AndroidMinSdkVersion: 25 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 0 aotOptions: @@ -451,9 +453,8 @@ PlayerSettings: - Oculus - OpenVR - m_BuildTarget: Android - m_Enabled: 1 - m_Devices: - - Oculus + m_Enabled: 0 + m_Devices: [] openGLRequireES31: 0 openGLRequireES31AEP: 0 openGLRequireES32: 0 diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index 6837483..3cf26a9 100644 --- a/ProjectSettings/QualitySettings.asset +++ b/ProjectSettings/QualitySettings.asset @@ -93,7 +93,7 @@ QualitySettings: skinWeights: 2 textureQuality: 0 anisotropicTextures: 2 - antiAliasing: 8 + antiAliasing: 0 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 diff --git a/ProjectSettings/XRSettings.asset b/ProjectSettings/XRSettings.asset index 1fe5691..ccaaf97 100644 --- a/ProjectSettings/XRSettings.asset +++ b/ProjectSettings/XRSettings.asset @@ -6,7 +6,7 @@ ], "m_SettingValues": [ "True", - "False", + "True", "Android" ] } \ No newline at end of file