public IEnumerator TestRadialSetPrefab()
        {
            var radialSet          = InstantiateInteractableFromPath(Vector3.forward, Quaternion.identity, RadialSetPrefabAssetPath);
            var firstRadialButton  = radialSet.transform.Find("Radial (1)");
            var secondRadialButton = radialSet.transform.Find("Radial (2)");
            var thirdRadialButton  = radialSet.transform.Find("Radial (3)");
            var testHand           = new TestHand(Handedness.Right);

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

            Assert.IsTrue(firstRadialButton.GetComponent <Interactable>().IsToggled);
            Assert.IsFalse(secondRadialButton.GetComponent <Interactable>().IsToggled);
            Assert.IsFalse(thirdRadialButton.GetComponent <Interactable>().IsToggled);

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

            var aBitBack = Vector3.forward * -0.2f;

            yield return(testHand.MoveTo(firstRadialButton.position));

            yield return(testHand.Move(aBitBack));

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

            yield return(testHand.Move(aBitBack));

            Assert.IsFalse(firstRadialButton.GetComponent <Interactable>().IsToggled);
            Assert.IsTrue(secondRadialButton.GetComponent <Interactable>().IsToggled);
            Assert.IsFalse(thirdRadialButton.GetComponent <Interactable>().IsToggled);

            //Cleanup
            GameObject.Destroy(radialSet);
        }
예제 #2
0
        public IEnumerator NearInteractionTouchableSetTouchableCollider()
        {
            GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

            cube.transform.position   = new Vector3(0, 0, 2f);
            cube.transform.localScale = new Vector3(0.3f, 0.3f, 0.3f);
            BoxCollider boxCollider = cube.GetComponent <BoxCollider>();

            var rightHand = new TestHand(Handedness.Right);

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

            // Add NearInteractionTouchable
            var nearIT = cube.AddComponent <NearInteractionTouchable>();

            // Create new gameObject for testing a new BoxCollider
            GameObject cube2 = GameObject.CreatePrimitive(PrimitiveType.Cube);

            cube2.transform.position   = new Vector3(-1f, 0, 2f);
            cube2.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);

            // Change touchableCollider to a new BoxCollider with a different size from another object
            BoxCollider newBoxCollider = cube2.GetComponent <BoxCollider>();

            newBoxCollider.size = new Vector3(4, 2, 1.2f);

            using (var catcher = CreateEventCatcher(nearIT))
            {
                // Touch started and completed when entering and exiting the collider
                yield return(rightHand.Move(new Vector3(0, 0, 0.4f)));

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

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

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

                // Set new touchableCollider bounds
                nearIT.SetTouchableCollider(newBoxCollider);

                // Move hand to the side
                yield return(rightHand.Move(new Vector3(0.5f, 0, 0)));

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

                // Move hand forward, on touch
                yield return(rightHand.Move(new Vector3(0, 0, 0.5f)));

                Assert.AreEqual(2, catcher.EventsStarted);

                // Move the hand back, on touch exit
                yield return(rightHand.Move(new Vector3(0, 0, -0.5f)));

                Assert.AreEqual(2, catcher.EventsCompleted);
            }
        }
        public IEnumerator TestAssembleTouchSnapSlider()
        {
            GameObject  pinchSliderObject;
            PinchSlider slider;

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

            // Set the slider to use step divisions
            slider.UseSliderStepDivisions = true;
            slider.SliderStepDivisions    = 4;

            // Set slider to snap with touch
            slider.SnapToPosition = true;
            slider.IsTouchable    = true;

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            bool interactionStarted = false;

            slider.OnInteractionStarted.AddListener((x) => interactionStarted = true);
            bool interactionUpdated = false;

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

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

            yield return(rightHand.Show(initialPos));

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

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

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

            Assert.AreEqual(0.75f, slider.SliderValue);

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

            Assert.AreEqual(0.25f, slider.SliderValue);

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

            Assert.AreEqual(0.5f, slider.SliderValue);

            bool interactionEnded = false;

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

            yield return(rightHand.Hide());

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

            GameObject.Destroy(pinchSliderObject);
        }
