Jelajahi Sumber

add python test for smoothness of interpolated rigid body motion

Signed-off-by: greerdv <[email protected]>
greerdv 3 tahun lalu
induk
melakukan
2ced6011e9

+ 6 - 0
AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main.py

@@ -91,4 +91,10 @@ class TestAutomation(TestAutomationBase):
     @revert_physics_config
     def test_C15425929_Undo_Redo(self, request, workspace, editor, launcher_platform):
         from .tests import Physics_UndoRedoWorksOnEntityWithPhysComponents as test_module
+        self._run_test(request, workspace, editor, test_module)
+
+    @pytest.mark.tick
+    @pytest.mark.xfail(reason="Test still under development.")
+    def test_Tick_InterpolatedRigidBodyMotionIsSmooth(self, request, workspace, editor, launcher_platform):
+        from .tests.tick import Tick_InterpolatedRigidBodyMotionIsSmooth as test_module
         self._run_test(request, workspace, editor, test_module)

+ 98 - 0
AutomatedTesting/Gem/PythonTests/Physics/tests/tick/Tick_InterpolatedRigidBodyMotionIsSmooth.py

@@ -0,0 +1,98 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+
+Test Case Title : Verify that a rigid body with "Interpolate motion" option selected moves smoothly.
+"""
+
+
+# fmt: off
+class Tests():
+    create_entity          = ("Created test entity",                           "Failed to create test entity")
+    rigid_body_added       = ("Added PhysX Rigid Body component",              "Failed to add PhysX Rigid Body component")
+    rigid_body_smooth      = ("Rigid body motion passed smoothness threshold", "Failed to meet smoothness threshold for rigid body motion")
+# fmt: on
+
+
+def Tick_InterpolatedRigidBodyMotionIsSmooth():
+    """
+    Summary:
+     Create entity with Mesh and PhysX Collider components and assign a fbx file in both the components.
+     Verify that the fbx is properly fitting the mesh.
+
+    Expected Behavior:
+     1) The fbx is properly fitting the mesh.
+     2) Multiple material slots show up under Materials section in the PhysX Collider component and that
+     they correspond to the number of surfaces as designed in the mesh.
+
+    Test Steps:
+     1) Load the empty level
+     2) Create an entity
+     3) Add rigid body component
+     4) Enter game mode and collect data for the rigid body's z co-ordinate and the time values for a series of frames
+     5) Check if the motion of the rigid body was sufficiently smooth
+
+    :return: None
+    """
+    # imports
+    import os
+    import azlmbr.legacy.general as general
+    import azlmbr.math as math
+    from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
+    from editor_python_test_tools.utils import Report
+    from editor_python_test_tools.utils import TestHelper as helper
+    from editor_python_test_tools.asset_utils import Asset
+    import numpy as np
+
+    # constants
+    COEFFICIENT_OF_DETERMINATION_THRESHOLD = 1 - 1e-4 # curves with values below this are not considered sufficiently smooth
+
+    helper.init_idle()
+    # 1) Load the empty level
+    helper.open_level("Physics", "Base")
+
+    # 2) Create an entity
+    test_entity = Entity.create_editor_entity("test_entity")
+    Report.result(Tests.create_entity, test_entity.id.IsValid())
+
+    azlmbr.components.TransformBus(
+        azlmbr.bus.Event, "SetWorldTranslation", test_entity.id, math.Vector3(0.0, 0.0, 0.0))
+
+    # 3) Add rigid body component
+    rigid_body_component = test_entity.add_component("PhysX Rigid Body")
+    rigid_body_component.set_component_property_value("Configuration|Interpolate motion", True)
+    azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "SetLinearDamping", test_entity.id, 0.0)
+    Report.result(Tests.rigid_body_added, test_entity.has_component("PhysX Rigid Body"))
+
+    # 4) Enter game mode and collect data for the rigid body's z co-ordinate and the time values for a series of frames
+    t = []
+    z = []
+    general.enter_game_mode()
+    general.idle_wait_frames(1)
+    game_entity_id = general.find_game_entity("test_entity")
+    for timestep in range(100):
+        t.append(azlmbr.components.TickRequestBus(azlmbr.bus.Broadcast, "GetTimeAtCurrentTick").GetSeconds())
+        z.append(azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", game_entity_id))
+        general.idle_wait_frames(1)
+    general.exit_game_mode()
+
+    # 5) Test that the z vs t curve is sufficiently smooth (if the interpolation is not working well, the curve will be less smooth)
+    # normalize the t and z data
+    t = np.array(t) - np.mean(t)
+    z = np.array(z) - np.mean(z)
+    # fit a polynomial to the z vs t curve
+    fit = np.poly1d(np.polyfit(t, z, 4))
+    residual = fit(t) - z
+    # calculate the coefficient of determination (a measure of how closely the polynomial curve fits the data)
+    # if the coefficient is very close to 1, then the curve fits the data very well, suggesting that the rigid body motion is smooth
+    # if the coefficient is significantly less than 1, then the z values vary more erratically relative to the smooth curve,
+    # indicating that the motion of the rigid body is not smooth
+    coefficient_of_determination = (1 - np.sum(residual * residual) / np.sum(z * z))
+    Report.result(Tests.rigid_body_smooth, bool(coefficient_of_determination > COEFFICIENT_OF_DETERMINATION_THRESHOLD))
+
+
+if __name__ == "__main__":
+    from editor_python_test_tools.utils import Report
+    Report.start_test(Tick_InterpolatedRigidBodyMotionIsSmooth)

+ 1 - 0
pytest.ini

@@ -22,4 +22,5 @@ markers = SUITE_smoke: Tiny, quick tests of fundamental operation (tests with no
           SUITE_awsi: Time consuming AWS integration end-to-end tests
 # secondary markers which may appear alongisde a suite marker:
           REQUIRES_gpu: Tests which require a physical GPU
+          tick: Tests which verify if systems update correctly with system ticks (for example, physics bodies should move smoothly)
 # custom markers not listed above will cause pytest to emit a typo warning