public IEnumerator NearInteractionTouchableVolumeVariant()
        {
            var touchable = CreateTouchable <NearInteractionTouchableVolume>(Vector3.one);

            yield return(new WaitForFixedUpdate());

            yield return(null);

            TestHand testHand = new TestHand(Handedness.Left);

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

            yield return(testHand.MoveTo(initialHandPosition));

            using (var catcher = CreateTouchEventCatcher(touchable))
            {
                // Touch started when entering collider
                yield return(testHand.MoveTo(objectPosition));

                Assert.AreEqual(1, catcher.EventsStarted);
                Assert.AreEqual(0, catcher.EventsCompleted);

                // Ensure no touch up event fires while moving hand/pokepointer through collider to each corner of volume
                Vector3[] cornerPositions = new Vector3[8];
                touchable.GetComponent <BoxCollider>().bounds.GetCornerPositions(ref cornerPositions);
                for (int i = 0; i < cornerPositions.Length; i++)
                {
                    yield return(testHand.MoveTo(cornerPositions[i]));

                    Assert.AreEqual(1, catcher.EventsStarted, "Received extra touch down when moving through volume to position " + cornerPositions[i]);
                    Assert.AreEqual(0, catcher.EventsCompleted, "Received extra touch up when moving through volume to position " + cornerPositions[i]);
                }

                // Touch up when exit collider
                yield return(testHand.MoveTo(rightPosition));

                Assert.AreEqual(1, catcher.EventsStarted);
                Assert.AreEqual(1, catcher.EventsCompleted);

                // No touch when moving outside the collider
                yield return(testHand.Hide());

                yield return(testHand.Show(backPosition));

                yield return(testHand.MoveTo(backPosition + new Vector3(2f, 0f, 0f)));

                Assert.AreEqual(1, catcher.EventsStarted);
                Assert.AreEqual(1, catcher.EventsCompleted);

                // Touch when moving off-center
                yield return(testHand.Hide());

                yield return(testHand.Show(initialHandPosition + outOfBoundsOffset));

                yield return(testHand.MoveTo(objectPosition + outOfBoundsOffset));

                yield return(testHand.MoveTo(rightPosition));

                Assert.AreEqual(2, catcher.EventsStarted);
                Assert.AreEqual(2, catcher.EventsCompleted);
            }

            UnityEngine.Object.Destroy(touchable.gameObject);
        }