예제 #4
0
        public IEnumerator TestTapToPlaceColliderTests()
        {
            TestUtilities.PlayspaceToOriginLookingForward();

            // Create a scene with 2 cubes
            GameObject colliderObj1 = GameObject.CreatePrimitive(PrimitiveType.Cube);

            colliderObj1.transform.localScale = new Vector3(0.3f, 0.3f, 0.05f);
            colliderObj1.transform.position   = new Vector3(0.3f, 0, 1.5f);

            GameObject colliderObj2 = GameObject.CreatePrimitive(PrimitiveType.Cube);

            colliderObj2.transform.localScale = new Vector3(0.3f, 0.3f, 0.05f);
            colliderObj2.transform.position   = new Vector3(-0.3f, 0, 1.5f);

            // Create a cube with Tap to Place attached
            var tapToPlaceObj = InstantiateTestSolver <TapToPlace>();

            tapToPlaceObj.target.transform.position = Vector3.forward * 2;
            TapToPlace tapToPlace = tapToPlaceObj.solver as TapToPlace;

            // Switching the TrackedTargetType to Controller Ray
            SolverHandler tapToPlaceSolverHandler = tapToPlaceObj.handler;

            tapToPlaceSolverHandler.TrackedTargetType = TrackedObjectType.ControllerRay;

            Vector3 handStartPosition = new Vector3(0, -0.15f, 0.5f);
            var     leftHand          = new TestHand(Handedness.Left);

            yield return(leftHand.Show(handStartPosition));

            // Start the placement via code instead of click from the hand
            tapToPlace.StartPlacement();
            yield return(null);

            Assert.True(tapToPlace.IsBeingPlaced);

            // Move hand, object should follow
            yield return(leftHand.Move(new Vector3(-0.15f, 0, 0), 30));

            Assert.True(tapToPlaceObj.target.transform.position.z < colliderObj1.transform.position.z);

            yield return(leftHand.Move(new Vector3(0.15f, 0, 0), 30));

            Assert.True(tapToPlaceObj.target.transform.position.z > colliderObj1.transform.position.z);

            yield return(leftHand.Move(new Vector3(0.15f, 0, 0), 30));

            Assert.True(tapToPlaceObj.target.transform.position.z < colliderObj1.transform.position.z);

            // Stop the placement via code instead of click from the hand
            tapToPlace.StopPlacement();

            Assert.False(tapToPlace.IsBeingPlaced);
        }
예제 #5
0
        public IEnumerator TestTapToPlaceOnClickControllerRay()
        {
            TestUtilities.PlayspaceToOriginLookingForward();

            // Create a cube with Tap to Place attached
            var tapToPlaceObj = InstantiateTestSolver <TapToPlace>();

            tapToPlaceObj.target.transform.position = Vector3.forward;
            TapToPlace tapToPlace = tapToPlaceObj.solver as TapToPlace;

            // Switch the TrackedTargetType to Controller Ray
            SolverHandler tapToPlaceSolverHandler = tapToPlaceObj.handler;

            tapToPlaceSolverHandler.TrackedTargetType = TrackedObjectType.ControllerRay;

            // Set hand position
            Vector3 handStartPosition = new Vector3(0, -0.1f, 0.6f);
            var     leftHand          = new TestHand(Handedness.Left);

            yield return(leftHand.Show(handStartPosition));

            Vector3 initialObjPosition = tapToPlaceObj.target.transform.position;

            yield return(leftHand.Click());

            // Make sure the object is being placed after selection
            Assert.True(tapToPlace.IsBeingPlaced);

            // Move hand, object should follow
            yield return(leftHand.Move(Vector3.forward));

            yield return(leftHand.Move(Vector3.up));

            // Make sure the object starting position is different from the current position
            Assert.True(initialObjPosition != tapToPlaceObj.target.transform.position);

            // Tap to place has a 0.5 sec timer between clicks to make sure a double click does not get registered
            // We need to wait at least 0.5 secs until another click is called or tap to place will ignore the action
            yield return(new WaitForSeconds(0.5f));

            // Click to stop the placement
            yield return(leftHand.Click());

            // Make sure the object is not being placed
            Assert.False(tapToPlace.IsBeingPlaced);

            // Get new position of the object after it is placed
            Vector3 newPosition = tapToPlaceObj.target.transform.position;

            // Move hand, the object should NOT move
            yield return(leftHand.Move(Vector3.back, 30));

            Assert.True(newPosition == tapToPlaceObj.target.transform.position);
        }
