Skip to content

Commit dde0dc2

Browse files
Move FaceUser/FaceAwayFromUser to a TransformConstraint
Also updated and implemented new tests.
1 parent 05a71e1 commit dde0dc2

File tree

7 files changed

+145
-41
lines changed

7 files changed

+145
-41
lines changed

Assets/MixedRealityToolkit.SDK/Experimental/Features/Input/Handlers/ObjectManipulator.cs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ public class ObjectManipulator : MonoBehaviour, IMixedRealityPointerHandler, IMi
2525
#region Public Enums
2626
public enum RotateInOneHandType
2727
{
28-
FaceUser,
29-
FaceAwayFromUser,
3028
MaintainOriginalRotation,
3129
RotateAboutObjectCenter,
3230
RotateAboutGrabPoint
@@ -283,15 +281,12 @@ public PointerData(IMixedRealityPointer pointer, Vector3 worldGrabPoint) : this(
283281
}
284282

285283
private Dictionary<uint, PointerData> pointerIdToPointerMap = new Dictionary<uint, PointerData>();
286-
private Quaternion objectToHandRotation;
287284
private Quaternion objectToGripRotation;
288285
private bool isNearManipulation;
289286
private bool isManipulationStarted;
290287

291288
private Rigidbody rigidBody;
292289
private bool wasKinematic = false;
293-
294-
private Quaternion hostWorldRotationOnManipulationStart;
295290

296291
private ConstraintManager constraints;
297292

@@ -573,15 +568,6 @@ private void HandleOneHandMoveStarted()
573568
PointerData pointerData = GetFirstPointer();
574569
IMixedRealityPointer pointer = pointerData.pointer;
575570

576-
// cache objects rotation on start to have a reference for constraint calculations
577-
// if we don't cache this on manipulation start the near rotation might drift off the hand
578-
// over time
579-
hostWorldRotationOnManipulationStart = HostTransform.rotation;
580-
581-
// Calculate relative transform from object to hand.
582-
Quaternion worldToPalmRotation = Quaternion.Inverse(pointer.Rotation);
583-
objectToHandRotation = worldToPalmRotation * HostTransform.rotation;
584-
585571
// Calculate relative transform from object to grip.
586572
Quaternion gripRotation;
587573
TryGetGripRotation(pointer, out gripRotation);
@@ -609,19 +595,6 @@ private void HandleOneHandMoveUpdated()
609595
case RotateInOneHandType.MaintainOriginalRotation:
610596
targetTransform.Rotation = HostTransform.rotation;
611597
break;
612-
case RotateInOneHandType.FaceUser:
613-
{
614-
Vector3 directionToTarget = pointerData.GrabPoint - CameraCache.Main.transform.position;
615-
// Vector3 directionToTarget = HostTransform.position - CameraCache.Main.transform.position;
616-
targetTransform.Rotation = Quaternion.LookRotation(-directionToTarget);
617-
break;
618-
}
619-
case RotateInOneHandType.FaceAwayFromUser:
620-
{
621-
Vector3 directionToTarget = pointerData.GrabPoint - CameraCache.Main.transform.position;
622-
targetTransform.Rotation = Quaternion.LookRotation(directionToTarget);
623-
break;
624-
}
625598
case RotateInOneHandType.RotateAboutObjectCenter:
626599
case RotateInOneHandType.RotateAboutGrabPoint:
627600
Quaternion gripRotation;

Assets/MixedRealityToolkit.SDK/Experimental/Features/Utilities/Migration/ObjectManipulatorMigrationHandler.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,27 @@ private void MigrateOneHandRotationModes(ref ObjectManipulator objManip, Manipul
142142
break;
143143
}
144144
case ManipulationHandler.RotateInOneHandType.FaceUser:
145-
newMode = ObjectManipulator.RotateInOneHandType.FaceUser;
146-
break;
145+
{
146+
newMode = ObjectManipulator.RotateInOneHandType.RotateAboutGrabPoint;
147+
148+
var rotConstraint = objManip.EnsureComponent<FaceUserConstraint>();
149+
rotConstraint.TargetTransform = objManip.HostTransform;
150+
rotConstraint.HandType = ManipulationHandFlags.OneHanded;
151+
rotConstraint.ProximityType = proximity;
152+
rotConstraint.FaceAway = false;
153+
break;
154+
}
147155
case ManipulationHandler.RotateInOneHandType.FaceAwayFromUser:
148-
newMode = ObjectManipulator.RotateInOneHandType.FaceAwayFromUser;
149-
break;
156+
{
157+
newMode = ObjectManipulator.RotateInOneHandType.RotateAboutGrabPoint;
158+
159+
var rotConstraint = objManip.EnsureComponent<FaceUserConstraint>();
160+
rotConstraint.TargetTransform = objManip.HostTransform;
161+
rotConstraint.HandType = ManipulationHandFlags.OneHanded;
162+
rotConstraint.ProximityType = proximity;
163+
rotConstraint.FaceAway = true;
164+
break;
165+
}
150166
case ManipulationHandler.RotateInOneHandType.MaintainOriginalRotation:
151167
newMode = ObjectManipulator.RotateInOneHandType.MaintainOriginalRotation;
152168
break;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
using Microsoft.MixedReality.Toolkit.Utilities;
5+
using UnityEngine;
6+
7+
namespace Microsoft.MixedReality.Toolkit.UI
8+
{
9+
/// <summary>
10+
/// Component for fixing the rotation of a manipulated object such that
11+
/// it always faces or faces away from the user
12+
/// </summary>
13+
public class FaceUserConstraint : TransformConstraint
14+
{
15+
#region Properties
16+
17+
[SerializeField]
18+
[Tooltip("Option to use this constraint to face away from the user")]
19+
private bool faceAway = false;
20+
21+
/// <summary>
22+
/// If true, this will constrain rotation to face away from the user
23+
/// </summary>
24+
public bool FaceAway
25+
{
26+
get => faceAway;
27+
set => faceAway = value;
28+
}
29+
30+
public override TransformFlags ConstraintType => TransformFlags.Rotate;
31+
32+
#endregion Properties
33+
34+
#region Public Methods
35+
36+
/// <summary>
37+
/// Updates an rotation so that its facing the camera
38+
/// </summary>
39+
public override void ApplyConstraint(ref MixedRealityTransform transform)
40+
{
41+
Vector3 directionToTarget = transform.Position - CameraCache.Main.transform.position;
42+
transform.Rotation = Quaternion.LookRotation(faceAway ? -directionToTarget : directionToTarget);
43+
}
44+
45+
#endregion Public Methods
46+
}
47+
}

Assets/MixedRealityToolkit.SDK/Features/Input/Handlers/Constraints/FaceUserConstraint.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/MixedRealityToolkit.SDK/Features/Input/Handlers/Constraints/FixedRotationToUserConstraint.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
namespace Microsoft.MixedReality.Toolkit.UI
88
{
99
/// <summary>
10-
/// Component for limiting the rotation of a manipulated object relative to the user
11-
/// or BoundingBox
10+
/// Component for fixing the rotation of a manipulated object relative to the user
1211
/// </summary>
1312
public class FixedRotationToUserConstraint : TransformConstraint
1413
{
@@ -31,8 +30,8 @@ public override void Initialize(MixedRealityPose worldPose)
3130
}
3231

3332
/// <summary>
34-
/// Removes rotation about given axis if its flag is found
35-
/// in ConstraintOnRotation
33+
/// Updates the objects rotation so that the rotation relative to the user
34+
/// is fixed
3635
/// </summary>
3736
public override void ApplyConstraint(ref MixedRealityTransform transform)
3837
{

Assets/MixedRealityToolkit.Tests/PlayModeTests/ConstraintTests.cs

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ public IEnumerator ConstrainByNumberOfHands()
645645
yield return new WaitForFixedUpdate();
646646
yield return null;
647647

648-
const int numHandSteps = 1;
648+
const int numHandSteps = 10;
649649

650650
TestHand leftHand = new TestHand(Handedness.Left);
651651
TestHand rightHand = new TestHand(Handedness.Right);
@@ -685,8 +685,7 @@ public IEnumerator ConstrainByNumberOfHands()
685685
public IEnumerator ConstrainByProximity()
686686
{
687687
TestUtilities.PlayspaceToOriginLookingForward();
688-
689-
// set up cube with manipulation handler
688+
690689
var testObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
691690
testObject.transform.localScale = Vector3.one * 0.2f;
692691
Vector3 originalPosition = Vector3.forward;
@@ -753,6 +752,67 @@ public IEnumerator ConstrainByProximity()
753752
TestUtilities.AssertNotAboutEqual(originalRotation, testObject.transform.rotation, "Rotation should not be equal for far interaction");
754753
TestUtilities.AssertAboutEqual(originalPosition, testObject.transform.position, "Position should be equal for far interaction");
755754
}
755+
756+
/// <summary>
757+
/// Tests that FaceUserConstraint updates the rotation to face the user
758+
/// </summary>
759+
[UnityTest]
760+
public IEnumerator ConstrainRotationFaceUser()
761+
{
762+
TestUtilities.PlayspaceToOriginLookingForward();
763+
764+
var testObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
765+
testObject.transform.localScale = Vector3.one * 0.2f;
766+
testObject.transform.position = Vector3.forward;
767+
var manipHandler = testObject.AddComponent<ObjectManipulator>();
768+
manipHandler.HostTransform = testObject.transform;
769+
manipHandler.SmoothingActive = false;
770+
manipHandler.ManipulationType = ManipulationHandFlags.OneHanded;
771+
manipHandler.OneHandRotationModeNear = ObjectManipulator.RotateInOneHandType.RotateAboutGrabPoint;
772+
773+
var rotConstraint = manipHandler.EnsureComponent<FaceUserConstraint>();
774+
rotConstraint.TargetTransform = manipHandler.HostTransform;
775+
rotConstraint.FaceAway = false;
776+
777+
// Face user first
778+
const int numHandSteps = 10;
779+
TestHand hand = new TestHand(Handedness.Right);
780+
781+
yield return hand.Show(new Vector3(0.05f, -0.1f, 0.45f));
782+
yield return hand.SetGesture(ArticulatedHandPose.GestureId.Pinch);
783+
yield return null;
784+
785+
Vector3 cameraToObject() => testObject.transform.position - CameraCache.Main.transform.position;
786+
Vector3 checkCollinear() => Vector3.Cross(testObject.transform.forward, cameraToObject());
787+
float checkNegative() => Vector3.Dot(testObject.transform.forward, cameraToObject());
788+
789+
TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
790+
Assert.Greater(checkNegative(), 0, "Object facing away");
791+
792+
// Move the hand
793+
yield return hand.Move(new Vector3(0.2f, 0.2f, 0), numHandSteps);
794+
yield return null;
795+
796+
Assert.AreNotEqual(Vector3.forward, testObject.transform.position); // ensure the object moved
797+
TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
798+
Assert.Greater(checkNegative(), 0, "Object facing away");
799+
800+
// Face away from user
801+
rotConstraint.FaceAway = true;
802+
yield return hand.Move(new Vector3(-0.2f, -0.2f, 0), numHandSteps);
803+
yield return null;
804+
805+
TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
806+
Assert.Less(checkNegative(), 0, "Object facing away");
807+
808+
// Move the hand
809+
yield return hand.Move(new Vector3(0.2f, 0.2f, 0), numHandSteps);
810+
yield return null;
811+
812+
Assert.AreNotEqual(Vector3.forward, testObject.transform.position); // ensure the object moved
813+
TestUtilities.AssertAboutEqual(checkCollinear(), Vector3.zero, "Object not facing camera", 0.002f);
814+
Assert.Less(checkNegative(), 0, "Object facing away");
815+
}
756816
}
757817
}
758818
#endif

Assets/MixedRealityToolkit.Tests/PlayModeTests/Experimental/ObjectManipulatorTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,7 @@ public IEnumerator ObjectManipulatorOneHandMoveFar()
357357
foreach (ObjectManipulator.RotateInOneHandType type in Enum.GetValues(typeof(ObjectManipulator.RotateInOneHandType)))
358358
{
359359
// Some rotation modes move the object on grab, don't test those
360-
if (type == ObjectManipulator.RotateInOneHandType.MaintainOriginalRotation ||
361-
type == ObjectManipulator.RotateInOneHandType.FaceAwayFromUser ||
362-
type == ObjectManipulator.RotateInOneHandType.FaceUser)
360+
if (type == ObjectManipulator.RotateInOneHandType.MaintainOriginalRotation)
363361
{
364362
continue;
365363
}

0 commit comments

Comments
 (0)