Esempio n. 2
0
        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 BBoxHandlerUI()
        {
            const int numSteps = 2;
            var       bbox     = InstantiateSceneAndDefaultBbox();

            bbox.ShowRotationHandleForX = true;
            bbox.ShowRotationHandleForY = true;
            bbox.ShowRotationHandleForZ = true;
            bbox.ShowScaleHandles       = true;
            bbox.ProximityEffectActive  = true;
            bbox.ScaleHandleSize        = 0.1f;
            bbox.RotationHandleSize     = 0.1f;
            bbox.FarScale    = 1.0f;
            bbox.MediumScale = 1.5f;
            bbox.CloseScale  = 1.5f;
            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();

            // Defining the edge and corner handlers that will be used
            Debug.Log(bbox.transform.Find("rigRoot/midpoint_0").GetChild(0));
            var originalCornerHandlerScale = bbox.transform.Find("rigRoot/corner_0/visualsScale/visuals").transform.localScale;
            var cornerHandlerPosition      = bbox.transform.Find("rigRoot/corner_0").transform.position;
            var originalEdgeHandlerScale   = bbox.transform.Find("rigRoot/midpoint_0/Sphere").transform.localScale;
            var edgeHandlerPosition        = bbox.transform.Find("rigRoot/midpoint_0").transform.position;

            // Wait for the scaling/unscaling animation to finish
            yield return(new WaitForSeconds(0.2f));

            // Move the hand to a handler on the corner
            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(cornerHandlerPosition, numSteps));

            // Wait for the scaling/unscaling animation to finish
            yield return(new WaitForSeconds(0.4f));

            TestUtilities.AssertAboutEqual(bbox.transform.Find("rigRoot/midpoint_0/Sphere").transform.localScale, originalEdgeHandlerScale, "The edge handler changed mistakingly");
            TestUtilities.AssertAboutEqual(bbox.transform.Find("rigRoot/corner_0/visualsScale/visuals").transform.localScale.normalized, originalCornerHandlerScale.normalized, "The corner handler scale has changed");
            Assert.AreApproximatelyEqual(bbox.transform.Find("rigRoot/corner_0/visualsScale/visuals").transform.localScale.x / originalCornerHandlerScale.x, bbox.MediumScale, 0.1f, "The corner handler did not grow when a pointer was near it");

            // Move the hand to a handler on the edge
            yield return(rightHand.MoveTo(edgeHandlerPosition, numSteps));

            // Wait for the scaling/unscaling animation to finish
            yield return(new WaitForSeconds(0.4f));

            TestUtilities.AssertAboutEqual(bbox.transform.Find("rigRoot/corner_0/visualsScale/visuals").transform.localScale, originalCornerHandlerScale, "The corner handler changed mistakingly");
            TestUtilities.AssertAboutEqual(bbox.transform.Find("rigRoot/midpoint_0/Sphere").transform.localScale.normalized, originalEdgeHandlerScale.normalized, "The edge handler scale has changed");
            Assert.AreApproximatelyEqual(bbox.transform.Find("rigRoot/midpoint_0/Sphere").transform.localScale.x / originalEdgeHandlerScale.x, bbox.MediumScale, 0.1f, "The edge handler did not grow when a pointer was near it");

            GameObject.Destroy(bbox.gameObject);
            // Wait for a frame to give Unity a change to actually destroy the object
            yield return(null);
        }
        public IEnumerator NearInteractionTouchablePointerEvents()
        {
            var touchable = CreateTouchable <NearInteractionTouchable>(objectScale);

            touchable.SetLocalForward(touchNormal);
            touchable.SetBounds(new Vector2(0.5f, 0.5f));
            touchable.EventsToReceive = TouchableEventType.Pointer;

            yield return(new WaitForFixedUpdate());

            yield return(null);

            TestHand testHand = new TestHand(Handedness.Right);

            yield return(testHand.Show(initialHandPosition));

            using (var catcher = CreatePointerEventCatcher(touchable))
            {
                yield return(testHand.MoveTo(objectPosition));

                Assert.AreEqual(1, catcher.EventsStarted);
                Assert.AreEqual(0, catcher.EventsCompleted);
                yield return(testHand.MoveTo(rightPosition));

                Assert.AreEqual(1, catcher.EventsStarted);
                Assert.AreEqual(1, catcher.EventsCompleted);
                Assert.Greater(catcher.DragEventCount, 0);

                // Touch started and completed when entering and exiting behind the plane
                yield return(testHand.MoveTo(initialHandPosition));

                yield return(testHand.MoveTo(objectPosition));

                Assert.AreEqual(2, catcher.EventsStarted);
                Assert.AreEqual(1, catcher.EventsCompleted);
                yield return(testHand.MoveTo(backPosition));

                Assert.AreEqual(2, catcher.EventsStarted);
                Assert.AreEqual(2, catcher.EventsCompleted);
                Assert.Greater(catcher.DragEventCount, 1);
                int dragEventCount = catcher.DragEventCount;

                // No touch when moving at behind the plane
                yield return(testHand.MoveTo(rightPosition));

                Assert.AreEqual(2, catcher.EventsStarted);
                Assert.AreEqual(2, catcher.EventsCompleted);
                Assert.AreEqual(dragEventCount, catcher.DragEventCount, "No drag events should fire when poke pointer moving behind plane");


                // No touch when moving outside the bounds
                yield return(testHand.MoveTo(initialHandPosition + outOfBoundsOffset));

                yield return(testHand.MoveTo(objectPosition + outOfBoundsOffset));

                yield return(testHand.MoveTo(rightPosition));

                Assert.AreEqual(2, catcher.EventsStarted);
                Assert.AreEqual(2, catcher.EventsCompleted);
                Assert.AreEqual(dragEventCount, catcher.DragEventCount, "No drag events should fire when poke pointer moving outside bounds");
            }

            yield return(testHand.Hide());

            UnityEngine.Object.Destroy(touchable.gameObject);
        }
