Beispiel #1
0
        public IEnumerator PrefabScrollUpZoomOutLimited()
        {
            var maxPanHorizontal = 4f;
            var maxPanVertical   = 4f;

            InstantiatePanLimitedSlateFromPrefab(maxPanHorizontal: maxPanHorizontal, maxPanVertical: maxPanVertical);

            yield return(ScrollToLimit(new Vector3(1, 1, 0)));

            // Right hand pinches slate
            TestHand handRight = new TestHand(Handedness.Right);

            yield return(handRight.MoveTo(panZoom.transform.position + Vector3.forward * -0.5f + Vector3.right * 0.2f));

            yield return(handRight.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            // Left hand pinches slate
            TestHand handLeft = new TestHand(Handedness.Left);

            yield return(handLeft.Show(panZoom.transform.position + Vector3.forward * -0.5f + Vector3.right * -0.2f));

            yield return(handLeft.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            // Use both hands to zoom out
            yield return(handLeft.Move(new Vector3(0.1f, 0.1f, 0f), 10));

            var uvs = new List <Vector2>();

            meshFilter.mesh.GetUVs(0, uvs);

#if UNITY_2019_1_OR_NEWER
            Assert.AreEqual(maxPanHorizontal * material.mainTextureScale.x, uvs[3].x, 0.05, "mesh uv is not correct");
            Assert.AreEqual(maxPanVertical * material.mainTextureScale.y, uvs[3].y, 0.05, "mesh uv is not correct");
#else
            Assert.AreEqual(maxPanHorizontal * material.mainTextureScale.x, uvs[1].x, 0.05, "mesh uv is not correct");
            Assert.AreEqual(maxPanVertical * material.mainTextureScale.y, uvs[1].y, 0.05, "mesh uv is not correct");
#endif

            yield return(handRight.Hide());

            yield return(handLeft.Hide());
        }
        public IEnumerator TestGaze()
        {
            PointerStateContainer gazeOn = new PointerStateContainer()
            {
                GazePointerEnabled   = true,
                GGVPointerEnabled    = true,
                PokePointerEnabled   = null,
                SpherePointerEnabled = null,
                LinePointerEnabled   = null
            };

            // set input simulation mode to GGV
            PlayModeTestUtilities.SetControllerSimulationMode(ControllerSimulationMode.HandGestures);

            TestHand rightHand = new TestHand(Handedness.Right);
            TestHand leftHand  = new TestHand(Handedness.Left);

            TestContext.Out.WriteLine("Show both hands");
            yield return(rightHand.Show(Vector3.zero));

            yield return(leftHand.Show(Vector3.zero));

            EnsurePointerStates(Handedness.Right, gazeOn);
            EnsurePointerStates(Handedness.Left, gazeOn);

            TestContext.Out.WriteLine("Turn off gaze cursor");
            PointerUtils.SetGazePointerBehavior(PointerBehavior.AlwaysOff);

            yield return(null);

            PointerStateContainer gazeOff = new PointerStateContainer()
            {
                GazePointerEnabled   = false,
                GGVPointerEnabled    = false,
                PokePointerEnabled   = null,
                SpherePointerEnabled = null,
                LinePointerEnabled   = null
            };

            EnsurePointerStates(Handedness.Right, gazeOff);
            EnsurePointerStates(Handedness.Left, gazeOff);
        }
        public IEnumerator TestDestroyFocusLockedObject()
        {
            TestUtilities.PlayspaceToOriginLookingForward();
            var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

            cube.AddComponent <ObjectManipulator>(); // Add focus handler so focus can lock
            cube.transform.position   = Vector3.right;
            cube.transform.localScale = Vector3.one * 0.2f;

            const int numHandSteps = 1;

            // No initial focus
            cube.transform.position = Vector3.forward;
            TestHand hand = new TestHand(Handedness.Right);

            yield return(hand.Show(Vector3.forward * 0.5f));

            yield return(null);

            var handRayPointer = hand.GetPointer <ShellHandRayPointer>();

            Assert.IsNull(handRayPointer.Result.CurrentPointerTarget);

            // Focus lock cube
            yield return(hand.MoveTo(new Vector3(0.06f, -0.1f, 0.5f), numHandSteps));

            yield return(hand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(null);

            Assert.IsTrue(handRayPointer.IsFocusLocked);
            Assert.AreEqual(cube, handRayPointer.Result.CurrentPointerTarget);

            // Destroy the cube
            Object.DestroyImmediate(cube);
            yield return(null);

            Assert.IsFalse(handRayPointer.IsFocusLocked);
            Assert.IsNull(handRayPointer.Result.CurrentPointerTarget);
            // Verify that CurrentPointer is not still referencing the destroyed GameObject
            Assert.IsTrue(ReferenceEquals(handRayPointer.Result.CurrentPointerTarget, null));
        }
Beispiel #4
0
        public IEnumerator TestAssembeInteractableAndEventsRaised()
        {
            GameObject  pinchSliderObject;
            PinchSlider slider;

            // This should not throw exception
            AssembleSlider(Vector3.forward, Vector3.zero, out pinchSliderObject, out slider);

            var     rightHand  = new TestHand(Handedness.Right);
            Vector3 initialPos = new Vector3(0.05f, 0, 1.0f);

            bool interactionStarted = false;

            slider.OnInteractionStarted.AddListener((x) => interactionStarted = true);
            yield return(rightHand.Show(initialPos));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            Assert.IsTrue(interactionStarted, "Slider did not raise interaction started.");

            bool interactionUpdated = false;

            slider.OnValueUpdated.AddListener((x) => interactionUpdated = true);

            yield return(rightHand.Move(new Vector3(0.1f, 0, 0)));

            Assert.IsTrue(interactionUpdated, "Slider did not raise SliderUpdated event.");

            bool interactionEnded = false;

            slider.OnInteractionEnded.AddListener((x) => interactionEnded = true);

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            yield return(rightHand.Hide());

            Assert.IsTrue(interactionEnded, "Slider did not raise interaction ended.");

            Assert.That(slider.SliderValue, Is.GreaterThan(0.5));

            GameObject.Destroy(pinchSliderObject);
        }
Beispiel #5
0
        /// <summary>
        /// Scroll a slate using GGV and ensure that the slate scrolls
        /// expected amount. Assumes panZoom has already been created.
        /// </summary>
        /// <param name="expectedScroll">The amount panZoom is expected to scroll</param>
        private IEnumerator RunGGVScrollTest(float expectedScroll)
        {
            PlayModeTestUtilities.SetHandSimulationMode(HandSimulationMode.Gestures);

            Vector2 totalPanDelta = Vector2.zero;

            panZoom.PanUpdated.AddListener((hpd) => totalPanDelta += hpd.PanDelta);

            TestHand h = new TestHand(Handedness.Right);

            yield return(h.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(h.Show(Vector3.zero));

            yield return(h.Move(new Vector3(0.0f, -0.1f, 0f)));

            Assert.AreEqual(expectedScroll, totalPanDelta.y, 0.05, "pan delta is not correct");

            yield return(h.Hide());
        }
        public IEnumerator HandRayTest()
        {
            yield return(null);

            Vector3 rightHandOrigin = new Vector3(-0.3f, -0.1f, 0.5f);

            // Create a hand (we will use the right hand)
            TestHand rightHand = new TestHand(Handedness.Right);

            yield return(rightHand.Show(rightHandOrigin));

            Ray  ray;
            bool success;

            TestContext.Out.WriteLine("Get the right hand ray");
            success = InputRayUtils.TryGetHandRay(Handedness.Right, out ray);
            Assert.True(success, "TryGetHandRay did not succeed");
            TestUtilities.AssertAboutEqual(ray.origin, rightHandOrigin, "hand ray origin is not correct", 0.1f);
            TestUtilities.AssertAboutEqual(ray.direction, new Vector3(-0.7f, 0.2f, 0.7f), "hand ray direction is not correct", 0.1f);
        }
        public IEnumerator TestDisableFocusObject()
        {
            TestUtilities.PlayspaceToOriginLookingForward();
            var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

            cube.transform.position   = Vector3.right;
            cube.transform.localScale = Vector3.one * 0.2f;

            const int numHandSteps = 1;

            // No initial focus
            cube.transform.position = Vector3.forward;
            TestHand hand = new TestHand(Handedness.Right);

            yield return(hand.Show(Vector3.forward * 0.5f));

            yield return(null);

            var handRayPointer = hand.GetPointer <ShellHandRayPointer>();

            Assert.IsNull(handRayPointer.Result.CurrentPointerTarget);

            // Focus on cube
            yield return(hand.MoveTo(new Vector3(0.06f, -0.1f, 0.5f), numHandSteps));

            yield return(null);

            Assert.AreEqual(cube, handRayPointer.Result.CurrentPointerTarget);

            // Deactivate the cube
            cube.SetActive(false);
            yield return(null);

            Assert.IsNull(handRayPointer.Result.CurrentPointerTarget);

            // Reactivate the cube
            cube.SetActive(true);
            yield return(null);

            Assert.AreEqual(cube, handRayPointer.Result.CurrentPointerTarget);
        }
        public IEnumerator TestRadialSetPrefab()
        {
            var radialSet          = InstantiateInteractableFromPath(Vector3.forward, Quaternion.identity, RadialSetPrefabAssetPath);
            var firstRadialButton  = radialSet.transform.Find("Radial (1)").GetComponent <Interactable>();
            var secondRadialButton = radialSet.transform.Find("Radial (2)").GetComponent <Interactable>();
            var thirdRadialButton  = radialSet.transform.Find("Radial (3)").GetComponent <Interactable>();
            var testHand           = new TestHand(Handedness.Right);

            yield return(testHand.Show(Vector3.zero));

            Assert.IsTrue(firstRadialButton.IsToggled);
            Assert.IsFalse(secondRadialButton.IsToggled);
            Assert.IsFalse(thirdRadialButton.IsToggled);

            var aBitBack = Vector3.forward * -0.2f;

            yield return(testHand.MoveTo(secondRadialButton.transform.position));

            yield return(testHand.Move(aBitBack));

            Assert.IsFalse(firstRadialButton.IsToggled);
            Assert.IsFalse(firstRadialButton.HasFocus);
            Assert.IsTrue(secondRadialButton.IsToggled);
            Assert.IsTrue(secondRadialButton.HasFocus);
            Assert.IsFalse(thirdRadialButton.IsToggled);
            Assert.IsFalse(thirdRadialButton.HasFocus);

            yield return(testHand.MoveTo(thirdRadialButton.transform.position));

            yield return(testHand.Move(aBitBack));

            Assert.IsFalse(firstRadialButton.IsToggled);
            Assert.IsFalse(firstRadialButton.HasFocus);
            Assert.IsFalse(secondRadialButton.IsToggled);
            Assert.IsFalse(secondRadialButton.HasFocus);
            Assert.IsTrue(thirdRadialButton.IsToggled);
            Assert.IsTrue(thirdRadialButton.HasFocus);

            //Cleanup
            GameObject.Destroy(radialSet);
        }
        public IEnumerator ArticulatedCursorState()
        {
            var inputSystem = PlayModeTestUtilities.GetInputSystem();

            // Show hand far enough from the test collider so the cursor is not on it
            var     hand         = new TestHand(Handedness.Right);
            Vector3 offObjectPos = TestUtilities.PositionRelativeToPlayspace(new Vector3(0.05f, 0, 1.0f));

            yield return(hand.Show(offObjectPos));

            VerifyCursorStateFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorStateEnum.Interact);

            // Move hand closer to the collider so the cursor is on it
            Vector3 onObjectPos = TestUtilities.PositionRelativeToPlayspace(new Vector3(0.05f, 0, 1.5f));

            yield return(hand.MoveTo(onObjectPos, numFramesPerMove));

            VerifyCursorStateFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorStateEnum.InteractHover);

            // Trigger pinch
            yield return(hand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            VerifyCursorStateFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorStateEnum.Select);

            // Release pinch
            yield return(hand.SetGesture(ArticulatedHandPose.GestureId.Open, false));

            VerifyCursorStateFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorStateEnum.Release);

            // Wait to transition back to InteractHover
            yield return(null);

            VerifyCursorStateFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorStateEnum.InteractHover);

            // Move back so the cursor is no longer on the object
            yield return(hand.MoveTo(offObjectPos, numFramesPerMove));

            VerifyCursorStateFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorStateEnum.Interact);

            yield return(null);
        }
        public IEnumerator TestGazeProviderTargetNotNull()
        {
            TestUtilities.PlayspaceToOriginLookingForward();
            var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

            cube.transform.position = Vector3.forward;

            yield return(null);

            yield return(null);

            Assert.NotNull(CoreServices.InputSystem.GazeProvider.GazeTarget, "GazeProvider target is null when looking at an object");

            TestHand h = new TestHand(Handedness.Right);

            yield return(h.Show(Vector3.forward * 0.2f));

            yield return(null);

            Assert.NotNull(CoreServices.InputSystem.GazeProvider.GazeTarget, "GazeProvider target is null when looking at an object with hand raised");
        }
        public IEnumerator TestRiggedHand()
        {
            // Initialize hand
            var rightHand = new TestHand(Handedness.Right);

            yield return(rightHand.Show(Vector3.zero));

            RiggedHandVisualizer handVisualizer = GameObject.FindObjectOfType <RiggedHandVisualizer>().GetComponent <RiggedHandVisualizer>();

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            Assert.IsTrue(handVisualizer.HandRenderer.sharedMaterial.GetFloat(handVisualizer.PinchStrengthMaterialProperty) < 0.5f);

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Grab));

            Assert.IsTrue(handVisualizer.HandRenderer.sharedMaterial.GetFloat(handVisualizer.PinchStrengthMaterialProperty) > 0.5f);

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.OpenSteadyGrabPoint));

            Assert.IsTrue(handVisualizer.HandRenderer.sharedMaterial.GetFloat(handVisualizer.PinchStrengthMaterialProperty) < 0.5f);
        }
        public IEnumerator PrefabZoomOutWithoutJitter()
        {
            var maxPan = 1.2f;

            InstantiatePanLimitedSlateFromPrefab(maxPanHorizontal: maxPan, maxPanVertical: maxPan);

            yield return(ScrollToLimit(new Vector3(-1, -1, 0)));

            // Right hand pinches slate
            TestHand handRight = new TestHand(Handedness.Right);

            yield return(handRight.MoveTo(panZoom.transform.position + Vector3.forward * -0.5f + Vector3.right * 0.2f));

            yield return(handRight.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            // Left hand pinches slate
            TestHand handLeft = new TestHand(Handedness.Left);

            yield return(handLeft.Show(panZoom.transform.position + Vector3.forward * -0.5f + Vector3.right * -0.2f));

            yield return(handLeft.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            // Use both hands to zoom out
            var previousUvs = new List <Vector2>();

            meshFilter.mesh.GetUVs(0, previousUvs);
            for (var i = 0; i < 10; i++)
            {
                yield return(handLeft.Move(new Vector3(0f, 0.02f, 0f), 1));

                var uvs = new List <Vector2>();
                meshFilter.mesh.GetUVs(0, uvs);
                for (int j = 0; j < uvs.Count; j++)
                {
                    Assert.AreEqual(previousUvs[j].x, uvs[j].x, 0.05, "mesh is jittering");
                    Assert.AreEqual(previousUvs[j].y, uvs[j].y, 0.05, "mesh is jittering");
                }
                previousUvs = uvs;
            }
        }
        public IEnumerator ScaleViaNearInteration()
        {
            const int numSteps = 2;
            var       bbox     = InstantiateSceneAndDefaultBbox();

            bbox.ScaleHandleSize = 0.1f;
            yield return(null);

            var bounds = bbox.GetComponent <BoxCollider>().bounds;

            Assert.AreEqual(new Vector3(0, 0, 1.5f), bounds.center);
            Assert.AreEqual(new Vector3(.5f, .5f, .5f), bounds.size);

            var inputSimulationService = PlayModeTestUtilities.GetInputSimulationService();

            // front right corner is corner 3
            var frontRightCornerPos = bbox.ScaleCorners[3].transform.position;

            TestHand rightHand = new TestHand(Handedness.Right);

            yield return(rightHand.Show(new Vector3(0, 0, 0.5f)));

            var delta = new Vector3(0.1f, 0.1f, 0f);

            yield return(rightHand.MoveTo(frontRightCornerPos, numSteps));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(rightHand.Move(delta, numSteps));

            var endBounds = bbox.GetComponent <BoxCollider>().bounds;

            TestUtilities.AssertAboutEqual(endBounds.center, new Vector3(0.033f, 0.033f, 1.467f), "endBounds incorrect center");
            TestUtilities.AssertAboutEqual(endBounds.size, Vector3.one * .567f, "endBounds incorrect size");

            GameObject.Destroy(bbox.gameObject);
            // Wait for a frame to give Unity a change to actually destroy the object
            yield return(null);
        }
        public IEnumerator TestHoldEvents()
        {
            // Hold
            var  holdReceiver = interactable.AddReceiver <InteractableOnHoldReceiver>();
            bool didHold      = false;

            holdReceiver.OnHold.AddListener(() => didHold = true);

            var testHand = new TestHand(Handedness.Right);

            yield return(testHand.Show(interactable.transform.position));

            yield return(testHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(new WaitForSeconds(holdReceiver.HoldTime));

            yield return(testHand.Hide());

            Assert.True(didHold, "Did not receive hold event");
            GameObject.Destroy(cube);
            yield return(null);
        }
Beispiel #15
0
        /// <summary>
        /// Scroll a slate using GGV and ensure that the slate scrolls
        /// expected amount. Assumes panZoom has already been created.
        /// </summary>
        /// <param name="expectedScroll">The amount panZoom is expected to scroll</param>
        private IEnumerator RunGGVScrollTest(float expectedScroll)
        {
            PlayModeTestUtilities.SetHandSimulationMode(HandSimulationMode.Gestures);

            Vector2 totalPanDelta = Vector2.zero;

            panZoom.PanUpdated.AddListener((hpd) => totalPanDelta += hpd.PanDelta);

            TestHand handRight = new TestHand(Handedness.Right);

            yield return(handRight.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(handRight.Show(Vector3.zero));

            // Move requires a slower action (i.e. higher numSteps) in order to
            // achieve a reliable pan.
            yield return(handRight.Move(new Vector3(0.0f, -0.1f, 0f), 30));

            Assert.AreEqual(expectedScroll, totalPanDelta.y, 0.1, "pan delta is not correct");

            yield return(handRight.Hide());
        }
        public IEnumerator Prefab_RayScroll()
        {
            InstantiateFromPrefab(Vector3.forward);
            Vector2 totalPanDelta = Vector2.zero;

            panZoom.PanUpdated.AddListener((hpd) => totalPanDelta += hpd.PanDelta);

            TestHand h           = new TestHand(Handedness.Right);
            Vector3  screenPoint = CameraCache.Main.ViewportToScreenPoint(new Vector3(0.5f, 0.25f, 0.5f));

            yield return(h.Show(CameraCache.Main.ScreenToWorldPoint(screenPoint)));

            yield return(h.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(h.Move(new Vector3(0, -0.05f, 0), 10));

            yield return(h.SetGesture(ArticulatedHandPose.GestureId.Open));

            Assert.AreEqual(0.1, totalPanDelta.y, 0.05, "pan delta is not correct");

            yield return(h.Hide());
        }
        /// <summary>
        /// Scroll contents to the limit in the specified direction
        /// </summary>
        /// <param name="direction">Scroll direction</param>
        private IEnumerator ScrollToLimit(Vector3 direction)
        {
            TestHand handRight = new TestHand(Handedness.Right);

            yield return(handRight.Show(Vector3.zero));

            Vector3 screenPoint = CameraCache.Main.ViewportToScreenPoint(new Vector3(0.5f, 0.0f, 0.5f));
            var     moveDelta   = -0.5f * direction;

            for (var i = 0; i < 3; i++)
            {
                yield return(handRight.MoveTo(CameraCache.Main.ScreenToWorldPoint(screenPoint)));

                yield return(handRight.SetGesture(ArticulatedHandPose.GestureId.Pinch));

                yield return(handRight.Move(moveDelta, 10));

                yield return(handRight.SetGesture(ArticulatedHandPose.GestureId.Open));
            }

            yield return(handRight.Hide());
        }
Beispiel #18
0
        public IEnumerator TestOverlap()
        {
            // Instantiate our test GameObject with solver.
            var testObjects = InstantiateTestSolver <Overlap>();

            testObjects.handler.TrackedTargetType = TrackedObjectType.HandJoint;
            var targetTransform = testObjects.target.transform;

            TestUtilities.AssertAboutEqual(targetTransform.position, Vector3.zero, "Overlap not at original position");
            TestUtilities.AssertAboutEqual(targetTransform.rotation, Quaternion.identity, "Overlap not at original rotation");

            // Test that the solver flies to the position of the left hand
            var handPosition = Vector3.forward - Vector3.right;
            var handRotation = Quaternion.LookRotation(handPosition);
            var leftHand     = new TestHand(Handedness.Left);

            yield return(leftHand.Show(handPosition));

            yield return(leftHand.SetRotation(handRotation));

            yield return(WaitForFrames(2));

            var hand = PlayModeTestUtilities.GetInputSimulationService().GetHandDevice(Handedness.Left);

            Assert.IsNotNull(hand);
            Assert.IsTrue(hand.TryGetJoint(TrackedHandJoint.Palm, out MixedRealityPose pose));

            TestUtilities.AssertAboutEqual(targetTransform.position, pose.Position, "Overlap solver is not at the same position as the left hand.");
            Assert.IsTrue(Quaternion.Angle(targetTransform.rotation, pose.Rotation) < 2.0f);

            // Make sure the solver did not move when hand was hidden
            yield return(leftHand.Hide());

            yield return(WaitForFrames(2));

            TestUtilities.AssertAboutEqual(targetTransform.position, pose.Position, "Overlap solver moved when the hand was hidden.");
            Assert.IsTrue(Quaternion.Angle(targetTransform.rotation, pose.Rotation) < 2.0f);
        }
Beispiel #19
0
        public IEnumerator TestToggleEvents()
        {
            var iss        = PlayModeTestUtilities.GetInputSimulationService();
            var oldSimMode = iss.ControllerSimulationMode;

            iss.ControllerSimulationMode = ControllerSimulationMode.HandGestures;

            var toggleReceiver = interactable.AddReceiver <InteractableOnToggleReceiver>();

            interactable.transform.position = Vector3.forward * 2f;
            interactable.NumOfDimensions    = 2;
            interactable.CanSelect          = true;
            interactable.CanDeselect        = true;
            bool didSelect   = false;
            bool didUnselect = false;

            toggleReceiver.OnSelect.AddListener(() => didSelect     = true);
            toggleReceiver.OnDeselect.AddListener(() => didUnselect = true);

            var testHand = new TestHand(Handedness.Right);

            yield return(testHand.Show(Vector3.forward));

            CameraCache.Main.transform.LookAt(interactable.transform.position);

            yield return(testHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            yield return(testHand.Click());

            yield return(testHand.Click());

            yield return(testHand.Hide());

            Assert.True(didSelect, "Toggle select did not fire");
            Assert.True(didUnselect, "Toggle unselect did not fire");

            iss.ControllerSimulationMode = oldSimMode;
        }
Beispiel #20
0
        private IEnumerator DirectPinchAndMoveSlider(PinchSlider slider, float toSliderValue)
        {
            Debug.Log($"moving hand to value {toSliderValue}");
            var     rightHand  = new TestHand(Handedness.Right);
            Vector3 initialPos = new Vector3(0.05f, 0, 1.0f);

            yield return(rightHand.Show(initialPos));

            yield return(rightHand.MoveTo(slider.ThumbRoot.transform.position));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            if (!(toSliderValue >= 0 && toSliderValue <= 1))
            {
                throw new System.ArgumentException("toSliderValue must be between 0 and 1");
            }

            yield return(rightHand.MoveTo(Vector3.Lerp(slider.SliderStartPosition, slider.SliderEndPosition, toSliderValue)));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            yield return(rightHand.Hide());
        }
Beispiel #21
0
        public IEnumerator GrabVolumesWithOverlap()
        {
            // Initialize overlapRect and cube
            overlapRect.SetActive(true);
            overlapRect.transform.localScale = Vector3.one * 2;
            overlapRect.transform.position   = Vector3.zero;

            cube.transform.localScale = Vector3.one;
            cube.transform.position   = Vector3.zero;

            // Initialize hand
            var rightHand = new TestHand(Handedness.Right);

            yield return(rightHand.Show(Vector3.zero));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.OpenSteadyGrabPoint));

            var pointer = rightHand.GetPointer <SpherePointer>();

            Assert.IsNotNull(pointer, "Expected to find SpherePointer in the hand controller");

            Assert.True(CoreServices.InputSystem.FocusProvider.GetFocusedObject(pointer) == cube, " the cube was not in focus");
            Assert.True(pointer.IsNearObject);
            Assert.True(pointer.IsInteractionEnabled);

            // Switch the scale of the cube and rect
            overlapRect.transform.localScale = Vector3.one;
            cube.transform.localScale        = Vector3.one * 2;

            // Wait for the input system to process the changes
            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.True(CoreServices.InputSystem.FocusProvider.GetFocusedObject(pointer) == overlapRect, " the overlapping rectangle was not in focus");

            // Reinitialize the overlapRect
            overlapRect.SetActive(false);
        }
Beispiel #22
0
        public IEnumerator TestPointerFOV()
        {
            var rightHand = new TestHand(Handedness.Right);

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

            cube.AddComponent <NearInteractionGrabbable>();
            cube.AddComponent <NearInteractionTouchableVolume>();
            yield return(rightHand.Show(Vector3.zero));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            var spherePointer = PointerUtils.GetPointer <SpherePointer>(Handedness.Right);
            var pokePointer   = PointerUtils.GetPointer <PokePointer>(Handedness.Right);

            yield return(TestPointerFOVHelper(spherePointer, cube, rightHand));

            yield return(TestPointerFOVHelper(pokePointer, cube, rightHand));

            rightHand.Hide();
            GameObject.Destroy(cube);
        }
Beispiel #23
0
        public IEnumerator Prefab_TouchZoom()
        {
            InstantiateFromPrefab(Vector3.forward);

            TestHand h = new TestHand(Handedness.Right);

            yield return(h.Show(Vector3.zero));

            yield return(h.MoveTo(panZoom.transform.position, 10));

            TestHand h2 = new TestHand(Handedness.Left);

            yield return(h2.Show(Vector3.zero));

            yield return(h2.MoveTo(panZoom.transform.position + Vector3.right * -0.01f, 10));

            yield return(h.Move(new Vector3(0.01f, 0f, 0f)));

            yield return(h2.Move(new Vector3(-0.01f, 0f, 0f)));

            Assert.AreEqual(0.4, panZoom.CurrentScale, 0.1, "slate did not zoom in using two finger touch");

            yield return(h.Hide());
        }
        public IEnumerator TestButtonStateResetWhenFocusLostAfterPinch()
        {
            TestButtonUtilities.InstantiateDefaultButton(
                TestButtonUtilities.DefaultButtonType.DefaultHL2Button,
                out Interactable interactable,
                out Transform interactableTransform);

            interactable.transform.position = new Vector3(0.0f, 0.1f, 0.4f);
            Assert.True(interactable.IsEnabled);

            var     rightHand     = new TestHand(Handedness.Right);
            Vector3 focusPosition = new Vector3(0.015f, 0.015f, 0.3f);
            Vector3 releaseDelta  = new Vector3(0.05f, 0, 0);

            // Focus the hand on the Button using the far ray pointer
            yield return(rightHand.Show(focusPosition));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.True(interactable.HasFocus);
            Assert.False(interactable.HasPress);
            Assert.False(interactable.HasGesture);
            Assert.True(interactable.StateManager.CurrentState().Index == (int)InteractableStates.InteractableStateEnum.Focus, "Interactable State is not Focus");

            // While keeping focus on the Button, engage the pinch gesture
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.True(interactable.HasFocus);
            Assert.True(interactable.HasPress);
            Assert.False(interactable.HasGesture);
            Assert.True(interactable.StateManager.CurrentState().Index == (int)InteractableStates.InteractableStateEnum.Pressed, "Interactable State is not Pressed");

            // Move Hand to remove focus. Button should go to Default State
            yield return(rightHand.Move(releaseDelta));

            yield return(new WaitForSeconds(0.25f));// Wait for Interactable rollOffTime for HasPress to reset

            Assert.False(interactable.HasFocus);
            Assert.False(interactable.HasPress);
            Assert.False(interactable.HasGesture);
            Assert.True(interactable.StateManager.CurrentState().Index == (int)InteractableStates.InteractableStateEnum.Default, "Interactable State is not Default");

            // Open hand. Button should stay on Default State
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.False(interactable.HasFocus);
            Assert.False(interactable.HasPress);
            Assert.False(interactable.HasGesture);
            Assert.True(interactable.StateManager.CurrentState().Index == (int)InteractableStates.InteractableStateEnum.Default, "Interactable State is not Default");

            // Move Hand back to Initial position and Pinch. Button should go to Pressed State
            yield return(rightHand.Move(-releaseDelta));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.True(interactable.HasFocus);
            Assert.True(interactable.HasPress);
            Assert.False(interactable.HasGesture);
            Assert.True(interactable.StateManager.CurrentState().Index == (int)InteractableStates.InteractableStateEnum.Pressed, "Interactable State is not Pressed");

            // Open Hand. Button should go to Focus State
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.True(interactable.HasFocus);
            Assert.False(interactable.HasPress);
            Assert.False(interactable.HasGesture);
            Assert.True(interactable.StateManager.CurrentState().Index == (int)InteractableStates.InteractableStateEnum.Focus, "Interactable State is not Focus");

            GameObject.Destroy(interactable.gameObject);
        }
Beispiel #25
0
        public IEnumerator CursorContextScaleRotate()
        {
            var inputSystem = PlayModeTestUtilities.GetInputSystem();

            var empty = new GameObject();
            var info  = cube.AddComponent <CursorContextInfo>();

            info.ObjectCenter = empty.transform;

            // Show hand on object
            var     hand    = new TestHand(Handedness.Right);
            Vector3 handPos = new Vector3(0.05f, 0, 1.5f);

            yield return(hand.Show(handPos));

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.None);

            // rotate, center north
            info.CurrentCursorAction = CursorContextInfo.CursorAction.Rotate;
            empty.transform.SetPositionAndRotation(cube.transform.position + Vector3.up, Quaternion.identity);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.RotateNorthSouth);

            // rotate, center east
            empty.transform.SetPositionAndRotation(cube.transform.position + Vector3.right, Quaternion.identity);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.RotateEastWest);

            // scale, center northeast
            info.CurrentCursorAction = CursorContextInfo.CursorAction.Scale;
            empty.transform.SetPositionAndRotation(cube.transform.position + Vector3.up + Vector3.right, Quaternion.identity);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.MoveNortheastSouthwest);

            // scale, center southeast
            empty.transform.SetPositionAndRotation(cube.transform.position + Vector3.down + Vector3.right, Quaternion.identity);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.MoveNorthwestSoutheast);

            // scale, center northwest
            empty.transform.SetPositionAndRotation(cube.transform.position + Vector3.up + Vector3.left, Quaternion.identity);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.MoveNorthwestSoutheast);

            // scale, center southwest
            empty.transform.SetPositionAndRotation(cube.transform.position + Vector3.down + Vector3.left, Quaternion.identity);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.MoveNortheastSouthwest);

            Object.Destroy(empty);
            Object.Destroy(info);
        }
