Skip to content

Commit 38626e1

Browse files
RogPodgekeveleigh
andauthored
Object Manipulator now maintains velocity on release (#9733)
* Velocity and Angular Velocity now calculated for XRSDK controllers * removing debug statements * object now maintains controller velocities on near interaction * Update Assets/MRTK/SDK/Features/Input/Handlers/ObjectManipulator.cs Co-authored-by: Kurtis <[email protected]> * moved velocity setting back to the rigidbody null protected block * added tests for far throwing with far interactions Co-authored-by: Kurtis <[email protected]>
1 parent ab01d39 commit 38626e1

File tree

3 files changed

+124
-31
lines changed

3 files changed

+124
-31
lines changed

Assets/MRTK/Providers/XRSDK/Controllers/GenericXRSDKController.cs

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,8 @@ public virtual void UpdateController(InputDevice inputDevice)
8686

8787
protected virtual void UpdateSixDofData(InputDevice inputDevice)
8888
{
89-
var lastState = TrackingState;
90-
LastControllerPose = CurrentControllerPose;
91-
92-
// Check for position and rotation.
93-
IsPositionAvailable = inputDevice.TryGetFeatureValue(CommonUsages.devicePosition, out CurrentControllerPosition);
94-
IsPositionApproximate = false;
95-
96-
IsRotationAvailable = inputDevice.TryGetFeatureValue(CommonUsages.deviceRotation, out CurrentControllerRotation);
97-
98-
// Devices are considered tracked if we receive position OR rotation data from the sensors.
99-
TrackingState = (IsPositionAvailable || IsRotationAvailable) ? TrackingState.Tracked : TrackingState.NotTracked;
100-
101-
CurrentControllerPosition = MixedRealityPlayspace.TransformPoint(CurrentControllerPosition);
102-
CurrentControllerRotation = MixedRealityPlayspace.Rotation * CurrentControllerRotation;
103-
104-
CurrentControllerPose.Position = CurrentControllerPosition;
105-
CurrentControllerPose.Rotation = CurrentControllerRotation;
106-
107-
// Raise input system events if it is enabled.
108-
if (lastState != TrackingState)
109-
{
110-
CoreServices.InputSystem?.RaiseSourceTrackingStateChanged(InputSource, this, TrackingState);
111-
}
89+
UpdateSourceData(inputDevice);
90+
UpdateVelocity(inputDevice);
11291

11392
if (TrackingState == TrackingState.Tracked && LastControllerPose != CurrentControllerPose)
11493
{
@@ -137,6 +116,61 @@ protected virtual void UpdateSixDofData(InputDevice inputDevice)
137116
}
138117
}
139118

119+
private static readonly ProfilerMarker UpdateSourceDataPerfMarker = new ProfilerMarker("[MRTK] BaseWindowsMixedRealitySource.UpdateSourceData");
120+
121+
/// <summary>
122+
/// Update the source input from the device.
123+
/// </summary>
124+
/// <param name="inputDevice">The InputDevice retrieved from the platform.</param>
125+
public void UpdateSourceData(InputDevice inputDevice)
126+
{
127+
using (UpdateSourceDataPerfMarker.Auto())
128+
{
129+
var lastState = TrackingState;
130+
LastControllerPose = CurrentControllerPose;
131+
132+
// Check for position and rotation.
133+
IsPositionAvailable = inputDevice.TryGetFeatureValue(CommonUsages.devicePosition, out CurrentControllerPosition);
134+
IsPositionApproximate = false;
135+
136+
IsRotationAvailable = inputDevice.TryGetFeatureValue(CommonUsages.deviceRotation, out CurrentControllerRotation);
137+
138+
// Devices are considered tracked if we receive position OR rotation data from the sensors.
139+
TrackingState = (IsPositionAvailable || IsRotationAvailable) ? TrackingState.Tracked : TrackingState.NotTracked;
140+
141+
CurrentControllerPosition = MixedRealityPlayspace.TransformPoint(CurrentControllerPosition);
142+
CurrentControllerRotation = MixedRealityPlayspace.Rotation * CurrentControllerRotation;
143+
144+
CurrentControllerPose.Position = CurrentControllerPosition;
145+
CurrentControllerPose.Rotation = CurrentControllerRotation;
146+
147+
// Raise input system events if it is enabled.
148+
if (lastState != TrackingState)
149+
{
150+
CoreServices.InputSystem?.RaiseSourceTrackingStateChanged(InputSource, this, TrackingState);
151+
}
152+
}
153+
}
154+
155+
private static readonly ProfilerMarker UpdateVelocityPerfMarker = new ProfilerMarker("[MRTK] GenericXRSDKController.UpdateVelocity");
156+
157+
public void UpdateVelocity(InputDevice inputDevice)
158+
{
159+
using (UpdateVelocityPerfMarker.Auto())
160+
{
161+
Vector3 newVelocity;
162+
if (inputDevice.TryGetFeatureValue(CommonUsages.deviceVelocity, out newVelocity))
163+
{
164+
Velocity = newVelocity;
165+
}
166+
Vector3 newAngularVelocity;
167+
if (inputDevice.TryGetFeatureValue(CommonUsages.deviceAngularVelocity, out newAngularVelocity))
168+
{
169+
AngularVelocity = newAngularVelocity;
170+
}
171+
}
172+
}
173+
140174
private static readonly ProfilerMarker UpdateButtonDataPerfMarker = new ProfilerMarker("[MRTK] GenericXRSDKController.UpdateButtonData");
141175

142176
/// <summary>

Assets/MRTK/SDK/Features/Input/Handlers/ObjectManipulator.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -974,14 +974,19 @@ private void ReleaseRigidBody(Vector3 velocity, Vector3 angularVelocity)
974974
rigidBody.useGravity = wasGravity;
975975
rigidBody.isKinematic = wasKinematic;
976976

977-
if (releaseBehavior.HasFlag(ReleaseBehaviorType.KeepVelocity))
977+
// Match the object's velocity to the controller for near interactions
978+
// Otherwise keep the objects current velocity so that it's not dampened unnaturally
979+
if (isNearManipulation)
978980
{
979-
rigidBody.velocity = velocity;
980-
}
981+
if (releaseBehavior.HasFlag(ReleaseBehaviorType.KeepVelocity))
982+
{
983+
rigidBody.velocity = velocity;
984+
}
981985

982-
if (releaseBehavior.HasFlag(ReleaseBehaviorType.KeepAngularVelocity))
983-
{
984-
rigidBody.angularVelocity = angularVelocity;
986+
if (releaseBehavior.HasFlag(ReleaseBehaviorType.KeepAngularVelocity))
987+
{
988+
rigidBody.angularVelocity = angularVelocity;
989+
}
985990
}
986991
}
987992
}

