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); }
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); }
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); }
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); }
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()); }
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); }
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()); }
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); }
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(); }
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); }
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); }
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); }
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); }
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); }
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); }
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()); }
/// <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()); }
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); }
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"); }
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"); }
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"); }