Esempio n. 5
0
        public IEnumerator ConstrainScaleMinMax()
        {
            float initialScale = 0.2f;
            float minScale     = 0.5f;
            float maxScale     = 2f;

            // set up cube with manipulation handler
            var testObject = GameObject.CreatePrimitive(PrimitiveType.Cube);

            testObject.transform.localScale = Vector3.one * initialScale;
            Vector3 initialObjectPosition = new Vector3(0f, 0f, 1f);

            testObject.transform.position = initialObjectPosition;
            var manipHandler = testObject.AddComponent <ObjectManipulator>();

            manipHandler.HostTransform    = testObject.transform;
            manipHandler.SmoothingActive  = false;
            manipHandler.ManipulationType = ManipulationHandFlags.TwoHanded;
            var scaleHandler = testObject.EnsureComponent <MinMaxScaleConstraint>();

            scaleHandler.ScaleMinimum = minScale;
            scaleHandler.ScaleMaximum = maxScale;

            // add near interaction grabbable to be able to grab the cube with the simulated articulated hand
            testObject.AddComponent <NearInteractionGrabbable>();
            yield return(new WaitForFixedUpdate());

            yield return(null);

            const int numHandSteps = 1;

            Vector3  initialHandPosition = new Vector3(0, 0, 0.5f);
            Vector3  leftGrabPosition    = new Vector3(-0.1f, -0.1f, 1f); // grab the bottom left corner of the cube
            Vector3  rightGrabPosition   = new Vector3(0.1f, -0.1f, 1f);  // grab the bottom right corner of the cube
            TestHand leftHand            = new TestHand(Handedness.Left);
            TestHand rightHand           = new TestHand(Handedness.Right);

            // Hands grab object at initial positions
            yield return(leftHand.Show(initialHandPosition));

            yield return(leftHand.MoveTo(leftGrabPosition, numHandSteps));

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

            yield return(rightHand.Show(initialHandPosition));

            yield return(rightHand.MoveTo(rightGrabPosition, numHandSteps));

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

            // No change to scale yet
            Assert.AreEqual(Vector3.one * initialScale, testObject.transform.localScale);

            // Move hands beyond max scale limit
            yield return(leftHand.MoveTo(new Vector3(-scaleHandler.ScaleMaximum, 0, 0) + leftGrabPosition, numHandSteps));

            yield return(rightHand.MoveTo(new Vector3(scaleHandler.ScaleMaximum, 0, 0) + rightGrabPosition, numHandSteps));

            // Assert scale at max
            Assert.AreEqual(Vector3.one * scaleHandler.ScaleMaximum, testObject.transform.localScale);

            // Move hands beyond min scale limit
            yield return(leftHand.MoveTo(new Vector3(scaleHandler.ScaleMinimum, 0, 0) + leftGrabPosition, numHandSteps));

            yield return(rightHand.MoveTo(new Vector3(-scaleHandler.ScaleMinimum, 0, 0) + rightGrabPosition, numHandSteps));

            // Assert scale at min
            Assert.AreEqual(Vector3.one * scaleHandler.ScaleMinimum, testObject.transform.localScale);
        }