예제 #6
0
        public IEnumerator ZoomRotatedSlate()
        {
            // Configuring camera and hands to interact with rotated slate
            InstantiateFromPrefab(Vector3.right, Quaternion.LookRotation(Vector3.right));
            MixedRealityPlayspace.PerformTransformation(p => p.Rotate(Vector3.up, 90));
            yield return(null);

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

            yield return(handRight.Show(panZoom.transform.position + Vector3.forward * -0.1f + Vector3.right * -0.3f));

            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.1f + Vector3.right * -0.3f));

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

            // Use both hands to zoom in
            yield return(handRight.Move(new Vector3(0f, 0f, -0.1f), 5));

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

            Assert.AreEqual(0.6, panZoom.CurrentScale, 0.1, "Rotated slate did not zoom in using near interaction");

            // Reset slate and hands configuration
            panZoom.Reset();
            yield return(handRight.SetGesture(ArticulatedHandPose.GestureId.Open));

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

            yield return(null);

            // Both hands touch slate
            yield return(handRight.MoveTo(panZoom.transform.position + Vector3.forward * -0.1f));

            yield return(handLeft.MoveTo(panZoom.transform.position + Vector3.forward * 0.1f));

            yield return(null);

            // Use both hands to zoom in
            yield return(handRight.Move(new Vector3(0f, 0f, -0.1f), 5));

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

            Assert.AreEqual(0.6, panZoom.CurrentScale, 0.1, "Rotated slate did not zoom in using far interaction");

            yield return(handRight.Hide());

            yield return(handLeft.Hide());
        }
예제 #7
0
        public IEnumerator ConstrainMovementFixedDistance()
        {
            TestUtilities.PlayspaceToArbitraryPose();

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

            testObject.transform.localScale = Vector3.one * 0.2f;
            testObject.transform.position   = TestUtilities.PositionRelativeToPlayspace(new Vector3(0f, 0f, 1f));
            var manipHandler = testObject.AddComponent <ObjectManipulator>();

            manipHandler.HostTransform          = testObject.transform;
            manipHandler.SmoothingFar           = false;
            manipHandler.ManipulationType       = ManipulationHandFlags.OneHanded;
            manipHandler.OneHandRotationModeFar = ObjectManipulator.RotateInOneHandType.RotateAboutObjectCenter;

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

            constraint.ConstraintTransform = CameraCache.Main.transform;

            float originalDist = (CameraCache.Main.transform.position - testObject.transform.position).magnitude;

            yield return(new WaitForFixedUpdate());

            yield return(null);

            const int numHandSteps = 1;

            // Hand pointing at middle of cube
            TestHand hand = new TestHand(Handedness.Right);

            yield return(hand.Show(TestUtilities.PositionRelativeToPlayspace(new Vector3(0.044f, -0.1f, 0.45f))));

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

            Vector3 worldDelta = TestUtilities.DirectionRelativeToPlayspace(Vector3.one);

            // Move and test that still same distance from head
            yield return(hand.Move(worldDelta * 0.5f, numHandSteps));

            yield return(null);

            Assert.AreEqual(originalDist, (CameraCache.Main.transform.position - testObject.transform.position).magnitude, 0.001f);

            yield return(hand.Move(worldDelta * -1f, numHandSteps));

            yield return(null);

            Assert.AreEqual(originalDist, (CameraCache.Main.transform.position - testObject.transform.position).magnitude, 0.001f);
        }