Assets/MRTK/Tests/PlayModeTests/ObjectManipulatorTests.cs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,11 @@ public IEnumerator ObjectManipulatorForceRelease()
169169

170170
/// <summary>
171171
/// Test validates throw behavior on manipulation handler. Box with disabled gravity should travel a
172-
/// certain distance when being released from grab during hand movement
172+
/// certain distance when being released from grab during hand movement. Specifically for near interactions,
173+
/// where we expect the thrown object to match the controllers velocities.
173174
/// </summary>
174175
[UnityTest]
175-
public IEnumerator ObjectManipulatorThrow()
176+
public IEnumerator ObjectManipulatorNearThrow()
176177
{
177178
// set up cube with manipulation handler
178179
var testObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
@@ -223,6 +224,59 @@ public IEnumerator ObjectManipulatorThrow()
223224
}
224225

225226

227+
/// <summary>
228+
/// Test validates throw behavior on manipulation handler. Box with disabled gravity should travel a
229+
/// certain distance when being released from grab during hand movement. Specifically for far interactions,
230+
/// where we expect the thrown object to maintain it's velocities after being thrown
231+
/// </summary>
232+
[UnityTest]
233+
public IEnumerator ObjectManipulatorFarThrow()
234+
{
235+
// set up cube with manipulation handler
236+
var testObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
237+
testObject.transform.localScale = Vector3.one * 0.2f;
238+
Vector3 initialObjectPosition = new Vector3(-0.637f, -0.679f, 1.13f);
239+
testObject.transform.position = initialObjectPosition;
240+
241+
var rigidBody = testObject.AddComponent<Rigidbody>();
242+
rigidBody.useGravity = false;
243+
244+
var manipHandler = testObject.AddComponent<ObjectManipulator>();
245+
manipHandler.HostTransform = testObject.transform;
246+
manipHandler.SmoothingFar = false;
247+
manipHandler.SmoothingNear = false;
248+
249+
yield return new WaitForFixedUpdate();
250+
yield return null;
251+
252+
TestHand hand = new TestHand(Handedness.Right);
253+
254+
// grab the cube - move it to the right
255+
var inputSimulationService = PlayModeTestUtilities.GetInputSimulationService();
256+
257+
Vector3 handOffset = new Vector3(0, 0, 0.1f);
258+
Vector3 initialHandPosition = Vector3.zero;
259+
Vector3 rightPosition = new Vector3(1f, 0f, 1f);
260+
261+
yield return hand.Show(initialHandPosition);
262+
263+
// Note: don't wait for a physics update after releasing, because it would recompute
264+
// the velocity of the hand and make it deviate from the rigid body velocity!
265+
yield return hand.GrabAndThrowAt(rightPosition, false);
266+
267+
// With simulated hand angular velocity would not be equal to 0, because of how simulation
268+
// moves hand when releasing the Pitch. Even though it doesn't directly follow from hand movement, there will always be some rotation.
269+
Assert.Zero(rigidBody.angularVelocity.magnitude, "Object should have maintained its angular velocity of zero being released.");
270+
Assert.IsTrue(rigidBody.velocity != hand.GetVelocity() && rigidBody.velocity.magnitude > 0.0f, "ObjectManipulator should not dampen it's velocity to match the hand's upon release.");
271+
272+
// This is just for debugging purposes, so object's movement after release can be seen.
273+
yield return hand.MoveTo(initialHandPosition);
274+
yield return hand.Hide();
275+
276+
GameObject.Destroy(testObject);
277+
yield return null;
278+
}
279+
226280
/// <summary>
227281
/// This tests the one hand near movement while camera (character) is moving around.
228282
/// The test will check the offset between object pivot and grab point and make sure we're not drifting

0 commit comments

Comments
 (0)