Esempio n. 6
0
        public IEnumerator CombinedConstraintFarNear()
        {
            TestUtilities.PlayspaceToOriginLookingForward();

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

            testObject.transform.localScale = Vector3.one * 0.2f;
            Vector3 originalPosition = Vector3.forward;

            testObject.transform.position = originalPosition;
            Quaternion originalRotation = Quaternion.identity;

            testObject.transform.rotation = originalRotation;
            var manipHandler = testObject.AddComponent <ObjectManipulator>();

            manipHandler.HostTransform          = testObject.transform;
            manipHandler.SmoothingActive        = false;
            manipHandler.OneHandRotationModeFar = ObjectManipulator.RotateInOneHandType.RotateAboutObjectCenter;

            // add near interaction grabbable to be able to grab the cube with the simulated articulated hand
            testObject.AddComponent <NearInteractionGrabbable>();

            // add an xyz rotate constraint for one handed so we can only move
            var rotateConstraint = manipHandler.EnsureComponent <RotationAxisConstraint>();

            rotateConstraint.UseLocalSpaceForConstraint = false;
            rotateConstraint.ConstraintOnRotation       = AxisFlags.XAxis | AxisFlags.YAxis | AxisFlags.ZAxis;
            rotateConstraint.ProximityType = ManipulationProximityFlags.Near;

            // add an xyz move constraint for two handed so we can only rotate
            var moveConstraint = manipHandler.EnsureComponent <MoveAxisConstraint>();

            moveConstraint.UseLocalSpaceForConstraint = false;
            moveConstraint.ConstraintOnMovement       = AxisFlags.XAxis | AxisFlags.YAxis | AxisFlags.ZAxis;
            moveConstraint.ProximityType = ManipulationProximityFlags.Far;

            yield return(new WaitForFixedUpdate());

            yield return(null);

            const int numHandSteps = 1;

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

            yield return(leftHand.Show(new Vector3(-0.05f, 0, 1)));

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

            yield return(null);

            // near interaction
            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

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

            yield return(leftHand.Move((Vector3.left + Vector3.up) * 0.2f, numHandSteps));

            yield return(null);

            TestUtilities.AssertAboutEqual(originalRotation, testObject.transform.rotation, "Rotation should be equal for near interaction");
            TestUtilities.AssertNotAboutEqual(originalPosition, testObject.transform.position, "Position should not be equal for near interaction");

            // far interaction
            yield return(leftHand.Move((Vector3.right + Vector3.down) * 0.2f, numHandSteps));

            yield return(null);

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

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

            yield return(null);

            yield return(leftHand.MoveTo(new Vector3(-0.05f, -0.1f, 0.45f), numHandSteps));

            yield return(rightHand.MoveTo(new Vector3(0.05f, -0.1f, 0.45f), numHandSteps));

            yield return(null);

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

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

            yield return(leftHand.Move((Vector3.left + Vector3.up) * 0.2f, numHandSteps));

            yield return(null);

            TestUtilities.AssertNotAboutEqual(originalRotation, testObject.transform.rotation, "Rotation should not be equal for far interaction");
            TestUtilities.AssertAboutEqual(originalPosition, testObject.transform.position, "Position should be equal for far interaction");
        }