예제 #8
0
        public IEnumerator PrefabGGVZoom()
        {
            InstantiateFromPrefab();

            PlayModeTestUtilities.SetHandSimulationMode(HandSimulationMode.Gestures);

            TestHand handRight = new TestHand(Handedness.Right);

            yield return(handRight.Show(new Vector3(0.0f, 0.0f, 0.6f)));

            TestHand handLeft = new TestHand(Handedness.Left);

            yield return(handLeft.Show(new Vector3(-0.1f, 0.0f, 0.6f)));

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

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

            yield return(handRight.Move(new Vector3(0.005f, 0.0f, 0.0f), 10));

            yield return(handLeft.Move(new Vector3(-0.005f, 0.0f, 0.0f), 10));

            Assert.AreEqual(0.5, panZoom.CurrentScale, 0.1, "slate did not zoom in using two ggv hands");

            yield return(handRight.Hide());

            yield return(handLeft.Hide());
        }
예제 #9
0
        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)));

            Assert.True(PointerUtils.TryGetHandRayEndPoint(Handedness.Right, out Vector3 hitPointStart));

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

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

            Assert.True(PointerUtils.TryGetHandRayEndPoint(Handedness.Right, out Vector3 hitPointEnd));
            yield return(h.SetGesture(ArticulatedHandPose.GestureId.Open));

            TestUtilities.AssertNotAboutEqual(hitPointStart, hitPointEnd, "ray should not stick on slate scrolling");
            Assert.AreEqual(0.1, totalPanDelta.y, 0.05, "pan delta is not correct");



            yield return(h.Hide());
        }
        /// <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)
        {
            var iss        = PlayModeTestUtilities.GetInputSimulationService();
            var oldSimMode = iss.ControllerSimulationMode;

            iss.ControllerSimulationMode = ControllerSimulationMode.HandGestures;

            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());

            iss.ControllerSimulationMode = oldSimMode;
            yield return(null);
        }
예제 #11
0
        public IEnumerator TestAssembleInteractableAndFarManip()
        {
            GameObject  pinchSliderObject;
            PinchSlider slider;

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

            Debug.Assert(slider.SliderValue == 0.5, "Slider should have value 0.5 at start");

            // Set up ggv simulation
            PlayModeTestUtilities.PushHandSimulationProfile();
            PlayModeTestUtilities.SetHandSimulationMode(ControllerSimulationMode.HandGestures);

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

            yield return(rightHand.Show(initialPos));

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

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

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

            yield return(rightHand.Hide());

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

            // clean up
            GameObject.Destroy(pinchSliderObject);
            PlayModeTestUtilities.PopHandSimulationProfile();
        }