Beispiel #26
0
        public IEnumerator CursorContextMove()
        {
            var inputSystem = PlayModeTestUtilities.GetInputSystem();

            // The cube needs to be moved from under the gaze cursor before we add the manipulation handler.
            // Because the cube is under the gaze cursor from the beginning, it gets a focus gained event
            // in Setup(). When we show the right hand, we get a focus lost event from the gaze pointer.
            // This messes with the CursorContextManipulationHandler hoverCount, as it decrements without
            // ever having incremented. To avoid this, we move the cube out of focus before we add the
            // ManipulationHandler and CursorContextManipulationHandler.
            cube.transform.localPosition = new Vector3(0, -2, 2);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            cube.AddComponent <ManipulationHandler>();
            var temp = cube.AddComponent <CursorContextManipulationHandler>();

            yield return(new WaitForFixedUpdate());

            yield return(null);

            // Move cube back to original postion (described above)
            cube.transform.localPosition = new Vector3(0, 0, 2);
            yield return(new WaitForFixedUpdate());

            yield return(null);

            // Show right hand on object
            var     rightHand = new TestHand(Handedness.Right);
            Vector3 rightPos  = new Vector3(0.05f, 0, 1.5f);

            yield return(rightHand.Show(rightPos));

            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.None);

            // Pinch right hand
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.MoveCross);

            // Show left hand on object
            var     leftHand = new TestHand(Handedness.Left);
            Vector3 leftPos  = new Vector3(-0.05f, 0, 1.5f);

            yield return(rightHand.Hide());

            yield return(leftHand.Show(leftPos));

            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.None);

            // Pinch left hand
            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.MoveCross);

            // Show both hands on object
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            yield return(rightHand.Show(rightPos));

            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorContextFromPointers(inputSystem.FocusProvider.GetPointers <ShellHandRayPointer>(), CursorContextEnum.MoveCross);

            Object.Destroy(cube.GetComponent <ManipulationHandler>());
            Object.Destroy(cube.GetComponent <CursorContextManipulationHandler>());
        }
