You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/AutomatedTesting/Gem/PythonTests/physics/C4044697_Material_PerfaceMa...

310 lines
15 KiB
Python

"""
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 ID : C4044697
# Test Case Title : Verify that each surface picks up the material assigned to it and behaves accordingly.
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
initial_orientaition_valid = ("Initial entity orientation valid", "Initial entity orientation not valid")
final_orientation_valid = ("Final entity orientation valid", "Final entity orientation not valid")
speed_comparision = ("Sphere 1 is faster than Sphere 2", "Sphere 1 is not faster than Sphere 2")
# Sphere 0
Sphere_0_found = ("Sphere 0 is valid", "Sphere 0 is not valid")
Sphere_0_position_found = ("Sphere 0 position is found", "Sphere 0 position is not found")
Sphere_0_velocity_found = ("Sphere 0 velocity is found", "Sphere 0 velocity is not found")
Sphere_0_velocity_valid = ("Sphere 0 velocity is valid", "Sphere 0 velocity is not valid")
Sphere_0_collided_with_perface = ("Sphere 0 collided w/Perface Entity", "Sphere 0 has not collided")
Sphere_0_final_velocity_valid = ("Sphere 0 final velocity is valid", "Sphere 0 final velocity is not valid")
# Sphere 1
Sphere_1_found = ("Sphere 1 is valid", "Sphere 1 is not valid")
Sphere_1_position_found = ("Sphere 1 position is found", "Sphere 1 position is not found")
Sphere_1_velocity_found = ("Sphere 1 velocity is found", "Sphere 1 velocity is not found")
Sphere_1_velocity_valid = ("Sphere 1 velocity is valid", "Sphere 1 velocity is not valid")
Sphere_1_collided_with_perface = ("Sphere 1 collided w/Perface Entity", "Sphere 1 has not collided")
Sphere_1_final_velocity_valid = ("Sphere 1 final velocity is valid", "Sphere 1 final velocity is not valid")
# Sphere 2
Sphere_2_found = ("Sphere 2 is valid", "Sphere 2 is not valid")
Sphere_2_position_found = ("Sphere 2 position is found", "Sphere 2 position is not found")
Sphere_2_velocity_found = ("Sphere 2 velocity is found", "Sphere 2 velocity is not found")
Sphere_2_velocity_valid = ("Sphere 2 velocity is valid", "Sphere 2 velocity is not valid")
Sphere_2_collided_with_perface = ("Sphere 2 collided w/Perface Entity", "Sphere 2 has not collided")
Sphere_2_final_velocity_valid = ("Sphere 2 final velocity is valid", "Sphere 2 final velocity is not valid")
# Perface Entity
Perface_Entity_found = ("Perface entity is valid", "Perface entity is not valid")
Perface_Entity_position_found = ("Perface entity position found", "Perface entity position not found")
# fmt: on
def C4044697_Material_PerfaceMaterialValidation():
"""
Summary: The perface has three different faces that can pick up different materials. To check that each face
picks up the material assigned to it I send three spheres of the same material at each face to see the
different reactions. If each sphere bounces away with the correct relative velocity it can be assumed
that the Perface entity is picking up the materials properly.
Level Description:
Perface Entity - The perface entity is an entity with a custom mesh that allows for multiple materials to be
applied to different parts of the mesh. In this case there seems to be three different areas of the mesh
that can be assigned with different materials and interacted. One of three spheres is lined up to interact
with one of each of the three areas. The mesh is included in the level "test.fbx". The entity is stationary
with three spheres inline along the x and y axis: has a PhysX collider and a Mesh component.
Sphere 0 - This entity is inline with the perface entity on the y axis and heading torward it with a velocity in
the -y direction: has a sphere shaped PhysX Collider, a PhysX Rigid Body, and a Sphere Shape.
Sphere 1 - This entity is inline with the perface entity on the x axis and heading torward it with a velocity in
the -x direction: has a sphere shaped PhysX Collider, a PhysX Rigid Body, and a Sphere Shape.
Sphere 2 - This entity is inline with the perface entity on the x axis and heading torward it with a velocity in
the +x direction: has a sphere shaped PhysX Collider, a PhysX Rigid Body, and a Sphere Shape.
Materials:
Bounce - All three spheres and the Perface mesh area lined up with Sphere 1 have the Bounce material applied to
them. This material interacts with other materials by bouncing with the restitution factor of an average of
each entity that collides restitution value. Has restitution value: 1
PartialBounce - The Perface mesh area lined up with Sphere 2 has the partial bounce material applied. This material
interacts with other materials by responding with a restitution factor that is an average of the two materials
that interact. Has restitution value: 0
NoBounce - The Perface mesh area lined up with Sphere 0 have the NoBounce material. This material interacts with
other materials by bouncing with the restitution factor of the material with the lowest restitution value.
Has restitution value: 0
Expected Behavior: Sphere 0 will not bounce, Sphere 1 will bounce away from the Perface Entity faster than
Sphere 2 will.
Test Steps:
1) Open Level
2) Enter Game Mode
3) Create Entity objects
4) Iterate through all entities and validate them
5) Validate that Entities Exist
6) Iterate through each of the three spheres and test their bounces
7) Further evaluate that sphere entities exist
8) Validate Initial Positions and Velocities
9) Set up handler and wait for collision
10) Get and Validate Final Positions and Velocities
11) Log Results
12) Validate Orientations and Final Velocities
13) Exit Game Mode
14) Close Editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
import os
import sys
import ImportPathHelper as imports
imports.init()
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
import azlmbr.math as math
# Constants
FLOAT_THRESHOLD = sys.float_info.epsilon
FINAL_VELOCITY_THRESHOLD = 0.01
STATIONARY_SPHERE_THRESHOLD = 2
TIMEOUT = 1.0
# Helper Functions
class Entity:
def __init__(self, name, expected_initial_velocity=None, expected_final_velocity=None):
self.id = general.find_game_entity(name)
self.name = name
self.EXPECTED_INITIAL_VELOCITY = expected_initial_velocity
self.EXPECTED_FINAL_VELOCITY = expected_final_velocity
self.initial_velocity = None
self.final_velocity = None
self.initial_position = None
self.final_position = None
self.collision_happened = False
self.handler = None
class Entity_Tests:
found = None
found_position = None
found_velocity = None
valid_init_velocity = None
valid_final_velocity = None
collision_happened = None
def check_id(self):
self.Entity_Tests.found = Tests.__dict__[self.name + "_found"]
Report.critical_result(self.Entity_Tests.found, self.id.isValid())
def activate_entity(self):
Report.info("Activating Entity : " + self.name)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "ActivateGameEntity", self.id)
def values_found(self):
self.Entity_Tests.found_position = Tests.__dict__[self.name + "_position_found"]
self.Entity_Tests.found_velocity = Tests.__dict__[self.name + "_velocity_found"]
Report.critical_result(self.Entity_Tests.found_position, vector_valid(self.initial_position, False))
Report.critical_result(self.Entity_Tests.found_velocity, vector_valid(self.initial_velocity, False))
def perface_values_found(self):
self.Entity_Tests.found_position = Tests.__dict__[self.name + "_position_found"]
Report.critical_result(self.Entity_Tests.found_position, vector_valid(self.initial_position, False))
def get_initial_position_and_velocity(self):
self.initial_velocity = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetLinearVelocity", self.id)
self.initial_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id)
def get_final_position_and_velocity(self):
self.final_velocity = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetLinearVelocity", self.id)
self.final_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id)
def validate_sphere_velocity(self):
if self.collision_happened:
velocity_valid = (
abs(self.final_velocity.x - self.EXPECTED_FINAL_VELOCITY.x) < FINAL_VELOCITY_THRESHOLD
and abs(self.final_velocity.y - self.EXPECTED_FINAL_VELOCITY.y) < FINAL_VELOCITY_THRESHOLD
and abs(self.final_velocity.z - self.EXPECTED_FINAL_VELOCITY.z) < FINAL_VELOCITY_THRESHOLD
)
self.Entity_Tests.valid_final_velocity = Tests.__dict__[self.name + "_final_velocity_valid"]
Report.result(self.Entity_Tests.valid_final_velocity, velocity_valid)
else:
velocity_valid = (
abs(self.initial_velocity.x - self.EXPECTED_INITIAL_VELOCITY.x) < FLOAT_THRESHOLD
and abs(self.initial_velocity.y - self.EXPECTED_INITIAL_VELOCITY.y) < FLOAT_THRESHOLD
and abs(self.initial_velocity.z - self.EXPECTED_INITIAL_VELOCITY.z) < FLOAT_THRESHOLD
)
self.Entity_Tests.valid_init_velocity = Tests.__dict__[self.name + "_velocity_valid"]
Report.critical_result(self.Entity_Tests.valid_init_velocity, velocity_valid)
def on_collision_begin(self, args):
if self.id.equal(args[0]):
self.collision_happened = True
def set_handler(self, id):
self.handler = azlmbr.physics.CollisionNotificationBusHandler()
self.handler.connect(id)
self.handler.add_callback("OnCollisionBegin", self.on_collision_begin)
def report_sphere_values(entity):
Report.info_vector3(entity.initial_position, "{} initial position: ".format(entity.name))
Report.info_vector3(entity.initial_velocity, "{} initial velocity: ".format(entity.name))
Report.info_vector3(entity.final_position, "{} final position: ".format(entity.name))
Report.info_vector3(entity.final_velocity, "{} final velocity: ".format(entity.name))
def report_perface_values(entity):
Report.info_vector3(entity.initial_position, "{} initial position: ".format(entity.name))
def validate_positions():
# Initial orientation is confirmed by z axis values, if there are further issues a collision
# will not as expected.
Report.info("Checking Initial Orientation")
initial_orientaition = (
sphere_0.initial_position.z
== sphere_1.initial_position.z
== sphere_2.initial_position.z
== perface_entity.initial_position.z
)
Report.result(Tests.initial_orientaition_valid, initial_orientaition)
# Final orientation is confirmed if Sphere 0 stopped next to the Perface Entity.
Report.info("Checking Final Orientation")
final_orientation = (
abs(perface_entity.final_position.x - sphere_0.final_position.x) < FLOAT_THRESHOLD
and abs(perface_entity.final_position.z - sphere_0.final_position.z) < FLOAT_THRESHOLD
and abs(perface_entity.final_position.y - sphere_0.final_position.y) < STATIONARY_SPHERE_THRESHOLD
)
Report.result(Tests.final_orientation_valid, final_orientation)
def vector_valid(vector, can_be_zero):
if can_be_zero:
return vector != None
else:
return vector != None and not vector.IsZero()
# Main Script
helper.init_idle()
# 1) Open Level
helper.open_level("Physics", "C4044697_Material_PerfaceMaterialValidation")
# 2) Enter Game Mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Create entity objects
sphere_0 = Entity("Sphere_0", math.Vector3(0.0, -10.0, 0.0), math.Vector3(0.0, 0.0, 0.0))
sphere_1 = Entity("Sphere_1", math.Vector3(-10.0, 0.0, 0.0), math.Vector3(10.09, 1.85, 1.18))
sphere_2 = Entity("Sphere_2", math.Vector3(10.0, 0.0, 0.0), math.Vector3(-5.0, 0.0, 0.0))
perface_entity = Entity("Perface_Entity")
entity_list = [sphere_0, sphere_1, sphere_2, perface_entity]
spheres = [sphere_0, sphere_1, sphere_2]
# 4) Iterate through all entities and validate them
for entity in entity_list:
# 5) Validate that Entities Exist
entity.check_id()
# Extra steps for Perface Entity as it will no longer be iterated
perface_entity.get_initial_position_and_velocity()
perface_entity.perface_values_found()
perface_entity.get_final_position_and_velocity()
report_perface_values(perface_entity)
# 6) Iterate through each of the three spheres and test their bounces
for entity in spheres:
# 7) Further evaluate that sphere entities exist
entity.activate_entity()
entity.get_initial_position_and_velocity()
# 8) Validate Initial Positions and Velocities
entity.values_found()
entity.validate_sphere_velocity()
# 9) Set up handler and wait for collision
entity.set_handler(perface_entity.id)
# Wait for collision
helper.wait_for_condition(lambda: entity.collision_happened, TIMEOUT)
# Report Collision
entity.Entity_Tests.collision_happened = Tests.__dict__[entity.name + "_collided_with_perface"]
Report.result(entity.Entity_Tests.collision_happened, entity.collision_happened)
# 10) Get and Validate Final Positions and Velocities
entity.get_final_position_and_velocity()
entity.validate_sphere_velocity()
# 11) Log Results
report_sphere_values(entity)
# 12) Validate Orientations and Final Velocities
validate_positions()
Report.result(
Tests.speed_comparision, sphere_1.final_velocity.GetLength() > sphere_2.final_velocity.GetLength()
)
# 13) Exit Game Mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
import ImportPathHelper as imports
imports.init()
from editor_python_test_tools.utils import Report
Report.start_test(C4044697_Material_PerfaceMaterialValidation)