예제 #12
0
        public IEnumerator PrefabTouchZoom()
        {
            InstantiateFromPrefab();

            TestHand handRight = new TestHand(Handedness.Right);

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

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

            TestHand handLeft = new TestHand(Handedness.Left);

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

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

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

            yield return(handLeft.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(handRight.Hide());

            yield return(handLeft.Hide());
        }
        public IEnumerator DisableObject()
        {
            float minScale = 0.5f;
            float maxScale = 2f;

            var bbox         = InstantiateSceneAndDefaultBbox();
            var scaleHandler = bbox.EnsureComponent <MinMaxScaleConstraint>();

            scaleHandler.ScaleMinimum = minScale;
            scaleHandler.ScaleMaximum = maxScale;
            yield return(null);

            Vector3 initialScale = bbox.transform.localScale;

            const int numHandSteps = 1;

            Vector3  initialHandPosition = new Vector3(0, 0, 0.5f);
            var      frontRightCornerPos = bbox.ScaleCorners[3].transform.position; // front right corner is corner 3
            TestHand hand = new TestHand(Handedness.Right);

            // Hands grab object at initial position
            yield return(hand.Show(initialHandPosition));

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

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

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

            // Verify that scale works before deactivating
            yield return(hand.Move(Vector3.right * 0.2f, numHandSteps));

            Vector3 afterTransformScale = bbox.transform.localScale;

            Assert.AreNotEqual(initialScale, afterTransformScale);

            // Deactivate object and ensure that we don't scale
            bbox.gameObject.SetActive(false);
            yield return(null);

            bbox.gameObject.SetActive(true);
            yield return(hand.Move(Vector3.right * 0.2f, numHandSteps));

            Assert.AreEqual(afterTransformScale, bbox.transform.localScale);
        }
예제 #14
0
        public IEnumerator ScaleViaHoloLens1Interaction()
        {
            var bbox = InstantiateSceneAndDefaultBbox();

            yield return(null);

            yield return(null);

            var bounds      = bbox.GetComponent <BoxCollider>().bounds;
            var startCenter = new Vector3(0, 0, 1.5f);
            var startSize   = new Vector3(.5f, .5f, .5f);

            TestUtilities.AssertAboutEqual(bounds.center, startCenter, "bbox incorrect center at start");
            TestUtilities.AssertAboutEqual(bounds.size, startSize, "bbox incorrect size at start");

            // Switch to hand gestures
            var iss        = PlayModeTestUtilities.GetInputSimulationService();
            var oldSimMode = iss.ControllerSimulationMode;

            iss.ControllerSimulationMode = ControllerSimulationMode.HandGestures;

            CameraCache.Main.transform.LookAt(bbox.ScaleCorners[3].transform);

            var      startHandPos = CameraCache.Main.transform.TransformPoint(new Vector3(0.1f, 0f, 1.5f));
            TestHand rightHand    = new TestHand(Handedness.Right);

            yield return(rightHand.Show(startHandPos));

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

            // After pinching, center should remain the same
            var afterPinchbounds = bbox.GetComponent <BoxCollider>().bounds;

            TestUtilities.AssertAboutEqual(afterPinchbounds.center, startCenter, "bbox incorrect center after pinch");
            TestUtilities.AssertAboutEqual(afterPinchbounds.size, startSize, "bbox incorrect size after pinch");

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

            yield return(rightHand.Move(delta));

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

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

            Object.Destroy(bbox.gameObject);
            // Wait for a frame to give Unity a change to actually destroy the object
            yield return(null);

            // Restore the input simulation profile
            iss.ControllerSimulationMode = oldSimMode;

            yield return(null);
        }
예제 #15
0
        public IEnumerator ConstrainScaleApparentSize()
        {
            TestUtilities.PlayspaceToArbitraryPose();

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

            testObject.transform.localScale = Vector3.one * 0.2f;
            testObject.transform.position   = TestUtilities.PositionRelativeToPlayspace(new Vector3(0f, 0f, 1f));
            testObject.transform.rotation   = CameraCache.Main.transform.rotation;
            var manipHandler = testObject.AddComponent <ObjectManipulator>();

            manipHandler.HostTransform          = testObject.transform;
            manipHandler.SmoothingFar           = false;
            manipHandler.ManipulationType       = ManipulationHandFlags.OneHanded;
            manipHandler.OneHandRotationModeFar = ObjectManipulator.RotateInOneHandType.RotateAboutObjectCenter;

            // add an xy move constraint so that the object's position does not change on screen
            var moveConstraint = manipHandler.EnsureComponent <MoveAxisConstraint>();

            moveConstraint.UseLocalSpaceForConstraint = true;
            moveConstraint.ConstraintOnMovement       = AxisFlags.XAxis | AxisFlags.YAxis;

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

            Vector3 topLeft       = testObject.transform.TransformPoint(new Vector3(-0.5f, 0.5f, -0.5f));
            Vector3 bottomRight   = testObject.transform.TransformPoint(new Vector3(0.5f, -0.5f, -0.5f));
            float   originalAngle = Vector3.Angle(topLeft - CameraCache.Main.transform.position, bottomRight - CameraCache.Main.transform.position);

            yield return(new WaitForFixedUpdate());

            yield return(null);

            const int numHandSteps = 1;

            // Hand pointing at middle of cube
            TestHand hand = new TestHand(Handedness.Right);

            yield return(hand.Show(TestUtilities.PositionRelativeToPlayspace(new Vector3(0.044f, -0.1f, 0.45f))));

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

            // Move and test that still same distance from head
            yield return(hand.Move(TestUtilities.DirectionRelativeToPlayspace(Vector3.forward * 0.5f), numHandSteps));

            yield return(null);

            Vector3 newtopLeft     = testObject.transform.TransformPoint(new Vector3(-0.5f, 0.5f, -0.5f));
            Vector3 newBottomRight = testObject.transform.TransformPoint(new Vector3(0.5f, -0.5f, -0.5f));
            float   newAngle       = Vector3.Angle(newtopLeft - CameraCache.Main.transform.position, newBottomRight - CameraCache.Main.transform.position);

            Assert.AreEqual(originalAngle, newAngle, 0.05f);
        }
예제 #16
0
        public IEnumerator TestRadialSetPrefab()
        {
            var radialSet          = TestButtonUtilities.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(TestUtilities.PositionRelativeToPlayspace(Vector3.zero)));

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

            var aBitBack = TestUtilities.DirectionRelativeToPlayspace(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);

            GameObject.Destroy(radialSet);
        }