Beispiel #27
0
        public IEnumerator GestureCursorState()
        {
            var inputSystem = PlayModeTestUtilities.GetInputSystem();

            var iss    = PlayModeTestUtilities.GetInputSimulationService();
            var oldIsp = iss.InputSimulationProfile;
            var isp    = ScriptableObject.CreateInstance <MixedRealityInputSimulationProfile>();

            isp.HandSimulationMode     = HandSimulationMode.Gestures;
            iss.InputSimulationProfile = isp;

            Vector3 underPointerPos = new Vector3(0, 0, 2);
            Vector3 abovePointerPos = new Vector3(0, -2, 2);

            var rightHand = new TestHand(Handedness.Right);
            var leftHand  = new TestHand(Handedness.Left);

            // No hands, pointer not on cube, hand open
            cube.transform.localPosition = abovePointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Observe);

            // No hands, pointer on cube, hand open
            cube.transform.localPosition = underPointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.ObserveHover);

            // Right hand, pointer not on cube, hand open
            cube.transform.localPosition = abovePointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(rightHand.Show(Vector3.zero));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Interact);

            // Both hands, pointer not on cube, hand open
            yield return(leftHand.Show(Vector3.zero));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Interact);

            // Left hand, pointer not on cube, hand open
            yield return(rightHand.Hide());

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Interact);

            // Left hand, pointer on cube, hand open
            cube.transform.localPosition = underPointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.InteractHover);

            // Both hands, pointer on cube, hand open
            yield return(rightHand.Show(Vector3.zero));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.InteractHover);

            // Right hand, pointer on cube, hand open
            yield return(leftHand.Hide());

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.InteractHover);

            // Right hand, pointer on cube, hand pinched
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            // Left hand, pointer on cube, hand pinched
            yield return(rightHand.Hide());

            yield return(leftHand.Show(Vector3.zero));

            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Both hands, pointer on cube, left pinched & right open
            yield return(rightHand.Show(Vector3.zero));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Both hands, pointer on cube, both pinched
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Both hands, pointer on cube, right pinched & left open
            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Restore the input simulation profile
            iss.InputSimulationProfile = oldIsp;
            yield return(null);
        }