Esempio n. 7
0
        public IEnumerator ConstrainMovementAxisWorldSpace()
        {
            TestUtilities.PlayspaceToOriginLookingForward();

            // set up cube with manipulation handler
            var testObject = GameObject.CreatePrimitive(PrimitiveType.Cube);

            testObject.transform.localScale = Vector3.one * 0.2f;
            Vector3 initialObjectPosition = new Vector3(0f, 0f, 1f);

            testObject.transform.position = initialObjectPosition;
            var manipHandler = testObject.AddComponent <ObjectManipulator>();

            manipHandler.HostTransform    = testObject.transform;
            manipHandler.SmoothingActive  = false;
            manipHandler.ManipulationType = ManipulationHandFlags.OneHanded;

            var constraint = manipHandler.EnsureComponent <MoveAxisConstraint>();

            constraint.UseLocalSpaceForConstraint = false;

            yield return(new WaitForFixedUpdate());

            yield return(null);

            float     moveAmount   = 1.5f;
            const int numHandSteps = 1;

            // Hand pointing at middle of cube
            Vector3  initialHandPosition = new Vector3(0.044f, -0.1f, 0.45f);
            TestHand hand = new TestHand(Handedness.Right);

            yield return(hand.Show(initialHandPosition));

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

            // Constrain x axis
            constraint.ConstraintOnMovement = AxisFlags.XAxis;

            yield return(hand.Move(Vector3.one * moveAmount, numHandSteps));

            yield return(null);

            Assert.AreEqual(initialObjectPosition.x, testObject.transform.position.x);
            Assert.AreNotEqual(initialObjectPosition.y, testObject.transform.position.y);
            Assert.AreNotEqual(initialObjectPosition.z, testObject.transform.position.z);

            yield return(hand.MoveTo(initialHandPosition, numHandSteps));

            yield return(null);

            // Constrain y axis
            constraint.ConstraintOnMovement = AxisFlags.YAxis;

            yield return(hand.Move(Vector3.one * moveAmount, numHandSteps));

            yield return(null);

            Assert.AreNotEqual(initialObjectPosition.x, testObject.transform.position.x);
            Assert.AreEqual(initialObjectPosition.y, testObject.transform.position.y);
            Assert.AreNotEqual(initialObjectPosition.z, testObject.transform.position.z);

            yield return(hand.MoveTo(initialHandPosition, numHandSteps));

            yield return(null);

            // Constrain z axis
            constraint.ConstraintOnMovement = AxisFlags.ZAxis;

            yield return(hand.Move(Vector3.one * moveAmount, numHandSteps));

            yield return(null);

            Assert.AreNotEqual(initialObjectPosition.x, testObject.transform.position.x);
            Assert.AreNotEqual(initialObjectPosition.y, testObject.transform.position.y);
            Assert.AreEqual(initialObjectPosition.z, testObject.transform.position.z);

            yield return(hand.MoveTo(initialHandPosition, numHandSteps));

            yield return(null);

            // Constrain two axes
            constraint.ConstraintOnMovement = AxisFlags.XAxis | AxisFlags.ZAxis;

            yield return(hand.Move(Vector3.one * moveAmount, numHandSteps));

            yield return(null);

            Assert.AreEqual(initialObjectPosition.x, testObject.transform.position.x);
            Assert.AreNotEqual(initialObjectPosition.y, testObject.transform.position.y);
            Assert.AreEqual(initialObjectPosition.z, testObject.transform.position.z);
        }
        public IEnumerator Test()
        {
            // Step once to receive focus events from gaze pointer
            yield return(null);

            var expected = new PointerHandler.State();

            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            expected.numFocusEnter++;
            handler.state.AssertEqual(expected);

            //
            // Test that the correct pointer events are raised when using a single pointer
            //

            // Show hand far enough from the test collider to not give it focus
            var     rightHand       = new TestHand(Handedness.Right);
            Vector3 rightNoFocusPos = new Vector3(0.05f, 0, 1.0f);

            yield return(rightHand.Show(rightNoFocusPos));

            // Should receive focus left events from gaze pointer
            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            expected.numFocusExit++;
            handler.state.AssertEqual(expected);

            // Move hand closer to the collider so it gives it focus
            Vector3 rightFocusPos = new Vector3(0.05f, 0, 1.5f);

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

            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            expected.numFocusEnter++;
            handler.state.AssertEqual(expected);

            // Trigger pinch
            int previousNumPointerDragged = handler.state.numPointerDragged;

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

            expected.numPointerDown++;
            handler.state.AssertEqual(expected);
            Assert.Greater(handler.state.numPointerDragged, previousNumPointerDragged);

            // Maintain pinch for a number of frames
            previousNumPointerDragged = handler.state.numPointerDragged;
            yield return(rightHand.MoveTo(rightFocusPos, numFramesPerMove));

            Assert.Greater(handler.state.numPointerDragged, previousNumPointerDragged);
            handler.state.AssertEqual(expected);

            // Release pinch
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Open));

            expected.numPointerUp++;
            expected.numPointerClicked++;
            handler.state.AssertEqual(expected);

            // Move back to no focus
            yield return(rightHand.MoveTo(rightNoFocusPos, numFramesPerMove));

            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            expected.numFocusExit++;
            handler.state.AssertEqual(expected);

            //
            // Test that the correct pointer events are raised when using two pointers
            //

            // Show left hand far enough from the test collider to not give it focus
            var     leftHand       = new TestHand(Handedness.Left);
            Vector3 leftNoFocusPos = new Vector3(-0.05f, 0, 1.0f);

            yield return(leftHand.Show(leftNoFocusPos));

            // Make sure no events have been raised
            handler.state.AssertEqual(expected);

            // Move left hand to give focus
            Vector3 leftFocusPos = new Vector3(-0.05f, 0, 1.5f);

            yield return(leftHand.MoveTo(leftFocusPos, numFramesPerMove));

            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            expected.numFocusEnter++;
            handler.state.AssertEqual(expected);

            // Move right hand to give focus
            yield return(rightHand.MoveTo(rightFocusPos, numFramesPerMove));

            // Focus enter should not be raised as the object is already in focus.
            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            handler.state.AssertEqual(expected);

            // Pinch left
            previousNumPointerDragged = handler.state.numPointerDragged;
            yield return(leftHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            expected.numPointerDown++;
            handler.state.AssertEqual(expected);
            Assert.Greater(handler.state.numPointerDragged, previousNumPointerDragged);

            // Pinch right
            previousNumPointerDragged = handler.state.numPointerDragged;
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            expected.numPointerDown++;
            handler.state.AssertEqual(expected);
            // Should be at least two greater, because there are two pointers down.
            // This is technically difficult to reason over because there can be arbitrary
            // but this is the best effort aside from tracking per-pointer drag counts.
            Assert.Greater(handler.state.numPointerDragged, previousNumPointerDragged + 1);

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

            expected.numPointerUp++;
            expected.numPointerClicked++;
            expected.numPointerDragged++; // Right pointer is still down
            handler.state.AssertEqual(expected);
            Assert.Greater(handler.state.numPointerDragged, previousNumPointerDragged);

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

            expected.numPointerUp++;
            expected.numPointerClicked++;
            handler.state.AssertEqual(expected);

            // Move left out of focus
            yield return(leftHand.MoveTo(leftNoFocusPos, numFramesPerMove));

            // Focus exit should not be raised as the object is still in focus.
            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            handler.state.AssertEqual(expected);

            // Move right out of focus
            yield return(rightHand.MoveTo(rightNoFocusPos, numFramesPerMove));

            expected.numBeforeFocusChange++;
            expected.numFocusChanged++;
            expected.numFocusExit++;
            handler.state.AssertEqual(expected);
        }
        public IEnumerator ReleaseButton([ValueSource(nameof(PressableButtonsTestPrefabFilenames))] string prefabFilename)
        {
            GameObject testButton = InstantiateDefaultPressableButton(prefabFilename);

            TestUtilities.PlayspaceToOriginLookingForward();

            PressableButton buttonComponent = testButton.GetComponent <PressableButton>();

            Assert.IsNotNull(buttonComponent);

            bool buttonPressed = false;

            buttonComponent.ButtonPressed.AddListener(() =>
            {
                buttonPressed = true;
            });

            bool buttonReleased = false;

            buttonComponent.ButtonReleased.AddListener(() =>
            {
                buttonReleased = true;
            });

            Vector3  startHand          = new Vector3(0, 0, -0.0081f);
            Vector3  inButtonOnPress    = new Vector3(0, 0, 0.002f);     // past press plane of mrtk pressablebutton prefab
            Vector3  rightOfButtonPress = new Vector3(0.02f, 0, 0.002f); // right of press plane, outside button
            Vector3  inButtonOnRelease  = new Vector3(0, 0, -0.0015f);   // release plane of mrtk pressablebutton prefab
            TestHand hand = new TestHand(Handedness.Right);

            // test scenarios in normal and low framerate
            int[] stepVariations = { 30, 2 };
            for (int i = 0; i < stepVariations.Length; ++i)
            {
                int numSteps = stepVariations[i];

                // test release
                yield return(hand.Show(startHand));

                yield return(hand.MoveTo(inButtonOnPress, numSteps));

                yield return(hand.MoveTo(inButtonOnRelease, numSteps));

                yield return(hand.Hide());

                Assert.IsTrue(buttonPressed, $"A{i} - Button did not get pressed when hand moved to press it.");
                Assert.IsTrue(buttonReleased, $"A{i} - Button did not get released.");

                buttonPressed  = false;
                buttonReleased = false;

                Assert.IsTrue(buttonComponent.ReleaseOnTouchEnd == true, "default behavior of button should be release on touch end");

                // test release on moving outside of button
                yield return(hand.Show(startHand));

                yield return(hand.MoveTo(inButtonOnPress, numSteps));

                yield return(hand.MoveTo(rightOfButtonPress, numSteps));

                yield return(hand.Hide());

                Assert.IsTrue(buttonPressed, $"B{i} - Button did not get pressed when hand moved to press it.");
                Assert.IsTrue(buttonReleased, $"B{i} - Button did not get released when hand exited the button.");

                buttonPressed  = false;
                buttonReleased = false;

                buttonComponent.ReleaseOnTouchEnd = false;

                // test no release on moving outside of button when releaseOnTouchEnd is disabled
                yield return(hand.Show(startHand));

                yield return(hand.MoveTo(inButtonOnPress, numSteps));

                yield return(hand.MoveTo(rightOfButtonPress, numSteps));

                yield return(hand.Hide());

                Assert.IsTrue(buttonPressed, $"C{i} - Button did not get pressed when hand moved to press it.");
                Assert.IsFalse(buttonReleased, $"C{i} - Button did got released on exit even though releaseOnTouchEnd wasn't set");

                buttonPressed  = false;
                buttonReleased = false;

                buttonComponent.ReleaseOnTouchEnd = true;
            }

            Object.Destroy(testButton);

            yield return(null);
        }
        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);
        }