예제 #17
0
        public IEnumerator ConstrainRotationFixToWorld()
        {
            TestUtilities.PlayspaceToOriginLookingForward();

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

            testObject.transform.localScale = Vector3.one * 0.2f;
            testObject.transform.position   = Vector3.forward;
            var manipHandler = testObject.AddComponent <ObjectManipulator>();

            manipHandler.HostTransform           = testObject.transform;
            manipHandler.SmoothingActive         = false;
            manipHandler.ManipulationType        = ManipulationHandFlags.OneHanded;
            manipHandler.OneHandRotationModeNear = ObjectManipulator.RotateInOneHandType.RotateAboutGrabPoint;

            var rotConstraint = manipHandler.EnsureComponent <FixedRotationToWorldConstraint>();

            rotConstraint.TargetTransform = manipHandler.HostTransform;

            // Face user first
            const int numHandSteps = 1;
            TestHand  hand         = new TestHand(Handedness.Right);

            yield return(hand.Show(new Vector3(0.05f, -0.1f, 0.45f)));

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

            yield return(null);

            // rotate the hand
            yield return(hand.SetRotation(Quaternion.Euler(45, 45, 45), numHandSteps));

            yield return(null);

            Assert.AreEqual(Quaternion.identity, testObject.transform.rotation);

            // move the hand
            yield return(hand.Move(Vector3.right * 0.2f, numHandSteps));

            yield return(null);

            Assert.AreEqual(Quaternion.identity, testObject.transform.rotation);

            // rotate the head
            CameraCache.Main.transform.Rotate(new Vector3(0, 10, 0));
            yield return(new WaitForFixedUpdate());

            yield return(null);

            Assert.AreEqual(Quaternion.identity, testObject.transform.rotation);
        }
예제 #18
0
        public IEnumerator Prefab_TouchScroll()
        {
            InstantiateFromPrefab(Vector3.forward);
            Vector2 totalPanDelta = Vector2.zero;

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

            TestHand h = new TestHand(Handedness.Right);;

            yield return(h.MoveTo(panObject.transform.position));

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

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

            yield return(h.Hide());
        }
        public IEnumerator TestAssembleInteractableAndEventsRaised()
        {
            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);

            yield return(PlayModeTestUtilities.WaitForInputSystemUpdate());

            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);
        }
