Tick_InterpolatedRigidBodyMotionIsSmooth.py 4.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. """
  2. Copyright (c) Contributors to the Open 3D Engine Project.
  3. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. SPDX-License-Identifier: Apache-2.0 OR MIT
  5. Test Case Title : Verify that a rigid body with "Interpolate motion" option selected moves smoothly.
  6. """
  7. # fmt: off
  8. class Tests():
  9. create_entity = ("Created test entity", "Failed to create test entity")
  10. rigid_body_added = ("Added PhysX Rigid Body component", "Failed to add PhysX Rigid Body component")
  11. enter_game_mode = ("Entered game mode", "Failed to enter game mode")
  12. exit_game_mode = ("Exited game mode", "Failed to exit game mode")
  13. rigid_body_smooth = ("Rigid body motion passed smoothness threshold", "Failed to meet smoothness threshold for rigid body motion")
  14. # fmt: on
  15. def Tick_InterpolatedRigidBodyMotionIsSmooth():
  16. """
  17. Summary:
  18. Create entity with PhysX Rigid Body component and turn on the Interpolate motion setting.
  19. Verify that the position of the rigid body varies smoothly with time.
  20. Expected Behavior:
  21. 1) The motion of the rigid body under gravity is a smooth curve, rather than an erratic/jittery movement.
  22. Test Steps:
  23. 1) Load the empty level
  24. 2) Create an entity
  25. 3) Add rigid body component
  26. 4) Enter game mode and collect data for the rigid body's z co-ordinate and the time values for a series of frames
  27. 5) Check if the motion of the rigid body was sufficiently smooth
  28. :return: None
  29. """
  30. # imports
  31. import os
  32. import azlmbr.legacy.general as general
  33. import azlmbr.math as math
  34. from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
  35. from editor_python_test_tools.utils import Report
  36. from editor_python_test_tools.utils import TestHelper as helper
  37. from editor_python_test_tools.asset_utils import Asset
  38. import numpy as np
  39. # constants
  40. COEFFICIENT_OF_DETERMINATION_THRESHOLD = 1 - 1e-4 # curves with values below this are not considered sufficiently smooth
  41. helper.init_idle()
  42. # 1) Load the empty level
  43. helper.open_level("", "Base")
  44. # 2) Create an entity
  45. test_entity = Entity.create_editor_entity("test_entity")
  46. Report.result(Tests.create_entity, test_entity.id.IsValid())
  47. azlmbr.components.TransformBus(
  48. azlmbr.bus.Event, "SetWorldTranslation", test_entity.id, math.Vector3(0.0, 0.0, 0.0))
  49. # 3) Add rigid body component
  50. rigid_body_component = test_entity.add_component("PhysX Dynamic Rigid Body")
  51. rigid_body_component.set_component_property_value("Configuration|Interpolate motion", True)
  52. azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "SetLinearDamping", test_entity.id, 0.0)
  53. Report.result(Tests.rigid_body_added, test_entity.has_component("PhysX Dynamic Rigid Body"))
  54. # 4) Enter game mode and collect data for the rigid body's z co-ordinate and the time values for a series of frames
  55. t = []
  56. z = []
  57. helper.enter_game_mode(Tests.enter_game_mode)
  58. general.idle_wait_frames(1)
  59. game_entity_id = general.find_game_entity("test_entity")
  60. for frame in range(100):
  61. t.append(azlmbr.components.TickRequestBus(azlmbr.bus.Broadcast, "GetTimeAtCurrentTick").GetSeconds())
  62. z.append(azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", game_entity_id))
  63. general.idle_wait_frames(1)
  64. helper.exit_game_mode(Tests.exit_game_mode)
  65. # 5) Test that the z vs t curve is sufficiently smooth (if the interpolation is not working well, the curve will be less smooth)
  66. # normalize the t and z data
  67. t = np.array(t) - np.mean(t)
  68. z = np.array(z) - np.mean(z)
  69. # fit a polynomial to the z vs t curve
  70. fit = np.poly1d(np.polyfit(t, z, 4))
  71. residual = fit(t) - z
  72. # calculate the coefficient of determination (a measure of how closely the polynomial curve fits the data)
  73. # if the coefficient is very close to 1, then the curve fits the data very well, suggesting that the rigid body motion is smooth
  74. # if the coefficient is significantly less than 1, then the z values vary more erratically relative to the smooth curve,
  75. # indicating that the motion of the rigid body is not smooth
  76. coefficient_of_determination = (1 - np.sum(residual * residual) / np.sum(z * z))
  77. Report.result(Tests.rigid_body_smooth, bool(coefficient_of_determination > COEFFICIENT_OF_DETERMINATION_THRESHOLD))
  78. if __name__ == "__main__":
  79. from editor_python_test_tools.utils import Report
  80. Report.start_test(Tick_InterpolatedRigidBodyMotionIsSmooth)