@@ -219,6 +219,79 @@ public IEnumerator TestSurfaceMagnetism()
219
219
Assert . IsTrue ( Mathf . Approximately ( 1.0f , Vector3 . Dot ( targetTransform . forward . normalized , Vector3 . forward ) ) ) ;
220
220
}
221
221
222
+ /// <summary>
223
+ /// Test Surface Magnetism against vertical normal and ensure no temporal instability (gimbal lock)
224
+ /// </summary>
225
+ [ UnityTest ]
226
+ public IEnumerator TestSurfaceMagnetismGimbalLock ( )
227
+ {
228
+ Vector3 floorCenter = Vector3 . forward * 10.0f + Vector3 . up * - 2.0f ;
229
+
230
+ // Reset view to origin
231
+ MixedRealityPlayspace . PerformTransformation ( p =>
232
+ {
233
+ p . position = Vector3 . zero ;
234
+ p . LookAt ( floorCenter ) ;
235
+ } ) ;
236
+
237
+ // Build floor to collide against
238
+ var floor = GameObject . CreatePrimitive ( PrimitiveType . Cube ) ;
239
+ floor . transform . localScale = new Vector3 ( 25.0f , 0.2f , 25.0f ) ;
240
+ floor . transform . position = floorCenter ;
241
+
242
+ // Give the floor a very small tilt
243
+ floor . transform . rotation = Quaternion . Euler ( 10 , 0 , 0 ) ;
244
+
245
+ yield return WaitForFrames ( 2 ) ;
246
+
247
+ // Instantiate our test GameObject with solver.
248
+ // Set layer to ignore raycast so solver doesn't raycast itself (i.e BoxCollider)
249
+ var testObjects = InstantiateTestSolver < SurfaceMagnetism > ( ) ;
250
+ testObjects . target . layer = LayerMask . NameToLayer ( "Ignore Raycast" ) ;
251
+ SurfaceMagnetism surfaceMag = testObjects . solver as SurfaceMagnetism ;
252
+
253
+ var targetTransform = testObjects . target . transform ;
254
+ var cameraTransform = CameraCache . Main . transform ;
255
+
256
+ yield return WaitForFrames ( 2 ) ;
257
+
258
+ // Change default orientation mode to surface normal
259
+ surfaceMag . CurrentOrientationMode = SurfaceMagnetism . OrientationMode . SurfaceNormal ;
260
+ surfaceMag . KeepOrientationVertical = false ;
261
+
262
+ yield return WaitForFrames ( 2 ) ;
263
+
264
+ // Test object should now be facing the floor
265
+ Assert . IsTrue ( Mathf . Approximately ( 1.0f , Vector3 . Dot ( - targetTransform . forward . normalized , floor . transform . up ) ) ) ;
266
+
267
+ // Cache test object's current right vector
268
+ Vector3 rightVector = testObjects . target . transform . right ;
269
+
270
+ floor . transform . Rotate ( new Vector3 ( - 20 , 0 , 0 ) ) ;
271
+ yield return WaitForFrames ( 2 ) ;
272
+
273
+ // Make sure that the target's right vector has not flip-flopped
274
+ Assert . IsTrue ( Mathf . Sign ( targetTransform . transform . right . x ) == Mathf . Sign ( rightVector . x ) ) ;
275
+
276
+ // Do the same, but with KeepOrientationVertical = true
277
+ surfaceMag . KeepOrientationVertical = true ;
278
+
279
+ // Cache test object's current right vector
280
+ rightVector = testObjects . target . transform . right ;
281
+
282
+ yield return WaitForFrames ( 2 ) ;
283
+
284
+ // Test object should now have proper upright orientation
285
+ Assert . IsTrue ( Mathf . Approximately ( 1.0f , Vector3 . Dot ( targetTransform . up . normalized , Vector3 . up ) ) ) ;
286
+ floor . transform . Rotate ( new Vector3 ( 20 , 0 , 0 ) ) ;
287
+ yield return WaitForFrames ( 2 ) ;
288
+
289
+ // Make sure that the target's right vector has not flip-flopped
290
+ Assert . IsTrue ( Mathf . Sign ( targetTransform . transform . right . x ) == Mathf . Sign ( rightVector . x ) ) ;
291
+
292
+
293
+ }
294
+
222
295
/// <summary>
223
296
/// Test solver system's ability to change target types at runtime
224
297
/// </summary>
0 commit comments