예제 #20
0
        public IEnumerator PressButtonWhenSecondButtonIsNearby([ValueSource(nameof(PressableButtonsTestPrefabPaths))] string prefabFilename)
        {
            GameObject testButton1 = InstantiateDefaultPressableButton(prefabFilename);
            GameObject testButton2 = InstantiateDefaultPressableButton(prefabFilename);

            // Move the camera to origin looking at +z to more easily see the button.
            TestUtilities.PlayspaceToOriginLookingForward();

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

            Assert.IsNotNull(buttonComponent);
            Assert.IsTrue(buttonComponent.EnforceFrontPush, "Button default behavior should have enforce front push enabled");

            // Positioning the start push plane of the second button just before first button max push plane, creating a small overlap
            float distance = Mathf.Abs(buttonComponent.MaxPushDistance) + Mathf.Abs(buttonComponent.StartPushDistance);

            distance = buttonComponent.DistanceSpaceMode == SpaceMode.Local ? distance * buttonComponent.LocalToWorldScale : distance;
            testButton2.transform.position += Vector3.forward * distance;

            bool buttonPressed = false;

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

            // Move the hand so the pointer passes through the two buttons
            TestHand hand      = new TestHand(Handedness.Right);
            float    handReach = 0.1f;
            int      numSteps  = (int)Mathf.Ceil(handReach / (distance * 0.5f)); // Maximum hand speed in order to trigger touch started in the first button before the second button becomes the closest touchable to pointer

            yield return(hand.Show(new Vector3(0, 0, -handReach / 2)));

            yield return(hand.Move(new Vector3(0, 0, handReach), numSteps));

            Assert.IsTrue(buttonPressed, "Button did not get pressed when a second button is nearby");

            Object.Destroy(testButton1);
            Object.Destroy(testButton2);

            yield return(null);
        }
        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());
        }
예제 #22
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 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;
            }
        }
        /// <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());
        }
예제 #25
0
        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());
        }
        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 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);
        }
예제 #28
0
        public IEnumerator ConstrainByNumberOfHands()
        {
            TestUtilities.PlayspaceToArbitraryPose();

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

            testObject.transform.localScale = Vector3.one * 0.2f;
            Vector3 originalPosition = TestUtilities.PositionRelativeToPlayspace(Vector3.forward);

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

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

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

            // 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.HandType = ManipulationHandFlags.OneHanded;

            // 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.HandType = ManipulationHandFlags.TwoHanded;

            yield return(new WaitForFixedUpdate());

            yield return(null);

            const int numHandSteps = 10;

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

            yield return(leftHand.Show(TestUtilities.PositionRelativeToPlayspace(new Vector3(-0.05f, -0.1f, 0.45f))));

            yield return(rightHand.Show(TestUtilities.PositionRelativeToPlayspace(new Vector3(0.05f, -0.1f, 0.45f))));

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

            yield return(leftHand.SetRotation(Quaternion.Euler(45, 45, 45), numHandSteps));

            yield return(null);

            TestUtilities.AssertAboutEqual(originalRotation, testObject.transform.rotation, "Rotation should be equal for one handed interaction");

            Vector3 worldLeftUp = TestUtilities.DirectionRelativeToPlayspace(Vector3.left + Vector3.up);

            yield return(leftHand.Move(worldLeftUp * 0.2f, numHandSteps));

            yield return(null);

            TestUtilities.AssertNotAboutEqual(originalPosition, testObject.transform.position, "Position should not be equal for one handed interaction");

            // return hand to original pose
            yield return(leftHand.SetRotation(Quaternion.identity, numHandSteps));

            yield return(leftHand.Move(-worldLeftUp * 0.2f, numHandSteps));

            yield return(null);

            // grab with both hands and move/rotate
            yield return(rightHand.SetGesture(ArticulatedHandPose.GestureId.Pinch));

            yield return(leftHand.Move(worldLeftUp * 0.2f, numHandSteps));

            yield return(null);

            TestUtilities.AssertNotAboutEqual(originalRotation, testObject.transform.rotation, "Rotation should not be equal for two handed interaction");
            TestUtilities.AssertAboutEqual(originalPosition, testObject.transform.position, "Position should be equal for two handed interaction");
        }