Beispiel #28
0
        public IEnumerator GestureCursorState()
        {
            var inputSystem = PlayModeTestUtilities.GetInputSystem();

            var iss            = PlayModeTestUtilities.GetInputSimulationService();
            var oldHandSimMode = iss.ControllerSimulationMode;

            iss.ControllerSimulationMode = ControllerSimulationMode.HandGestures;

            Vector3 underPointerPos = TestUtilities.PositionRelativeToPlayspace(new Vector3(0, 0, 2));
            Vector3 abovePointerPos = TestUtilities.PositionRelativeToPlayspace(new Vector3(0, -2, 2));
            Vector3 zeroPos         = TestUtilities.PositionRelativeToPlayspace(Vector3.zero);

            var rightHand = new TestHand(Handedness.Right);
            var leftHand  = new TestHand(Handedness.Left);

            // No hands, pointer not on cube, hand open
            cube.transform.localPosition = abovePointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Observe);

            // No hands, pointer on cube, hand open
            cube.transform.localPosition = underPointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.ObserveHover);

            // Right hand, pointer not on cube, hand open
            cube.transform.localPosition = abovePointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(rightHand.Show(zeroPos));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Interact);

            // Both hands, pointer not on cube, hand open
            yield return(leftHand.Show(zeroPos));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Interact);

            // Left hand, pointer not on cube, hand open
            yield return(rightHand.Hide());

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Interact);

            // Left hand, pointer on cube, hand open
            cube.transform.localPosition = underPointerPos;
            yield return(new WaitForFixedUpdate());

            yield return(null);

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.InteractHover);

            // Both hands, pointer on cube, hand open
            yield return(rightHand.Show(zeroPos));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.InteractHover);

            // Right hand, pointer on cube, hand open
            yield return(leftHand.Hide());

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.InteractHover);

            // Right hand, pointer on cube, hand pinched
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            // Left hand, pointer on cube, hand pinched
            yield return(rightHand.Hide());

            yield return(leftHand.Show(zeroPos));

            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Both hands, pointer on cube, left pinched & right open
            yield return(rightHand.Show(zeroPos));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Both hands, pointer on cube, both pinched
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Both hands, pointer on cube, right pinched & left open
            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            VerifyCursorState(inputSystem.GazeProvider.GazeCursor, CursorStateEnum.Select);

            // Restore the input simulation profile
            iss.ControllerSimulationMode = oldHandSimMode;
            yield return(null);
        }
        public IEnumerator SpherePointerDistances()
        {
            var rightHand = new TestHand(Handedness.Right);

            // Show hand far enough from the test collider
            Vector3 idlePos = new Vector3(0.05f, 0, 1.0f);

            yield return(rightHand.Show(idlePos));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.OpenSteadyGrabPoint));

            var pointer = rightHand.GetPointer <SpherePointer>();

            pointer.NearObjectSectorAngle = 360.0f;
            pointer.PullbackDistance      = 0.0f;

            Vector3 margin           = new Vector3(0, 0, 0.001f);
            Vector3 nearObjectMargin = new Vector3(0, 0, 0.001f + (pointer.NearObjectSmoothingFactor + 1) * pointer.NearObjectRadius);

            Assert.IsNotNull(pointer, "Expected to find SpherePointer in the hand controller");
            Vector3 nearObjectPos         = new Vector3(0.05f, 0, colliderSurfaceZ - pointer.NearObjectRadius);
            Vector3 interactionEnabledPos = new Vector3(0.05f, 0, colliderSurfaceZ - pointer.SphereCastRadius);

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Move hand closer to the collider to enable IsNearObject
            yield return(rightHand.MoveTo(nearObjectPos - nearObjectMargin, numFramesPerMove));

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
            yield return(rightHand.MoveTo(nearObjectPos + margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Move hand closer to the collider to enable IsInteractionEnabled
            yield return(rightHand.MoveTo(interactionEnabledPos - margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
            yield return(rightHand.MoveTo(interactionEnabledPos + margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.True(pointer.IsInteractionEnabled);
            // Move hand back out to disable IsInteractionEnabled
            yield return(rightHand.MoveTo(interactionEnabledPos - margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Move hand back out to disable IsNearObject
            yield return(rightHand.MoveTo(nearObjectPos + margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
            yield return(rightHand.MoveTo(nearObjectPos - nearObjectMargin, numFramesPerMove));

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Testing that we have more leeway when the pointer's nearObject smoothing factor is set
            // Move hand back out to disable IsNearObject
            yield return(rightHand.MoveTo(nearObjectPos + margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
            yield return(rightHand.MoveTo(nearObjectPos - margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            yield return(rightHand.MoveTo(idlePos, numFramesPerMove));

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
        }
        public IEnumerator SpherePointerSectorAngle()
        {
            var rightHand = new TestHand(Handedness.Right);

            // Show hand far enough from the test collider
            Vector3 idlePos = new Vector3(0.05f, 0, 1.0f);

            yield return(rightHand.Show(idlePos));

            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.OpenSteadyGrabPoint));

            var pointer = rightHand.GetPointer <SpherePointer>();

            pointer.NearObjectSectorAngle = 180.0f;
            pointer.PullbackDistance      = 0.0f;
            // Orient the right hand so the grab axis is approximately aligned with the z axis

            Vector3 margin           = new Vector3(0, 0, 0.001f);
            Vector3 nearObjectMargin = new Vector3(0, 0, 0.001f + (pointer.NearObjectSmoothingFactor + 1) * pointer.NearObjectRadius);

            Assert.IsNotNull(pointer, "Expected to find SpherePointer in the hand controller");
            Vector3 nearObjectPos         = new Vector3(0.05f, 0, colliderSurfaceZ - pointer.NearObjectRadius);
            Vector3 interactionEnabledPos = new Vector3(0.05f, 0, colliderSurfaceZ - pointer.SphereCastRadius);

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Move hand closer to the collider to enable IsNearObject
            yield return(rightHand.MoveTo(nearObjectPos - margin, numFramesPerMove));

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            yield return(rightHand.MoveTo(nearObjectPos + margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Rotate hand but maintain IsNearObject
            yield return(rightHand.SetRotation(Quaternion.Euler(0, 90, 0), numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Rotate hand 200 degrees and lose IsNearObject
            yield return(rightHand.SetRotation(Quaternion.Euler(0, 200, 0), numFramesPerMove));

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Rotate hand back to original orientation
            yield return(rightHand.SetRotation(Quaternion.Euler(0, 0, 0), numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Move hand closer to the collider to enable IsInteractionEnabled
            yield return(rightHand.MoveTo(interactionEnabledPos - margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
            yield return(rightHand.MoveTo(interactionEnabledPos + margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.True(pointer.IsInteractionEnabled);

            // Move hand back out to disable IsInteractionEnabled
            yield return(rightHand.MoveTo(interactionEnabledPos - margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            // Move hand back out to disable IsNearObject
            yield return(rightHand.MoveTo(nearObjectPos + margin, numFramesPerMove));

            Assert.True(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
            yield return(rightHand.MoveTo(nearObjectPos - nearObjectMargin, numFramesPerMove));

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);

            yield return(rightHand.MoveTo(idlePos, numFramesPerMove));

            Assert.False(pointer.IsNearObject);
            Assert.False(pointer.IsInteractionEnabled);
        }