Esempio n. 11
0
        public IEnumerator TestDialogPrefabResults()
        {
            TestHand handRight = new TestHand(Handedness.Right);
            int      handsteps = 30;

            // Testing near interactions
            handRight.Show(Vector3.zero);
            InstantiateFromPrefab("Test Dialog", "This is an example dialog", DialogButtonType.OK, true);
            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.IsTrue(dialogComponent.State == DialogState.WaitingForInput);
            yield return(handRight.Move(new Vector3(0.0f, -0.1f, 1.0f), handsteps));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.AreEqual(dialogResult, DialogButtonType.OK);
            Assert.AreEqual(dialogComponent.State, DialogState.Closed);

            GameObject.Destroy(dialogGameObject);
            GameObject.Destroy(dialogComponent);
            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            // The dialog only supports displaying up to two options
            yield return(handRight.MoveTo(Vector3.zero));

            InstantiateFromPrefab("Test Dialog", "This is an example dialog", DialogButtonType.Yes | DialogButtonType.No, true);
            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.IsTrue(dialogComponent.State == DialogState.WaitingForInput);
            yield return(handRight.Move(new Vector3(0.1f, -0.1f, 1.0f), handsteps));

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            Assert.AreEqual(dialogResult, DialogButtonType.No);
            Assert.AreEqual(dialogComponent.State, DialogState.Closed);

            GameObject.Destroy(dialogGameObject);
            GameObject.Destroy(dialogComponent);
            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            // Testing far interactions
            // The dialog only supports displaying up to two options
            yield return(handRight.MoveTo(Vector3.zero));

            InstantiateFromPrefab("Test Dialog", "This is an example dialog", DialogButtonType.Yes | DialogButtonType.No, false);
            // Wait for the dialog to move to a stable position
            yield return(new WaitForSeconds(0.5f));

            Assert.IsTrue(dialogComponent.State == DialogState.WaitingForInput);
            // moving the hand to an appropriate position to click on the dialog
            yield return(handRight.Move(new Vector3(-0.1f, -0.2f, 0.7f), handsteps));

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

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

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

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());


            Assert.AreEqual(dialogResult, DialogButtonType.Yes);
            Assert.AreEqual(dialogComponent.State, DialogState.Closed);

            GameObject.Destroy(dialogGameObject);
            GameObject.Destroy(dialogComponent);
        }