예제 #29
0
        public IEnumerator ConstrainRotationFaceUser()
        {
            TestUtilities.PlayspaceToArbitraryPose();

            Vector3 initialPosition = TestUtilities.PositionRelativeToPlayspace(Vector3.forward);
            var     testObject      = GameObject.CreatePrimitive(PrimitiveType.Cube);

            testObject.transform.localScale = Vector3.one * 0.2f;
            testObject.transform.position   = initialPosition;
            var manipHandler = testObject.AddComponent <ObjectManipulator>();

            manipHandler.HostTransform           = testObject.transform;
            manipHandler.SmoothingFar            = false;
            manipHandler.ManipulationType        = ManipulationHandFlags.OneHanded;
            manipHandler.OneHandRotationModeNear = ObjectManipulator.RotateInOneHandType.RotateAboutGrabPoint;

            var rotConstraint = manipHandler.EnsureComponent <FaceUserConstraint>();

            rotConstraint.FaceAway = false;

            // Face user first
            const int numHandSteps = 10;
            TestHand  hand         = new TestHand(Handedness.Right);

            yield return(hand.Show(TestUtilities.PositionRelativeToPlayspace(new Vector3(0.05f, -0.1f, 0.45f))));

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

            yield return(null);

            Vector3 cameraToObject() => testObject.transform.position - CameraCache.Main.transform.position;
            Vector3 checkCollinear() => Vector3.Cross(testObject.transform.forward, cameraToObject());
            float checkNegative() => Vector3.Dot(testObject.transform.forward, cameraToObject());

            TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
            Assert.Less(checkNegative(), 0, "Object facing away");

            // Move the hand
            yield return(hand.Move(TestUtilities.DirectionRelativeToPlayspace(new Vector3(0.2f, 0.2f, 0)), numHandSteps));

            yield return(null);

            Assert.AreNotEqual(initialPosition, testObject.transform.position); // ensure the object moved
            TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
            Assert.Less(checkNegative(), 0, "Object facing away");

            // Face away from user
            rotConstraint.FaceAway = true;
            yield return(hand.Move(TestUtilities.DirectionRelativeToPlayspace(new Vector3(-0.2f, -0.2f, 0)), numHandSteps));

            yield return(null);

            TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
            Assert.Greater(checkNegative(), 0, "Object facing away");

            // Move the hand
            yield return(hand.Move(TestUtilities.DirectionRelativeToPlayspace(new Vector3(0.2f, 0.2f, 0)), numHandSteps));

            yield return(null);

            Assert.AreNotEqual(initialPosition, testObject.transform.position); // ensure the object moved
            TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
            Assert.Greater(checkNegative(), 0, "Object facing away");
        }
예제 #30
0
        public IEnumerator CombinedConstraintFarNear()
        {
            TestUtilities.PlayspaceToArbitraryPose();

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

            testObject.transform.localScale = Vector3.one * 0.2f;
            Vector3 originalPosition = TestUtilities.PositionRelativeToPlayspace(Vector3.forward);

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

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

            manipHandler.HostTransform          = testObject.transform;
            manipHandler.SmoothingFar           = 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(TestUtilities.PositionRelativeToPlayspace(new Vector3(-0.05f, 0, 1))));

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

            yield return(null);

            Vector3 worldLeftUp = TestUtilities.DirectionRelativeToPlayspace(Vector3.left + Vector3.up);

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

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

            yield return(leftHand.Move(worldLeftUp * 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(-worldLeftUp * 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(TestUtilities.PositionRelativeToPlayspace(new Vector3(-0.05f, -0.1f, 0.45f)), numHandSteps));

            yield return(rightHand.MoveTo(TestUtilities.PositionRelativeToPlayspace(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(worldLeftUp * 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");
        }