Merge branch 'development' into Prefab/DestroyGameEntitySupport
Signed-off-by: srikappa-amzn <srikappa@amazon.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<svg width="24" height="33" viewBox="0 0 24 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" y="7" width="2" height="12" fill="#808080"/>
|
||||
<rect x="5" y="19" width="2" height="14" fill="#808080"/>
|
||||
<rect x="17" y="16" width="2" height="12" transform="rotate(90 17 16)" fill="#808080"/>
|
||||
<circle cx="6" cy="6" r="2" fill="#808080"/>
|
||||
<circle cx="18" cy="17" r="2" fill="#808080"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 398 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" width="2" height="12" fill="grey"/>
|
||||
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
|
||||
<circle cx="18" cy="13" r="2" fill="grey"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 280 B |
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" width="2" height="12" fill="grey"/>
|
||||
<rect x="5" y="14" width="2" height="12" fill="grey"/>
|
||||
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
|
||||
<circle cx="18" cy="13" r="2" fill="grey"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 335 B |
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" y="7" width="2" height="7" fill="#808080"/>
|
||||
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="#808080"/>
|
||||
<circle cx="6" cy="6" r="2" fill="#808080"/>
|
||||
<circle cx="18" cy="13" r="2" fill="#808080"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 339 B |
@@ -8098,7 +8098,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM0_TOOLTIP">
|
||||
<source>COLOR_FROMVALUES_PARAM0_TOOLTIP</source>
|
||||
<translation type="unfinished">The Red value of hte Color [0, 255]</translation>
|
||||
<translation type="unfinished">The Red value of the Color [0.0-1.0]</translation>
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM1_NAME">
|
||||
<source>COLOR_FROMVALUES_PARAM1_NAME</source>
|
||||
@@ -8107,7 +8107,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM1_TOOLTIP">
|
||||
<source>COLOR_FROMVALUES_PARAM1_TOOLTIP</source>
|
||||
<translation type="unfinished">The Green value of the Color [0, 255]</translation>
|
||||
<translation type="unfinished">The Green value of the Color [0.0-1.0]</translation>
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM2_NAME">
|
||||
<source>COLOR_FROMVALUES_PARAM2_NAME</source>
|
||||
@@ -8116,7 +8116,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM2_TOOLTIP">
|
||||
<source>COLOR_FROMVALUES_PARAM2_TOOLTIP</source>
|
||||
<translation type="unfinished">The Blue value of the Color [0, 255]</translation>
|
||||
<translation type="unfinished">The Blue value of the Color [0.0-1.0]</translation>
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM3_NAME">
|
||||
<source>COLOR_FROMVALUES_PARAM3_NAME</source>
|
||||
@@ -8125,7 +8125,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM3_TOOLTIP">
|
||||
<source>COLOR_FROMVALUES_PARAM3_TOOLTIP</source>
|
||||
<translation type="unfinished">The Alpha value of the Color [0, 255]</translation>
|
||||
<translation type="unfinished">The Alpha value of the Color [0.0-1.0]</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
3. Open a new Command Prompt window at the engine root and set the following environment variables:
|
||||
Set O3DE_AWS_PROJECT_NAME=AWSAUTO
|
||||
Set O3DE_AWS_DEPLOY_REGION=us-east-1
|
||||
Set ASSUME_ROLE_ARN="arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests"
|
||||
Set ASSUME_ROLE_ARN=arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests
|
||||
Set COMMIT_ID=HEAD
|
||||
4. In the same Command Prompt window, Deploy the CDK applications for AWS gems by running deploy_cdk_applications.cmd.
|
||||
|
||||
|
||||
+25
-19
@@ -31,7 +31,7 @@ def setup(launcher: pytest.fixture,
|
||||
Set up the resource mapping configuration and start the log monitor.
|
||||
:param launcher: Client launcher for running the test level.
|
||||
:param asset_processor: asset_processor fixture.
|
||||
:return log monitor object, metrics file path and the metrics stack name.
|
||||
:return log monitor object.
|
||||
"""
|
||||
asset_processor.start()
|
||||
asset_processor.wait_for_idle()
|
||||
@@ -73,12 +73,11 @@ def monitor_metrics_submission(log_monitor: pytest.fixture) -> None:
|
||||
f'unexpected_lines values: {unexpected_lines}')
|
||||
|
||||
|
||||
def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings: pytest.fixture, stack_name: str) -> None:
|
||||
def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings: pytest.fixture) -> None:
|
||||
"""
|
||||
Verify that the metrics events are delivered to the S3 bucket and can be queried.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
:param stack_name: name of the CloudFormation stack.
|
||||
"""
|
||||
aws_metrics_utils.verify_s3_delivery(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName')
|
||||
@@ -89,23 +88,24 @@ def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings:
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.EventsCrawlerName'))
|
||||
|
||||
# Remove the events_json table if exists so that the sample query can create a table with the same name.
|
||||
aws_metrics_utils.delete_table(f'{stack_name}-eventsdatabase', 'events_json')
|
||||
aws_metrics_utils.run_named_queries(f'{stack_name}-AthenaWorkGroup')
|
||||
aws_metrics_utils.delete_table(resource_mappings.get_resource_name_id('AWSMetrics.EventDatabaseName'), 'events_json')
|
||||
aws_metrics_utils.run_named_queries(resource_mappings.get_resource_name_id('AWSMetrics.AthenaWorkGroupName'))
|
||||
logger.info('Query metrics from S3 successfully.')
|
||||
|
||||
|
||||
def verify_operational_metrics(aws_metrics_utils: pytest.fixture, stack_name: str, start_time: datetime) -> None:
|
||||
def verify_operational_metrics(aws_metrics_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture, start_time: datetime) -> None:
|
||||
"""
|
||||
Verify that operational health metrics are delivered to CloudWatch.
|
||||
aws_metrics_utils: aws_metrics_utils fixture.
|
||||
stack_name: name of the CloudFormation stack.
|
||||
start_time: Time when the game launcher starts.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
:param start_time: Time when the game launcher starts.
|
||||
"""
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': f'{stack_name}-AnalyticsProcessingLambda'}],
|
||||
'Value': resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsProcessingLambdaName')}],
|
||||
start_time)
|
||||
logger.info('AnalyticsProcessingLambda metrics are sent to CloudWatch.')
|
||||
|
||||
@@ -113,7 +113,7 @@ def verify_operational_metrics(aws_metrics_utils: pytest.fixture, stack_name: st
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': f'{stack_name}-EventsProcessingLambda'}],
|
||||
'Value': resource_mappings.get_resource_name_id('AWSMetrics.EventProcessingLambdaName')}],
|
||||
start_time)
|
||||
logger.info('EventsProcessingLambda metrics are sent to CloudWatch.')
|
||||
|
||||
@@ -139,7 +139,6 @@ def update_kinesis_analytics_application_status(aws_metrics_utils: pytest.fixtur
|
||||
@pytest.mark.usefixtures('resource_mappings')
|
||||
@pytest.mark.parametrize('assume_role_arn', [constants.ASSUME_ROLE_ARN])
|
||||
@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME])
|
||||
@pytest.mark.parametrize('level', ['AWS/Metrics'])
|
||||
@pytest.mark.parametrize('profile_name', ['AWSAutomationTest'])
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
@pytest.mark.parametrize('region_name', [constants.AWS_REGION])
|
||||
@@ -150,6 +149,7 @@ class TestAWSMetricsWindows(object):
|
||||
"""
|
||||
Test class to verify the real-time and batch analytics for metrics.
|
||||
"""
|
||||
@pytest.mark.parametrize('level', ['AWS/Metrics'])
|
||||
def test_realtime_and_batch_analytics(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
@@ -157,7 +157,6 @@ class TestAWSMetricsWindows(object):
|
||||
workspace: pytest.fixture,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
stacks: typing.List,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Verify that the metrics events are sent to CloudWatch and S3 for analytics.
|
||||
@@ -189,10 +188,10 @@ class TestAWSMetricsWindows(object):
|
||||
operational_threads = list()
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=query_metrics_from_s3,
|
||||
args=(aws_metrics_utils, resource_mappings, stacks[0])))
|
||||
args=(aws_metrics_utils, resource_mappings)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=verify_operational_metrics,
|
||||
args=(aws_metrics_utils, stacks[0], start_time)))
|
||||
args=(aws_metrics_utils, resource_mappings, start_time)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, False)))
|
||||
@@ -201,10 +200,7 @@ class TestAWSMetricsWindows(object):
|
||||
for thread in operational_threads:
|
||||
thread.join()
|
||||
|
||||
# Clear the analytics bucket objects so that the S3 bucket can be destroyed during tear down.
|
||||
aws_metrics_utils.empty_bucket(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName'))
|
||||
|
||||
@pytest.mark.parametrize('level', ['AWS/Metrics'])
|
||||
def test_unauthorized_user_request_rejected(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
@@ -227,3 +223,13 @@ class TestAWSMetricsWindows(object):
|
||||
halt_on_unexpected=True)
|
||||
assert result, 'Metrics events are sent successfully by unauthorized user'
|
||||
logger.info('Unauthorized user is rejected to send metrics.')
|
||||
|
||||
def test_clean_up_s3_bucket(self,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Clear the analytics bucket objects so that the S3 bucket can be destroyed during tear down.
|
||||
"""
|
||||
aws_metrics_utils.empty_bucket(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName'))
|
||||
|
||||
+25
-17
@@ -13,48 +13,56 @@
|
||||
|
||||
if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::AtomRenderer_HydraTests_Main
|
||||
NAME AutomatedTesting::Atom_TestSuite_Main
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_MainSuite.py
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
|
||||
TEST_SERIAL
|
||||
TIMEOUT 600
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::AtomRenderer_HydraTests_Sandbox
|
||||
NAME AutomatedTesting::Atom_TestSuite_Main_Optimized
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
|
||||
TEST_SERIAL
|
||||
TIMEOUT 600
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::Atom_TestSuite_Sandbox
|
||||
TEST_SUITE sandbox
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_SandboxSuite.py
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox.py
|
||||
TEST_SERIAL
|
||||
TIMEOUT 400
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::AtomRenderer_HydraTests_GPUTests
|
||||
NAME AutomatedTesting::Atom_TestSuite_Main_GPU
|
||||
TEST_SUITE main
|
||||
TEST_REQUIRES gpu
|
||||
TEST_SERIAL
|
||||
TIMEOUT 1200
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_GPUTests.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::AtomRenderer_HydraTests_ShaderBuildPipeline
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_ShaderBuildPipelineSuite.py
|
||||
TEST_SERIAL
|
||||
TIMEOUT 600
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
endif()
|
||||
+16
-16
@@ -13,10 +13,10 @@ import pytest
|
||||
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
from atom_renderer.atom_utils.atom_constants import LIGHT_TYPES
|
||||
from Atom.atom_utils.atom_constants import LIGHT_TYPES
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@@ -38,24 +38,24 @@ class TestAtomEditorComponentsMain(object):
|
||||
7. Exposure Control
|
||||
8. Directional Light
|
||||
9. DepthOfField
|
||||
10. Decal (Atom)
|
||||
10. Decal
|
||||
"""
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
# Decal (Atom) Component
|
||||
"Decal (Atom) Entity successfully created",
|
||||
"Decal (Atom)_test: Component added to the entity: True",
|
||||
"Decal (Atom)_test: Component removed after UNDO: True",
|
||||
"Decal (Atom)_test: Component added after REDO: True",
|
||||
"Decal (Atom)_test: Entered game mode: True",
|
||||
"Decal (Atom)_test: Exit game mode: True",
|
||||
"Decal (Atom) Controller|Configuration|Material: SUCCESS",
|
||||
"Decal (Atom)_test: Entity is hidden: True",
|
||||
"Decal (Atom)_test: Entity is shown: True",
|
||||
"Decal (Atom)_test: Entity deleted: True",
|
||||
"Decal (Atom)_test: UNDO entity deletion works: True",
|
||||
"Decal (Atom)_test: REDO entity deletion works: True",
|
||||
# Decal Component
|
||||
"Decal Entity successfully created",
|
||||
"Decal_test: Component added to the entity: True",
|
||||
"Decal_test: Component removed after UNDO: True",
|
||||
"Decal_test: Component added after REDO: True",
|
||||
"Decal_test: Entered game mode: True",
|
||||
"Decal_test: Exit game mode: True",
|
||||
"Decal Controller|Configuration|Material: SUCCESS",
|
||||
"Decal_test: Entity is hidden: True",
|
||||
"Decal_test: Entity is shown: True",
|
||||
"Decal_test: Entity deleted: True",
|
||||
"Decal_test: UNDO entity deletion works: True",
|
||||
"Decal_test: REDO entity deletion works: True",
|
||||
# DepthOfField Component
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField_test: Component added to the entity: True",
|
||||
+1
-3
@@ -3,8 +3,6 @@ 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
|
||||
|
||||
Tests that require a GPU in order to run.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
@@ -22,7 +20,7 @@ import editor_python_test_tools.hydra_test_utils as hydra
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
|
||||
|
||||
def golden_images_directory():
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
|
||||
class AtomEditorComponents_DecalAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
|
||||
|
||||
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
|
||||
|
||||
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
|
||||
|
||||
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
|
||||
|
||||
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
|
||||
|
||||
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
|
||||
|
||||
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import (
|
||||
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
|
||||
|
||||
class AtomEditorComponents_LightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
|
||||
|
||||
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
|
||||
|
||||
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
|
||||
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"Source" : "DependencyValidation.azsl",
|
||||
|
||||
"DepthStencilState" : {
|
||||
"DepthStencilState" : {
|
||||
"Depth" : { "Enable" : false, "CompareFunc" : "GreaterEqual" }
|
||||
},
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+1
-1
@@ -12,5 +12,5 @@
|
||||
|
||||
float4 GetTest2Color(float4 color)
|
||||
{
|
||||
return color * 0.5;
|
||||
return color * 0.5;
|
||||
}
|
||||
+1
-1
@@ -12,5 +12,5 @@
|
||||
|
||||
float4 GetTest3Color(float4 color)
|
||||
{
|
||||
return color * 0.13;
|
||||
return color * 0.13;
|
||||
}
|
||||
+1
-1
@@ -184,7 +184,7 @@ def run():
|
||||
material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Decal (Atom)", lambda entity_obj: verify_set_property(
|
||||
"Decal", lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Material", material_asset))
|
||||
|
||||
# Directional Light Component
|
||||
@@ -0,0 +1,151 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
decal_creation = ("Decal Entity successfully created", "Decal Entity failed to be created")
|
||||
decal_component = ("Entity has a Decal component", "Entity failed to find Decal component")
|
||||
material_property_set = ("Material property set on Decal component", "Couldn't set Material property on Decal component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_Decal_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Decal component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Decal entity with no components.
|
||||
2) Add Decal component to Decal entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Set Material property on Decal component.
|
||||
9) Delete Decal entity.
|
||||
10) UNDO deletion.
|
||||
11) REDO deletion.
|
||||
12) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Decal entity with no components.
|
||||
decal_name = "Decal"
|
||||
decal_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), decal_name)
|
||||
Report.critical_result(Tests.decal_creation, decal_entity.exists())
|
||||
|
||||
# 2. Add Decal component to Decal entity.
|
||||
decal_component = decal_entity.add_component(decal_name)
|
||||
Report.critical_result(Tests.decal_component, decal_entity.has_component(decal_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not decal_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, decal_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
decal_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, decal_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
decal_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, decal_entity.is_visible() is True)
|
||||
|
||||
# 8. Set Material property on Decal component.
|
||||
decal_material_property_path = "Controller|Configuration|Material"
|
||||
decal_material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
decal_material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", decal_material_asset_path, math.Uuid(), False)
|
||||
decal_component.set_component_property_value(decal_material_property_path, decal_material_asset)
|
||||
get_material_property = decal_component.get_component_property_value(decal_material_property_path)
|
||||
Report.result(Tests.material_property_set, get_material_property == decal_material_asset)
|
||||
|
||||
# 9. Delete Decal entity.
|
||||
decal_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not decal_entity.exists())
|
||||
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, decal_entity.exists())
|
||||
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not decal_entity.exists())
|
||||
|
||||
# 12. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_Decal_AddedToEntity)
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to Camera entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
camera_property_set = ("DepthOfField Entity set Camera Entity", "DepthOfField Entity could not set Camera Entity")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
depth_of_field_creation = ("DepthOfField Entity successfully created", "DepthOfField Entity failed to be created")
|
||||
depth_of_field_component = ("Entity has a DepthOfField component", "Entity failed to find DepthOfField component")
|
||||
depth_of_field_disabled = ("DepthOfField component disabled", "DepthOfField component was not disabled.")
|
||||
post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component")
|
||||
depth_of_field_enabled = ("DepthOfField component enabled", "DepthOfField component was not enabled.")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the DepthOfField component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a DepthOfField entity with no components.
|
||||
2) Add a DepthOfField component to DepthOfField entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify DepthOfField component not enabled.
|
||||
6) Add Post FX Layer component since it is required by the DepthOfField component.
|
||||
7) Verify DepthOfField component is enabled.
|
||||
8) Enter/Exit game mode.
|
||||
9) Test IsHidden.
|
||||
10) Test IsVisible.
|
||||
11) Add Camera entity.
|
||||
12) Add Camera component to Camera entity.
|
||||
13) Set the DepthOfField components's Camera Entity to the newly created Camera entity.
|
||||
14) Delete DepthOfField entity.
|
||||
15) UNDO deletion.
|
||||
16) REDO deletion.
|
||||
17) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a DepthOfField entity with no components.
|
||||
depth_of_field_name = "DepthOfField"
|
||||
depth_of_field_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), depth_of_field_name)
|
||||
Report.critical_result(Tests.depth_of_field_creation, depth_of_field_entity.exists())
|
||||
|
||||
# 2. Add a DepthOfField component to DepthOfField entity.
|
||||
depth_of_field_component = depth_of_field_entity.add_component(depth_of_field_name)
|
||||
Report.critical_result(Tests.depth_of_field_component, depth_of_field_entity.has_component(depth_of_field_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not depth_of_field_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, depth_of_field_entity.exists())
|
||||
|
||||
# 5. Verify DepthOfField component not enabled.
|
||||
Report.result(Tests.depth_of_field_disabled, not depth_of_field_component.is_enabled())
|
||||
|
||||
# 6. Add Post FX Layer component since it is required by the DepthOfField component.
|
||||
post_fx_layer = "PostFX Layer"
|
||||
depth_of_field_entity.add_component(post_fx_layer)
|
||||
Report.result(Tests.post_fx_component, depth_of_field_entity.has_component(post_fx_layer))
|
||||
|
||||
# 7. Verify DepthOfField component is enabled.
|
||||
Report.result(Tests.depth_of_field_enabled, depth_of_field_component.is_enabled())
|
||||
|
||||
# 8. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 9. Test IsHidden.
|
||||
depth_of_field_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, depth_of_field_entity.is_hidden() is True)
|
||||
|
||||
# 10. Test IsVisible.
|
||||
depth_of_field_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, depth_of_field_entity.is_visible() is True)
|
||||
|
||||
# 11. Add Camera entity.
|
||||
camera_name = "Camera"
|
||||
camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name)
|
||||
Report.result(Tests.camera_creation, camera_entity.exists())
|
||||
|
||||
# 12. Add Camera component to Camera entity.
|
||||
camera_entity.add_component(camera_name)
|
||||
Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
|
||||
|
||||
# 13. Set the DepthOfField components's Camera Entity to the newly created Camera entity.
|
||||
depth_of_field_camera_property_path = "Controller|Configuration|Camera Entity"
|
||||
depth_of_field_component.set_component_property_value(depth_of_field_camera_property_path, camera_entity.id)
|
||||
camera_entity_set = depth_of_field_component.get_component_property_value(depth_of_field_camera_property_path)
|
||||
Report.result(Tests.camera_property_set, camera_entity.id == camera_entity_set)
|
||||
|
||||
# 14. Delete DepthOfField entity.
|
||||
depth_of_field_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not depth_of_field_entity.exists())
|
||||
|
||||
# 15. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, depth_of_field_entity.exists())
|
||||
|
||||
# 16. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not depth_of_field_entity.exists())
|
||||
|
||||
# 17. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_DepthOfField_AddedToEntity)
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
directional_light_creation = ("Directional Light Entity successfully created", "Directional Light Entity failed to be created")
|
||||
directional_light_component = ("Entity has a Directional Light component", "Entity failed to find Directional Light component")
|
||||
shadow_camera_check = ("Directional Light component Shadow camera set", "Directional Light component Shadow camera was not set")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Directional Light component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Directional Light entity with no components.
|
||||
2) Add Directional Light component to Directional Light entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Add Camera entity.
|
||||
9) Add Camera component to Camera entity
|
||||
10) Set the Directional Light component property Shadow|Camera to the Camera entity.
|
||||
11) Delete Directional Light entity.
|
||||
12) UNDO deletion.
|
||||
13) REDO deletion.
|
||||
14) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Directional Light entity with no components.
|
||||
directional_light_name = "Directional Light"
|
||||
directional_light_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), directional_light_name)
|
||||
Report.critical_result(Tests.directional_light_creation, directional_light_entity.exists())
|
||||
|
||||
# 2. Add Directional Light component to Directional Light entity.
|
||||
directional_light_component = directional_light_entity.add_component(directional_light_name)
|
||||
Report.critical_result(
|
||||
Tests.directional_light_component, directional_light_entity.has_component(directional_light_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not directional_light_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, directional_light_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
directional_light_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, directional_light_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
directional_light_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, directional_light_entity.is_visible() is True)
|
||||
|
||||
# 8. Add Camera entity.
|
||||
camera_name = "Camera"
|
||||
camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name)
|
||||
Report.result(Tests.camera_creation, camera_entity.exists())
|
||||
|
||||
# 9. Add Camera component to Camera entity.
|
||||
camera_entity.add_component(camera_name)
|
||||
Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
|
||||
|
||||
# 10. Set the Directional Light component property Shadow|Camera to the Camera entity.
|
||||
shadow_camera_property_path = "Controller|Configuration|Shadow|Camera"
|
||||
directional_light_component.set_component_property_value(shadow_camera_property_path, camera_entity.id)
|
||||
shadow_camera_set = directional_light_component.get_component_property_value(shadow_camera_property_path)
|
||||
Report.result(Tests.shadow_camera_check, camera_entity.id == shadow_camera_set)
|
||||
|
||||
# 11. Delete DirectionalLight entity.
|
||||
directional_light_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not directional_light_entity.exists())
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, directional_light_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not directional_light_entity.exists())
|
||||
|
||||
# 14. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_DirectionalLight_AddedToEntity)
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
display_mapper_creation = ("Display Mapper Entity successfully created", "Display Mapper Entity failed to be created")
|
||||
display_mapper_component = ("Entity has a Display Mapper component", "Entity failed to find Display Mapper component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_DisplayMapper_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Display Mapper component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Display Mapper entity with no components.
|
||||
2) Add Display Mapper component to Display Mapper entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Delete Display Mapper entity.
|
||||
9) UNDO deletion.
|
||||
10) REDO deletion.
|
||||
11) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Display Mapper entity with no components.
|
||||
display_mapper = "Display Mapper"
|
||||
display_mapper_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), f"{display_mapper}")
|
||||
Report.critical_result(Tests.display_mapper_creation, display_mapper_entity.exists())
|
||||
|
||||
# 2. Add Display Mapper component to Display Mapper entity.
|
||||
display_mapper_entity.add_component(display_mapper)
|
||||
Report.critical_result(Tests.display_mapper_component, display_mapper_entity.has_component(display_mapper))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not display_mapper_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, display_mapper_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
display_mapper_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
display_mapper_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
|
||||
|
||||
# 8. Delete Display Mapper entity.
|
||||
display_mapper_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, display_mapper_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
|
||||
|
||||
# 11. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_DisplayMapper_AddedToEntity)
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
exposure_control_creation = ("ExposureControl Entity successfully created", "ExposureControl Entity failed to be created")
|
||||
exposure_control_component = ("Entity has a Exposure Control component", "Entity failed to find Exposure Control component")
|
||||
post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_ExposureControl_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Exposure Control component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an Exposure Control entity with no components.
|
||||
2) Add Exposure Control component to Exposure Control entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Add Post FX Layer component.
|
||||
9) Delete Exposure Control entity.
|
||||
10) UNDO deletion.
|
||||
11) REDO deletion.
|
||||
12) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Creation of Exposure Control entity with no components.
|
||||
exposure_control_name = "Exposure Control"
|
||||
exposure_control_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), f"{exposure_control_name}")
|
||||
Report.critical_result(Tests.exposure_control_creation, exposure_control_entity.exists())
|
||||
|
||||
# 2. Add Exposure Control component to Exposure Control entity.
|
||||
exposure_control_entity.add_component(exposure_control_name)
|
||||
Report.critical_result(
|
||||
Tests.exposure_control_component, exposure_control_entity.has_component(exposure_control_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not exposure_control_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, exposure_control_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
exposure_control_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, exposure_control_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
exposure_control_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, exposure_control_entity.is_visible() is True)
|
||||
|
||||
# 8. Add Post FX Layer component.
|
||||
post_fx_layer_name = "PostFX Layer"
|
||||
exposure_control_entity.add_component(post_fx_layer_name)
|
||||
Report.result(Tests.post_fx_component, exposure_control_entity.has_component(post_fx_layer_name))
|
||||
|
||||
# 9. Delete ExposureControl entity.
|
||||
exposure_control_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not exposure_control_entity.exists())
|
||||
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, exposure_control_entity.exists())
|
||||
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not exposure_control_entity.exists())
|
||||
|
||||
# 12. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_ExposureControl_AddedToEntity)
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
global_skylight_creation = ("Global Skylight (IBL) Entity successfully created", "Global Skylight (IBL) Entity failed to be created")
|
||||
global_skylight_component = ("Entity has a Global Skylight (IBL) component", "Entity failed to find Global Skylight (IBL) component")
|
||||
diffuse_image_set = ("Entity has the Diffuse Image set", "Entity did not the Diffuse Image set")
|
||||
specular_image_set = ("Entity has the Specular Image set", "Entity did not the Specular Image set")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Global Skylight (IBL) component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Global Skylight (IBL) entity with no components.
|
||||
2) Add Global Skylight (IBL) component to Global Skylight (IBL) entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Add Post FX Layer component.
|
||||
9) Add Camera component
|
||||
10) Delete Global Skylight (IBL) entity.
|
||||
11) UNDO deletion.
|
||||
12) REDO deletion.
|
||||
13) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.asset_utils import Asset
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Global Skylight (IBL) entity with no components.
|
||||
global_skylight_name = "Global Skylight (IBL)"
|
||||
global_skylight_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), global_skylight_name)
|
||||
Report.critical_result(Tests.global_skylight_creation, global_skylight_entity.exists())
|
||||
|
||||
# 2. Add Global Skylight (IBL) component to Global Skylight (IBL) entity.
|
||||
global_skylight_component = global_skylight_entity.add_component(global_skylight_name)
|
||||
Report.critical_result(
|
||||
Tests.global_skylight_component, global_skylight_entity.has_component(global_skylight_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not global_skylight_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, global_skylight_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
global_skylight_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, global_skylight_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
global_skylight_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, global_skylight_entity.is_visible() is True)
|
||||
|
||||
# 8. Set the Diffuse Image asset on the Global Skylight (IBL) entity.
|
||||
global_skylight_diffuse_image_property = "Controller|Configuration|Diffuse Image"
|
||||
diffuse_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
|
||||
diffuse_image_asset = Asset.find_asset_by_path(diffuse_image_path, False)
|
||||
global_skylight_component.set_component_property_value(
|
||||
global_skylight_diffuse_image_property, diffuse_image_asset.id)
|
||||
diffuse_image_set = global_skylight_component.get_component_property_value(
|
||||
global_skylight_diffuse_image_property)
|
||||
Report.result(Tests.diffuse_image_set, diffuse_image_set == diffuse_image_asset.id)
|
||||
|
||||
# 9. Set the Specular Image asset on the Global Light (IBL) entity.
|
||||
global_skylight_specular_image_property = "Controller|Configuration|Specular Image"
|
||||
specular_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
|
||||
specular_image_asset = Asset.find_asset_by_path(specular_image_path, False)
|
||||
global_skylight_component.set_component_property_value(
|
||||
global_skylight_specular_image_property, specular_image_asset.id)
|
||||
specular_image_added = global_skylight_component.get_component_property_value(
|
||||
global_skylight_specular_image_property)
|
||||
Report.result(Tests.specular_image_set, specular_image_added == specular_image_asset.id)
|
||||
|
||||
# 10. Delete Global Skylight (IBL) entity.
|
||||
global_skylight_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not global_skylight_entity.exists())
|
||||
|
||||
# 11. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, global_skylight_entity.exists())
|
||||
|
||||
# 12. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not global_skylight_entity.exists())
|
||||
|
||||
# 13. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_GlobalSkylightIBL_AddedToEntity)
|
||||
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
light_creation = ("Light Entity successfully created", "Light Entity failed to be created")
|
||||
light_component = ("Entity has a Light component", "Entity failed to find Light component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_Light_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Light component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Light entity with no components.
|
||||
2) Add Light component to the Light entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Delete Light entity.
|
||||
9) UNDO deletion.
|
||||
10) REDO deletion.
|
||||
11) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Light entity with no components.
|
||||
light_name = "Light"
|
||||
light_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), light_name)
|
||||
Report.critical_result(Tests.light_creation, light_entity.exists())
|
||||
|
||||
# 2. Add Light component to the Light entity.
|
||||
light_entity.add_component(light_name)
|
||||
Report.critical_result(Tests.light_component, light_entity.has_component(light_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not light_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, light_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
light_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, light_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
light_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, light_entity.is_visible() is True)
|
||||
|
||||
# 8. Delete Light entity.
|
||||
light_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not light_entity.exists())
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, light_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not light_entity.exists())
|
||||
|
||||
# 11. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_Light_AddedToEntity)
|
||||
+3
-5
@@ -1,10 +1,8 @@
|
||||
"""
|
||||
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.
|
||||
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
|
||||
|
||||
Hydra script that creates an entity, attaches the Light component to it for test verifications.
|
||||
The test verifies that each light type option is available and can be selected without errors.
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -19,7 +17,7 @@ import azlmbr.legacy.general as general
|
||||
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from atom_renderer.atom_utils.atom_constants import LIGHT_TYPES
|
||||
from Atom.atom_utils.atom_constants import LIGHT_TYPES
|
||||
|
||||
LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type'
|
||||
SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES = [
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
physical_sky_creation = ("Physical Sky Entity successfully created", "Physical Sky Entity failed to be created")
|
||||
physical_sky_component = ("Entity has a Physical Sky component", "Entity failed to find Physical Sky component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_PhysicalSky_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Physical Sky component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Physical Sky entity with no components.
|
||||
2) Add Physical Sky component to Physical Sky entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Delete Physical Sky entity.
|
||||
9) UNDO deletion.
|
||||
10) REDO deletion.
|
||||
11) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Physical Sky entity with no components.
|
||||
physical_sky_name = "Physical Sky"
|
||||
physical_sky_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), physical_sky_name)
|
||||
Report.critical_result(Tests.physical_sky_creation, physical_sky_entity.exists())
|
||||
|
||||
# 2. Add Physical Sky component to Physical Sky entity.
|
||||
physical_sky_entity.add_component(physical_sky_name)
|
||||
Report.critical_result(Tests.physical_sky_component, physical_sky_entity.has_component(physical_sky_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not physical_sky_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, physical_sky_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
physical_sky_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, physical_sky_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
physical_sky_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, physical_sky_entity.is_visible() is True)
|
||||
|
||||
# 8. Delete Physical Sky entity.
|
||||
physical_sky_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not physical_sky_entity.exists())
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, physical_sky_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not physical_sky_entity.exists())
|
||||
|
||||
# 11. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_PhysicalSky_AddedToEntity)
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
postfx_radius_weight_creation = ("PostFX Radius Weight Modifier Entity successfully created", "PostFX Radius Weight Modifier Entity failed to be created")
|
||||
postfx_radius_weight_component = ("Entity has a PostFX Radius Weight Modifier component", "Entity failed to find PostFX Radius Weight Modifier component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the PostFX Radius Weight Modifier component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Post FX Radius Weight Modifier entity with no components.
|
||||
2) Add Post FX Radius Weight Modifier component to Post FX Radius Weight Modifier entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Delete PostFX Radius Weight Modifier entity.
|
||||
9) UNDO deletion.
|
||||
10) REDO deletion.
|
||||
11) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Post FX Radius Weight Modifier entity with no components.
|
||||
postfx_radius_weight_name = "PostFX Radius Weight Modifier"
|
||||
postfx_radius_weight_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), postfx_radius_weight_name)
|
||||
Report.critical_result(Tests.postfx_radius_weight_creation, postfx_radius_weight_entity.exists())
|
||||
|
||||
# 2. Add Post FX Radius Weight Modifier component to Post FX Radius Weight Modifier entity.
|
||||
postfx_radius_weight_entity.add_component(postfx_radius_weight_name)
|
||||
Report.critical_result(
|
||||
Tests.postfx_radius_weight_component, postfx_radius_weight_entity.has_component(postfx_radius_weight_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not postfx_radius_weight_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, postfx_radius_weight_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
postfx_radius_weight_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, postfx_radius_weight_entity.is_hidden() is True)
|
||||
|
||||
# 7. Test IsVisible.
|
||||
postfx_radius_weight_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, postfx_radius_weight_entity.is_visible() is True)
|
||||
|
||||
# 8. Delete PostFX Radius Weight Modifier entity.
|
||||
postfx_radius_weight_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not postfx_radius_weight_entity.exists())
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, postfx_radius_weight_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not postfx_radius_weight_entity.exists())
|
||||
|
||||
# 11. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity)
|
||||
+5
-5
@@ -3,12 +3,12 @@ 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
|
||||
|
||||
import azlmbr.materialeditor will fail with a ModuleNotFound error when using this script with Editor.exe
|
||||
This is because azlmbr.materialeditor only binds to MaterialEditor.exe and not Editor.exe
|
||||
You need to launch this script with MaterialEditor.exe in order for azlmbr.materialeditor to appear.
|
||||
"""
|
||||
|
||||
# import azlmbr.materialeditor will fail with a ModuleNotFound error when using this script with Editor.exe
|
||||
# This is because azlmbr.materialeditor only binds to MaterialEditor.exe and not Editor.exe
|
||||
# You need to launch this script with MaterialEditor.exe in order for azlmbr.materialeditor to appear.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
@@ -18,7 +18,7 @@ import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
|
||||
|
||||
import atom_renderer.atom_utils.material_editor_utils as material_editor
|
||||
import Atom.atom_utils.material_editor_utils as material_editor
|
||||
|
||||
NEW_MATERIAL = "test_material.material"
|
||||
NEW_MATERIAL_1 = "test_material_1.material"
|
||||
+1
-6
@@ -3,11 +3,6 @@ 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
|
||||
|
||||
Hydra script that is used to create a new level with a default rendering setup.
|
||||
After the level is setup, screenshots are diffed against golden images are used to verify pass/fail results of the test.
|
||||
|
||||
See the run() function for more in-depth test info.
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -19,7 +14,7 @@ sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "P
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from atom_renderer.atom_utils.benchmark_utils import BenchmarkHelper
|
||||
from Atom.atom_utils.benchmark_utils import BenchmarkHelper
|
||||
|
||||
SCREEN_WIDTH = 1280
|
||||
SCREEN_HEIGHT = 720
|
||||
+1
-6
@@ -3,11 +3,6 @@ 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
|
||||
|
||||
Hydra script that is used to create a new level with a default rendering setup.
|
||||
After the level is setup, screenshots are diffed against golden images are used to verify pass/fail results of the test.
|
||||
|
||||
See the run() function for more in-depth test info.
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -26,7 +21,7 @@ sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "P
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from atom_renderer.atom_utils.screenshot_utils import ScreenshotHelper
|
||||
from Atom.atom_utils.screenshot_utils import ScreenshotHelper
|
||||
|
||||
SCREEN_WIDTH = 1280
|
||||
SCREEN_HEIGHT = 720
|
||||
+1
-7
@@ -3,12 +3,6 @@ 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
|
||||
|
||||
Hydra script that is used to create an entity with a Light component attached.
|
||||
It then updates the property values of the Light component and takes a screenshot.
|
||||
The screenshot is compared against an expected golden image for test verification.
|
||||
|
||||
See the run() function for more in-depth test info.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
@@ -23,7 +17,7 @@ import azlmbr.legacy.general as general
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from atom_renderer.atom_utils import atom_component_helper, atom_constants, screenshot_utils
|
||||
from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
|
||||
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
|
||||
+83
-84
@@ -3,78 +3,19 @@ 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
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
def _copy_file(src_file, src_path, target_file, target_path):
|
||||
# type: (str, str, str, str) -> None
|
||||
"""
|
||||
Copies the [src_file] located in [src_path] to the [target_file] located at [target_path].
|
||||
Leaves the [target_file] unlocked for reading and writing privileges
|
||||
:param src_file: The source file to copy (file name)
|
||||
:param src_path: The source file's path
|
||||
:param target_file: The target file to copy into (file name)
|
||||
:param target_path: The target file's path
|
||||
:return: None
|
||||
"""
|
||||
target_file_path = os.path.join(target_path, target_file)
|
||||
src_file_path = os.path.join(src_path, src_file)
|
||||
if os.path.exists(target_file_path):
|
||||
fs.unlock_file(target_file_path)
|
||||
shutil.copyfile(src_file_path, target_file_path)
|
||||
|
||||
def _copy_tmp_files_in_order(src_directory, file_list, dst_directory, wait_time_in_between = 0.0):
|
||||
# type: (str, list, str, float) -> None
|
||||
"""
|
||||
This function assumes that for each file name listed in @file_list
|
||||
there's file named "@filename.txt" which the original source file
|
||||
but they will be copied with just the @filename (.txt removed).
|
||||
"""
|
||||
for filename in file_list:
|
||||
src_name = f"{filename}.txt"
|
||||
_copy_file(src_name, src_directory, filename, dst_directory)
|
||||
if wait_time_in_between > 0.0:
|
||||
print(f"Created {filename} in {dst_directory}")
|
||||
general.idle_wait(wait_time_in_between)
|
||||
|
||||
|
||||
def _remove_file(src_file, src_path):
|
||||
# type: (str, str) -> None
|
||||
"""
|
||||
Removes the [src_file] located in [src_path].
|
||||
:param src_file: The source file to copy (file name)
|
||||
:param src_path: The source file's path
|
||||
:return: None
|
||||
"""
|
||||
src_file_path = os.path.join(src_path, src_file)
|
||||
if os.path.exists(src_file_path):
|
||||
fs.unlock_file(src_file_path)
|
||||
os.remove(src_file_path)
|
||||
|
||||
|
||||
def _remove_files(directory, file_list):
|
||||
for filename in file_list:
|
||||
_remove_file(filename, directory)
|
||||
|
||||
|
||||
def _asset_exists(cache_relative_path):
|
||||
asset_id = azasset.AssetCatalogRequestBus(azbus.Broadcast, "GetAssetIdByPath", cache_relative_path, azmath.Uuid(), False)
|
||||
return asset_id.is_valid()
|
||||
|
||||
# List of results that we want to check, this is not 100% necessary but it's a good
|
||||
# practice to make it easier to debug tests.
|
||||
# Here we define a tuple of tests
|
||||
class Results():
|
||||
azshader_was_removed = ("azshader was removed", "Failed to remove azshader")
|
||||
azshader_was_compiled = ("azshader was compiled", "Failed to compile azshader")
|
||||
# fmt: off
|
||||
class Tests():
|
||||
azshader_was_removed = ("azshader was removed", "Failed to remove azshader")
|
||||
azshader_was_compiled = ("azshader was compiled", "Failed to compile azshader")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
|
||||
"""
|
||||
This test validates [ATOM-5441] Shader Builders May Fail When Multiple New Files Are Added
|
||||
This test validates: "Shader Builders May Fail When Multiple New Files Are Added"
|
||||
It creates source assets to compile a particular shader.
|
||||
1- The first phase generates the source assets out of order and slowly. The AP should
|
||||
wakeup each time one of the source dependencies appears but will fail each time. Only when the
|
||||
@@ -82,6 +23,71 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
|
||||
2- The second phase is similar as above, except that all source assets will be created
|
||||
at once and We also expect that in the end the shader is built successfully.
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import azlmbr.asset as azasset
|
||||
import azlmbr.bus as azbus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as azmath
|
||||
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
from editor_python_test_tools.utils import Tracer
|
||||
import ly_test_tools.environment.file_system as fs
|
||||
|
||||
def _copy_file(src_file, src_path, target_file, target_path):
|
||||
# type: (str, str, str, str) -> None
|
||||
"""
|
||||
Copies the [src_file] located in [src_path] to the [target_file] located at [target_path].
|
||||
Leaves the [target_file] unlocked for reading and writing privileges
|
||||
:param src_file: The source file to copy (file name)
|
||||
:param src_path: The source file's path
|
||||
:param target_file: The target file to copy into (file name)
|
||||
:param target_path: The target file's path
|
||||
:return: None
|
||||
"""
|
||||
target_file_path = os.path.join(target_path, target_file)
|
||||
src_file_path = os.path.join(src_path, src_file)
|
||||
if os.path.exists(target_file_path):
|
||||
fs.unlock_file(target_file_path)
|
||||
shutil.copyfile(src_file_path, target_file_path)
|
||||
|
||||
def _copy_tmp_files_in_order(src_directory, file_list, dst_directory, wait_time_in_between=0.0):
|
||||
# type: (str, list, str, float) -> None
|
||||
"""
|
||||
This function assumes that for each file name listed in @file_list
|
||||
there's file named "@filename.txt" which the original source file
|
||||
but they will be copied with just the @filename (.txt removed).
|
||||
"""
|
||||
for filename in file_list:
|
||||
src_name = f"{filename}.txt"
|
||||
_copy_file(src_name, src_directory, filename, dst_directory)
|
||||
if wait_time_in_between > 0.0:
|
||||
print(f"Created {filename} in {dst_directory}")
|
||||
general.idle_wait(wait_time_in_between)
|
||||
|
||||
def _remove_file(src_file, src_path):
|
||||
# type: (str, str) -> None
|
||||
"""
|
||||
Removes the [src_file] located in [src_path].
|
||||
:param src_file: The source file to copy (file name)
|
||||
:param src_path: The source file's path
|
||||
:return: None
|
||||
"""
|
||||
src_file_path = os.path.join(src_path, src_file)
|
||||
if os.path.exists(src_file_path):
|
||||
fs.unlock_file(src_file_path)
|
||||
os.remove(src_file_path)
|
||||
|
||||
def _remove_files(directory, file_list):
|
||||
for filename in file_list:
|
||||
_remove_file(filename, directory)
|
||||
|
||||
def _asset_exists(cache_relative_path):
|
||||
asset_id = azasset.AssetCatalogRequestBus(azbus.Broadcast, "GetAssetIdByPath", cache_relative_path,
|
||||
azmath.Uuid(), False)
|
||||
return asset_id.is_valid()
|
||||
|
||||
# Required for automated tests
|
||||
helper.init_idle()
|
||||
|
||||
@@ -115,14 +121,14 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
|
||||
azshader_name = "assets/dependencyvalidation.azshader"
|
||||
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
|
||||
|
||||
Report.critical_result(Results.azshader_was_removed, not _asset_exists(azshader_name))
|
||||
Report.critical_result(Tests.azshader_was_removed, not _asset_exists(azshader_name))
|
||||
|
||||
_copy_tmp_files_in_order(src_assets_subdir, file_list, game_asset_path, 1.0)
|
||||
|
||||
# Give enough time to AP to compile the shader
|
||||
helper.wait_for_condition(lambda: _asset_exists(azshader_name), 60.0)
|
||||
|
||||
Report.critical_result(Results.azshader_was_compiled, _asset_exists(azshader_name))
|
||||
Report.critical_result(Tests.azshader_was_compiled, _asset_exists(azshader_name))
|
||||
|
||||
# The first part was about compiling the shader under normal conditions.
|
||||
# Let's remove the files from the previous phase and will proceed
|
||||
@@ -130,7 +136,7 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
|
||||
# ShaderAssetBuilder will only succeed when the last file becomes visible.
|
||||
_remove_files(game_asset_path, reverse_file_list)
|
||||
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
|
||||
Report.critical_result(Results.azshader_was_removed, not _asset_exists(azshader_name))
|
||||
Report.critical_result(Tests.azshader_was_removed, not _asset_exists(azshader_name))
|
||||
|
||||
# Remark, if you are running this test manually from the Editor with "pyRunFile",
|
||||
# You'll notice how the AP issues notifications that it fails to compile the shader
|
||||
@@ -148,7 +154,7 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
|
||||
# Give enough time to AP to compile the shader
|
||||
helper.wait_for_condition(lambda: _asset_exists(azshader_name), 60.0)
|
||||
|
||||
Report.critical_result(Results.azshader_was_compiled, _asset_exists(azshader_name))
|
||||
Report.critical_result(Tests.azshader_was_compiled, _asset_exists(azshader_name))
|
||||
|
||||
# The last phase of the test puts stress on potential race conditions
|
||||
# when all required files appear as soon as possible.
|
||||
@@ -157,7 +163,7 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
|
||||
# Remove left over files.
|
||||
_remove_files(game_asset_path, reverse_file_list)
|
||||
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
|
||||
Report.critical_result(Results.azshader_was_removed, not _asset_exists(azshader_name))
|
||||
Report.critical_result(Tests.azshader_was_removed, not _asset_exists(azshader_name))
|
||||
|
||||
# Now let's copy all the source files to the "Assets" folder as fast as possible.
|
||||
_copy_tmp_files_in_order(src_assets_subdir, reverse_file_list, game_asset_path)
|
||||
@@ -165,24 +171,17 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
|
||||
# Give enough time to AP to compile the shader
|
||||
helper.wait_for_condition(lambda: _asset_exists(azshader_name), 60.0)
|
||||
|
||||
Report.critical_result(Results.azshader_was_compiled, _asset_exists(azshader_name))
|
||||
Report.critical_result(Tests.azshader_was_compiled, _asset_exists(azshader_name))
|
||||
|
||||
# All good, let's cleanup leftover files before closing the test.
|
||||
_remove_files(game_asset_path, reverse_file_list)
|
||||
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
|
||||
|
||||
# Look for errors to raise.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# All exposed python bindings are in azlmbr
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as azbus
|
||||
import azlmbr.asset as azasset
|
||||
import azlmbr.math as azmath
|
||||
|
||||
# Import report and test helper utilities
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
from editor_python_test_tools.utils import Tracer
|
||||
import ly_test_tools.environment.file_system as fs
|
||||
|
||||
Report.start_test(ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges)
|
||||
Report.start_test(ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges)
|
||||
@@ -18,7 +18,7 @@ include(${pal_dir}/PAL_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
||||
add_subdirectory(assetpipeline)
|
||||
|
||||
## Atom Renderer ##
|
||||
add_subdirectory(atom_renderer)
|
||||
add_subdirectory(Atom)
|
||||
|
||||
## Physics ##
|
||||
add_subdirectory(Physics)
|
||||
|
||||
+45
-2
@@ -20,6 +20,7 @@ import azlmbr.legacy.general as general
|
||||
# Helper file Imports
|
||||
from editor_python_test_tools.utils import Report
|
||||
|
||||
|
||||
class EditorComponent:
|
||||
"""
|
||||
EditorComponent class used to set and get the component property value using path
|
||||
@@ -28,7 +29,6 @@ class EditorComponent:
|
||||
which also assigns self.id and self.type_id to the EditorComponent object.
|
||||
"""
|
||||
|
||||
# Methods
|
||||
def get_component_name(self) -> str:
|
||||
"""
|
||||
Used to get name of component
|
||||
@@ -87,6 +87,13 @@ class EditorComponent:
|
||||
outcome.IsSuccess()
|
||||
), f"Failure: Could not set value to '{self.get_component_name()}' : '{component_property_path}'"
|
||||
|
||||
def is_enabled(self):
|
||||
"""
|
||||
Used to verify if the component is enabled.
|
||||
:return: True if enabled, otherwise False.
|
||||
"""
|
||||
return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", self.id)
|
||||
|
||||
@staticmethod
|
||||
def get_type_ids(component_names: list) -> list:
|
||||
"""
|
||||
@@ -254,7 +261,7 @@ class EditorEntity:
|
||||
def get_components_of_type(self, component_names: list) -> List[EditorComponent]:
|
||||
"""
|
||||
Used to get components of type component_name that already exists on Entity
|
||||
:param component_name: Name to component to check
|
||||
:param component_names: List of names of components to check
|
||||
:return: List of Entity Component objects of given component name
|
||||
"""
|
||||
component_list = []
|
||||
@@ -318,3 +325,39 @@ class EditorEntity:
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetStartStatus", self.id, status_to_set)
|
||||
set_status = self.get_start_status()
|
||||
assert set_status == status_to_set, f"Failed to set start status of {desired_start_status} to {self.get_name}"
|
||||
|
||||
def delete(self) -> None:
|
||||
"""
|
||||
Used to delete the Entity.
|
||||
:return: None
|
||||
"""
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", self.id)
|
||||
|
||||
def set_visibility_state(self, is_visible: bool) -> None:
|
||||
"""
|
||||
Sets the visibility state on the object to visible or not visible.
|
||||
:param is_visible: True for making visible, False to make not visible.
|
||||
:return: None
|
||||
"""
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", self.id, is_visible)
|
||||
|
||||
def exists(self) -> bool:
|
||||
"""
|
||||
Used to verify if the Entity exists.
|
||||
:return: True if the Entity exists, False otherwise.
|
||||
"""
|
||||
return editor.ToolsApplicationRequestBus(bus.Broadcast, "EntityExists", self.id)
|
||||
|
||||
def is_hidden(self) -> bool:
|
||||
"""
|
||||
Gets the "isHidden" value from the Entity.
|
||||
:return: True if "isHidden" is enabled, False otherwise.
|
||||
"""
|
||||
return editor.EditorEntityInfoRequestBus(bus.Event, "IsHidden", self.id)
|
||||
|
||||
def is_visible(self) -> bool:
|
||||
"""
|
||||
Gets the "isVisible" value from the Entity.
|
||||
:return: True if "isVisible" is enabled, False otherwise.
|
||||
"""
|
||||
return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id)
|
||||
|
||||
+4
-2
@@ -81,7 +81,8 @@ def launch_and_validate_results(request, test_directory, editor, editor_script,
|
||||
|
||||
|
||||
def launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines, null_renderer=True,
|
||||
port_listener_timeout=120, log_monitor_timeout=300, remote_console_port=4600):
|
||||
port_listener_timeout=120, log_monitor_timeout=300, remote_console_port=4600,
|
||||
launch_ap=True):
|
||||
"""
|
||||
Runs the launcher with the specified level, and monitors Game.log for expected lines.
|
||||
:param launcher: Configured launcher object to run test against.
|
||||
@@ -92,6 +93,7 @@ def launch_and_validate_results_launcher(launcher, level, remote_console_instanc
|
||||
:param port_listener_timeout: Timeout for verifying successful connection to Remote Console.
|
||||
:param log_monitor_timeout: Timeout for monitoring for lines in Game.log
|
||||
:param remote_console_port: The port used to communicate with the Remote Console.
|
||||
:param launch_ap: Whether or not to launch AP. Defaults to True.
|
||||
"""
|
||||
|
||||
def _check_for_listening_port(port):
|
||||
@@ -110,7 +112,7 @@ def launch_and_validate_results_launcher(launcher, level, remote_console_instanc
|
||||
launcher.args.extend(["-rhi=Null"])
|
||||
|
||||
# Start the Launcher
|
||||
with launcher.start():
|
||||
with launcher.start(launch_ap=launch_ap):
|
||||
|
||||
# Ensure Remote Console can be reached
|
||||
waiter.wait_for(
|
||||
|
||||
@@ -17,5 +17,14 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
AZ::AssetProcessorBatch
|
||||
AZ::AssetProcessor
|
||||
)
|
||||
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AssetPipelineTests.Fbx_Tests
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/fbx_test/fbx_test.py
|
||||
TEST_SUITE sandbox
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessorBatch
|
||||
AZ::AssetProcessor
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -34,11 +34,13 @@ logger = logging.getLogger(__name__)
|
||||
targetProjects = ["AutomatedTesting"]
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.mark.SUITE_sandbox
|
||||
def local_resources(request, workspace, ap_setup_fixture):
|
||||
ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
@dataclass
|
||||
@pytest.mark.SUITE_sandbox
|
||||
class BlackboxAssetTest:
|
||||
test_name: str
|
||||
asset_folder: str
|
||||
@@ -338,9 +340,11 @@ blackbox_fbx_special_tests = [
|
||||
@pytest.mark.usefixtures("local_resources")
|
||||
@pytest.mark.parametrize("project", targetProjects)
|
||||
@pytest.mark.assetpipeline
|
||||
@pytest.mark.SUITE_sandbox
|
||||
class TestsFBX_AllPlatforms(object):
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests)
|
||||
def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace,
|
||||
ap_setup_fixture, asset_processor, project,
|
||||
@@ -359,6 +363,7 @@ class TestsFBX_AllPlatforms(object):
|
||||
asset_processor, project, blackbox_param)
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests)
|
||||
def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self,
|
||||
workspace, ap_setup_fixture,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
"""
|
||||
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
|
||||
|
||||
Main suite tests for the Shader Build Pipeline.
|
||||
"""
|
||||
import pytest
|
||||
from ly_test_tools import LAUNCHERS
|
||||
from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestShaderBuildPipelineMain(EditorTestSuite):
|
||||
"""Holds tests for Shader Build Pipeline validation"""
|
||||
|
||||
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSingleTest):
|
||||
from .atom_hydra_scripts import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
|
||||
@@ -14,8 +14,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
NAME AutomatedTesting::DynamicVegetationTests_Main
|
||||
TEST_SERIAL
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Main.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
@@ -27,104 +26,33 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationTests_Sandbox
|
||||
NAME AutomatedTesting::DynamicVegetationTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE sandbox
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "SUITE_sandbox"
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Periodic.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
AutomatedTesting.GameLauncher
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationFilterTests_Periodic
|
||||
NAME AutomatedTesting::DynamicVegetationTests_Main_Optimized
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_filter"
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Main_Optimized.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
AutomatedTesting.GameLauncher
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationModifierTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_modifier"
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationRegressionTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_regression"
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationAreaTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_area"
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationMiscTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_misc"
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationSurfaceTagTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_surfacetagemitter"
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
## LandscapeCanvas ##
|
||||
|
||||
ly_add_pytest(
|
||||
|
||||
+94
-94
@@ -5,119 +5,119 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
C4814463 - Altitude Filter overrides function as expected
|
||||
C4847477 - Altitude Min/Max can be manually set
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
prefilter_instance_count = (
|
||||
"Pre-filter instance counts are accurate",
|
||||
"Unexpected number of pre-filter instances found"
|
||||
)
|
||||
postfilter_instance_count = (
|
||||
"Post-filter instance counts are accurate",
|
||||
"Unexpected number of post-filter instances found"
|
||||
)
|
||||
postfilter_overrides_instance_count = (
|
||||
"Override instance counts are accurate",
|
||||
"Unexpected number of override instances found"
|
||||
)
|
||||
|
||||
|
||||
class TestAltitudeFilterComponentAndOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AltitudeFilterComponentAndOverrides", args=["level"])
|
||||
def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude():
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
|
||||
on Z. An Altitude Filter is added to the spawner entity, and Altitude Min/Max values are set. Instance counts
|
||||
are validated. The same test is then performed for Altitude Filter overrides.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
|
||||
on Z. An Altitude Filter is added to the spawner entity, and Altitude Min/Max values are set. Instance counts
|
||||
are validated. The same test is then performed for Altitude Filter overrides.
|
||||
Expected Behavior:
|
||||
Instances are only spawned within the specified altitude ranges.
|
||||
|
||||
Expected Behavior:
|
||||
Instances are only spawned within the specified altitude ranges.
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create an instance spawner entity
|
||||
3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
|
||||
4) Initial instance counts pre-filter are verified.
|
||||
5) Altitude Min/Max is set on the Vegetation Altitude Filter component.
|
||||
6) Instance counts post-filter are verified.
|
||||
7) Altitude Min/Max is set on descriptor overrides.
|
||||
8) Instance counts post-filter are verified.
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level
|
||||
2) Create an instance spawner entity
|
||||
3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
|
||||
4) Initial instance counts pre-filter are verified.
|
||||
5) Altitude Min/Max is set on the Vegetation Altitude Filter component.
|
||||
6) Instance counts post-filter are verified.
|
||||
7) Altitude Min/Max is set on descriptor overrides.
|
||||
8) Instance counts post-filter are verified.
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Add a Vegetation Altitude Filter
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 3) Add surfaces to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
|
||||
dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
|
||||
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
# Add a Vegetation Altitude Filter
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = (40 * 40) * 2 # 20 instances per 16m per side x 2 surfaces
|
||||
spawner_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and spawner_success
|
||||
# 3) Add surfaces to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
|
||||
dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# 5) Set min/max vegetation altitude, instances should now only appear between 35-37m on the Z-axis
|
||||
spawner_entity.get_set_test(3, "Configuration|Altitude Min", 35)
|
||||
spawner_entity.get_set_test(3, "Configuration|Altitude Max", 37)
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
|
||||
# 6) Validate expected instance counts
|
||||
num_expected = 40 * 40 # Instances should now only plant on the elevated surface
|
||||
altitude_min_max_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and altitude_min_max_success
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = (40 * 40) * 2 # 20 instances per 16m per side x 2 surfaces
|
||||
spawner_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.prefilter_instance_count, spawner_success)
|
||||
|
||||
# Resize Spawner Entity's Box Shape component to allow monitoring for a different instance count
|
||||
box_size = math.Vector3(16.0, 16.0, 16.0)
|
||||
spawner_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions", box_size)
|
||||
# 5) Set min/max vegetation altitude, instances should now only appear between 35-37m on the Z-axis
|
||||
spawner_entity.get_set_test(3, "Configuration|Altitude Min", 35)
|
||||
spawner_entity.get_set_test(3, "Configuration|Altitude Max", 37)
|
||||
|
||||
# 7) Allow overrides on Altitude Filter and set Altitude Filter Min/Max overrides on descriptor
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Override Enabled", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Min", 35)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Max", 37)
|
||||
# 6) Validate expected instance counts
|
||||
num_expected = 40 * 40 # Instances should now only plant on the elevated surface
|
||||
altitude_min_max_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.postfilter_instance_count, altitude_min_max_success)
|
||||
|
||||
# 8) Validate expected instances at specified elevations
|
||||
num_expected = 20 * 20 # 20 instances per 16m per side
|
||||
overrides_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and overrides_success
|
||||
# Resize Spawner Entity's Box Shape component to allow monitoring for a different instance count
|
||||
box_size = math.Vector3(16.0, 16.0, 16.0)
|
||||
spawner_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions", box_size)
|
||||
|
||||
# 7) Allow overrides on Altitude Filter and set Altitude Filter Min/Max overrides on descriptor
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Override Enabled", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Min", 35)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Max", 37)
|
||||
|
||||
# 8) Validate expected instances at specified elevations
|
||||
num_expected = 20 * 20 # 20 instances per 16m per side
|
||||
overrides_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.postfilter_overrides_instance_count, overrides_success)
|
||||
|
||||
|
||||
test = TestAltitudeFilterComponentAndOverrides()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude)
|
||||
|
||||
+65
-67
@@ -5,90 +5,88 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
preprocess_instance_count = (
|
||||
"Pre-process instance counts are accurate",
|
||||
"Unexpected number of pre-process instances found"
|
||||
)
|
||||
postprocess_instance_count = (
|
||||
"Post-process instance counts are accurate",
|
||||
"Unexpected number of post-process instances found"
|
||||
)
|
||||
|
||||
|
||||
class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AltitudeFilter_FilterStageToggle", args=["level"])
|
||||
def AltitudeFilter_FilterStageToggle():
|
||||
"""
|
||||
Summary:
|
||||
Filter Stage toggle affects final vegetation position
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Filter Stage toggle affects final vegetation position
|
||||
Expected Result:
|
||||
Vegetation instances plant differently depending on the Filter Stage setting.
|
||||
PostProcess should cause some number of plants that appear above and below the desired altitude range to disappear.
|
||||
|
||||
Expected Result:
|
||||
Vegetation instances plant differently depending on the Filter Stage setting.
|
||||
PostProcess should cause some number of plants that appear above and below the desired altitude range to disappear.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
PREPROCESS_INSTANCE_COUNT = 44
|
||||
POSTPROCESS_INSTANCE_COUNT = 34
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Create empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
PREPROCESS_INSTANCE_COUNT = 44
|
||||
POSTPROCESS_INSTANCE_COUNT = 34
|
||||
|
||||
# Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Add a Vegetation Altitude Filter to the vegetation area entity
|
||||
vegetation.add_component("Vegetation Altitude Filter")
|
||||
# Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
|
||||
# Add a Vegetation Altitude Filter to the vegetation area entity
|
||||
vegetation.add_component("Vegetation Altitude Filter")
|
||||
|
||||
# Add entity with Mesh to replicate creation of hills
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 10.0)
|
||||
# Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# Set a Min Altitude of 38 and Max of 40 in Vegetation Altitude Filter
|
||||
vegetation.get_set_test(3, "Configuration|Altitude Min", 38.0)
|
||||
vegetation.get_set_test(3, "Configuration|Altitude Max", 40.0)
|
||||
# Add entity with Mesh to replicate creation of hills
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 10.0)
|
||||
|
||||
# Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient
|
||||
# Transform Modifier, and Box Shape component
|
||||
random_noise = hydra.Entity("random_noise")
|
||||
random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
|
||||
random_noise.set_test_parent_entity(vegetation)
|
||||
# Set a Min Altitude of 38 and Max of 40 in Vegetation Altitude Filter
|
||||
vegetation.get_set_test(3, "Configuration|Altitude Min", 38.0)
|
||||
vegetation.get_set_test(3, "Configuration|Altitude Max", 40.0)
|
||||
|
||||
# Add a Vegetation Position Modifier to the vegetation area entity.
|
||||
vegetation.add_component("Vegetation Position Modifier")
|
||||
# Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient
|
||||
# Transform Modifier, and Box Shape component
|
||||
random_noise = hydra.Entity("random_noise")
|
||||
random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
|
||||
random_noise.set_test_parent_entity(vegetation)
|
||||
|
||||
# Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
|
||||
vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
|
||||
# Add a Vegetation Position Modifier to the vegetation area entity.
|
||||
vegetation.add_component("Vegetation Position Modifier")
|
||||
|
||||
# Toggle between PreProcess and PostProcess in Vegetation Altitude Filter
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, PREPROCESS_INSTANCE_COUNT), 2.0)
|
||||
self.log(f"Vegetation instances count equal to expected value for PREPROCESS filter stage: {result}")
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, POSTPROCESS_INSTANCE_COUNT), 2.0)
|
||||
self.log(f"Vegetation instances count equal to expected value for POSTPROCESS filter stage: {result}")
|
||||
# Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
|
||||
vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
|
||||
|
||||
# Toggle between PreProcess and PostProcess in Vegetation Altitude Filter
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, PREPROCESS_INSTANCE_COUNT), 2.0)
|
||||
Report.result(Tests.preprocess_instance_count, result)
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, POSTPROCESS_INSTANCE_COUNT), 2.0)
|
||||
Report.result(Tests.postprocess_instance_count, result)
|
||||
|
||||
|
||||
test = TestAltitudeFilterFilterStageToggle()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AltitudeFilter_FilterStageToggle)
|
||||
|
||||
+83
-82
@@ -5,104 +5,105 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
prefilter_instance_count = (
|
||||
"Pre-filter instance counts are accurate",
|
||||
"Unexpected number of pre-filter instances found"
|
||||
)
|
||||
postfilter_instance_count = (
|
||||
"Post-filter instance counts are accurate",
|
||||
"Unexpected number of post-filter instances found"
|
||||
)
|
||||
|
||||
|
||||
class TestAltitudeFilterShapeSample(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AltitudeFilterShapeSample", args=["level"])
|
||||
def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude():
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
|
||||
on Z. An Altitude Filter is added to the spawner entity, and set to sample a shape entity. Instance counts are
|
||||
validated.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
|
||||
on Z. An Altitude Filter is added to the spawner entity, and set to sample a shape entity. Instance counts are
|
||||
validated.
|
||||
Expected Behavior:
|
||||
Instances are only spawned within the altitude range specified by the sampled shape.
|
||||
|
||||
Expected Behavior:
|
||||
Instances are only spawned within the altitude range specified by the sampled shape.
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create an instance spawner entity
|
||||
3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
|
||||
4) Initial instance counts pre-filter are verified.
|
||||
5) A new entity with shape is created, an sampled on the Vegetation Altitude Filter.
|
||||
6) Instance counts post-filter are verified.
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level
|
||||
2) Create an instance spawner entity
|
||||
3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
|
||||
4) Initial instance counts pre-filter are verified.
|
||||
5) A new entity with shape is created, an sampled on the Vegetation Altitude Filter.
|
||||
6) Instance counts post-filter are verified.
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, asset_path)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Add a Vegetation Altitude Filter
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 3) Add surfaces to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
|
||||
dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
# Add a Vegetation Altitude Filter
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = (20 * 20) * 2 # 20 instances per 16m per side x 2 surfaces
|
||||
spawner_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and spawner_success
|
||||
# 3) Add surfaces to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
|
||||
dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# 5) Create a new entity with a shape at 36 on the Z-axis, and pin the entity to the Vegetation Altitude Filter
|
||||
shape_sampler_center_point = math.Vector3(512.0, 512.0, 36.0)
|
||||
shape_sampler = hydra.Entity("Shape Sampler")
|
||||
shape_sampler.create_entity(
|
||||
shape_sampler_center_point,
|
||||
["Box Shape"]
|
||||
)
|
||||
if shape_sampler.id.IsValid():
|
||||
print(f"'{shape_sampler.name}' created")
|
||||
spawner_entity.get_set_test(3, 'Configuration|Pin To Shape Entity Id', shape_sampler.id)
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
|
||||
# 6) Validate expected instance counts
|
||||
num_expected = 20 * 20 # Instances should now only plant on the elevated surface
|
||||
sampler_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and sampler_success
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = (20 * 20) * 2 # 20 instances per 16m per side x 2 surfaces
|
||||
spawner_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.prefilter_instance_count, spawner_success)
|
||||
|
||||
# 5) Create a new entity with a shape at 36 on the Z-axis, and pin the entity to the Vegetation Altitude Filter
|
||||
shape_sampler_center_point = math.Vector3(512.0, 512.0, 36.0)
|
||||
shape_sampler = hydra.Entity("Shape Sampler")
|
||||
shape_sampler.create_entity(
|
||||
shape_sampler_center_point,
|
||||
["Box Shape"]
|
||||
)
|
||||
if shape_sampler.id.IsValid():
|
||||
print(f"'{shape_sampler.name}' created")
|
||||
spawner_entity.get_set_test(3, 'Configuration|Pin To Shape Entity Id', shape_sampler.id)
|
||||
|
||||
# 6) Validate expected instance counts
|
||||
num_expected = 20 * 20 # Instances should now only plant on the elevated surface
|
||||
sampler_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.postfilter_instance_count, sampler_success)
|
||||
|
||||
|
||||
test = TestAltitudeFilterShapeSample()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude)
|
||||
|
||||
-125
@@ -1,125 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.slice as slice
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestAreaComponentsSliceCreationAndVisibilityToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(
|
||||
self, log_prefix="AreaComponentSlices_SliceCreationAndVisibilityToggle", args=["level"]
|
||||
)
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
C2627900 Verifies if a slice containing the component can be created.
|
||||
C2627905 A slice containing the Vegetation Layer Blender component can be created.
|
||||
C2627904: Hiding a slice containing the component clears any visuals from the Viewport.
|
||||
|
||||
Expected Result:
|
||||
C2627900, C2627905: Slice is created, and is properly processed in the Asset Processor.
|
||||
C2627904: Vegetation area visuals are hidden from the Viewport.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def path_is_valid_asset(asset_path):
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False)
|
||||
return asset_id.invoke("IsValid")
|
||||
|
||||
# 1) Create empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 2) C2627900 Verifies if a slice containing the Vegetation Layer Spawner component can be created.
|
||||
# 2.1) Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
veg_1 = dynveg.create_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# 2.2) Create slice from the entity
|
||||
slice_path = os.path.join("slices", "TestSlice_1.slice")
|
||||
slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", veg_1.id, slice_path)
|
||||
|
||||
# 2.3) Verify if the slice has been created successfully
|
||||
self.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
|
||||
self.log(
|
||||
f"Slice has been created successfully (entity with spawner component): {path_is_valid_asset(slice_path)}"
|
||||
)
|
||||
|
||||
# 3) C2627904: Hiding a slice containing the component clears any visuals from the Viewport
|
||||
# 3.1) Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# 3.2) Initially verify instance count before hiding slice
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400))
|
||||
self.log(
|
||||
f"Vegetation plants initially when slice is shown: {dynveg.validate_instance_count(position, 16.0, 400)}"
|
||||
)
|
||||
|
||||
# 3.3) Hide the slice and verify instance count
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, False)
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 0))
|
||||
self.log(f"Vegetation is cleared when slice is hidden: {dynveg.validate_instance_count(position, 16.0, 0)}")
|
||||
|
||||
# 3.4) Unhide the slice
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, True)
|
||||
|
||||
# 4) C2627905 A slice containing the Vegetation Layer Blender component can be created.
|
||||
# 4.1) Create another vegetation entity to add to blender component
|
||||
veg_2 = dynveg.create_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0, "")
|
||||
|
||||
# 4.2) Create entity with Vegetation Layer Blender
|
||||
components_to_add = ["Box Shape", "Vegetation Layer Blender"]
|
||||
blender_entity = hydra.Entity("blender_entity")
|
||||
blender_entity.create_entity(position, components_to_add)
|
||||
|
||||
# 4.3) Pin both the vegetation areas to the blender entity
|
||||
pte = hydra.get_property_tree(blender_entity.components[1])
|
||||
path = "Configuration|Vegetation Areas"
|
||||
pte.update_container_item(path, 0, veg_1.id)
|
||||
pte.add_container_item(path, 1, veg_2.id)
|
||||
|
||||
# 4.4) Drag the simple vegetation areas under the Vegetation Layer Blender entity to create an entity hierarchy.
|
||||
veg_1.set_test_parent_entity(blender_entity)
|
||||
veg_2.set_test_parent_entity(blender_entity)
|
||||
|
||||
# 4.5) Create slice from blender entity
|
||||
slice_path = os.path.join("slices", "TestSlice_2.slice")
|
||||
slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", blender_entity.id, slice_path)
|
||||
|
||||
# 4.6) Verify if the slice has been created successfully
|
||||
self.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
|
||||
self.log(
|
||||
f"Slice has been created successfully (entity with blender component): {path_is_valid_asset(slice_path)}"
|
||||
)
|
||||
|
||||
|
||||
test = TestAreaComponentsSliceCreationAndVisibilityToggle()
|
||||
test.run()
|
||||
+139
-134
@@ -5,162 +5,167 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.vegetation as vegetation
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
combined_instance_count_validation = (
|
||||
"Combined instance counts are as expected",
|
||||
"Found an unexpected number of instances"
|
||||
)
|
||||
replaced_asset_list_combined_instance_count_validation = (
|
||||
"Combined instance counts are as expected after replacing an Asset List reference",
|
||||
"Found an unexpected number of instances after replacing an Asset List reference"
|
||||
)
|
||||
removed_asset_lists_combined_instance_count_validation = (
|
||||
"Instance counts are as expected after removing the referenced Asset Lists",
|
||||
"Found an unexpected number of instances after removing the referenced Asset Lists"
|
||||
)
|
||||
|
||||
|
||||
class TestAssetListCombiner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AssetListCombiner_CombinedDescriptors", args=["level"])
|
||||
def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea():
|
||||
"""
|
||||
Summary:
|
||||
Combined descriptors appear as expected in a vegetation area. Also verifies remove/replace of assigned Asset
|
||||
Lists.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Combined descriptors appear as expected in a vegetation area. Also verifies remove/replace of assigned Asset
|
||||
Lists.
|
||||
Expected Behavior:
|
||||
Vegetation fills in the area using the assets assigned to both Vegetation Asset Lists.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation fills in the area using the assets assigned to both Vegetation Asset Lists.
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
|
||||
3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
|
||||
on center instead of corner
|
||||
4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
|
||||
spawning empty assets
|
||||
5) Add 2 of the Asset List entities to the Vegetation Asset List Combiner component (PinkFlower and Empty)
|
||||
6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
|
||||
as a child of the Constant Gradient entity, and configure for a checkerboard pattern
|
||||
7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
|
||||
8) Validate instance count with configured Asset List Combiner
|
||||
9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
|
||||
instance count
|
||||
10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
|
||||
Combiner component to force a refresh, and validate instance count
|
||||
|
||||
Test Steps:
|
||||
1) Create a new, temporary level
|
||||
2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
|
||||
3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
|
||||
on center instead of corner
|
||||
4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
|
||||
spawning empty assets
|
||||
5) Add 2 of the Asset List entities to the Vegetation Asset List Combiner component (PinkFlower and Empty)
|
||||
6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
|
||||
as a child of the Constant Gradient entity, and configure for a checkerboard pattern
|
||||
7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
|
||||
8) Validate instance count with configured Asset List Combiner
|
||||
9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
|
||||
instance count
|
||||
10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
|
||||
Combiner component to force a refresh, and validate instance count
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
def create_asset_list_entity(name, center, dynamic_slice_asset_path):
|
||||
asset_list_entity = hydra.Entity(name)
|
||||
asset_list_entity.create_entity(
|
||||
center,
|
||||
["Vegetation Asset List"]
|
||||
)
|
||||
if asset_list_entity.id.IsValid():
|
||||
print(f"'{asset_list_entity.name}' created")
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.vegetation as vegetation
|
||||
|
||||
# Set the Asset List to a Dynamic Slice spawner with a specific slice asset selected
|
||||
dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
|
||||
dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
|
||||
descriptor = hydra.get_component_property_value(asset_list_entity.components[0],
|
||||
"Configuration|Embedded Assets|[0]")
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
asset_list_entity.get_set_test(0, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
return asset_list_entity
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
def create_asset_list_entity(name, center, dynamic_slice_asset_path):
|
||||
asset_list_entity = hydra.Entity(name)
|
||||
asset_list_entity.create_entity(
|
||||
center,
|
||||
["Vegetation Asset List"]
|
||||
)
|
||||
if asset_list_entity.id.IsValid():
|
||||
print(f"'{asset_list_entity.name}' created")
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
# Set the Asset List to a Dynamic Slice spawner with a specific slice asset selected
|
||||
dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
|
||||
dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
|
||||
descriptor = hydra.get_component_property_value(asset_list_entity.components[0],
|
||||
"Configuration|Embedded Assets|[0]")
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
asset_list_entity.get_set_test(0, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
return asset_list_entity
|
||||
|
||||
# 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
asset_path2 = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
asset_list_entity = create_asset_list_entity("Asset List 1", center_point, asset_path)
|
||||
asset_list_entity2 = create_asset_list_entity("Asset List 2", center_point, None)
|
||||
asset_list_entity3 = create_asset_list_entity("Asset List 3", center_point, asset_path2)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
|
||||
# on center instead of corner
|
||||
dynveg.create_surface_entity("Surface Entity", center_point, 32.0, 32.0, 1.0)
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
|
||||
# spawning empty assets
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", center_point, 16.0, 16.0, 16.0, None)
|
||||
spawner_entity.remove_component("Vegetation Asset List")
|
||||
spawner_entity.add_component("Vegetation Asset List Combiner")
|
||||
spawner_entity.add_component("Vegetation Asset Weight Selector")
|
||||
spawner_entity.get_set_test(0, "Configuration|Allow Empty Assets", False)
|
||||
# 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
asset_path2 = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
asset_list_entity = create_asset_list_entity("Asset List 1", center_point, asset_path)
|
||||
asset_list_entity2 = create_asset_list_entity("Asset List 2", center_point, None)
|
||||
asset_list_entity3 = create_asset_list_entity("Asset List 3", center_point, asset_path2)
|
||||
|
||||
# 5) Add the Asset List entities to the Vegetation Asset List Combiner component
|
||||
asset_list_entities = [asset_list_entity.id, asset_list_entity2.id]
|
||||
spawner_entity.get_set_test(2, "Configuration|Descriptor Providers", asset_list_entities)
|
||||
# 3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
|
||||
# on center instead of corner
|
||||
dynveg.create_surface_entity("Surface Entity", center_point, 32.0, 32.0, 1.0)
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
|
||||
# 6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
|
||||
# as a child of the Constant Gradient entity, and configure for a checkerboard pattern
|
||||
components_to_add = ["Constant Gradient"]
|
||||
constant_gradient_entity = hydra.Entity("Constant Gradient Entity")
|
||||
constant_gradient_entity.create_entity(center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
constant_gradient_entity.get_set_test(0, "Configuration|Value", 0.5)
|
||||
# 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
|
||||
# spawning empty assets
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", center_point, 16.0, 16.0, 16.0, None)
|
||||
spawner_entity.remove_component("Vegetation Asset List")
|
||||
spawner_entity.add_component("Vegetation Asset List Combiner")
|
||||
spawner_entity.add_component("Vegetation Asset Weight Selector")
|
||||
spawner_entity.get_set_test(0, "Configuration|Allow Empty Assets", False)
|
||||
|
||||
components_to_add = ["Dither Gradient Modifier"]
|
||||
dither_gradient_entity = hydra.Entity("Dither Gradient Entity")
|
||||
dither_gradient_entity.create_entity(center_point, components_to_add, parent_id=constant_gradient_entity.id)
|
||||
dither_gradient_entity.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", constant_gradient_entity.id)
|
||||
# 5) Add the Asset List entities to the Vegetation Asset List Combiner component
|
||||
asset_list_entities = [asset_list_entity.id, asset_list_entity2.id]
|
||||
spawner_entity.get_set_test(2, "Configuration|Descriptor Providers", asset_list_entities)
|
||||
|
||||
# 7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", dither_gradient_entity.id)
|
||||
# 6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
|
||||
# as a child of the Constant Gradient entity, and configure for a checkerboard pattern
|
||||
components_to_add = ["Constant Gradient"]
|
||||
constant_gradient_entity = hydra.Entity("Constant Gradient Entity")
|
||||
constant_gradient_entity.create_entity(center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
constant_gradient_entity.get_set_test(0, "Configuration|Value", 0.5)
|
||||
|
||||
# 8) Validate instance count. We should now have 200 instances in the spawner area as every other instance
|
||||
# should be an empty asset which the spawner is set to disallow
|
||||
num_expected = 20 * 20 / 2
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
components_to_add = ["Dither Gradient Modifier"]
|
||||
dither_gradient_entity = hydra.Entity("Dither Gradient Entity")
|
||||
dither_gradient_entity.create_entity(center_point, components_to_add, parent_id=constant_gradient_entity.id)
|
||||
dither_gradient_entity.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", constant_gradient_entity.id)
|
||||
|
||||
# 9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
|
||||
# instance count. Should now be 400 instances as the empty spaces can now be claimed by the new descriptor
|
||||
spawner_entity.get_set_test(2, "Configuration|Descriptor Providers|[1]", asset_list_entity3.id)
|
||||
num_expected = 20 * 20
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
# 7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", dither_gradient_entity.id)
|
||||
|
||||
# 10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
|
||||
# Combiner component to force a refresh, and validate instance count. We should now have 0 instances.
|
||||
pte = hydra.get_property_tree(spawner_entity.components[2])
|
||||
path = "Configuration|Descriptor Providers"
|
||||
pte.reset_container(path)
|
||||
# Component refresh is currently necessary due to container operations not causing a refresh (LY-120947)
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [spawner_entity.components[2]])
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "EnableComponents", [spawner_entity.components[2]])
|
||||
num_expected = 0
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
# 8) Validate instance count. We should now have 200 instances in the spawner area as every other instance
|
||||
# should be an empty asset which the spawner is set to disallow
|
||||
num_expected = 20 * 20 / 2
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.combined_instance_count_validation, success)
|
||||
|
||||
# 9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
|
||||
# instance count. Should now be 400 instances as the empty spaces can now be claimed by the new descriptor
|
||||
spawner_entity.get_set_test(2, "Configuration|Descriptor Providers|[1]", asset_list_entity3.id)
|
||||
num_expected = 20 * 20
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.replaced_asset_list_combined_instance_count_validation, success)
|
||||
|
||||
# 10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
|
||||
# Combiner component to force a refresh, and validate instance count. We should now have 0 instances.
|
||||
pte = hydra.get_property_tree(spawner_entity.components[2])
|
||||
path = "Configuration|Descriptor Providers"
|
||||
pte.reset_container(path)
|
||||
# Component refresh is currently necessary due to container operations not causing a refresh (LY-120947)
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [spawner_entity.components[2]])
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "EnableComponents", [spawner_entity.components[2]])
|
||||
num_expected = 0
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.removed_asset_lists_combined_instance_count_validation, success)
|
||||
|
||||
|
||||
test = TestAssetListCombiner()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea)
|
||||
|
||||
+88
-90
@@ -5,112 +5,110 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
C6269654: Vegetation areas using weight selectors properly distribute instances according to Sort By Weight setting
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
highest_weight_instance_count = (
|
||||
"Found the expected number of instances when sorting by highest weight",
|
||||
"Found an unexpected number of instances when sorting by highest weight"
|
||||
)
|
||||
lowest_weight_instance_count = (
|
||||
"Found the expected number of instances when sorting by lowest weight",
|
||||
"Found an unexpected number of instances when sorting by lowest weight"
|
||||
)
|
||||
|
||||
|
||||
class TestAssetWeightSelectorSortByWeight(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AssetWeightSelector_SortByWeight", args=["level"])
|
||||
def AssetWeightSelector_InstancesExpressBasedOnWeight():
|
||||
"""
|
||||
Summary:
|
||||
Vegetation areas using weight selectors properly distribute instances according to Sort By Weight setting
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Vegetation areas using weight selectors properly distribute instances according to Sort By Weight setting
|
||||
Expected Behavior:
|
||||
Vegetation is planted in the area according to the generated gradient pattern.
|
||||
Higher weight assets are more likely to express when "Descending (highest first)" is selected.
|
||||
Lower weight assets are more likely to express when "Ascending (lowest first)" is selected.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation is planted in the area according to the generated gradient pattern.
|
||||
Higher weight assets are more likely to express when "Descending (highest first)" is selected.
|
||||
Lower weight assets are more likely to express when "Ascending (lowest first)" is selected.
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create instance spawner with 2 descriptors, one with an Empty Asset
|
||||
3) Create a planting surface
|
||||
4) Create a child entity of the instance spawner with a Constant Gradient component with default values (1.0)
|
||||
5) Pin the child entity to Vegetation Asset Weight Selector of the instance spawner entity
|
||||
6) Set first descriptor to a higher weight, and toggle off Allow Empty Assets
|
||||
7) Validate instance count with initial setup/sort values
|
||||
8) Change sort values and validate instance count
|
||||
|
||||
Test Steps:
|
||||
1) Create new level
|
||||
2) Create instance spawner with 2 descriptors, one with an Empty Asset
|
||||
3) Create a planting surface
|
||||
4) Create a child entity of the instance spawner with a Constant Gradient component with default values (1.0)
|
||||
5) Pin the child entity to Vegetation Asset Weight Selector of the instance spawner entity
|
||||
6) Set first descriptor to a higher weight, and toggle off Allow Empty Assets
|
||||
7) Validate instance count with initial setup/sort values
|
||||
8) Change sort values and validate instance count
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import os
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors, one set to a
|
||||
# valid slice entity, and one set to None
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
desc_asset = hydra.get_component_property_value(spawner_entity.components[2],
|
||||
"Configuration|Embedded Assets")[0]
|
||||
desc_list = [desc_asset, desc_asset]
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[1]|Instance|Slice Asset", None)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Add an Asset Weight Selector component to the spawner entity
|
||||
spawner_entity.add_component("Vegetation Asset Weight Selector")
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 3) Create a planting surface
|
||||
dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 1.0)
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 4) Create a child entity of the spawner entity with a Constant Gradient component
|
||||
components_to_add = ["Constant Gradient"]
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
# 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors, one set to a
|
||||
# valid slice entity, and one set to None
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
desc_asset = hydra.get_component_property_value(spawner_entity.components[2],
|
||||
"Configuration|Embedded Assets")[0]
|
||||
desc_list = [desc_asset, desc_asset]
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[1]|Instance|Slice Asset", None)
|
||||
|
||||
# 5) Pin the Constant Gradient to the Vegetation Asset Weight Selector
|
||||
spawner_entity.get_set_test(3, 'Configuration|Gradient|Gradient Entity Id', gradient_entity.id)
|
||||
# Add an Asset Weight Selector component to the spawner entity
|
||||
spawner_entity.add_component("Vegetation Asset Weight Selector")
|
||||
|
||||
# 6) Set the first descriptor weight to a higher value and toggle off Allow Empty Assets on the Layer Spawner
|
||||
# component
|
||||
spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Weight', 50)
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
# 3) Create a planting surface
|
||||
dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# 7) Query for expected instances with default settings. We should have 0 instances with default Constant
|
||||
# Gradient setup sorting by higher weight first
|
||||
num_expected = 0
|
||||
initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = initial_success and self.test_success
|
||||
# 4) Create a child entity of the spawner entity with a Constant Gradient component
|
||||
components_to_add = ["Constant Gradient"]
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
|
||||
# 8) Sort by lowest weight first, and verify instance counts. We should now have 400 instances as the highest
|
||||
# priority instance won't be allowed to claim space due to "Allow Empty Assets" being False
|
||||
spawner_entity.get_set_test(3, 'Configuration|Sort By Weight', 1)
|
||||
num_expected = 20 * 20
|
||||
final_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = final_success and self.test_success
|
||||
# 5) Pin the Constant Gradient to the Vegetation Asset Weight Selector
|
||||
spawner_entity.get_set_test(3, 'Configuration|Gradient|Gradient Entity Id', gradient_entity.id)
|
||||
|
||||
# 6) Set the first descriptor weight to a higher value and toggle off Allow Empty Assets on the Layer Spawner
|
||||
# component
|
||||
spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Weight', 50)
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
|
||||
# 7) Query for expected instances with default settings. We should have 0 instances with default Constant
|
||||
# Gradient setup sorting by higher weight first
|
||||
num_expected = 0
|
||||
initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.highest_weight_instance_count, initial_success)
|
||||
|
||||
# 8) Sort by lowest weight first, and verify instance counts. We should now have 400 instances as the highest
|
||||
# priority instance won't be allowed to claim space due to "Allow Empty Assets" being False
|
||||
spawner_entity.get_set_test(3, 'Configuration|Sort By Weight', 1)
|
||||
num_expected = 20 * 20
|
||||
final_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.lowest_weight_instance_count, final_success)
|
||||
|
||||
|
||||
test = TestAssetWeightSelectorSortByWeight()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AssetWeightSelector_InstancesExpressBasedOnWeight)
|
||||
|
||||
+97
-87
@@ -5,108 +5,118 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
initial_instance_counts = (
|
||||
"Initial instance counts are as expected",
|
||||
"Unexpected number of initial instances found"
|
||||
)
|
||||
instance_counts_1m = (
|
||||
"Instance counts with 1 meters between instances are as expected",
|
||||
"Unexpected number of instances found with 1 meters between instances"
|
||||
)
|
||||
instance_counts_2m = (
|
||||
"Instance counts with 2 meters between instances are as expected",
|
||||
"Unexpected number of instances found with 2 meters between instances"
|
||||
)
|
||||
instance_counts_16m = (
|
||||
"Instance counts with 16 meters between instances are as expected",
|
||||
"Unexpected number of instances found with 16 meters between instances"
|
||||
)
|
||||
|
||||
|
||||
class TestDistanceBetweenFilterComponentOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DistanceBetweenFilterComponentOverrides", args=["level"])
|
||||
def DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius():
|
||||
"""
|
||||
Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
|
||||
added and the min radius is changed as an override on the descriptor. Instance counts at specific points are
|
||||
validated.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
|
||||
added and the min radius is changed as an override on the descriptor. Instance counts at specific points are
|
||||
validated.
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create a vegetation area
|
||||
3) Create a surface for planting
|
||||
4) Add the Vegetation System Settings component and setup for the test
|
||||
5-8) Add the Distance Between Filter, setup overrides on both the component and descriptor, and validate
|
||||
expected instance counts with a few different Radius values
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level
|
||||
2) Create a vegetation area
|
||||
3) Create a surface for planting
|
||||
4) Add the Vegetation System Settings component and setup for the test
|
||||
5-8) Add the Distance Between Filter, setup overrides on both the component and descriptor, and validate
|
||||
expected instance counts with a few different Radius values
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
|
||||
instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
|
||||
instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
|
||||
instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
|
||||
instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
|
||||
|
||||
# 3) Create a surface to plant on
|
||||
surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Density', 16)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 5) Add a Vegetation Distance Between Filter, toggle overrides on both the component and descriptor,
|
||||
# and verify initial instance counts are accurate
|
||||
spawner_entity.add_component("Vegetation Distance Between Filter")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Override Enabled", True)
|
||||
num_expected = 16 * 16
|
||||
initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and initial_success
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
|
||||
# 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 1.0)
|
||||
point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
|
||||
self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
|
||||
# 3) Create a surface to plant on
|
||||
surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
|
||||
|
||||
# 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 2.0)
|
||||
point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
|
||||
self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
|
||||
# 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Density', 16)
|
||||
|
||||
# 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate, only a single instance should plant
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 16.0)
|
||||
num_expected_instances = 1
|
||||
final_check_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and final_check_success
|
||||
# 5) Add a Vegetation Distance Between Filter, toggle overrides on both the component and descriptor,
|
||||
# and verify initial instance counts are accurate
|
||||
spawner_entity.add_component("Vegetation Distance Between Filter")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Override Enabled", True)
|
||||
num_expected = 16 * 16
|
||||
initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.initial_instance_counts, initial_success)
|
||||
|
||||
# 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 1.0)
|
||||
point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
|
||||
Report.result(Tests.instance_counts_1m, point_a_success and point_b_success and point_c_success)
|
||||
|
||||
# 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 2.0)
|
||||
point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
|
||||
Report.result(Tests.instance_counts_2m, point_a_success and point_b_success and point_c_success)
|
||||
|
||||
# 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate, only a single instance should plant
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 16.0)
|
||||
num_expected_instances = 1
|
||||
final_check_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
Report.result(Tests.instance_counts_16m, final_check_success)
|
||||
|
||||
|
||||
test = TestDistanceBetweenFilterComponentOverrides()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius)
|
||||
|
||||
+92
-83
@@ -5,104 +5,113 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
initial_instance_counts = (
|
||||
"Initial instance counts are as expected",
|
||||
"Unexpected number of initial instances found"
|
||||
)
|
||||
instance_counts_1m = (
|
||||
"Instance counts with 1 meters between instances are as expected",
|
||||
"Unexpected number of instances found with 1 meters between instances"
|
||||
)
|
||||
instance_counts_2m = (
|
||||
"Instance counts with 2 meters between instances are as expected",
|
||||
"Unexpected number of instances found with 2 meters between instances"
|
||||
)
|
||||
instance_counts_16m = (
|
||||
"Instance counts with 16 meters between instances are as expected",
|
||||
"Unexpected number of instances found with 16 meters between instances"
|
||||
)
|
||||
|
||||
|
||||
class TestDistanceBetweenFilterComponent(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DistanceBetweenFilterComponent", args=["level"])
|
||||
def DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius():
|
||||
"""
|
||||
Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
|
||||
added and the min radius is changed. Instance counts at specific points are validated.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
|
||||
added and the min radius is changed. Instance counts at specific points are validated.
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create a vegetation area
|
||||
3) Create a surface for planting
|
||||
4) Add the Vegetation System Settings component and setup for the test
|
||||
5-8) Add the Distance Between Filter, and validate expected instance counts with a few different Radius values
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level
|
||||
2) Create a vegetation area
|
||||
3) Create a surface for planting
|
||||
4) Add the Vegetation System Settings component and setup for the test
|
||||
5-8) Add the Distance Between Filter, and validate expected instance counts with a few different Radius values
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
|
||||
instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
|
||||
instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
|
||||
instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
|
||||
instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
|
||||
|
||||
# 3) Create a surface to plant on
|
||||
surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Density', 16)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 5) Add a Vegetation Distance Between Filter and verify initial instance counts are accurate
|
||||
spawner_entity.add_component("Vegetation Distance Between Filter")
|
||||
num_expected = 16 * 16
|
||||
num_expected = 16 * 16
|
||||
initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and initial_success
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
|
||||
# 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(3, "Configuration|Radius Min", 1.0)
|
||||
point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
|
||||
self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
|
||||
# 3) Create a surface to plant on
|
||||
surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
|
||||
|
||||
# 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(3, "Configuration|Radius Min", 2.0)
|
||||
point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
|
||||
self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
|
||||
# 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Density', 16)
|
||||
|
||||
# 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(3, "Configuration|Radius Min", 16.0)
|
||||
num_expected_instances = 1
|
||||
final_check_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = final_check_success and self.test_success
|
||||
# 5) Add a Vegetation Distance Between Filter and verify initial instance counts are accurate
|
||||
spawner_entity.add_component("Vegetation Distance Between Filter")
|
||||
num_expected = 16 * 16
|
||||
initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.initial_instance_counts, initial_success)
|
||||
|
||||
# 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(3, "Configuration|Radius Min", 1.0)
|
||||
point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
|
||||
Report.result(Tests.instance_counts_1m, point_a_success and point_b_success and point_c_success)
|
||||
|
||||
# 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(3, "Configuration|Radius Min", 2.0)
|
||||
point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
|
||||
point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
|
||||
point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
|
||||
Report.result(Tests.instance_counts_2m, point_a_success and point_b_success and point_c_success)
|
||||
|
||||
# 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate
|
||||
spawner_entity.get_set_test(3, "Configuration|Radius Min", 16.0)
|
||||
num_expected_instances = 1
|
||||
final_check_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
Report.result(Tests.instance_counts_16m, final_check_success)
|
||||
|
||||
|
||||
test = TestDistanceBetweenFilterComponent()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius)
|
||||
|
||||
+160
-122
@@ -5,140 +5,178 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class BehaviorContextTests:
|
||||
spawner_initialized = (
|
||||
"Successfully initialized a Dynamic Slice Instance Spawner",
|
||||
"Failed to initialize a Dynamic Slice Instance Spawner"
|
||||
)
|
||||
spawner_slice_asset_path_set = (
|
||||
"Successfully set a Dynamic Slice asset path",
|
||||
"Failed to set a Dynamic Slice asset path"
|
||||
)
|
||||
spawner_empty_slice_asset_path_set = (
|
||||
"Successfully set an empty Dynamic Slice asset path",
|
||||
"Failed to set an empty Dynamic Slice asset path"
|
||||
)
|
||||
desc_spawnertype_sets_spawner = (
|
||||
"Setting spawnerType sets spawner too",
|
||||
"Setting spawnerType failed to set spawner to expected value"
|
||||
)
|
||||
desc_spawner_sets_spawnertype = (
|
||||
"Setting spawner sets spawnerType too",
|
||||
"Setting spawner failed to set spawnerType to expected value"
|
||||
)
|
||||
|
||||
|
||||
class TestDynamicSliceInstanceSpawner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawner", args=["level"])
|
||||
class PropertyTreeTests:
|
||||
entity_created = (
|
||||
"Spawner entity created successfully",
|
||||
"Failed to create spawner entity"
|
||||
)
|
||||
spawner_type_set = (
|
||||
"Successfully set spawner type",
|
||||
"Failed to set spawner type"
|
||||
)
|
||||
empty_instance_count_validation = (
|
||||
"Expected number of empty instances planted",
|
||||
"Unexpected number of empty instances planted"
|
||||
)
|
||||
no_instances_when_empty_disallowed = (
|
||||
"No empty instances found when Empty Assets are not allowed",
|
||||
"Unexpectedly found empty instances when Empty Assets are not allowed"
|
||||
)
|
||||
nonempty_asset_instance_count_validation = (
|
||||
"Expected number of instances planted",
|
||||
"Unexpected number of instances planted"
|
||||
)
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Test aspects of the DynamicSliceInstanceSpawner through the BehaviorContext and the Property Tree.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
# 1) Open an empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
def DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks():
|
||||
"""
|
||||
Summary:
|
||||
Test aspects of the DynamicSliceInstanceSpawner through the BehaviorContext and the Property Tree.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Grab the UUID that we need for creating an Dynamic Slice Instance Spawner
|
||||
dynamic_slice_spawner_uuid = azlmbr.math.Uuid_CreateString('{BBA5CC1E-B4CA-4792-89F7-93711E98FBD1}', 0)
|
||||
|
||||
# Grab a path to a test dynamic slice asset
|
||||
test_slice_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
|
||||
# 2) Test DynamicSliceInstanceSpawner BehaviorContext
|
||||
behavior_context_test_success = True
|
||||
dynamic_slice_spawner = azlmbr.vegetation.DynamicSliceInstanceSpawner()
|
||||
behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner is not None)
|
||||
behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner.typename == 'DynamicSliceInstanceSpawner')
|
||||
Report.critical_result(BehaviorContextTests.spawner_initialized, behavior_context_test_success)
|
||||
# Try to get/set the slice asset path with a valid asset
|
||||
dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
|
||||
validate_path = dynamic_slice_spawner.GetSliceAssetPath()
|
||||
# We expect the path to get lowercased and normalized with a forward slash, so we compare our result
|
||||
# vs that instead of directly against test_slice_asset_path.
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.compare_values('slices/pinkflower.dynamicslice', validate_path, 'GetSliceAssetPath - valid')
|
||||
Report.result(BehaviorContextTests.spawner_slice_asset_path_set, behavior_context_test_success)
|
||||
# Try to get/set the slice asset path with an empty path
|
||||
dynamic_slice_spawner.SetSliceAssetPath('')
|
||||
validate_path = dynamic_slice_spawner.GetSliceAssetPath()
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.compare_values('', validate_path, 'GetSliceAssetPath - empty')
|
||||
Report.result(BehaviorContextTests.spawner_empty_slice_asset_path_set, behavior_context_test_success)
|
||||
Report.info(f'DynamicSliceInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
|
||||
|
||||
# 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
|
||||
spawner_type_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', dynamic_slice_spawner_uuid)
|
||||
spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
|
||||
Report.result(BehaviorContextTests.desc_spawnertype_sets_spawner, spawner_type_test_success)
|
||||
Report.info(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
|
||||
|
||||
# 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
|
||||
spawner_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(dynamic_slice_spawner_uuid))
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
|
||||
Report.result(BehaviorContextTests.desc_spawner_sets_spawnertype, spawner_test_success)
|
||||
Report.info(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
|
||||
|
||||
### Setup for Property Tree set of tests
|
||||
|
||||
# Create a new entity with required vegetation area components
|
||||
spawner_entity = hydra.Entity("Veg Area")
|
||||
spawner_entity.create_entity(
|
||||
math.Vector3(512.0, 512.0, 32.0),
|
||||
["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
|
||||
)
|
||||
general.idle_wait(1.0)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
Report.critical_result(PropertyTreeTests.entity_created, spawner_entity.id.IsValid())
|
||||
|
||||
# Grab the UUID that we need for creating an Dynamic Slice Instance Spawner
|
||||
dynamic_slice_spawner_uuid = azlmbr.math.Uuid_CreateString('{BBA5CC1E-B4CA-4792-89F7-93711E98FBD1}', 0)
|
||||
# Resize the Box Shape component
|
||||
new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
|
||||
box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
|
||||
spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
|
||||
|
||||
# Grab a path to a test dynamic slice asset
|
||||
test_slice_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
# Create a surface to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
|
||||
|
||||
# 2) Test DynamicSliceInstanceSpawner BehaviorContext
|
||||
behavior_context_test_success = True
|
||||
dynamic_slice_spawner = azlmbr.vegetation.DynamicSliceInstanceSpawner()
|
||||
behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner is not None)
|
||||
behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner.typename == 'DynamicSliceInstanceSpawner')
|
||||
# Try to get/set the slice asset path with a valid asset
|
||||
dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
|
||||
validate_path = dynamic_slice_spawner.GetSliceAssetPath()
|
||||
# We expect the path to get lowercased and normalized with a forward slash, so we compare our result
|
||||
# vs that instead of directly against test_slice_asset_path.
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.compare_values('slices/pinkflower.dynamicslice', validate_path, 'GetSliceAssetPath - valid')
|
||||
# Try to get/set the slice asset path with an empty path
|
||||
dynamic_slice_spawner.SetSliceAssetPath('')
|
||||
validate_path = dynamic_slice_spawner.GetSliceAssetPath()
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.compare_values('', validate_path, 'GetSliceAssetPath - empty')
|
||||
self.test_success = self.test_success and behavior_context_test_success
|
||||
self.log(f'DynamicSliceInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
|
||||
# 5) Descriptor Property Tree test: spawner type can be set
|
||||
|
||||
# 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
|
||||
spawner_type_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', dynamic_slice_spawner_uuid)
|
||||
spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
|
||||
self.test_success = self.test_success and spawner_type_test_success
|
||||
self.log(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
|
||||
# - Validate the dynamic slice spawner type can be set correctly.
|
||||
property_tree_success = True
|
||||
property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', dynamic_slice_spawner_uuid)
|
||||
Report.result(PropertyTreeTests.spawner_type_set, property_tree_success)
|
||||
|
||||
# 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
|
||||
spawner_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(dynamic_slice_spawner_uuid))
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
|
||||
self.test_success = self.test_success and spawner_test_success
|
||||
self.log(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
|
||||
# This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
|
||||
# 20 instances per 16 meters
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', True)
|
||||
num_expected_instances = 20 * 20
|
||||
property_tree_success = property_tree_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
Report.result(PropertyTreeTests.empty_instance_count_validation, property_tree_success)
|
||||
Report.info(f'Property Tree spawner type test: {property_tree_success}')
|
||||
|
||||
### Setup for Property Tree set of tests
|
||||
# 6) Validate that the "Allow Empty Assets" setting affects the DynamicSliceInstanceSpawner
|
||||
allow_empty_assets_success = True
|
||||
# Since we have an empty slice path, we should have 0 instances once we disable 'Allow Empty Assets'
|
||||
num_expected_instances = 0
|
||||
allow_empty_assets_success = allow_empty_assets_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
Report.info('Allow Empty Assets test:')
|
||||
allow_empty_assets_success = allow_empty_assets_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
Report.result(PropertyTreeTests.no_instances_when_empty_disallowed, allow_empty_assets_success)
|
||||
Report.info(f'Allow Empty Assets test: {allow_empty_assets_success}')
|
||||
|
||||
# Create a new entity with required vegetation area components
|
||||
spawner_entity = hydra.Entity("Veg Area")
|
||||
spawner_entity.create_entity(
|
||||
math.Vector3(512.0, 512.0, 32.0),
|
||||
["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
|
||||
)
|
||||
if (spawner_entity.id.IsValid()):
|
||||
self.log(f"'{spawner_entity.name}' created")
|
||||
|
||||
# Resize the Box Shape component
|
||||
new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
|
||||
box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
|
||||
spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
|
||||
|
||||
# Create a surface to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
|
||||
|
||||
# 5) Descriptor Property Tree test: spawner type can be set
|
||||
|
||||
# - Validate the dynamic slice spawner type can be set correctly.
|
||||
property_tree_success = True
|
||||
property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', dynamic_slice_spawner_uuid)
|
||||
|
||||
# This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
|
||||
# 20 instances per 16 meters
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', True)
|
||||
num_expected_instances = 20 * 20
|
||||
property_tree_success = property_tree_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and property_tree_success
|
||||
self.log(f'Property Tree spawner type test: {property_tree_success}')
|
||||
|
||||
# 6) Validate that the "Allow Empty Assets" setting affects the DynamicSliceInstanceSpawner
|
||||
allow_empty_assets_success = True
|
||||
# Since we have an empty slice path, we should have 0 instances once we disable 'Allow Empty Assets'
|
||||
num_expected_instances = 0
|
||||
allow_empty_assets_success = allow_empty_assets_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
self.log('Allow Empty Assets test:')
|
||||
allow_empty_assets_success = allow_empty_assets_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and allow_empty_assets_success
|
||||
self.log(f'Allow Empty Assets test: {allow_empty_assets_success}')
|
||||
|
||||
# 7) Validate that with 'Allow Empty Assets' set to False, a non-empty slice asset gives us the number
|
||||
# of instances we expect.
|
||||
spawns_slices_success = True
|
||||
num_expected_instances = 20 * 20
|
||||
dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
|
||||
spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
self.log('Spawn dynamic slices test:')
|
||||
spawns_slices_success = spawns_slices_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and spawns_slices_success
|
||||
self.log(f'Spawn dynamic slices test: {spawns_slices_success}')
|
||||
# 7) Validate that with 'Allow Empty Assets' set to False, a non-empty slice asset gives us the number
|
||||
# of instances we expect.
|
||||
spawns_slices_success = True
|
||||
num_expected_instances = 20 * 20
|
||||
dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
|
||||
spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
Report.info('Spawn dynamic slices test:')
|
||||
spawns_slices_success = spawns_slices_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
Report.result(PropertyTreeTests.nonempty_asset_instance_count_validation, spawns_slices_success)
|
||||
Report.info(f'Spawn dynamic slices test: {spawns_slices_success}')
|
||||
|
||||
|
||||
test = TestDynamicSliceInstanceSpawner()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks)
|
||||
|
||||
+95
-79
@@ -5,99 +5,115 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.components as components
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
level_created = (
|
||||
"Successfully created level",
|
||||
"Failed to create level"
|
||||
)
|
||||
spawner_entity_created = (
|
||||
"Spawner entity created successfully",
|
||||
"Failed to create spawner entity"
|
||||
)
|
||||
surface_entity_created = (
|
||||
"Surface entity created successfully",
|
||||
"Failed to create surface entity"
|
||||
)
|
||||
instance_count = (
|
||||
"Found the expected number of instances",
|
||||
"Found an unexpected number of instances"
|
||||
)
|
||||
saved_and_exported = (
|
||||
"Saved and exported level successfully",
|
||||
"Failed to save and export level"
|
||||
)
|
||||
|
||||
|
||||
class TestDynamicSliceInstanceSpawnerEmbeddedEditor(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawnerEmbeddedEditor", args=["level"])
|
||||
def DynamicSliceInstanceSpawner_Embedded_E2E():
|
||||
"""
|
||||
Summary:
|
||||
A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
|
||||
Dynamic Slice Instance Spawner type.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
|
||||
Dynamic Slice Instance Spawner type.
|
||||
Expected Behavior:
|
||||
Instances plant as expected in the assigned area.
|
||||
|
||||
Expected Behavior:
|
||||
Instances plant as expected in the assigned area.
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
|
||||
3) Create a surface to plant on
|
||||
4) Verify expected instance counts
|
||||
5) Add a camera component looking at the planting area for visual debugging
|
||||
6) Save and export to engine
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
|
||||
3) Create a surface to plant on
|
||||
4) Verify expected instance counts
|
||||
5) Add a camera component looking at the planting area for visual debugging
|
||||
6) Save and export to engine
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths as paths
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, asset_path)
|
||||
spawner_entity.add_component("Script Canvas")
|
||||
instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
|
||||
instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
|
||||
math.Uuid(), False)
|
||||
spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
|
||||
# 1) Create a new, temporary level
|
||||
lvl_name = "tmp_level"
|
||||
helper.init_idle()
|
||||
level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
|
||||
general.idle_wait(1.0)
|
||||
Report.critical_result(Tests.level_created, level_created == 0)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 3) Create a surface to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 128.0, 128.0, 1.0)
|
||||
# 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, asset_path)
|
||||
spawner_entity.add_component("Script Canvas")
|
||||
instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
|
||||
instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
|
||||
math.Uuid(), False)
|
||||
spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
|
||||
Report.result(Tests.spawner_entity_created, spawner_entity.id.IsValid() and hydra.has_components(spawner_entity.id,
|
||||
["Script Canvas"]))
|
||||
|
||||
# 4) Verify instance counts are accurate
|
||||
general.idle_wait(3.0) # Allow a few seconds for instances to spawn
|
||||
num_expected_instances = 20 * 20
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
|
||||
self.test_success = self.test_success and num_found == num_expected_instances
|
||||
# 3) Create a surface to plant on
|
||||
surface_entity = dynveg.create_surface_entity("Planting Surface", center_point, 128.0, 128.0, 1.0)
|
||||
Report.result(Tests.surface_entity_created, surface_entity.id.IsValid())
|
||||
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
# 4) Verify instance counts are accurate
|
||||
num_expected_instances = 20 * 20
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected_instances), 5.0)
|
||||
Report.result(Tests.instance_count, success)
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.idle_wait(1.0)
|
||||
general.export_to_engine()
|
||||
general.idle_wait(1.0)
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.export_to_engine()
|
||||
pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
|
||||
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
|
||||
|
||||
|
||||
test = TestDynamicSliceInstanceSpawnerEmbeddedEditor()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(DynamicSliceInstanceSpawner_Embedded_E2E)
|
||||
|
||||
+114
-99
@@ -5,122 +5,137 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
level_created = (
|
||||
"Successfully created level",
|
||||
"Failed to create level"
|
||||
)
|
||||
spawner_entity_created = (
|
||||
"Spawner entity created successfully",
|
||||
"Failed to create spawner entity"
|
||||
)
|
||||
surface_entity_created = (
|
||||
"Surface entity created successfully",
|
||||
"Failed to create surface entity"
|
||||
)
|
||||
instance_count = (
|
||||
"Found the expected number of instances",
|
||||
"Found an unexpected number of instances"
|
||||
)
|
||||
saved_and_exported = (
|
||||
"Saved and exported level successfully",
|
||||
"Failed to save and export level"
|
||||
)
|
||||
|
||||
|
||||
class TestDynamicSliceInstanceSpawnerExternalEditor(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawnerExternalEditor", args=["level"])
|
||||
def DynamicSliceInstanceSpawner_External_E2E():
|
||||
"""
|
||||
Summary:
|
||||
A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
|
||||
Dynamic Slice Instance Spawner type using external assets.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
|
||||
Dynamic Slice Instance Spawner type using external assets.
|
||||
Expected Behavior:
|
||||
Instances plant as expected in the assigned area.
|
||||
|
||||
Expected Behavior:
|
||||
Instances plant as expected in the assigned area.
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
|
||||
3) Create a surface to plant on
|
||||
4) Verify expected instance counts
|
||||
5) Add a camera component looking at the planting area for visual debugging
|
||||
6) Save and export to engine
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
|
||||
3) Create a surface to plant on
|
||||
4) Verify expected instance counts
|
||||
5) Add a camera component looking at the planting area for visual debugging
|
||||
6) Save and export to engine
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.components as components
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths as paths
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components and switch the Vegetation Asset List Source
|
||||
# Type to External
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
veg_area_required_components = ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List",
|
||||
"Script Canvas"]
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
|
||||
)
|
||||
if new_entity_id.IsValid():
|
||||
self.log("Spawner entity created")
|
||||
spawner_entity = hydra.Entity("Spawner Entity", new_entity_id)
|
||||
spawner_entity.components = []
|
||||
for component in veg_area_required_components:
|
||||
spawner_entity.components.append(hydra.add_component(component, new_entity_id))
|
||||
hydra.get_set_test(spawner_entity, 2, "Configuration|Source Type", 1)
|
||||
# 1) Create a new, temporary level
|
||||
lvl_name = "tmp_level"
|
||||
helper.init_idle()
|
||||
level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
|
||||
general.idle_wait(1.0)
|
||||
Report.critical_result(Tests.level_created, level_created == 0)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Add a Script Canvas component with instance_counter script for launcher tests
|
||||
instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
|
||||
instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
|
||||
math.Uuid(), False)
|
||||
spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
|
||||
# 2) Create a new entity with required vegetation area components and switch the Vegetation Asset List Source
|
||||
# Type to External
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
veg_area_required_components = ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List",
|
||||
"Script Canvas"]
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
|
||||
)
|
||||
spawner_entity = hydra.Entity("Spawner Entity", new_entity_id)
|
||||
spawner_entity.components = []
|
||||
for component in veg_area_required_components:
|
||||
spawner_entity.components.append(hydra.add_component(component, new_entity_id))
|
||||
hydra.get_set_test(spawner_entity, 2, "Configuration|Source Type", 1)
|
||||
|
||||
# Assign a Vegetation Descriptor List asset to the Vegetation Asset List component
|
||||
descriptor_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("Assets", "VegDescriptorLists", "flower_pink.vegdescriptorlist"), math.Uuid(),
|
||||
False)
|
||||
hydra.get_set_test(spawner_entity, 2, "Configuration|External Assets", descriptor_asset)
|
||||
# Add a Script Canvas component with instance_counter script for launcher tests
|
||||
instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
|
||||
instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
|
||||
math.Uuid(), False)
|
||||
spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
|
||||
Report.result(Tests.spawner_entity_created, spawner_entity.id.IsValid() and hydra.has_components(spawner_entity.id,
|
||||
["Script Canvas"]))
|
||||
|
||||
# Resize the Box Shape component
|
||||
new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
|
||||
box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
|
||||
hydra.get_set_test(spawner_entity, 1, box_dimensions_path, new_box_dimensions)
|
||||
# Assign a Vegetation Descriptor List asset to the Vegetation Asset List component
|
||||
descriptor_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("Assets", "VegDescriptorLists", "flower_pink.vegdescriptorlist"), math.Uuid(),
|
||||
False)
|
||||
hydra.get_set_test(spawner_entity, 2, "Configuration|External Assets", descriptor_asset)
|
||||
|
||||
# 3) Create a surface to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", entity_position, 128.0, 128.0, 1.0)
|
||||
# Resize the Box Shape component
|
||||
new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
|
||||
box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
|
||||
hydra.get_set_test(spawner_entity, 1, box_dimensions_path, new_box_dimensions)
|
||||
|
||||
# 4) Verify instance counts are accurate
|
||||
general.idle_wait(3.0) # Allow a few seconds for instances to spawn
|
||||
num_expected_instances = 20 * 20
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
|
||||
self.test_success = self.test_success and num_found == num_expected_instances
|
||||
# 3) Create a surface to plant on
|
||||
surface_entity = dynveg.create_surface_entity("Planting Surface", entity_position, 128.0, 128.0, 1.0)
|
||||
Report.result(Tests.surface_entity_created, surface_entity.id.IsValid())
|
||||
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
# 4) Verify instance counts are accurate
|
||||
num_expected_instances = 20 * 20
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected_instances), 5.0)
|
||||
Report.result(Tests.instance_count, success)
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.idle_wait(1.0)
|
||||
general.export_to_engine()
|
||||
general.idle_wait(1.0)
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.export_to_engine()
|
||||
pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
|
||||
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
|
||||
|
||||
|
||||
test = TestDynamicSliceInstanceSpawnerExternalEditor()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(DynamicSliceInstanceSpawner_External_E2E)
|
||||
|
||||
+114
-92
@@ -5,109 +5,131 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class BehaviorContextTests:
|
||||
spawner_initialized = (
|
||||
"Successfully initialized an Empty Instance Spawner",
|
||||
"Failed to initialize an Empty Instance Spawner"
|
||||
)
|
||||
desc_spawnertype_sets_spawner = (
|
||||
"Setting spawnerType sets spawner too",
|
||||
"Setting spawnerType failed to set spawner to expected value"
|
||||
)
|
||||
desc_spawner_sets_spawnertype = (
|
||||
"Setting spawner sets spawnerType too",
|
||||
"Setting spawner failed to set spawnerType to expected value"
|
||||
)
|
||||
|
||||
|
||||
class TestEmptyInstanceSpawner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="EmptyInstanceSpawner", args=["level"])
|
||||
class PropertyTreeTests:
|
||||
entity_created = (
|
||||
"Spawner entity created successfully",
|
||||
"Failed to create spawner entity"
|
||||
)
|
||||
spawner_type_set = (
|
||||
"Successfully set spawner type",
|
||||
"Failed to set spawner type"
|
||||
)
|
||||
empty_instance_count_validation = (
|
||||
"Expected number of empty instances planted",
|
||||
"Unexpected number of empty instances planted"
|
||||
)
|
||||
not_affected_by_allow_empty_assets = (
|
||||
"Instance count unaffected by Allow Empty Assets toggle",
|
||||
"Instance count was unexpectedly affected by Allow Empty Assets toggle"
|
||||
)
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Test aspects of the EmptyInstanceSpawner through the BehaviorContext and the Property Tree.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
# 1) Open an empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
def EmptyInstanceSpawner_EmptySpawnerWorks():
|
||||
"""
|
||||
Summary:
|
||||
Test aspects of the EmptyInstanceSpawner through the BehaviorContext and the Property Tree.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Grab the UUID that we need for creating an Empty Spawner
|
||||
empty_spawner_uuid = azlmbr.math.Uuid_CreateString('{23C40FD4-A55F-4BD3-BE5B-DC5423F217C2}', 0)
|
||||
|
||||
# 2) Test EmptyInstanceSpawner BehaviorContext
|
||||
behavior_context_test_success = True
|
||||
empty_spawner = azlmbr.vegetation.EmptyInstanceSpawner()
|
||||
behavior_context_test_success = behavior_context_test_success and (empty_spawner is not None)
|
||||
behavior_context_test_success = behavior_context_test_success and (empty_spawner.typename == 'EmptyInstanceSpawner')
|
||||
Report.critical_result(BehaviorContextTests.spawner_initialized, behavior_context_test_success)
|
||||
Report.info(f'EmptyInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
|
||||
|
||||
# 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
|
||||
spawner_type_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', empty_spawner_uuid)
|
||||
spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
|
||||
Report.result(BehaviorContextTests.desc_spawnertype_sets_spawner, spawner_type_test_success)
|
||||
Report.info(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
|
||||
|
||||
# 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
|
||||
spawner_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
descriptor.spawner = empty_spawner
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(empty_spawner_uuid))
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
|
||||
Report.result(BehaviorContextTests.desc_spawner_sets_spawnertype, spawner_test_success)
|
||||
Report.info(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
|
||||
|
||||
### Setup for Property Tree set of tests
|
||||
|
||||
# Create a new entity with required vegetation area components
|
||||
spawner_entity = hydra.Entity("Veg Area")
|
||||
spawner_entity.create_entity(
|
||||
math.Vector3(512.0, 512.0, 32.0),
|
||||
["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
|
||||
)
|
||||
general.idle_wait(1.0)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
Report.critical_result(PropertyTreeTests.entity_created, spawner_entity.id.IsValid())
|
||||
|
||||
# Grab the UUID that we need for creating an Empty Spawner
|
||||
empty_spawner_uuid = azlmbr.math.Uuid_CreateString('{23C40FD4-A55F-4BD3-BE5B-DC5423F217C2}', 0)
|
||||
# Resize the Box Shape component
|
||||
new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
|
||||
box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
|
||||
spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
|
||||
|
||||
# 2) Test EmptyInstanceSpawner BehaviorContext
|
||||
behavior_context_test_success = True
|
||||
empty_spawner = azlmbr.vegetation.EmptyInstanceSpawner()
|
||||
behavior_context_test_success = behavior_context_test_success and (empty_spawner is not None)
|
||||
behavior_context_test_success = behavior_context_test_success and (empty_spawner.typename == 'EmptyInstanceSpawner')
|
||||
self.test_success = self.test_success and behavior_context_test_success
|
||||
self.log(f'EmptyInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
|
||||
# Create a surface to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
|
||||
|
||||
# 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
|
||||
spawner_type_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', empty_spawner_uuid)
|
||||
spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
|
||||
self.test_success = self.test_success and spawner_type_test_success
|
||||
self.log(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
|
||||
# 5) Descriptor Property Tree test: spawner type can be set
|
||||
|
||||
# 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
|
||||
spawner_test_success = True
|
||||
descriptor = azlmbr.vegetation.Descriptor()
|
||||
descriptor.spawner = empty_spawner
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(empty_spawner_uuid))
|
||||
spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
|
||||
self.test_success = self.test_success and spawner_test_success
|
||||
self.log(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
|
||||
# - Validate the empty spawner type can be set correctly.
|
||||
property_tree_success = True
|
||||
property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', empty_spawner_uuid)
|
||||
Report.result(PropertyTreeTests.spawner_type_set, property_tree_success)
|
||||
|
||||
### Setup for Property Tree set of tests
|
||||
# This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
|
||||
# 20 instances per 16 meters
|
||||
num_expected_instances = 20 * 20
|
||||
property_tree_success = property_tree_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
Report.result(PropertyTreeTests.empty_instance_count_validation, property_tree_success)
|
||||
Report.info(f'Property Tree spawner type test: {property_tree_success}')
|
||||
|
||||
# Create a new entity with required vegetation area components
|
||||
spawner_entity = hydra.Entity("Veg Area")
|
||||
spawner_entity.create_entity(
|
||||
math.Vector3(512.0, 512.0, 32.0),
|
||||
["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
|
||||
)
|
||||
if spawner_entity.id.IsValid():
|
||||
self.log(f"'{spawner_entity.name}' created")
|
||||
|
||||
# Resize the Box Shape component
|
||||
new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
|
||||
box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
|
||||
spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
|
||||
|
||||
# Create a surface to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
|
||||
|
||||
# 5) Descriptor Property Tree test: spawner type can be set
|
||||
|
||||
# - Validate the empty spawner type can be set correctly.
|
||||
property_tree_success = True
|
||||
property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', empty_spawner_uuid)
|
||||
|
||||
# This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
|
||||
# 20 instances per 16 meters
|
||||
num_expected_instances = 20 * 20
|
||||
property_tree_success = property_tree_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and property_tree_success
|
||||
self.log(f'Property Tree spawner type test: {property_tree_success}')
|
||||
|
||||
# 6) Validate that the "Allow Empty Assets" setting doesn't affect the EmptyInstanceSpawner
|
||||
allow_empty_assets_success = True
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
allow_empty_assets_success = allow_empty_assets_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and allow_empty_assets_success
|
||||
self.log(f'Allow Empty Assets test: {allow_empty_assets_success}')
|
||||
# 6) Validate that the "Allow Empty Assets" setting doesn't affect the EmptyInstanceSpawner
|
||||
allow_empty_assets_success = True
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
allow_empty_assets_success = allow_empty_assets_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
Report.result(PropertyTreeTests.not_affected_by_allow_empty_assets, allow_empty_assets_success)
|
||||
Report.info(f'Allow Empty Assets test: {allow_empty_assets_success}')
|
||||
|
||||
|
||||
test = TestEmptyInstanceSpawner()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(EmptyInstanceSpawner_EmptySpawnerWorks)
|
||||
|
||||
+93
-89
@@ -5,111 +5,115 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.vegetation as vegetation
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
initial_instance_count = (
|
||||
"Initial instance count is as expected",
|
||||
"Initial instance count does not match expected results"
|
||||
)
|
||||
layer_priority_instance_count = (
|
||||
"Instance count is as expected after updating layer priorities",
|
||||
"Instance count does not match expected results after updating layer priorities"
|
||||
)
|
||||
sub_priority_instance_count = (
|
||||
"Instance count is as expected after updating sub priorities",
|
||||
"Instance count does not match expected results after updating sub priorities"
|
||||
)
|
||||
|
||||
|
||||
class TestInstanceSpawnerPriority(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="InstanceSpawnerPriority", args=["level"])
|
||||
def InstanceSpawnerPriority_LayerAndSubPriority():
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. An instance spawner area and blocker area are setup to overlap. Instance counts are
|
||||
verified with the initial setup. Layer priority on the blocker area is set to lower than the instance spawner
|
||||
area, and instance counts are re-verified.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. An instance spawner area and blocker area are setup to overlap. Instance counts are
|
||||
verified with the initial setup. Layer priority on the blocker area is set to lower than the instance spawner
|
||||
area, and instance counts are re-verified.
|
||||
Expected Behavior:
|
||||
Vegetation areas with a higher Layer Priority plant over those with a lower Layer Priority
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation areas with a higher Layer Priority plant over those with a lower Layer Priority
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create overlapping instance spawner and blocker areas
|
||||
3) Create a surface to plant on
|
||||
4) Validate initial instance counts in the spawner area
|
||||
5) Reduce the Layer Priority of the blocker area
|
||||
6) Validate instance counts in the spawner area
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level
|
||||
2) Create overlapping instance spawner and blocker areas
|
||||
3) Create a surface to plant on
|
||||
4) Validate initial instance counts in the spawner area
|
||||
5) Reduce the Layer Priority of the blocker area
|
||||
6) Validate instance counts in the spawner area
|
||||
|
||||
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.
|
||||
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
|
||||
"""
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import os
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
# 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
|
||||
spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0,
|
||||
asset_path)
|
||||
blocker_center_point = math.Vector3(516.0, 516.0, 32.0)
|
||||
blocker_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 3) Create a surface for planting
|
||||
planting_surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Planting Surface", planting_surface_center_point, 64.0, 64.0, 1.0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 4) Validate the expected instance count with initial setup. GetAreaProductCount is used as
|
||||
# GetInstanceCountInAabb does not filter out blocked instances
|
||||
num_expected = (20 * 20) - (10 * 10) # 20 instances per 16m per side minus 1 blocked quadrant
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = self.test_success and result
|
||||
# 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
|
||||
spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0,
|
||||
asset_path)
|
||||
blocker_center_point = math.Vector3(516.0, 516.0, 32.0)
|
||||
blocker_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0)
|
||||
|
||||
# 5) Change the Instance Spawner area to a higher layer priority than the Instance Blocker
|
||||
blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 0)
|
||||
# 3) Create a surface for planting
|
||||
planting_surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Planting Surface", planting_surface_center_point, 64.0, 64.0, 1.0)
|
||||
|
||||
# 6) Validate the expected instance count with changed area priorities
|
||||
num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = self.test_success and result
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
|
||||
# 7) Revert Layer Priority changes so both areas are equal, and change Sub Priority to a higher value on the
|
||||
# Instance Spawner area
|
||||
blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 1)
|
||||
spawner_entity.get_set_test(0, 'Configuration|Sub Priority', 100)
|
||||
blocker_entity.get_set_test(0, 'Configuration|Sub Priority', 1)
|
||||
# 4) Validate the expected instance count with initial setup. GetAreaProductCount is used as
|
||||
# GetInstanceCountInAabb does not filter out blocked instances
|
||||
num_expected = (20 * 20) - (10 * 10) # 20 instances per 16m per side minus 1 blocked quadrant
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.initial_instance_count, result)
|
||||
|
||||
# 8) Validate the expected instance count with changed area priorities
|
||||
num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = self.test_success and result
|
||||
# 5) Change the Instance Spawner area to a higher layer priority than the Instance Blocker
|
||||
blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 0)
|
||||
|
||||
# 6) Validate the expected instance count with changed area priorities
|
||||
num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.layer_priority_instance_count, result)
|
||||
|
||||
# 7) Revert Layer Priority changes so both areas are equal, and change Sub Priority to a higher value on the
|
||||
# Instance Spawner area
|
||||
blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 1)
|
||||
spawner_entity.get_set_test(0, 'Configuration|Sub Priority', 100)
|
||||
blocker_entity.get_set_test(0, 'Configuration|Sub Priority', 1)
|
||||
|
||||
# 8) Validate the expected instance count with changed area priorities
|
||||
num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.sub_priority_instance_count, result)
|
||||
|
||||
|
||||
test = TestInstanceSpawnerPriority()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(InstanceSpawnerPriority_LayerAndSubPriority)
|
||||
|
||||
+135
-125
@@ -5,151 +5,161 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
C2627906: A simple Vegetation Layer Blender area can be created
|
||||
"""
|
||||
|
||||
import os
|
||||
from math import radians
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.math as math
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
level_created = (
|
||||
"Successfully created level",
|
||||
"Failed to create level"
|
||||
)
|
||||
blender_entity_created = (
|
||||
"Blender entity created successfully",
|
||||
"Failed to create Blender entity"
|
||||
)
|
||||
instance_count = (
|
||||
"Found the expected number of instances in the Blender area",
|
||||
"Found an unexpected number of instances in the Blender area"
|
||||
)
|
||||
instances_blended = (
|
||||
"Instances from each spawner are blended as expected",
|
||||
"Found an unexpected number of instances from each spawner"
|
||||
)
|
||||
saved_and_exported = (
|
||||
"Saved and exported level successfully",
|
||||
"Failed to save and export level"
|
||||
)
|
||||
|
||||
|
||||
class TestVegLayerBlenderCreated(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerBlender_E2E_Editor", args=["level"])
|
||||
self.screenshot_count = 0
|
||||
def LayerBlender_E2E_Editor():
|
||||
"""
|
||||
Summary:
|
||||
A temporary level is loaded. Two vegetation areas with different meshes are added and then
|
||||
pinned to a vegetation blender. Screenshots are taken in the editor normal mode and in game mode.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A temporary level is loaded. Two vegetation areas with different meshes are added and then
|
||||
pinned to a vegetation blender. Screenshots are taken in the editor normal mode and in game mode.
|
||||
Expected Behavior:
|
||||
The specified assets plant in the specified blend area and are visible in the Viewport in
|
||||
Edit Mode, Game Mode.
|
||||
|
||||
Expected Behavior:
|
||||
The specified assets plant in the specified blend area and are visible in the Viewport in
|
||||
Edit Mode, Game Mode.
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create 2 vegetation areas with different meshes
|
||||
3) Create Blender entity and pin the vegetation areas
|
||||
4) Take screenshot in normal mode
|
||||
5) Create a new entity with a Camera component for testing in the launcher
|
||||
6) Save level and take screenshot in game mode
|
||||
7) Export to engine
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create 2 vegetation areas with different meshes
|
||||
3) Create Blender entity and pin the vegetation areas
|
||||
4) Take screenshot in normal mode
|
||||
5) Create a new entity with a Camera component for testing in the launcher
|
||||
6) Save level and take screenshot in game mode
|
||||
7) Export to engine
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
from math import radians
|
||||
|
||||
# 1) Create/prepare a new level and set an appropriate view of blender area
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.paths as paths
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.math as math
|
||||
import azlmbr.entity as entity
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create 2 vegetation areas with different meshes
|
||||
purple_position = math.Vector3(504.0, 512.0, 32.0)
|
||||
purple_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity_1 = dynveg.create_vegetation_area("Purple Spawner",
|
||||
purple_position,
|
||||
16.0, 16.0, 1.0,
|
||||
purple_asset_path)
|
||||
# 1) Create a new, temporary level
|
||||
lvl_name = "tmp_level"
|
||||
helper.init_idle()
|
||||
level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
|
||||
general.idle_wait(1.0)
|
||||
Report.critical_result(Tests.level_created, level_created == 0)
|
||||
|
||||
pink_position = math.Vector3(520.0, 512.0, 32.0)
|
||||
pink_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity_2 = dynveg.create_vegetation_area("Pink Spawner",
|
||||
pink_position,
|
||||
16.0, 16.0, 1.0,
|
||||
pink_asset_path)
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
base_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Surface Entity",
|
||||
base_position,
|
||||
16.0, 16.0, 1.0)
|
||||
# 2) Create 2 vegetation areas with different meshes
|
||||
purple_position = math.Vector3(504.0, 512.0, 32.0)
|
||||
purple_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity_1 = dynveg.create_vegetation_area("Purple Spawner",
|
||||
purple_position,
|
||||
16.0, 16.0, 1.0,
|
||||
purple_asset_path)
|
||||
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
pink_position = math.Vector3(520.0, 512.0, 32.0)
|
||||
pink_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity_2 = dynveg.create_vegetation_area("Pink Spawner",
|
||||
pink_position,
|
||||
16.0, 16.0, 1.0,
|
||||
pink_asset_path)
|
||||
|
||||
# 3) Create Blender entity and pin the vegetation areas. We also add and attach a Lua script to validate in the
|
||||
# launcher for the follow-up test
|
||||
blender_entity = hydra.Entity("Blender")
|
||||
blender_entity.create_entity(
|
||||
base_position,
|
||||
["Box Shape", "Vegetation Layer Blender", "Lua Script"]
|
||||
)
|
||||
if blender_entity.id.IsValid():
|
||||
print(f"'{blender_entity.name}' created")
|
||||
base_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Surface Entity",
|
||||
base_position,
|
||||
16.0, 16.0, 1.0)
|
||||
|
||||
blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
|
||||
blender_entity.get_set_test(1, "Configuration|Vegetation Areas", [spawner_entity_1.id, spawner_entity_2.id])
|
||||
instance_counter_path = os.path.join("luascripts", "instance_counter_blender.lua")
|
||||
instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
|
||||
math.Uuid(), False)
|
||||
blender_entity.get_set_test(2, "Script properties|Asset", instance_counter_script)
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 4) Verify instances in blender area are equally represented by both descriptors
|
||||
# 3) Create Blender entity and pin the vegetation areas. We also add and attach a Lua script to validate in the
|
||||
# launcher for the follow-up test
|
||||
blender_entity = hydra.Entity("Blender")
|
||||
blender_entity.create_entity(
|
||||
base_position,
|
||||
["Box Shape", "Vegetation Layer Blender", "Lua Script"]
|
||||
)
|
||||
Report.result(Tests.blender_entity_created, blender_entity.id.IsValid())
|
||||
|
||||
# Wait for instances to spawn
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
num_expected = 20 * 20
|
||||
self.test_success = self.test_success and self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count(base_position, 8.0, num_expected), 5.0)
|
||||
blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
|
||||
blender_entity.get_set_test(1, "Configuration|Vegetation Areas", [spawner_entity_1.id, spawner_entity_2.id])
|
||||
instance_counter_path = os.path.join("luascripts", "instance_counter_blender.lua")
|
||||
instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
|
||||
math.Uuid(), False)
|
||||
blender_entity.get_set_test(2, "Script properties|Asset", instance_counter_script)
|
||||
|
||||
if self.test_success:
|
||||
box = math.Aabb_CreateCenterRadius(base_position, 8.0)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
pink_count = 0
|
||||
purple_count = 0
|
||||
for instance in instances:
|
||||
purple_asset_path = purple_asset_path.replace("\\", "/").lower()
|
||||
pink_asset_path = pink_asset_path.replace("\\", "/").lower()
|
||||
if instance.descriptor.spawner.GetSliceAssetPath() == pink_asset_path:
|
||||
pink_count += 1
|
||||
elif instance.descriptor.spawner.GetSliceAssetPath() == purple_asset_path:
|
||||
purple_count += 1
|
||||
self.test_success = pink_count == purple_count and (pink_count + purple_count == num_expected) and self.test_success
|
||||
# 4) Verify instances in blender area are equally represented by both descriptors
|
||||
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(500.0, 500.0, 47.0)
|
||||
cam_rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", search_entity_ids[0], cam_rot_degrees_vector)
|
||||
# Wait for instances to spawn
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
num_expected = 20 * 20
|
||||
success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count(base_position, 8.0, num_expected), 5.0)
|
||||
Report.critical_result(Tests.instance_count, success)
|
||||
|
||||
# 6) Save and export level
|
||||
general.save_level()
|
||||
general.idle_wait(1.0)
|
||||
general.export_to_engine()
|
||||
general.idle_wait(1.0)
|
||||
box = math.Aabb_CreateCenterRadius(base_position, 8.0)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
pink_count = 0
|
||||
purple_count = 0
|
||||
for instance in instances:
|
||||
purple_asset_path = purple_asset_path.replace("\\", "/").lower()
|
||||
pink_asset_path = pink_asset_path.replace("\\", "/").lower()
|
||||
if instance.descriptor.spawner.GetSliceAssetPath() == pink_asset_path:
|
||||
pink_count += 1
|
||||
elif instance.descriptor.spawner.GetSliceAssetPath() == purple_asset_path:
|
||||
purple_count += 1
|
||||
Report.result(Tests.instances_blended, pink_count == purple_count and (pink_count + purple_count == num_expected))
|
||||
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(500.0, 500.0, 47.0)
|
||||
cam_rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", search_entity_ids[0], cam_rot_degrees_vector)
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.export_to_engine()
|
||||
pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
|
||||
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
|
||||
|
||||
|
||||
test = TestVegLayerBlenderCreated()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(LayerBlender_E2E_Editor)
|
||||
|
||||
+84
-81
@@ -5,102 +5,105 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
initial_instance_count = (
|
||||
"Initial instance count is as expected",
|
||||
"Unexpected number of initial instances found"
|
||||
)
|
||||
blocked_instance_count = (
|
||||
"Expected number of instances found after configuring Blocker",
|
||||
"Unexpected number of instances found after configuring Blocker"
|
||||
)
|
||||
|
||||
|
||||
class TestLayerBlocker(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerBlocker_InstancesBlocked", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
An empty level is created. A Vegetation Layer Spawner area is configured. A Vegetation Layer Blocker area is
|
||||
configured to block instances in the spawner area.
|
||||
def LayerBlocker_InstancesBlockedInConfiguredArea():
|
||||
"""
|
||||
Summary:
|
||||
An empty level is created. A Vegetation Layer Spawner area is configured. A Vegetation Layer Blocker area is
|
||||
configured to block instances in the spawner area.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation is blocked by the configured Blocker area.
|
||||
Expected Behavior:
|
||||
Vegetation is blocked by the configured Blocker area.
|
||||
|
||||
Test Steps:
|
||||
1. A new level is created
|
||||
2. Vegetation Layer Spawner area is created
|
||||
3. Planting surface is created
|
||||
4. Vegetation System Settings level component is added, and Snap Mode set to center to ensure expected instance
|
||||
counts are accurate in the configured vegetation area
|
||||
5. Initial instance counts pre-blocker are validated
|
||||
6. A Vegetation Layer Blocker area is created, overlapping the spawner area
|
||||
7. Post-blocker instance counts are validated
|
||||
Test Steps:
|
||||
1. A simple level is opened
|
||||
2. Vegetation Layer Spawner area is created
|
||||
3. Planting surface is created
|
||||
4. Vegetation System Settings level component is added, and Snap Mode set to center to ensure expected instance
|
||||
counts are accurate in the configured vegetation area
|
||||
5. Initial instance counts pre-blocker are validated
|
||||
6. A Vegetation Layer Blocker area is created, overlapping the spawner area
|
||||
7. Post-blocker instance counts are validated
|
||||
|
||||
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.
|
||||
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
|
||||
"""
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import os
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
# 2) Create a new instance spawner entity
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 3) Create surface for planting on
|
||||
dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 5) Verify initial instance counts
|
||||
num_expected = 20 * 20
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
# 2) Create a new instance spawner entity
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
|
||||
# 6) Create a new Vegetation Layer Blocker area overlapping the spawner area
|
||||
blocker_entity = hydra.Entity("Blocker Area")
|
||||
blocker_entity.create_entity(
|
||||
spawner_center_point,
|
||||
["Vegetation Layer Blocker", "Box Shape"]
|
||||
)
|
||||
if blocker_entity.id.IsValid():
|
||||
print(f"'{blocker_entity.name}' created")
|
||||
blocker_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions",
|
||||
math.Vector3(3.0, 3.0, 3.0))
|
||||
# 3) Create surface for planting on
|
||||
dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# 7) Validate instance counts post-blocker. 16 instances should now be blocked in the center of the spawner area
|
||||
num_expected = (20 * 20) - 16
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
# 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
|
||||
# 5) Verify initial instance counts
|
||||
num_expected = 20 * 20
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.initial_instance_count, success)
|
||||
|
||||
# 6) Create a new Vegetation Layer Blocker area overlapping the spawner area
|
||||
blocker_entity = hydra.Entity("Blocker Area")
|
||||
blocker_entity.create_entity(
|
||||
spawner_center_point,
|
||||
["Vegetation Layer Blocker", "Box Shape"]
|
||||
)
|
||||
if blocker_entity.id.IsValid():
|
||||
print(f"'{blocker_entity.name}' created")
|
||||
blocker_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions",
|
||||
math.Vector3(3.0, 3.0, 3.0))
|
||||
|
||||
# 7) Validate instance counts post-blocker. 16 instances should now be blocked in the center of the spawner area
|
||||
num_expected = (20 * 20) - 16
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.blocked_instance_count, success)
|
||||
|
||||
|
||||
test = TestLayerBlocker()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(LayerBlocker_InstancesBlockedInConfiguredArea)
|
||||
|
||||
+63
-65
@@ -5,85 +5,83 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
preprocess_instance_count = (
|
||||
"Preprocess filter stage vegetation instance count is as expected",
|
||||
"Preprocess filter stage instance count found an unexpected number of instances"
|
||||
)
|
||||
postprocess_instance_count = (
|
||||
"Postprocess filter stage vegetation instance count is as expected",
|
||||
"Postprocess filter stage instance count found an unexpected number of instances"
|
||||
)
|
||||
|
||||
|
||||
class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerSpawner_FilterStageToggle", args=["level"])
|
||||
def LayerSpawner_FilterStageToggle():
|
||||
"""
|
||||
Summary:
|
||||
Filter Stage toggle affects final vegetation position.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
C4765973 Filter Stage toggle affects final vegetation position.
|
||||
Expected Result:
|
||||
Vegetation instances plant differently depending on the Filter Stage setting.
|
||||
|
||||
Expected Result:
|
||||
Vegetation instances plant differently depending on the Filter Stage setting.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
PREPROCESS_INSTANCE_COUNT = 21
|
||||
POSTPROCESS_INSTANCE_COUNT = 19
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Create empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
PREPROCESS_INSTANCE_COUNT = 21
|
||||
POSTPROCESS_INSTANCE_COUNT = 19
|
||||
|
||||
# Create a vegetation area with all needed components
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
vegetation_entity = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
|
||||
vegetation_entity.add_component("Vegetation Altitude Filter")
|
||||
vegetation_entity.add_component("Vegetation Position Modifier")
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Create a child entity under vegetation area
|
||||
child_entity = hydra.Entity("child_entity")
|
||||
components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"]
|
||||
child_entity.create_entity(position, components_to_add, vegetation_entity.id)
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# Set the Gradient Id in X and Y direction
|
||||
vegetation_entity.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", child_entity.id)
|
||||
vegetation_entity.get_set_test(4, "Configuration|Position Y|Gradient|Gradient Entity Id", child_entity.id)
|
||||
# Create a vegetation area with all needed components
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
vegetation_entity = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
|
||||
vegetation_entity.add_component("Vegetation Altitude Filter")
|
||||
vegetation_entity.add_component("Vegetation Position Modifier")
|
||||
|
||||
# Set the min and max values for Altitude Filter
|
||||
vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 34.0)
|
||||
vegetation_entity.get_set_test(3, "Configuration|Altitude Max", 38.0)
|
||||
# Create a child entity under vegetation area
|
||||
child_entity = hydra.Entity("child_entity")
|
||||
components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"]
|
||||
child_entity.create_entity(position, components_to_add, vegetation_entity.id)
|
||||
|
||||
# Add entity with Mesh to replicate creation of hills and a flat surface to plant on
|
||||
dynveg.create_surface_entity("Flat Surface", position, 32.0, 32.0, 1.0)
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0)
|
||||
# Set the Gradient Id in X and Y direction
|
||||
vegetation_entity.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", child_entity.id)
|
||||
vegetation_entity.get_set_test(4, "Configuration|Position Y|Gradient|Gradient Entity Id", child_entity.id)
|
||||
|
||||
# Set the filter stage to preprocess and postprocess respectively and verify instance count
|
||||
vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1)
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, PREPROCESS_INSTANCE_COUNT), 3.0)
|
||||
result = dynveg.validate_instance_count(position, 16.0, PREPROCESS_INSTANCE_COUNT)
|
||||
self.log(f"Preprocess filter stage vegetation instance count is as expected: {result}")
|
||||
vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 2)
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, POSTPROCESS_INSTANCE_COUNT), 3.0)
|
||||
result = dynveg.validate_instance_count(position, 16.0, POSTPROCESS_INSTANCE_COUNT)
|
||||
self.log(f"Postprocess filter vegetation instance stage count is as expected: {result}")
|
||||
# Set the min and max values for Altitude Filter
|
||||
vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 34.0)
|
||||
vegetation_entity.get_set_test(3, "Configuration|Altitude Max", 38.0)
|
||||
|
||||
# Add entity with Mesh to replicate creation of hills and a flat surface to plant on
|
||||
dynveg.create_surface_entity("Flat Surface", position, 32.0, 32.0, 1.0)
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0)
|
||||
|
||||
# Set the filter stage to preprocess and postprocess respectively and verify instance count
|
||||
vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, PREPROCESS_INSTANCE_COUNT), 3.0)
|
||||
Report.result(Tests.preprocess_instance_count, result)
|
||||
vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 2)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, POSTPROCESS_INSTANCE_COUNT), 3.0)
|
||||
Report.result(Tests.postprocess_instance_count, result)
|
||||
|
||||
|
||||
test = TestLayerSpawnerFilterStageToggle()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(LayerSpawner_FilterStageToggle)
|
||||
|
||||
+92
-94
@@ -5,118 +5,116 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.paths
|
||||
import azlmbr.surface_data as surface_data
|
||||
import azlmbr.vegetation as vegetation
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
inherit_behavior_checked = (
|
||||
"Found no instances with Inherit Behavior checked as expected",
|
||||
"Unexpectedly found instances with Inherit Behavior checked"
|
||||
)
|
||||
inherit_behavior_unchecked = (
|
||||
"Found instances with Inherit Behavior unchecked as expected",
|
||||
"Unexpectedly found no instances with Inherit Behavior unchecked"
|
||||
)
|
||||
|
||||
|
||||
class TestLayerSpawnerInheritBehavior(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerSpawner_InheritBehavior", args=["level"])
|
||||
def LayerSpawner_InheritBehaviorFlag():
|
||||
"""
|
||||
Summary:
|
||||
Verifies if Inherit Behavior Flag works as expected.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
C4762381 Verifies if Inherit Behavior Flag works as expected.
|
||||
Expected Result:
|
||||
The spawner with Inherit Behavior toggled off no longer obeys
|
||||
Vegetation Surface Mask Filter of the Vegetation Layer Blender entity and plants on the surface.
|
||||
|
||||
Expected Result:
|
||||
The spawner with Inherit Behavior toggled off no longer obeys
|
||||
Vegetation Surface Mask Filter of the Vegetation Layer Blender entity and plants on the surface.
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.surface_data as surface_data
|
||||
import azlmbr.vegetation as vegetation
|
||||
|
||||
SURFACE_TAG = "test_tag"
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
def set_dynamic_slice_asset(entity_obj, component_index, dynamic_slice_asset_path):
|
||||
dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
|
||||
dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
|
||||
descriptor = hydra.get_component_property_value(
|
||||
entity_obj.components[component_index], "Configuration|Embedded Assets|[0]"
|
||||
)
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
entity_obj.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
SURFACE_TAG = "test_tag"
|
||||
|
||||
# Create empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
def set_dynamic_slice_asset(entity_obj, component_index, dynamic_slice_asset_path):
|
||||
dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
|
||||
dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
|
||||
descriptor = hydra.get_component_property_value(
|
||||
entity_obj.components[component_index], "Configuration|Embedded Assets|[0]"
|
||||
)
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
entity_obj.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Create Emitter entity and add the required components
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
emitter_entity = dynveg.create_surface_entity("emitter_entity", position, 16.0, 16.0, 1.0)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Add surface tag to the Surface Tag Emitter
|
||||
tag = surface_data.SurfaceTag()
|
||||
tag.SetTag(SURFACE_TAG)
|
||||
pte = hydra.get_property_tree(emitter_entity.components[1])
|
||||
path = "Configuration|Generated Tags"
|
||||
pte.add_container_item(path, 0, tag)
|
||||
emitter_entity.get_set_test(1, "Configuration|Generated Tags|[0]", tag)
|
||||
# Create Emitter entity and add the required components
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
emitter_entity = dynveg.create_surface_entity("emitter_entity", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# Create Blender entity and add required components
|
||||
components_to_add = ["Box Shape", "Vegetation Layer Blender"]
|
||||
blender_entity = hydra.Entity("blender_entity")
|
||||
blender_entity.create_entity(position, components_to_add)
|
||||
blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
|
||||
# Add surface tag to the Surface Tag Emitter
|
||||
tag = surface_data.SurfaceTag()
|
||||
tag.SetTag(SURFACE_TAG)
|
||||
pte = hydra.get_property_tree(emitter_entity.components[1])
|
||||
path = "Configuration|Generated Tags"
|
||||
pte.add_container_item(path, 0, tag)
|
||||
emitter_entity.get_set_test(1, "Configuration|Generated Tags|[0]", tag)
|
||||
|
||||
# Create Vegetation area and assign a valid asset
|
||||
veg_1 = hydra.Entity("veg_1")
|
||||
veg_1.create_entity(
|
||||
position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
|
||||
)
|
||||
set_dynamic_slice_asset(veg_1, 2, os.path.join("Slices", "PinkFlower.dynamicslice"))
|
||||
veg_1.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
|
||||
# Create Blender entity and add required components
|
||||
components_to_add = ["Box Shape", "Vegetation Layer Blender"]
|
||||
blender_entity = hydra.Entity("blender_entity")
|
||||
blender_entity.create_entity(position, components_to_add)
|
||||
blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
|
||||
|
||||
# Create second vegetation area and assign a valid asset
|
||||
veg_2 = hydra.Entity("veg_2")
|
||||
veg_2.create_entity(
|
||||
position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
|
||||
)
|
||||
set_dynamic_slice_asset(veg_2, 2, os.path.join("Slices", "PurpleFlower.dynamicslice"))
|
||||
veg_2.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
|
||||
# Create Vegetation area and assign a valid asset
|
||||
veg_1 = hydra.Entity("veg_1")
|
||||
veg_1.create_entity(
|
||||
position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
|
||||
)
|
||||
set_dynamic_slice_asset(veg_1, 2, os.path.join("Slices", "PinkFlower.dynamicslice"))
|
||||
veg_1.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
|
||||
|
||||
# Assign the vegetation areas to the Blender entity
|
||||
pte = hydra.get_property_tree(blender_entity.components[1])
|
||||
path = "Configuration|Vegetation Areas"
|
||||
pte.update_container_item(path, 0, veg_1.id)
|
||||
pte.add_container_item(path, 1, veg_2.id)
|
||||
# Create second vegetation area and assign a valid asset
|
||||
veg_2 = hydra.Entity("veg_2")
|
||||
veg_2.create_entity(
|
||||
position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
|
||||
)
|
||||
set_dynamic_slice_asset(veg_2, 2, os.path.join("Slices", "PurpleFlower.dynamicslice"))
|
||||
veg_2.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
|
||||
|
||||
# Add Vegetation Surface Mask Filter to the blender entity and add a Exclusion tag
|
||||
tag = surface_data.SurfaceTag()
|
||||
tag.SetTag(SURFACE_TAG)
|
||||
blender_entity.add_component("Vegetation Surface Mask Filter")
|
||||
pte = hydra.get_property_tree(blender_entity.components[2])
|
||||
path = "Configuration|Exclusion|Surface Tags"
|
||||
pte.add_container_item(path, 0, tag)
|
||||
blender_entity.get_set_test(2, "Configuration|Exclusion|Surface Tags|[0]", tag)
|
||||
# Assign the vegetation areas to the Blender entity
|
||||
pte = hydra.get_property_tree(blender_entity.components[1])
|
||||
path = "Configuration|Vegetation Areas"
|
||||
pte.update_container_item(path, 0, veg_1.id)
|
||||
pte.add_container_item(path, 1, veg_2.id)
|
||||
|
||||
# Toggle Inherit Behavior flag and verify vegetation instances
|
||||
self.log(
|
||||
f"Vegetation is not planted when Inherit Behavior flag is checked: {dynveg.validate_instance_count(position, 16.0, 0)}"
|
||||
)
|
||||
veg_1.get_set_test(0, "Configuration|Inherit Behavior", False)
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400), 2.0)
|
||||
self.log(
|
||||
f"Vegetation plant when Inherit Behavior flag is unchecked: {dynveg.validate_instance_count(position, 16.0, 400)}"
|
||||
)
|
||||
# Add Vegetation Surface Mask Filter to the blender entity and add a Exclusion tag
|
||||
tag = surface_data.SurfaceTag()
|
||||
tag.SetTag(SURFACE_TAG)
|
||||
blender_entity.add_component("Vegetation Surface Mask Filter")
|
||||
pte = hydra.get_property_tree(blender_entity.components[2])
|
||||
path = "Configuration|Exclusion|Surface Tags"
|
||||
pte.add_container_item(path, 0, tag)
|
||||
blender_entity.get_set_test(2, "Configuration|Exclusion|Surface Tags|[0]", tag)
|
||||
|
||||
# Toggle Inherit Behavior flag and verify vegetation instances
|
||||
flag_checked_instance_count = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 0), 2.0)
|
||||
Report.result(Tests.inherit_behavior_checked, flag_checked_instance_count)
|
||||
veg_1.get_set_test(0, "Configuration|Inherit Behavior", False)
|
||||
flag_unchecked_instance_count = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400), 2.0)
|
||||
Report.result(Tests.inherit_behavior_unchecked, flag_unchecked_instance_count)
|
||||
|
||||
|
||||
test = TestLayerSpawnerInheritBehavior()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(LayerSpawner_InheritBehaviorFlag)
|
||||
|
||||
+103
-109
@@ -5,134 +5,128 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.math as math
|
||||
def LayerSpawner_InstancesPlantInAllSupportedShapes():
|
||||
"""
|
||||
Summary:
|
||||
The level is loaded and vegetation area is created. Then the Vegetation Reference Shape
|
||||
component of vegetation area is pinned with entities of different shape components to check
|
||||
if the vegetation plants in different shaped areas.
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
Expected Behavior:
|
||||
Vegetation properly plants in areas of any shape.
|
||||
|
||||
Test Steps:
|
||||
1) Open a level
|
||||
2) Create basic vegetation area entity and set the properties
|
||||
3) Box Shape Entity: create, set properties and pin to vegetation
|
||||
4) Capsule Shape Entity: create, set properties and pin to vegetation
|
||||
5) Tube Shape Entity: create, set properties and pin to vegetation
|
||||
6) Sphere Shape Entity: create, set properties and pin to vegetation
|
||||
7) Cylinder Shape Entity: create, set properties and pin to vegetation
|
||||
8) Prism Shape Entity: create, set properties and pin to vegetation
|
||||
9) Compound Shape Entity: create, set properties and pin to vegetation
|
||||
|
||||
class TestLayerSpawner_AllShapesPlant(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="TestLayerSpawner_AllShapesPlant", args=["level"])
|
||||
Note:
|
||||
- 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.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
The level is loaded and vegetation area is created. Then the Vegetation Reference Shape
|
||||
component of vegetation area is pinned with entities of different shape components to check
|
||||
if the vegetation plants in different shaped areas.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation properly plants in areas of any shape.
|
||||
import os
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create basic vegetation area entity and set the properties
|
||||
3) Box Shape Entity: create, set properties and pin to vegetation
|
||||
4) Capsule Shape Entity: create, set properties and pin to vegetation
|
||||
5) Tube Shape Entity: create, set properties and pin to vegetation
|
||||
6) Sphere Shape Entity: create, set properties and pin to vegetation
|
||||
7) Cylinder Shape Entity: create, set properties and pin to vegetation
|
||||
8) Prism Shape Entity: create, set properties and pin to vegetation
|
||||
9) Compound Shape Entity: create, set properties and pin to vegetation
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.math as math
|
||||
|
||||
Note:
|
||||
- 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.
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def pin_shape_and_check_count(entity_id, count):
|
||||
hydra.get_set_test(vegetation, 2, "Configuration|Shape Entity Id", entity_id)
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(vegetation.id,
|
||||
count), 2.0)
|
||||
self.test_success = self.test_success and result
|
||||
|
||||
# 1) Create level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
def pin_shape_and_check_count(entity, count):
|
||||
hydra.get_set_test(vegetation, 2, "Configuration|Shape Entity Id", entity.id)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(vegetation.id,
|
||||
count), 2.0)
|
||||
success = (
|
||||
f"Found the expected number of instances in {entity.name} shape",
|
||||
f"Unexpected number of instances found in {entity.name} shape"
|
||||
)
|
||||
Report.result(success, result)
|
||||
|
||||
# 2) Create basic vegetation area entity and set the properties
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
vegetation = dynveg.create_vegetation_area("Instance Spawner",
|
||||
entity_position,
|
||||
10.0, 10.0, 10.0,
|
||||
asset_path)
|
||||
vegetation.remove_component("Box Shape")
|
||||
vegetation.add_component("Vegetation Reference Shape")
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Create surface for planting on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 60.0, 60.0, 1.0)
|
||||
# 2) Create basic vegetation area entity and set the properties
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
vegetation = dynveg.create_vegetation_area("Instance Spawner",
|
||||
entity_position,
|
||||
10.0, 10.0, 10.0,
|
||||
asset_path)
|
||||
vegetation.remove_component("Box Shape")
|
||||
vegetation.add_component("Vegetation Reference Shape")
|
||||
|
||||
# Adjust camera to be close to the vegetation entity
|
||||
general.set_current_view_position(135.0, 102.0, 39.0)
|
||||
general.set_current_view_rotation(-15.0, 0, 0)
|
||||
# Create surface for planting on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 60.0, 60.0, 1.0)
|
||||
|
||||
# 3) Box Shape Entity: create, set properties and pin to vegetation
|
||||
box = hydra.Entity("box")
|
||||
box.create_entity(math.Vector3(124.0, 126.0, 32.0), ["Box Shape"])
|
||||
new_box_dimension = math.Vector3(10.0, 10.0, 1.0)
|
||||
hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
|
||||
# This and subsequent counts are the number of "PurpleFlower" that spawn in the shape with given dimensions
|
||||
pin_shape_and_check_count(box.id, 156)
|
||||
# Adjust camera to be close to the vegetation entity
|
||||
general.set_current_view_position(135.0, 102.0, 39.0)
|
||||
general.set_current_view_rotation(-15.0, 0, 0)
|
||||
|
||||
# 4) Capsule Shape Entity: create, set properties and pin to vegetation
|
||||
capsule = hydra.Entity("capsule")
|
||||
capsule.create_entity(math.Vector3(120.0, 142.0, 32.0), ["Capsule Shape"])
|
||||
hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Height", 10.0)
|
||||
hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Radius", 2.0)
|
||||
pin_shape_and_check_count(capsule.id, 20)
|
||||
# 3) Box Shape Entity: create, set properties and pin to vegetation
|
||||
box = hydra.Entity("Box")
|
||||
box.create_entity(math.Vector3(124.0, 126.0, 32.0), ["Box Shape"])
|
||||
new_box_dimension = math.Vector3(10.0, 10.0, 1.0)
|
||||
hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
|
||||
# This and subsequent counts are the number of "PurpleFlower" that spawn in the shape with given dimensions
|
||||
pin_shape_and_check_count(box, 156)
|
||||
|
||||
# 5) Tube Shape Entity: create, set properties and pin to vegetation
|
||||
tube = hydra.Entity("tube")
|
||||
tube.create_entity(math.Vector3(124.0, 136.0, 32.0), ["Tube Shape", "Spline"])
|
||||
pin_shape_and_check_count(tube.id, 27)
|
||||
# 4) Capsule Shape Entity: create, set properties and pin to vegetation
|
||||
capsule = hydra.Entity("Capsule")
|
||||
capsule.create_entity(math.Vector3(120.0, 142.0, 32.0), ["Capsule Shape"])
|
||||
hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Height", 10.0)
|
||||
hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Radius", 2.0)
|
||||
pin_shape_and_check_count(capsule, 20)
|
||||
|
||||
# 6) Sphere Shape Entity: create, set properties and pin to vegetation
|
||||
sphere = hydra.Entity("sphere")
|
||||
sphere.create_entity(math.Vector3(112.0, 143.0, 32.0), ["Sphere Shape"])
|
||||
hydra.get_set_test(sphere, 0, "Sphere Shape|Sphere Configuration|Radius", 5.0)
|
||||
pin_shape_and_check_count(sphere.id, 122)
|
||||
# 5) Tube Shape Entity: create, set properties and pin to vegetation
|
||||
tube = hydra.Entity("Tube")
|
||||
tube.create_entity(math.Vector3(124.0, 136.0, 32.0), ["Tube Shape", "Spline"])
|
||||
pin_shape_and_check_count(tube, 27)
|
||||
|
||||
# 7) Cylinder Shape Entity: create, set properties and pin to vegetation
|
||||
cylinder = hydra.Entity("cylinder")
|
||||
cylinder.create_entity(math.Vector3(136.0, 143.0, 32.0), ["Cylinder Shape"])
|
||||
hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
|
||||
hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
|
||||
pin_shape_and_check_count(cylinder.id, 124)
|
||||
# 6) Sphere Shape Entity: create, set properties and pin to vegetation
|
||||
sphere = hydra.Entity("Sphere")
|
||||
sphere.create_entity(math.Vector3(112.0, 143.0, 32.0), ["Sphere Shape"])
|
||||
hydra.get_set_test(sphere, 0, "Sphere Shape|Sphere Configuration|Radius", 5.0)
|
||||
pin_shape_and_check_count(sphere, 122)
|
||||
|
||||
# 8) Prism Shape Entity: create, set properties and pin to vegetation
|
||||
polygon_prism = hydra.Entity("polygonprism")
|
||||
polygon_prism.create_entity(math.Vector3(127.0, 142.0, 32.0), ["Polygon Prism Shape"])
|
||||
pin_shape_and_check_count(polygon_prism.id, 20)
|
||||
# 7) Cylinder Shape Entity: create, set properties and pin to vegetation
|
||||
cylinder = hydra.Entity("Cylinder")
|
||||
cylinder.create_entity(math.Vector3(136.0, 143.0, 32.0), ["Cylinder Shape"])
|
||||
hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
|
||||
hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
|
||||
pin_shape_and_check_count(cylinder, 124)
|
||||
|
||||
# 9) Compound Shape Entity: create, set properties and pin to vegetation
|
||||
compound = hydra.Entity("Compound")
|
||||
compound.create_entity(math.Vector3(125.0, 136.0, 32.0), ["Compound Shape"])
|
||||
pte = hydra.get_property_tree(compound.components[0])
|
||||
shapes = [box.id, capsule.id, tube.id, sphere.id, cylinder.id, polygon_prism.id]
|
||||
for index in range(6):
|
||||
pte.add_container_item("Configuration|Child Shape Entities", index, EntityId.EntityId())
|
||||
for index, element in enumerate(shapes):
|
||||
hydra.get_set_test(compound, 0, f"Configuration|Child Shape Entities|[{index}]", element)
|
||||
pin_shape_and_check_count(compound.id, 469)
|
||||
# 8) Prism Shape Entity: create, set properties and pin to vegetation
|
||||
polygon_prism = hydra.Entity("Polygon Prism")
|
||||
polygon_prism.create_entity(math.Vector3(127.0, 142.0, 32.0), ["Polygon Prism Shape"])
|
||||
pin_shape_and_check_count(polygon_prism, 20)
|
||||
|
||||
# 9) Compound Shape Entity: create, set properties and pin to vegetation
|
||||
compound = hydra.Entity("Compound")
|
||||
compound.create_entity(math.Vector3(125.0, 136.0, 32.0), ["Compound Shape"])
|
||||
pte = hydra.get_property_tree(compound.components[0])
|
||||
shapes = [box.id, capsule.id, tube.id, sphere.id, cylinder.id, polygon_prism.id]
|
||||
for index in range(6):
|
||||
pte.add_container_item("Configuration|Child Shape Entities", index, EntityId.EntityId())
|
||||
for index, element in enumerate(shapes):
|
||||
hydra.get_set_test(compound, 0, f"Configuration|Child Shape Entities|[{index}]", element)
|
||||
pin_shape_and_check_count(compound, 469)
|
||||
|
||||
|
||||
test = TestLayerSpawner_AllShapesPlant()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(LayerSpawner_InstancesPlantInAllSupportedShapes)
|
||||
|
||||
+114
-98
@@ -5,115 +5,131 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
viewport_config_updated = (
|
||||
"Viewport is now configured for test",
|
||||
"Failed to configure viewport for test"
|
||||
)
|
||||
first_viewport_active_instance_count = (
|
||||
"Expected number of instances found in left viewport",
|
||||
"Unexpected number of instances found in left viewport"
|
||||
)
|
||||
second_viewport_inactive_instance_count = (
|
||||
"No instances found in right viewport",
|
||||
"Unexpectedly found instances in right viewport while not active"
|
||||
)
|
||||
first_viewport_inactive_instance_count = (
|
||||
"No instances found in left viewport",
|
||||
"Unexpectedly found instances in left viewport while not active"
|
||||
)
|
||||
second_viewport_active_instance_count = (
|
||||
"Expected number of instances found in right viewport",
|
||||
"Unexpected number of instances found in right viewport"
|
||||
)
|
||||
|
||||
|
||||
class TestLayerSpawnerInstanceCameraRefresh(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerSpawner_InstanceCameraRefresh", args=["level"])
|
||||
def LayerSpawner_InstancesRefreshUsingCorrectViewportCamera():
|
||||
"""
|
||||
Summary:
|
||||
Test that the Dynamic Vegetation System is using the current Editor viewport camera as the center
|
||||
of the spawn area for vegetation. To verify this, we create two separate Editor viewports pointed
|
||||
at two different vegetation areas, and verify that as we switch between active viewports, only the
|
||||
area directly underneath that viewport's camera has vegetation.
|
||||
"""
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Test that the Dynamic Vegetation System is using the current Editor viewport camera as the center
|
||||
of the spawn area for vegetation. To verify this, we create two separate Editor viewports pointed
|
||||
at two different vegetation areas, and verify that as we switch between active viewports, only the
|
||||
area directly underneath that viewport's camera has vegetation.
|
||||
"""
|
||||
# Create an empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=128,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
# Set up a test environment to validate that switching viewports correctly changes which camera
|
||||
# the vegetation system uses.
|
||||
# The test environment consists of the following:
|
||||
# - two 32 x 32 x 1 box shapes located far apart that emit a surface with no tags
|
||||
# - two 32 x 32 x 32 vegetation areas that place vegetation on the boxes
|
||||
import os
|
||||
|
||||
# Initialize some constants for our test.
|
||||
# The boxes are intentionally shifted by 0.5 meters to ensure that we get a predictable number
|
||||
# of vegetation points. By default, vegetation plants on grid corners, so if our boxes are aligned
|
||||
# with grid corner points, the right/bottom edges will include more points than we might intuitively expect.
|
||||
# By shifting by 0.5 meters, the vegetation grid points don't fall on the box edges, making the total count
|
||||
# more predictable.
|
||||
first_entity_center_point = math.Vector3(0.5, 0.5, 100.0)
|
||||
# The second box needs to be far enough away from the first that the vegetation system will never spawn instances
|
||||
# in both at the same time.
|
||||
second_entity_center_point = math.Vector3(1024.5, 1024.5, 100.0)
|
||||
box_size = 32.0
|
||||
surface_height = 1.0
|
||||
# By default, vegetation spawns 20 instances per 16 meters, so for our box of 32 meters, we should have
|
||||
# ((20 instances / 16 m) * 32 m) ^ 2 instances.
|
||||
filled_vegetation_area_instance_count = (20 * 2) * (20 * 2)
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Change the Editor view to contain two viewports
|
||||
general.set_view_pane_layout(1)
|
||||
get_view_pane_layout_success = self.wait_for_condition(lambda: (general.get_view_pane_layout() == 1), 2)
|
||||
get_viewport_count_success = self.wait_for_condition(lambda: (general.get_viewport_count() == 2), 2)
|
||||
self.test_success = get_view_pane_layout_success and self.test_success
|
||||
self.test_success = get_viewport_count_success and self.test_success
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Set the view in the first viewport to point down at the first box
|
||||
general.set_active_viewport(0)
|
||||
self.wait_for_condition(lambda: general.get_active_viewport() == 0, 2)
|
||||
general.set_current_view_position(first_entity_center_point.x, first_entity_center_point.y,
|
||||
first_entity_center_point.z + 30.0)
|
||||
general.set_current_view_rotation(-85.0, 0.0, 0.0)
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Set the view in the second viewport to point down at the second box
|
||||
general.set_active_viewport(1)
|
||||
self.wait_for_condition(lambda: general.get_active_viewport() == 1, 2)
|
||||
general.set_current_view_position(second_entity_center_point.x, second_entity_center_point.y,
|
||||
second_entity_center_point.z + 30.0)
|
||||
general.set_current_view_rotation(-85.0, 0.0, 0.0)
|
||||
# Set up a test environment to validate that switching viewports correctly changes which camera
|
||||
# the vegetation system uses.
|
||||
# The test environment consists of the following:
|
||||
# - two 32 x 32 x 1 box shapes located far apart that emit a surface with no tags
|
||||
# - two 32 x 32 x 32 vegetation areas that place vegetation on the boxes
|
||||
|
||||
# Create the "flat surface" entities to use as our vegetation surfaces
|
||||
first_surface_entity = dynveg.create_surface_entity("Surface 1", first_entity_center_point, box_size, box_size,
|
||||
surface_height)
|
||||
second_surface_entity = dynveg.create_surface_entity("Surface 2", second_entity_center_point, box_size, box_size,
|
||||
surface_height)
|
||||
# Initialize some constants for our test.
|
||||
# The boxes are intentionally shifted by 0.5 meters to ensure that we get a predictable number
|
||||
# of vegetation points. By default, vegetation plants on grid corners, so if our boxes are aligned
|
||||
# with grid corner points, the right/bottom edges will include more points than we might intuitively expect.
|
||||
# By shifting by 0.5 meters, the vegetation grid points don't fall on the box edges, making the total count
|
||||
# more predictable.
|
||||
first_entity_center_point = math.Vector3(0.5, 0.5, 100.0)
|
||||
# The second box needs to be far enough away from the first that the vegetation system will never spawn instances
|
||||
# in both at the same time.
|
||||
second_entity_center_point = math.Vector3(1024.5, 1024.5, 100.0)
|
||||
box_size = 32.0
|
||||
surface_height = 1.0
|
||||
# By default, vegetation spawns 20 instances per 16 meters, so for our box of 32 meters, we should have
|
||||
# ((20 instances / 16 m) * 32 m) ^ 2 instances.
|
||||
filled_vegetation_area_instance_count = (20 * 2) * (20 * 2)
|
||||
|
||||
# Create the two vegetation areas
|
||||
test_slice_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
first_veg_entity = dynveg.create_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size,
|
||||
box_size, test_slice_asset_path)
|
||||
second_veg_entity = dynveg.create_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size,
|
||||
box_size, test_slice_asset_path)
|
||||
# Change the Editor view to contain two viewports
|
||||
general.set_view_pane_layout(1)
|
||||
get_view_pane_layout_success = helper.wait_for_condition(lambda: (general.get_view_pane_layout() == 1), 2)
|
||||
get_viewport_count_success = helper.wait_for_condition(lambda: (general.get_viewport_count() == 2), 2)
|
||||
Report.critical_result(Tests.viewport_config_updated, get_view_pane_layout_success and get_viewport_count_success)
|
||||
|
||||
# When the first viewport is active, the first area should be full of instances, and the second should be empty
|
||||
general.set_active_viewport(0)
|
||||
viewport_0_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
|
||||
box_size / 2.0,
|
||||
filled_vegetation_area_instance_count), 5)
|
||||
self.test_success = viewport_0_success and self.test_success
|
||||
viewport_1_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
|
||||
box_size / 2.0, 0), 5)
|
||||
self.test_success = viewport_1_success and self.test_success
|
||||
# Set the view in the first viewport to point down at the first box
|
||||
general.set_active_viewport(0)
|
||||
helper.wait_for_condition(lambda: general.get_active_viewport() == 0, 2)
|
||||
general.set_current_view_position(first_entity_center_point.x, first_entity_center_point.y,
|
||||
first_entity_center_point.z + 30.0)
|
||||
general.set_current_view_rotation(-85.0, 0.0, 0.0)
|
||||
|
||||
# When the second viewport is active, the second area should be full of instances, and the first should be empty
|
||||
general.set_active_viewport(1)
|
||||
viewport_0_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
|
||||
box_size / 2.0, 0), 5)
|
||||
self.test_success = viewport_0_success and self.test_success
|
||||
viewport_1_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
|
||||
box_size / 2.0,
|
||||
filled_vegetation_area_instance_count), 5)
|
||||
self.test_success = viewport_1_success and self.test_success
|
||||
# Set the view in the second viewport to point down at the second box
|
||||
general.set_active_viewport(1)
|
||||
helper.wait_for_condition(lambda: general.get_active_viewport() == 1, 2)
|
||||
general.set_current_view_position(second_entity_center_point.x, second_entity_center_point.y,
|
||||
second_entity_center_point.z + 30.0)
|
||||
general.set_current_view_rotation(-85.0, 0.0, 0.0)
|
||||
|
||||
# Create the "flat surface" entities to use as our vegetation surfaces
|
||||
first_surface_entity = dynveg.create_surface_entity("Surface 1", first_entity_center_point, box_size, box_size,
|
||||
surface_height)
|
||||
second_surface_entity = dynveg.create_surface_entity("Surface 2", second_entity_center_point, box_size, box_size,
|
||||
surface_height)
|
||||
|
||||
# Create the two vegetation areas
|
||||
test_slice_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
first_veg_entity = dynveg.create_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size,
|
||||
box_size, test_slice_asset_path)
|
||||
second_veg_entity = dynveg.create_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size,
|
||||
box_size, test_slice_asset_path)
|
||||
|
||||
# When the first viewport is active, the first area should be full of instances, and the second should be empty
|
||||
general.set_active_viewport(0)
|
||||
helper.wait_for_condition(lambda: general.get_active_viewport() == 0, 2)
|
||||
viewport_0_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
|
||||
box_size / 2.0,
|
||||
filled_vegetation_area_instance_count), 5)
|
||||
viewport_1_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
|
||||
box_size / 2.0, 0), 5)
|
||||
Report.result(Tests.first_viewport_active_instance_count, viewport_0_success)
|
||||
Report.result(Tests.second_viewport_inactive_instance_count, viewport_1_success)
|
||||
|
||||
# When the second viewport is active, the second area should be full of instances, and the first should be empty
|
||||
general.set_active_viewport(1)
|
||||
helper.wait_for_condition(lambda: general.get_active_viewport() == 1, 2)
|
||||
viewport_0_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
|
||||
box_size / 2.0, 0), 5)
|
||||
Report.result(Tests.first_viewport_inactive_instance_count, viewport_0_success)
|
||||
viewport_1_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
|
||||
box_size / 2.0,
|
||||
filled_vegetation_area_instance_count), 5)
|
||||
Report.result(Tests.second_viewport_active_instance_count, viewport_1_success)
|
||||
|
||||
|
||||
test = TestLayerSpawnerInstanceCameraRefresh()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(LayerSpawner_InstancesRefreshUsingCorrectViewportCamera)
|
||||
|
||||
+71
-73
@@ -5,92 +5,90 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
blocked_instance_count = (
|
||||
"Instance count is as expected wih a Blocker setup",
|
||||
"Found unexpected instances with a Blocker setup"
|
||||
)
|
||||
|
||||
|
||||
class test_MeshBlocker_InstancesBlockedByMesh(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshBlocker_InstancesBlockedByMesh", args=["level"])
|
||||
def MeshBlocker_InstancesBlockedByMesh():
|
||||
"""
|
||||
Summary:
|
||||
Level is created. An entity with a vegetation spawner and entity with vegetation blocker (Mesh) component are
|
||||
added. Finally, the instance counts are checked to verify expected numbers after blocker is applied.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Level is created. An entity with a vegetation spawner and entity with vegetation blocker (Mesh) component are
|
||||
added. Finally, the instance counts are checked to verify expected numbers after blocker is applied.
|
||||
Expected Behavior:
|
||||
The vegetation planted in the Spawner area is blocked by the Mesh of the Vegetation Blocker Mesh component.
|
||||
|
||||
Expected Behavior:
|
||||
The vegetation planted in the Spawner area is blocked by the Mesh of the Vegetation Blocker Mesh component.
|
||||
Test Steps:
|
||||
--> Open a level
|
||||
--> Create Spawner Entity
|
||||
--> Create Surface Entity to spawn vegetation instances on
|
||||
--> Create Blocker Entity with cube mesh
|
||||
--> Verify spawned vegetation instance counts
|
||||
|
||||
Test Steps:
|
||||
--> Create level
|
||||
--> Create Spawner Entity
|
||||
--> Create Surface Entity to spawn vegetation instances on
|
||||
--> Create Blocker Entity with cube mesh
|
||||
--> Verify spawned vegetation instance counts
|
||||
Note:
|
||||
- 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.
|
||||
|
||||
Note:
|
||||
- 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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
# Create a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
|
||||
entity_position,
|
||||
10.0, 10.0, 10.0,
|
||||
asset_path)
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Create surface entity to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# Create blocker entity with cube mesh
|
||||
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
|
||||
blocker_entity = hydra.Entity("Blocker Entity")
|
||||
blocker_entity.create_entity(entity_position,
|
||||
["Vegetation Layer Blocker (Mesh)"])
|
||||
blocker_entity.add_component_of_type(mesh_type_id)
|
||||
if blocker_entity.id.IsValid():
|
||||
print(f"'{blocker_entity.name}' created")
|
||||
cubeId = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 2.0)
|
||||
# Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
|
||||
entity_position,
|
||||
10.0, 10.0, 10.0,
|
||||
asset_path)
|
||||
|
||||
# Verify spawned instance counts are accurate after addition of Blocker Entity
|
||||
num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 2m blocker cube
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 2.0)
|
||||
self.test_success = self.test_success and result
|
||||
# Create surface entity to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
|
||||
|
||||
# Create blocker entity with cube mesh
|
||||
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
|
||||
blocker_entity = hydra.Entity("Blocker Entity")
|
||||
blocker_entity.create_entity(entity_position,
|
||||
["Vegetation Layer Blocker (Mesh)"])
|
||||
blocker_entity.add_component_of_type(mesh_type_id)
|
||||
if blocker_entity.id.IsValid():
|
||||
print(f"'{blocker_entity.name}' created")
|
||||
cubeId = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 2.0)
|
||||
|
||||
# Verify spawned instance counts are accurate after addition of Blocker Entity
|
||||
num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 2m blocker cube
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 2.0)
|
||||
Report.result(Tests.blocked_instance_count, result)
|
||||
|
||||
|
||||
test = test_MeshBlocker_InstancesBlockedByMesh()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(MeshBlocker_InstancesBlockedByMesh)
|
||||
|
||||
+91
-95
@@ -5,104 +5,100 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import math as pymath
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
class Tests:
|
||||
blocked_instance_count = (
|
||||
"Instance count is as expected wih a Blocker setup",
|
||||
"Found unexpected instances with a Blocker setup"
|
||||
)
|
||||
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
def MeshBlocker_InstancesBlockedByMeshHeightTuning():
|
||||
"""
|
||||
Summary:
|
||||
A temporary level is created, then a simple vegetation area is created. A blocker area is created and it is
|
||||
verified that the tuning of the height percent blocker setting works as expected.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation is blocked only around the trunk of the tree, while it still plants under the areas covered by branches.
|
||||
|
||||
Test Steps:
|
||||
1) Open a level
|
||||
2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
3) Create surface entity
|
||||
4) Create blocker entity with sphere mesh
|
||||
5) Adjust the height Min/Max percentage values of blocker
|
||||
6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
|
||||
|
||||
Note:
|
||||
- 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 math as pymath
|
||||
|
||||
import azlmbr
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
|
||||
entity_position,
|
||||
10.0, 10.0, 10.0,
|
||||
asset_path)
|
||||
|
||||
# 3) Create surface entity to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
|
||||
|
||||
# 4) Create blocker entity with rotated cube mesh
|
||||
y_rotation = pymath.radians(45.0)
|
||||
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
|
||||
blocker_entity = hydra.Entity("Blocker Entity")
|
||||
blocker_entity.create_entity(entity_position,
|
||||
["Vegetation Layer Blocker (Mesh)"])
|
||||
blocker_entity.add_component_of_type(mesh_type_id)
|
||||
if blocker_entity.id.IsValid():
|
||||
Report.info(f"'{blocker_entity.name}' created")
|
||||
sphere_id = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 5.0)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", blocker_entity.id, math.Vector3(0.0, y_rotation, 0.0))
|
||||
|
||||
# 5) Adjust the height Max percentage values of blocker
|
||||
blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8)
|
||||
|
||||
# 6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
|
||||
# The number of "PurpleFlower" instances that plant on a 10 x 10 surface minus those blocked by the rotated at
|
||||
# 80% max height factored in.
|
||||
num_expected = 127
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.blocked_instance_count, result)
|
||||
|
||||
|
||||
class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshBlocker_InstancesBlockedByMeshHeightTuning", args=["level"])
|
||||
if __name__ == "__main__":
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A temporary level is created, then a simple vegetation area is created. A blocker area is created and it is
|
||||
verified that the tuning of the height percent blocker setting works as expected.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation is blocked only around the trunk of the tree, while it still plants under the areas covered by branches.
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
3) Create surface entity
|
||||
4) Create blocker entity with sphere mesh
|
||||
5) Adjust the height Min/Max percentage values of blocker
|
||||
6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
|
||||
|
||||
Note:
|
||||
- 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
|
||||
"""
|
||||
|
||||
# 1) Create level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
|
||||
entity_position,
|
||||
10.0, 10.0, 10.0,
|
||||
asset_path)
|
||||
|
||||
# 3) Create surface entity to plant on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
|
||||
|
||||
# 4) Create blocker entity with rotated cube mesh
|
||||
y_rotation = pymath.radians(45.0)
|
||||
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
|
||||
blocker_entity = hydra.Entity("Blocker Entity")
|
||||
blocker_entity.create_entity(entity_position,
|
||||
["Vegetation Layer Blocker (Mesh)"])
|
||||
blocker_entity.add_component_of_type(mesh_type_id)
|
||||
if blocker_entity.id.IsValid():
|
||||
print(f"'{blocker_entity.name}' created")
|
||||
sphere_id = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 5.0)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", blocker_entity.id, math.Vector3(0.0, y_rotation, 0.0))
|
||||
|
||||
# 5) Adjust the height Max percentage values of blocker
|
||||
blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8)
|
||||
|
||||
# 6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
|
||||
# The number of "PurpleFlower" instances that plant on a 10 x 10 surface minus those blocked by the rotated at
|
||||
# 80% max height factored in.
|
||||
num_expected = 127
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = self.test_success and result
|
||||
|
||||
|
||||
test = test_MeshBlocker_InstancesBlockedByMeshHeightTuning()
|
||||
test.run()
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(MeshBlocker_InstancesBlockedByMeshHeightTuning)
|
||||
|
||||
+68
-74
@@ -5,93 +5,87 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
class Tests:
|
||||
new_entity_created = (
|
||||
"Successfully created new entity",
|
||||
"Failed to create new entity"
|
||||
)
|
||||
emitter_disabled_before_mesh = (
|
||||
"Mesh Surface Tag Emitter is disabled without a Mesh component",
|
||||
"Mesh Surface Tag Emitter is unexpectedly enabled without a Mesh component"
|
||||
)
|
||||
emitter_enabled_after_mesh = (
|
||||
"Mesh Surface Tag Emitter is enabled after adding a Mesh component",
|
||||
"Mesh Surface Tag Emitter is unexpectedly disabled after adding a Mesh component"
|
||||
)
|
||||
|
||||
|
||||
class TestMeshSurfaceTagEmitter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshSurfaceTagEmitter_DependentOnMeshComponent", args=["level"])
|
||||
def MeshSurfaceTagEmitter_DependentOnMeshComponent():
|
||||
"""
|
||||
Summary:
|
||||
A New level is loaded. A New entity is created with component "Mesh Surface Tag Emitter". Adding a component
|
||||
"Mesh" to the same entity.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A New level is loaded. A New entity is created with component "Mesh Surface Tag Emitter". Adding a component
|
||||
"Mesh" to the same entity.
|
||||
Expected Behavior:
|
||||
Mesh Surface Tag Emitter is disabled until the required Mesh component is added to the entity.
|
||||
|
||||
Expected Behavior:
|
||||
Mesh Surface Tag Emitter is disabled until the required Mesh component is added to the entity.
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create a new entity with component "Mesh Surface Tag Emitter"
|
||||
3) Make sure Mesh Surface Tag Emitter is disabled
|
||||
4) Add Mesh to the same entity
|
||||
5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create a new entity with component "Mesh Surface Tag Emitter"
|
||||
3) Make sure Mesh Surface Tag Emitter is disabled
|
||||
4) Add Mesh to the same entity
|
||||
5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.math as math
|
||||
|
||||
def is_component_enabled(EntityComponentIdPair):
|
||||
return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
def is_component_enabled(EntityComponentIdPair):
|
||||
return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair)
|
||||
|
||||
# 2) Create a new entity with component "Mesh Surface Tag Emitter"
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
component_to_add = "Mesh Surface Tag Emitter"
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
meshentity = hydra.Entity("meshentity", entity_id)
|
||||
meshentity.components = []
|
||||
meshentity.components.append(hydra.add_component(component_to_add, entity_id))
|
||||
if entity_id.IsValid():
|
||||
print("New Entity Created")
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 3) Make sure Mesh Surface Tag Emitter is disabled
|
||||
is_enabled = is_component_enabled(meshentity.components[0])
|
||||
self.test_success = self.test_success and not is_enabled
|
||||
if not is_enabled:
|
||||
print(f"{component_to_add} is Disabled")
|
||||
elif is_enabled:
|
||||
print(f"{component_to_add} is Enabled. But It should be disabled before adding Mesh")
|
||||
# 2) Create a new entity with component "Mesh Surface Tag Emitter"
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
component_to_add = "Mesh Surface Tag Emitter"
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
meshentity = hydra.Entity("meshentity", entity_id)
|
||||
meshentity.components = []
|
||||
meshentity.components.append(hydra.add_component(component_to_add, entity_id))
|
||||
Report.critical_result(Tests.new_entity_created, entity_id.IsValid())
|
||||
|
||||
# 4) Add Mesh to the same entity
|
||||
component = "Mesh"
|
||||
meshentity.components.append(hydra.add_component(component, entity_id))
|
||||
# 3) Make sure Mesh Surface Tag Emitter is disabled
|
||||
is_enabled = is_component_enabled(meshentity.components[0])
|
||||
Report.result(Tests.emitter_disabled_before_mesh, not is_enabled)
|
||||
|
||||
# 5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
|
||||
is_enabled = is_component_enabled(meshentity.components[0])
|
||||
self.test_success = self.test_success and is_enabled
|
||||
if is_enabled:
|
||||
print(f"{component_to_add} is Enabled")
|
||||
elif not is_enabled:
|
||||
print(f"{component_to_add} is Disabled. But It should be enabled after adding Mesh")
|
||||
# 4) Add Mesh to the same entity
|
||||
component = "Mesh"
|
||||
meshentity.components.append(hydra.add_component(component, entity_id))
|
||||
|
||||
# 5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
|
||||
is_enabled = is_component_enabled(meshentity.components[0])
|
||||
Report.result(Tests.emitter_enabled_after_mesh, is_enabled)
|
||||
|
||||
|
||||
test = TestMeshSurfaceTagEmitter()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(MeshSurfaceTagEmitter_DependentOnMeshComponent)
|
||||
|
||||
+55
-59
@@ -5,75 +5,71 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
class Tests:
|
||||
add_surface_tag = (
|
||||
"Surface Tag added successfully",
|
||||
"Failed to add Surface Tag"
|
||||
)
|
||||
remove_surface_tag = (
|
||||
"Successfully removed Surface Tag",
|
||||
"Failed to remove Surface Tag"
|
||||
)
|
||||
|
||||
|
||||
class TestMeshSurfaceTagEmitter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSucessfully",
|
||||
args=["level"])
|
||||
def MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully():
|
||||
"""
|
||||
Summary:
|
||||
An enity with Mesh Tag Emitter and a Mesh is added to the viewport to verify if we are able to
|
||||
add/remove surface tags.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
An enity with Mesh Tag Emitter and a Mesh is added to the viewport to verify if we are able to
|
||||
add/remove surface tags.
|
||||
Expected Behavior:
|
||||
A new Surface Tag can be added and removed from the component.
|
||||
|
||||
Expected Behavior:
|
||||
A new Surface Tag can be added and removed from the component.
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh"
|
||||
3) Add/ remove Surface Tags
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh"
|
||||
3) Add/ remove Surface Tags
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import azlmbr.math as math
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh"
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
components_to_add = ["Mesh Surface Tag Emitter", "Mesh"]
|
||||
entity = hydra.Entity("entity")
|
||||
entity.create_entity(entity_position, components_to_add)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 3) Add/ remove Surface Tags
|
||||
tag = surface_data.SurfaceTag()
|
||||
tag.SetTag("water")
|
||||
pte = hydra.get_property_tree(entity.components[0])
|
||||
path = "Configuration|Generated Tags"
|
||||
pte.add_container_item(path, 0, tag)
|
||||
success = self.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1, 5.0)
|
||||
self.test_success = self.test_success and success
|
||||
print(f"Added SurfaceTag: container count is {pte.get_container_count(path).GetValue()}")
|
||||
pte.remove_container_item(path, 0)
|
||||
success = self.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 0, 5.0)
|
||||
self.test_success = self.test_success and success
|
||||
print(f"Removed SurfaceTag: container count is {pte.get_container_count(path).GetValue()}")
|
||||
# 2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh"
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
components_to_add = ["Mesh Surface Tag Emitter", "Mesh"]
|
||||
entity = hydra.Entity("entity")
|
||||
entity.create_entity(entity_position, components_to_add)
|
||||
|
||||
# 3) Add/ remove Surface Tags
|
||||
tag = surface_data.SurfaceTag()
|
||||
tag.SetTag("water")
|
||||
pte = hydra.get_property_tree(entity.components[0])
|
||||
path = "Configuration|Generated Tags"
|
||||
pte.add_container_item(path, 0, tag)
|
||||
success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1, 5.0)
|
||||
Report.result(Tests.add_surface_tag, success)
|
||||
pte.remove_container_item(path, 0)
|
||||
success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 0, 5.0)
|
||||
Report.result(Tests.remove_surface_tag, success)
|
||||
|
||||
|
||||
test = TestMeshSurfaceTagEmitter()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully)
|
||||
|
||||
+183
-162
@@ -5,27 +5,30 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
def PhysXColliderSurfaceTagEmitter_E2E_Editor():
|
||||
"""
|
||||
Summary:
|
||||
Test aspects of the PhysX Collider Surface Tag Emitter Component through the BehaviorContext and the Property
|
||||
Tree.
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="PhysXColliderSurfaceTagEmitter_E2E_Editor", args=["level"])
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
def validate_behavior_context(self):
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
def validate_behavior_context():
|
||||
# Verify that we can create the component through the BehaviorContext
|
||||
behavior_context_test_success = True
|
||||
test_component = azlmbr.surface_data.SurfaceDataColliderComponent()
|
||||
@@ -38,163 +41,181 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper):
|
||||
provider_tag2 = azlmbr.surface_data.SurfaceTag('provider_tag2')
|
||||
modifier_tag1 = azlmbr.surface_data.SurfaceTag('modifier_tag1')
|
||||
modifier_tag2 = azlmbr.surface_data.SurfaceTag('modifier_tag2')
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(test_component,
|
||||
'providerTags',
|
||||
[provider_tag1,
|
||||
provider_tag2])
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(test_component,
|
||||
'modifierTags',
|
||||
[modifier_tag1,
|
||||
modifier_tag2])
|
||||
self.log(f'SurfaceDataColliderComponent() BehaviorContext test: {behavior_context_test_success}')
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(
|
||||
test_component,
|
||||
'providerTags',
|
||||
[provider_tag1,
|
||||
provider_tag2])
|
||||
behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(
|
||||
test_component,
|
||||
'modifierTags',
|
||||
[modifier_tag1,
|
||||
modifier_tag2])
|
||||
Report.info(f'SurfaceDataColliderComponent() BehaviorContext test: {behavior_context_test_success}')
|
||||
return behavior_context_test_success
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Test aspects of the PhysX Collider Surface Tag Emitter Component through the BehaviorContext and the Property Tree.
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
:return: None
|
||||
"""
|
||||
# Create an empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
# Verify all of the BehaviorContext API:
|
||||
behavior_context = (
|
||||
"SurfaceDataColliderComponent() Behavior Context tests were successful",
|
||||
"SurfaceDataColliderComponent() Behavior Context tests failed"
|
||||
)
|
||||
Report.result(behavior_context, validate_behavior_context())
|
||||
|
||||
# Set up a test environment to validate the PhysX Collider Surface Tag Emitter Component.
|
||||
# The test environment will consist of the following:
|
||||
# - a 32 x 32 x 1 box shape that emits a surface with no tags
|
||||
# - a 32 x 32 x 32 vegetation area that will only place vegetation on surfaces with the 'test' tag
|
||||
# With this setup, no vegetation will appear until a Surface Tag Emitter either emits new points with
|
||||
# the correct tag, or modifies points on our box shape to emit the correct tag.
|
||||
|
||||
# Initialize some arbitrary constants for our test
|
||||
entity_center_point = math.Vector3(512.0, 512.0, 100.0)
|
||||
invalid_tag = azlmbr.surface_data.SurfaceTag('invalid')
|
||||
surface_tag = azlmbr.surface_data.SurfaceTag('test')
|
||||
test_box_size = 32.0
|
||||
baseline_surface_height = 1.0
|
||||
collider_radius = 4.0
|
||||
collider_diameter = collider_radius * 2.0
|
||||
|
||||
# Set viewport view of area under test, and toggle helpers back on
|
||||
general.set_current_view_position(512.0, 485.0, 110.0)
|
||||
general.set_current_view_rotation(-35.0, 0.0, 0.0)
|
||||
general.toggle_helpers()
|
||||
|
||||
# Create the "flat surface" entity to use as our baseline surface
|
||||
dynveg.create_surface_entity("Baseline Surface", entity_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# Create a new entity with required vegetation area components
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Veg Area", entity_center_point, 32.0, 32.0, 32.0, asset_path)
|
||||
|
||||
# Add a Vegetation Surface Mask Filter component to the spawner entity and set it to include the "test" tag
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
spawner_entity.get_set_test(3, "Configuration|Inclusion|Surface Tags", [surface_tag])
|
||||
|
||||
# At this point, there should be 0 instances within our entire veg area
|
||||
initial_instance_count = (
|
||||
"Found no instances as expected with initial setup",
|
||||
"Unexpected found instances with initial setup"
|
||||
)
|
||||
initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(entity_center_point, 16.0, 0),
|
||||
5.0)
|
||||
Report.result(initial_instance_count, initial_success)
|
||||
|
||||
# Create an entity with a PhysX Collider and our PhysX Collider Surface Tag Emitter
|
||||
collider_entity_created = (
|
||||
"Successfully created a Collider entity",
|
||||
"Failed to create Collider entity"
|
||||
)
|
||||
collider_entity = hydra.Entity("Collider Surface")
|
||||
collider_entity.create_entity(
|
||||
entity_center_point,
|
||||
["PhysX Collider", "PhysX Collider Surface Tag Emitter"]
|
||||
)
|
||||
Report.result(collider_entity_created, collider_entity.id.IsValid())
|
||||
|
||||
# Verify all of the BehaviorContext API:
|
||||
self.test_success = self.test_success and self.validate_behavior_context()
|
||||
# Set up the PhysX Collider so that each shape type (sphere, box, capsule) has the same test height.
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Sphere|Radius", collider_radius)
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Box|Dimensions", math.Vector3(collider_diameter,
|
||||
collider_diameter,
|
||||
collider_diameter))
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Capsule|Height", collider_diameter)
|
||||
|
||||
# Set up a test environment to validate the PhysX Collider Surface Tag Emitter Component.
|
||||
# The test environment will consist of the following:
|
||||
# - a 32 x 32 x 1 box shape that emits a surface with no tags
|
||||
# - a 32 x 32 x 32 vegetation area that will only place vegetation on surfaces with the 'test' tag
|
||||
# With this setup, no vegetation will appear until a Surface Tag Emitter either emits new points with
|
||||
# the correct tag, or modifies points on our box shape to emit the correct tag.
|
||||
|
||||
# Initialize some arbitrary constants for our test
|
||||
entity_center_point = math.Vector3(512.0, 512.0, 100.0)
|
||||
invalid_tag = azlmbr.surface_data.SurfaceTag('invalid')
|
||||
surface_tag = azlmbr.surface_data.SurfaceTag('test')
|
||||
test_box_size = 32.0
|
||||
baseline_surface_height = 1.0
|
||||
collider_radius = 4.0
|
||||
collider_diameter = collider_radius * 2.0
|
||||
|
||||
# Set viewport view of area under test, and toggle helpers back on
|
||||
general.set_current_view_position(512.0, 485.0, 110.0)
|
||||
general.set_current_view_rotation(-35.0, 0.0, 0.0)
|
||||
general.toggle_helpers()
|
||||
|
||||
# Create the "flat surface" entity to use as our baseline surface
|
||||
dynveg.create_surface_entity("Baseline Surface", entity_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# Create a new entity with required vegetation area components
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Veg Area", entity_center_point, 32.0, 32.0, 32.0, asset_path)
|
||||
|
||||
# Add a Vegetation Surface Mask Filter component to the spawner entity and set it to include the "test" tag
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
spawner_entity.get_set_test(3, "Configuration|Inclusion|Surface Tags", [surface_tag])
|
||||
|
||||
# At this point, there should be 0 instances within our entire veg area
|
||||
initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(entity_center_point, 16.0, 0),
|
||||
5.0)
|
||||
self.test_success = self.test_success and initial_success
|
||||
|
||||
# Create an entity with a PhysX Collider and our PhysX Collider Surface Tag Emitter
|
||||
collider_entity = hydra.Entity("Collider Surface")
|
||||
collider_entity.create_entity(
|
||||
entity_center_point,
|
||||
["PhysX Collider", "PhysX Collider Surface Tag Emitter"]
|
||||
)
|
||||
if collider_entity.id.IsValid():
|
||||
self.log(f"'{collider_entity.name}' created")
|
||||
|
||||
# Set up the PhysX Collider so that each shape type (sphere, box, capsule) has the same test height.
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Sphere|Radius", collider_radius)
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Box|Dimensions", math.Vector3(collider_diameter,
|
||||
collider_diameter,
|
||||
collider_diameter))
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Capsule|Height", collider_diameter)
|
||||
|
||||
# Run through each collider shape type (sphere, box, capsule) and verify the surface generation
|
||||
# and surface modification of the PhysX Collision Surface Tag Emitter Component.
|
||||
for collider_shape in range(0, 3):
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Shape", collider_shape)
|
||||
|
||||
# Test: Generate a new surface on the collider.
|
||||
# There should be one instance at the very top of the collider sphere, and none on the baseline surface
|
||||
# (We use a small query box to only check for one placed instance point)
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [surface_tag])
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [invalid_tag])
|
||||
top_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
|
||||
collider_radius)
|
||||
baseline_surface_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
|
||||
(baseline_surface_height / 2.0))
|
||||
top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0)
|
||||
self.test_success = self.test_success and top_point_success
|
||||
baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 0), 5.0)
|
||||
self.test_success = self.test_success and baseline_success
|
||||
|
||||
# Test: Modify an existing surface inside the collider.
|
||||
# There should be no instances at the very top of the collider sphere, and one on the baseline surface
|
||||
# within our query box.
|
||||
# (We use a small query box to only check for one placed instance point)
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [invalid_tag])
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [surface_tag])
|
||||
top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0)
|
||||
self.test_success = self.test_success and top_point_success
|
||||
baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 1), 5.0)
|
||||
self.test_success = self.test_success and baseline_success
|
||||
|
||||
# Setup collider entity with a PhysX Mesh
|
||||
test_physx_mesh_asset_id = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("levels", "physics",
|
||||
"Material_PerFaceMaterialGetsCorrectMaterial",
|
||||
"test.pxmesh"), math.Uuid(), False)
|
||||
|
||||
# Remove/re-add component due to LYN-5496
|
||||
collider_entity.remove_component("PhysX Collider")
|
||||
collider_entity.add_component("PhysX Collider")
|
||||
self.wait_for_condition(lambda: editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled',
|
||||
collider_entity.components[1]), 5.0)
|
||||
hydra.get_set_test(collider_entity, 1, "Shape Configuration|Shape", 7)
|
||||
hydra.get_set_test(collider_entity, 1, "Shape Configuration|Asset|PhysX Mesh", test_physx_mesh_asset_id)
|
||||
|
||||
# Set the asset scale to match the test heights of the shapes tested
|
||||
asset_scale = math.Vector3(1.0, 1.0, 9.0)
|
||||
collider_entity.get_set_test(1, "Shape Configuration|Asset|Configuration|Asset Scale", asset_scale)
|
||||
# Run through each collider shape type (sphere, box, capsule) and verify the surface generation
|
||||
# and surface modification of the PhysX Collision Surface Tag Emitter Component.
|
||||
for collider_shape in range(0, 3):
|
||||
collider_shapes = {0: "Sphere", 1: "Box", 2: "Capsule"}
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Shape", collider_shape)
|
||||
|
||||
# Test: Generate a new surface on the collider.
|
||||
# There should be one instance at the very top of the collider mesh, and none on the baseline surface
|
||||
# There should be one instance at the very top of the collider sphere, and none on the baseline surface
|
||||
# (We use a small query box to only check for one placed instance point)
|
||||
self.log("Starting PhysX Mesh Collider Test")
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [surface_tag])
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [invalid_tag])
|
||||
top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0)
|
||||
self.test_success = self.test_success and top_point_success
|
||||
baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 0), 5.0)
|
||||
self.test_success = self.test_success and baseline_success
|
||||
on_collider_top_point_count = (
|
||||
f"Expected number of instances found on the top point for {collider_shapes[collider_shape]} shape",
|
||||
f"Found an unexpected number of instances on the top point for {collider_shapes[collider_shape]} shape"
|
||||
)
|
||||
on_collider_baseline_count = (
|
||||
f"Expected number of instances found on the baseline point for {collider_shapes[collider_shape]} shape",
|
||||
f"Found an unexpected number of instances on the baseline point for {collider_shapes[collider_shape]} shape"
|
||||
)
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [surface_tag])
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [invalid_tag])
|
||||
top_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
|
||||
collider_radius)
|
||||
baseline_surface_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
|
||||
(baseline_surface_height / 2.0))
|
||||
top_point_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0)
|
||||
Report.result(on_collider_top_point_count, top_point_success)
|
||||
baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 0), 5.0)
|
||||
Report.result(on_collider_baseline_count, baseline_success)
|
||||
|
||||
# Test: Modify an existing surface inside the collider.
|
||||
# There should be no instances at the very top of the collider mesh, and none on the baseline surface within
|
||||
# our query box as PhysX meshes are treated as hollow shells, not solid volumes.
|
||||
# There should be no instances at the very top of the collider sphere, and one on the baseline surface
|
||||
# within our query box.
|
||||
# (We use a small query box to only check for one placed instance point)
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [invalid_tag])
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [surface_tag])
|
||||
top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0)
|
||||
self.test_success = self.test_success and top_point_success
|
||||
baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 0), 5.0)
|
||||
self.test_success = self.test_success and baseline_success
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [invalid_tag])
|
||||
hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [surface_tag])
|
||||
top_point_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0)
|
||||
Report.result(on_collider_top_point_count, top_point_success)
|
||||
baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 1), 5.0)
|
||||
Report.result(on_collider_baseline_count, baseline_success)
|
||||
|
||||
# Setup collider entity with a PhysX Mesh
|
||||
test_physx_mesh_asset_id = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("levels", "physics",
|
||||
"Material_PerFaceMaterialGetsCorrectMaterial",
|
||||
"test.pxmesh"), math.Uuid(), False)
|
||||
collider_entity.remove_component("PhysX Collider")
|
||||
collider_entity.add_component("PhysX Collider")
|
||||
helper.wait_for_condition(lambda: editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled',
|
||||
collider_entity.components[1]), 5.0)
|
||||
hydra.get_set_test(collider_entity, 1, "Shape Configuration|Shape", 7)
|
||||
hydra.get_set_test(collider_entity, 1, "Shape Configuration|Asset|PhysX Mesh", test_physx_mesh_asset_id)
|
||||
|
||||
# Set the asset scale to match the test heights of the shapes tested
|
||||
asset_scale = math.Vector3(1.0, 1.0, 9.0)
|
||||
collider_entity.get_set_test(1, "Shape Configuration|Asset|Configuration|Asset Scale", asset_scale)
|
||||
|
||||
# Test: Generate a new surface on the collider.
|
||||
# There should be one instance at the very top of the collider mesh, and none on the baseline surface
|
||||
# (We use a small query box to only check for one placed instance point)
|
||||
Report.info("Starting PhysX Mesh Collider Test")
|
||||
on_collider_top_point_count = (
|
||||
f"Expected number of instances found on the top point for a PhysX Mesh",
|
||||
f"Found an unexpected number of instances on the top point for a PhysX Mesh"
|
||||
)
|
||||
on_collider_baseline_count = (
|
||||
f"Expected number of instances found on the baseline point for a PhysX Mesh",
|
||||
f"Found an unexpected number of instances on the baseline point for a PhysX Mesh"
|
||||
)
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [surface_tag])
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [invalid_tag])
|
||||
top_point_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0)
|
||||
Report.result(on_collider_top_point_count, top_point_success)
|
||||
baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 0), 5.0)
|
||||
Report.result(on_collider_baseline_count, baseline_success)
|
||||
|
||||
# Test: Modify an existing surface inside the collider.
|
||||
# There should be no instances at the very top of the collider mesh, and none on the baseline surface within
|
||||
# our query box as PhysX meshes are treated as hollow shells, not solid volumes.
|
||||
# (We use a small query box to only check for one placed instance point)
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [invalid_tag])
|
||||
hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [surface_tag])
|
||||
top_point_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0)
|
||||
Report.result(on_collider_top_point_count, top_point_success)
|
||||
baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
|
||||
0.25, 0), 5.0)
|
||||
Report.result(on_collider_baseline_count, baseline_success)
|
||||
|
||||
|
||||
test = TestPhysXColliderSurfaceTagEmitter()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(PhysXColliderSurfaceTagEmitter_E2E_Editor)
|
||||
|
||||
+109
-112
@@ -5,136 +5,133 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
initial_instance_count = (
|
||||
"Initial instance count is as expected",
|
||||
"Found an unexpected number of initial instances"
|
||||
)
|
||||
autosnap_enabled_instance_count = (
|
||||
"Found the expected number of instances with Auto Snap to Surface enabled",
|
||||
"Found an unexpected number of instances with Auto Snap to Surface enabled"
|
||||
)
|
||||
autosnap_disabled_instance_count = (
|
||||
"Found the expected number of instances with Auto Snap to Surface disabled",
|
||||
"Found an unexpected number of instances with Auto Snap to Surface disabled"
|
||||
)
|
||||
|
||||
|
||||
class TestPositionModifierAutoSnapToSurface(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="PositionModifier_AutoSnapToSurface", args=["level"])
|
||||
def PositionModifier_AutoSnapToSurfaceWorks():
|
||||
"""
|
||||
Summary:
|
||||
Instance spawner is setup to plant on a spherical mesh. Offsets are set on the x-axis, and checks are performed
|
||||
to ensure instances plant where expected depending on the toggle setting.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Instance spawner is setup to plant on a spherical mesh. Offsets are set on the x-axis, and checks are performed
|
||||
to ensure instances plant where expected depending on the toggle setting.
|
||||
Expected Behavior:
|
||||
Offset instances snap to the expected surface when Auto Snap to Surface is enabled, and offset away from surface
|
||||
when it is disabled.
|
||||
|
||||
Expected Behavior:
|
||||
Offset instances snap to the expected surface when Auto Snap to Surface is enabled, and offset away from surface
|
||||
when it is disabled.
|
||||
Test Steps:
|
||||
1) Open a simple level
|
||||
2) Create a new entity with required vegetation area components and a Position Modifier
|
||||
3) Create a spherical planting surface
|
||||
4) Verify initial instance counts pre-filter
|
||||
5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
|
||||
6) Set the Position Modifier offset to 5 on the x-axis
|
||||
7) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface enabled
|
||||
8) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface disabled
|
||||
|
||||
Test Steps:
|
||||
1) Create a new, temporary level
|
||||
2) Create a new entity with required vegetation area components and a Position Modifier
|
||||
3) Create a spherical planting surface
|
||||
4) Verify initial instance counts pre-filter
|
||||
5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
|
||||
6) Set the Position Modifier offset to 5 on the x-axis
|
||||
7) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface enabled
|
||||
8) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface disabled
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
|
||||
'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
|
||||
'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components and a Position Modifier
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
|
||||
'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
|
||||
'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
|
||||
|
||||
# Add a Vegetation Position Modifier and set offset values to 0
|
||||
spawner_entity.add_component("Vegetation Position Modifier")
|
||||
for path in position_modifier_paths:
|
||||
spawner_entity.get_set_test(3, path, 0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 3) Create a spherical planting surface and a flat surface
|
||||
flat_entity = dynveg.create_surface_entity("Flat Surface", spawner_center_point, 32.0, 32.0, 1.0)
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("Planting Surface", spawner_center_point, 5.0)
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# Disable the Flat Surface Box Shape component, and temporarily ignore initial instance counts due to LYN-2245
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [flat_entity.components[0]])
|
||||
"""
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = 121
|
||||
spawner_success = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and spawner_success
|
||||
"""
|
||||
# 2) Create a new entity with required vegetation area components and a Position Modifier
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
|
||||
# 5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
|
||||
components_to_add = ["Constant Gradient"]
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
# Add a Vegetation Position Modifier and set offset values to 0
|
||||
spawner_entity.add_component("Vegetation Position Modifier")
|
||||
for path in position_modifier_paths:
|
||||
spawner_entity.get_set_test(3, path, 0)
|
||||
|
||||
# Pin the Constant Gradient to the X axis of the spawner's Position Modifier component
|
||||
spawner_entity.get_set_test(3, 'Configuration|Position X|Gradient|Gradient Entity Id', gradient_entity.id)
|
||||
# 3) Create a spherical planting surface
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("Planting Surface", spawner_center_point, 5.0)
|
||||
|
||||
# 6) Set the Position Modifier offset to 2.5 on the x-axis
|
||||
spawner_entity.get_set_test(3, position_modifier_paths[0], 2.5)
|
||||
spawner_entity.get_set_test(3, position_modifier_paths[1], 2.5)
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = 29
|
||||
spawner_success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.initial_instance_count, spawner_success)
|
||||
|
||||
# 7) Validate instance count at the top of the sphere mesh and inside the sphere mesh while Auto Snap to Surface
|
||||
# is enabled
|
||||
top_point = math.Vector3(512.0, 512.0, 37.0)
|
||||
inside_point = math.Vector3(512.0, 512.0, 35.0)
|
||||
radius = 0.5
|
||||
num_expected = 1
|
||||
self.log(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
|
||||
top_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
|
||||
5.0)
|
||||
self.test_success = top_success and self.test_success
|
||||
num_expected = 0
|
||||
self.log(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
|
||||
inside_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
|
||||
num_expected), 5.0)
|
||||
self.test_success = inside_success and self.test_success
|
||||
# 5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
|
||||
components_to_add = ["Constant Gradient"]
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
|
||||
# 8) Toggle off Auto Snap to Surface. Instances should now plant inside the sphere and no longer on top
|
||||
spawner_entity.get_set_test(3, "Configuration|Auto Snap To Surface", False)
|
||||
num_expected = 0
|
||||
self.log(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
|
||||
top_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
|
||||
5.0)
|
||||
self.test_success = top_success and self.test_success
|
||||
num_expected = 1
|
||||
self.log(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
|
||||
inside_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
|
||||
num_expected), 5.0)
|
||||
self.test_success = inside_success and self.test_success
|
||||
# Pin the Constant Gradient to the X axis of the spawner's Position Modifier component
|
||||
spawner_entity.get_set_test(3, 'Configuration|Position X|Gradient|Gradient Entity Id', gradient_entity.id)
|
||||
|
||||
# 6) Set the Position Modifier offset to 2.5 on the x-axis
|
||||
spawner_entity.get_set_test(3, position_modifier_paths[0], 2.5)
|
||||
spawner_entity.get_set_test(3, position_modifier_paths[1], 2.5)
|
||||
|
||||
# 7) Validate instance count at the top of the sphere mesh and inside the sphere mesh while Auto Snap to Surface
|
||||
# is enabled
|
||||
top_point = math.Vector3(512.0, 512.0, 37.0)
|
||||
inside_point = math.Vector3(512.0, 512.0, 35.0)
|
||||
radius = 0.5
|
||||
num_expected = 1
|
||||
Report.info(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
|
||||
top_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
|
||||
5.0)
|
||||
num_expected = 0
|
||||
Report.info(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
|
||||
inside_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.autosnap_enabled_instance_count, top_success and inside_success)
|
||||
|
||||
# 8) Toggle off Auto Snap to Surface. Instances should now plant inside the sphere and no longer on top
|
||||
spawner_entity.get_set_test(3, "Configuration|Auto Snap To Surface", False)
|
||||
num_expected = 0
|
||||
Report.info(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
|
||||
top_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
|
||||
5.0)
|
||||
num_expected = 1
|
||||
Report.info(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
|
||||
inside_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.autosnap_disabled_instance_count, top_success and inside_success)
|
||||
|
||||
|
||||
test = TestPositionModifierAutoSnapToSurface()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(PositionModifier_AutoSnapToSurfaceWorks)
|
||||
|
||||
+136
-131
@@ -5,159 +5,164 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
initial_instance_count = (
|
||||
"Initial instance count is as expected",
|
||||
"Found an unexpected number of initial instances"
|
||||
)
|
||||
position_offset = (
|
||||
"Found instances at all expected locations with Position Modifier offsets configured",
|
||||
"Failed to find all expected instances at all locations with Position Modifier offsets configured"
|
||||
)
|
||||
position_offset_overrides = (
|
||||
"Found instances at all expected locations with Position Modifier offset overrides configured",
|
||||
"Failed to find all expected instances at all locations with Position Modifier offset overrides configured"
|
||||
)
|
||||
|
||||
|
||||
class TestPositionModifierComponentAndOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="PositionModifierComponentAndOverrides_InstanceOffset", args=["level"])
|
||||
def PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets():
|
||||
"""
|
||||
Summary: Range Min/Max in the Vegetation Position Modifier component and component overrides can be set for all
|
||||
axes, and functions as expected when fed a gradient signal.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary: Range Min/Max in the Vegetation Position Modifier component and component overrides can be set for all
|
||||
axes, and functions as expected when fed a gradient signal.
|
||||
Expected Behavior: Instances are offset by the specified amount.
|
||||
|
||||
Expected Behavior: Instances are offset by the specified amount.
|
||||
Test Steps:
|
||||
1) Open an existing level
|
||||
2) Spawner area is setup with all necessary components
|
||||
3) Surface for planting is created
|
||||
4) Initial instance count validation pre-filter is performed
|
||||
5) An entity with a Constant Gradient of 1 is added as a child to the spawner entity, and pinned to the Position
|
||||
Modifier Gradient Entity Id fields
|
||||
6) Sector size is adjusted on a Vegetation System Settings component to allow for offset instances to not fall
|
||||
outside of the queried sector
|
||||
7) Random offsets are set for each axis of the Position Modifier component, and instance counts are validated
|
||||
8) Overrides are enabled on the Position Modifier component
|
||||
9) Random offsets are set for each axis of the descriptor's Position Modifier overrides, and instance counts
|
||||
are validated
|
||||
|
||||
Test Steps:
|
||||
1) New test level is created
|
||||
2) Spawner area is setup with all necessary components
|
||||
3) Surface for planting is created
|
||||
4) Initial instance count validation pre-filter is performed
|
||||
5) An entity with a Constant Gradient of 1 is added as a child to the spawner entity, and pinned to the Position
|
||||
Modifier Gradient Entity Id fields
|
||||
6) Sector size is adjusted on a Vegetation System Settings component to allow for offset instances to not fall
|
||||
outside of the queried sector
|
||||
7) Random offsets are set for each axis of the Position Modifier component, and instance counts are validated
|
||||
8) Overrides are enabled on the Position Modifier component
|
||||
9) Random offsets are set for each axis of the descriptor's Position Modifier overrides, and instance counts
|
||||
are validated
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
|
||||
'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
|
||||
'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
|
||||
import os
|
||||
import random
|
||||
|
||||
override_position_modifier_paths = ['Configuration|Embedded Assets|[0]|Position Modifier|Min X',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Max X',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Min Y',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Max Y',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Min Z',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Max Z']
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
def generate_random_offset_list():
|
||||
offset_list = []
|
||||
while len(offset_list) < 10:
|
||||
offset = round(random.uniform(-8.0, 8.0), 2)
|
||||
if not -1.0 <= offset <= 1.0:
|
||||
offset_list.append(offset)
|
||||
print("List of values to test against = " + str(offset_list))
|
||||
return offset_list
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
def set_offset_and_verify_instance_counts(offset_to_test, center, is_override=False):
|
||||
print(f"Starting test with an offset of {offset_to_test}")
|
||||
# Set min/max values to the offset value
|
||||
if not is_override:
|
||||
for path in position_modifier_paths:
|
||||
spawner_entity.get_set_test(3, path, offset_to_test)
|
||||
else:
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Position Modifier|Override Enabled",
|
||||
True)
|
||||
for path in override_position_modifier_paths:
|
||||
spawner_entity.get_set_test(2, path, offset_to_test)
|
||||
center_point = math.Vector3(center.x + offset_to_test, center.y + offset_to_test, center.z + offset_to_test)
|
||||
radius = 0.5
|
||||
print(f"Querying for instances in a {radius * 2}m area around {center_point.ToString()}")
|
||||
offset_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(center_point, radius, 1), 5.0)
|
||||
offset_success2 = self.wait_for_condition(lambda: dynveg.validate_instance_count(center, radius, 0), 5.0)
|
||||
self.test_success = offset_success and offset_success2 and self.test_success
|
||||
position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
|
||||
'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
|
||||
'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
override_position_modifier_paths = ['Configuration|Embedded Assets|[0]|Position Modifier|Min X',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Max X',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Min Y',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Max Y',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Min Z',
|
||||
'Configuration|Embedded Assets|[0]|Position Modifier|Max Z']
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(16.0, -5.0, 32.0)
|
||||
def generate_random_offset_list():
|
||||
offset_list = []
|
||||
while len(offset_list) < 10:
|
||||
offset = round(random.uniform(-8.0, 8.0), 2)
|
||||
if not -1.0 <= offset <= 1.0:
|
||||
offset_list.append(offset)
|
||||
Report.info("List of values to test against = " + str(offset_list))
|
||||
return offset_list
|
||||
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, 1.0, asset_path)
|
||||
def set_offset_and_verify_instance_counts(offset_to_test, center, is_override=False):
|
||||
Report.info(f"Starting test with an offset of {offset_to_test}")
|
||||
# Set min/max values to the offset value
|
||||
if not is_override:
|
||||
for path in position_modifier_paths:
|
||||
spawner_entity.get_set_test(3, path, offset_to_test)
|
||||
else:
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Position Modifier|Override Enabled",
|
||||
True)
|
||||
for path in override_position_modifier_paths:
|
||||
spawner_entity.get_set_test(2, path, offset_to_test)
|
||||
center_point = math.Vector3(center.x + offset_to_test, center.y + offset_to_test, center.z + offset_to_test)
|
||||
radius = 0.5
|
||||
Report.info(f"Querying for instances in a {radius * 2}m area around {center_point.ToString()}")
|
||||
offset_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(center_point, radius, 1), 5.0)
|
||||
offset_success2 = helper.wait_for_condition(lambda: dynveg.validate_instance_count(center, radius, 0), 5.0)
|
||||
return offset_success and offset_success2
|
||||
|
||||
# Add a Vegetation Position Modifier and set offset values to 0
|
||||
spawner_entity.add_component("Vegetation Position Modifier")
|
||||
for path in position_modifier_paths:
|
||||
spawner_entity.get_set_test(3, path, 0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 3) Add flat surface to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 0.0)
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(16.0, -5.0, 32.0)
|
||||
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = 1 # Single instance planted
|
||||
spawner_success = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = self.test_success and spawner_success
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, 1.0, asset_path)
|
||||
|
||||
# 5) Create a child entity of the spawner entity with a Constant Gradient component
|
||||
components_to_add = ["Constant Gradient"]
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
# Add a Vegetation Position Modifier and set offset values to 0
|
||||
spawner_entity.add_component("Vegetation Position Modifier")
|
||||
for path in position_modifier_paths:
|
||||
spawner_entity.get_set_test(3, path, 0)
|
||||
|
||||
# Pin the Constant Gradient to each axis of the Position Modifier
|
||||
position_modifier_gradient_paths = ['Configuration|Position X|Gradient|Gradient Entity Id',
|
||||
'Configuration|Position Y|Gradient|Gradient Entity Id',
|
||||
'Configuration|Position Z|Gradient|Gradient Entity Id']
|
||||
for path in position_modifier_gradient_paths:
|
||||
spawner_entity.get_set_test(3, path, gradient_entity.id)
|
||||
# 3) Add flat surface to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 0.0)
|
||||
|
||||
# 6) Add a Vegetation System Settings Level component and change sector size to 32 sq meters so instances can
|
||||
# offset to a greater range and still be validated
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
"Configuration|Area System Settings|Sector Size In Meters", 32)
|
||||
sector_size = hydra.get_component_property_value(veg_system_settings_component,
|
||||
"Configuration|Area System Settings|Sector Size In Meters")
|
||||
self.test_success = (sector_size == 32) and self.test_success
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = 1 # Single instance planted
|
||||
spawner_success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.initial_instance_count, spawner_success)
|
||||
|
||||
# 7) Set offsets on all axes and verify instance counts
|
||||
offsets_to_test = generate_random_offset_list()
|
||||
for offset in offsets_to_test:
|
||||
if self.test_success:
|
||||
set_offset_and_verify_instance_counts(offset, spawner_center_point)
|
||||
# 5) Create a child entity of the spawner entity with a Constant Gradient component
|
||||
components_to_add = ["Constant Gradient"]
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
|
||||
|
||||
# 8) Toggle on allow overrides on the Position Modifier Component
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
# Pin the Constant Gradient to each axis of the Position Modifier
|
||||
position_modifier_gradient_paths = ['Configuration|Position X|Gradient|Gradient Entity Id',
|
||||
'Configuration|Position Y|Gradient|Gradient Entity Id',
|
||||
'Configuration|Position Z|Gradient|Gradient Entity Id']
|
||||
for path in position_modifier_gradient_paths:
|
||||
spawner_entity.get_set_test(3, path, gradient_entity.id)
|
||||
|
||||
# 9) Set offsets on all axes on descriptor overrides and verify instance counts
|
||||
for offset in offsets_to_test:
|
||||
if self.test_success:
|
||||
set_offset_and_verify_instance_counts(offset, spawner_center_point, is_override=True)
|
||||
# 6) Add a Vegetation System Settings Level component and change sector size to 32 sq meters so instances can
|
||||
# offset to a greater range and still be validated
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
"Configuration|Area System Settings|Sector Size In Meters", 32)
|
||||
|
||||
# 7) Set offsets on all axes and verify instance counts
|
||||
offsets_to_test = generate_random_offset_list()
|
||||
success = True
|
||||
for offset in offsets_to_test:
|
||||
success = success and set_offset_and_verify_instance_counts(offset, spawner_center_point)
|
||||
Report.result(Tests.position_offset, success)
|
||||
|
||||
# 8) Toggle on allow overrides on the Position Modifier Component
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
|
||||
# 9) Set offsets on all axes on descriptor overrides and verify instance counts
|
||||
success = True
|
||||
for offset in offsets_to_test:
|
||||
success = success and set_offset_and_verify_instance_counts(offset, spawner_center_point, is_override=True)
|
||||
Report.result(Tests.position_offset_overrides, success)
|
||||
|
||||
|
||||
test = TestPositionModifierComponentAndOverrides()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets)
|
||||
|
||||
+115
-116
@@ -5,139 +5,138 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
C4814460: A level with simple vegetation is created. A child entity with required components is then created,
|
||||
and pinned to the gradient entity id in Z direction for vegetation entity. The changes in vegetation area are observed.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.areasystem as areasystem
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
gradient_entity_created = (
|
||||
"Successfully created new Gradient entity",
|
||||
"Failed to create Gradient entity"
|
||||
)
|
||||
non_override_rotation_check = (
|
||||
"Instances are rotated at expected values after initial setup",
|
||||
"Found unexpectedly rotated instances after initial setup"
|
||||
)
|
||||
override_rotation_check = (
|
||||
"Instances are rotated at expected values after configuring overrides",
|
||||
"Found unexpectedly rotated instances after configuring overrides"
|
||||
)
|
||||
|
||||
|
||||
class TestRotationModifierOverrides_InstancesRotateWithinRange(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="RotationModifierOverrides_InstancesRotateWithinRange", args=["level"])
|
||||
def RotationModifierOverrides_InstancesRotateWithinRange():
|
||||
"""
|
||||
Summary:
|
||||
A level with simple vegetation is created. A child entity with required components is then created,
|
||||
and pinned to the gradient entity id in Z direction for vegetation entity. The changes in vegetation
|
||||
area are observed.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A level with simple vegetation is created. A child entity with required components is then created,
|
||||
and pinned to the gradient entity id in Z direction for vegetation entity. The changes in vegetation
|
||||
area are observed.
|
||||
Expected Behavior:
|
||||
Vegetation instances all rotate randomly between 0-360 degrees on the Z-axis.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation instances all rotate randomly between 0-360 degrees on the Z-axis.
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Create vegetation entity and add components
|
||||
3) Set properties for vegetation entity
|
||||
4) Create new child entity
|
||||
5) Pin the child entity to vegetation entity as gradient entity id
|
||||
6) Verify rotation without per-item overrides
|
||||
7) Verify rotation with per-item overrides
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create vegetation entity and add components
|
||||
3) Set properties for vegetation entity
|
||||
4) Create new child entity
|
||||
5) Pin the child entity to vegetation entity as gradient entity id
|
||||
6) Verify rotation without per-item overrides
|
||||
7) Verify rotation with per-item overrides
|
||||
Note:
|
||||
- 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.
|
||||
|
||||
Note:
|
||||
- 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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
def get_expected_rotation(min, max, gradient_value):
|
||||
return min + ((max - min) * gradient_value)
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.areasystem as areasystem
|
||||
|
||||
def validate_rotation(center, radius, num_expected, rot_degrees_vector):
|
||||
# Verify that every instance in the given area has the expected rotation.
|
||||
box = math.Aabb_CreateCenterRadius(center, radius)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
num_found = len(instances)
|
||||
num_validated = 0
|
||||
result = (num_found == num_expected)
|
||||
print(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
|
||||
for instance in instances:
|
||||
is_close = instance.rotation.IsClose(expected_rotation)
|
||||
result = result and is_close
|
||||
if is_close:
|
||||
num_validated = num_validated + 1
|
||||
#else:
|
||||
# print(f'instance rotation validation: {is_close} (rotation={instance.rotation} expected={expected_rotation})')
|
||||
print(f'instance rotation validation: {result} (num_validated={num_validated})')
|
||||
return result
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Create level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
def get_expected_rotation(min, max, gradient_value):
|
||||
return min + ((max - min) * gradient_value)
|
||||
|
||||
# 2) Create vegetation entity and add components
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, asset_path)
|
||||
spawner_entity.add_component("Vegetation Rotation Modifier")
|
||||
# Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances.
|
||||
num_expected = 20 * 20
|
||||
# This is technically twice as big as we need, but we want to make sure our query radius is large enough to discover every
|
||||
# instance we've created.
|
||||
area_radius = 16.0
|
||||
def validate_rotation(center, radius, num_expected, rot_degrees_vector):
|
||||
# Verify that every instance in the given area has the expected rotation.
|
||||
box = math.Aabb_CreateCenterRadius(center, radius)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
num_found = len(instances)
|
||||
num_validated = 0
|
||||
result = (num_found == num_expected)
|
||||
Report.info(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
|
||||
for instance in instances:
|
||||
is_close = instance.rotation.IsClose(expected_rotation)
|
||||
result = result and is_close
|
||||
if is_close:
|
||||
num_validated = num_validated + 1
|
||||
Report.info(f'instance rotation validation: {result} (num_validated={num_validated})')
|
||||
return result
|
||||
|
||||
# Create surface to spawn on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 16.0, 16.0, 1.0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 3) Set properties for the rotation override on the descriptor, but don't set "allow overrides" on the rotation modifier yet.
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Override Enabled", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Min Z", -70.0)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Max Z", 30.0)
|
||||
# 2) Create vegetation entity and add components
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, asset_path)
|
||||
spawner_entity.add_component("Vegetation Rotation Modifier")
|
||||
# Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances.
|
||||
num_expected = 20 * 20
|
||||
# This is technically twice as big as we need, but we want to make sure our query radius is large enough to discover
|
||||
# every instance we've created.
|
||||
area_radius = 16.0
|
||||
|
||||
# 4) Create new child entity with a constant gradient
|
||||
constant_gradient_value = 0.25
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
entity_position,
|
||||
["Constant Gradient"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
if gradient_entity.id.IsValid():
|
||||
self.log(f"'{gradient_entity.name}' created")
|
||||
gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
|
||||
# Create surface to spawn on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 16.0, 16.0, 1.0)
|
||||
|
||||
# 5) Pin the child entity to vegetation entity as gradient entity id
|
||||
spawner_entity.get_set_test(3, "Configuration|Rotation Z|Gradient|Gradient Entity Id", gradient_entity.id)
|
||||
# 3) Set properties for the rotation override on the descriptor, but don't set "allow overrides" on the rotation
|
||||
# modifier yet
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Override Enabled", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Min Z", -70.0)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Max Z", 30.0)
|
||||
|
||||
# 6) Verify that without per-item overrides, the rotation matches the one calculated from the default rotation range.
|
||||
general.idle_wait(1.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 180.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
# 4) Create new child entity with a constant gradient
|
||||
constant_gradient_value = 0.25
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
entity_position,
|
||||
["Constant Gradient"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
Report.critical_result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
|
||||
gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
|
||||
|
||||
# 7) Verify that with per-item overrides enabled, the rotation matches the one calculated from the override range.
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
rotation_degrees = get_expected_rotation(-70.0, 30.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
# 5) Pin the child entity to vegetation entity as gradient entity id
|
||||
spawner_entity.get_set_test(3, "Configuration|Rotation Z|Gradient|Gradient Entity Id", gradient_entity.id)
|
||||
|
||||
# 6) Verify that without per-item overrides, the rotation matches the one calculated from the default rotation range
|
||||
general.idle_wait(1.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 180.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
Report.result(Tests.non_override_rotation_check, rotation_success)
|
||||
|
||||
# 7) Verify that with per-item overrides enabled, the rotation matches the one calculated from the override range.
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
rotation_degrees = get_expected_rotation(-70.0, 30.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
Report.result(Tests.override_rotation_check, rotation_success)
|
||||
|
||||
|
||||
test = TestRotationModifierOverrides_InstancesRotateWithinRange()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(RotationModifierOverrides_InstancesRotateWithinRange)
|
||||
|
||||
+194
-175
@@ -5,207 +5,226 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.areasystem as areasystem
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
gradient_entity_created = (
|
||||
"Successfully created new Gradient entity",
|
||||
"Failed to create Gradient entity"
|
||||
)
|
||||
rotation_baseline = (
|
||||
"Instances are not rotated after initial setup",
|
||||
"Unexpectedly found rotated instances after initial setup"
|
||||
)
|
||||
x_axis_rotation_180 = (
|
||||
"Instances rotated 180 degrees on X-axis as expected",
|
||||
"Found unexpected instance rotation on X-axis"
|
||||
)
|
||||
x_axis_rotation_90 = (
|
||||
"Instances rotated 90 degrees on X-axis as expected",
|
||||
"Found unexpected instance rotation on X-axis"
|
||||
)
|
||||
y_axis_rotation_180 = (
|
||||
"Instances rotated 180 degrees on Y-axis as expected",
|
||||
"Found unexpected instance rotation on Y-axis"
|
||||
)
|
||||
y_axis_rotation_90 = (
|
||||
"Instances rotated 90 degrees on Y-axis as expected",
|
||||
"Found unexpected instance rotation on Y-axis"
|
||||
)
|
||||
z_axis_rotation_180 = (
|
||||
"Instances rotated 180 degrees on Z-axis as expected",
|
||||
"Found unexpected instance rotation on Z-axis"
|
||||
)
|
||||
z_axis_rotation_90 = (
|
||||
"Instances rotated 90 degrees on Z-axis as expected",
|
||||
"Found unexpected instance rotation on Z-axis"
|
||||
)
|
||||
|
||||
|
||||
class TestRotationModifier_InstancesRotateWithinRange(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="RotationModifier_InstancesRotateWithinRange", args=["level"])
|
||||
def RotationModifier_InstancesRotateWithinRange():
|
||||
"""
|
||||
Summary: Range Min/Max in the Vegetation Rotation Modifier component can be set for all axes,
|
||||
and functions as expected when fed a gradient signal
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary: Range Min/Max in the Vegetation Rotation Modifier component can be set for all axes,
|
||||
and functions as expected when fed a gradient signal
|
||||
|
||||
Vegetation Entity: Set in the middle of the level it holds a child entity and the following components:
|
||||
Vegetation Asset List
|
||||
Box Shape (size: <10, 10, 10>)
|
||||
Vegetation Layer Spawner
|
||||
Vegetation Rotation Modifier
|
||||
Rotation X (gradient: child, Range Min: Variable, Range Max: Variable)
|
||||
Rotation Y (gradient: child, Range Min: Variable, Range Max: Variable)
|
||||
Rotation Z (gradient: child, Range Min: Variable, Range Max: Variable)
|
||||
Vegetation Entity: Set in the middle of the level it holds a child entity and the following components:
|
||||
Vegetation Asset List
|
||||
Box Shape (size: <10, 10, 10>)
|
||||
Vegetation Layer Spawner
|
||||
Vegetation Rotation Modifier
|
||||
Rotation X (gradient: child, Range Min: Variable, Range Max: Variable)
|
||||
Rotation Y (gradient: child, Range Min: Variable, Range Max: Variable)
|
||||
Rotation Z (gradient: child, Range Min: Variable, Range Max: Variable)
|
||||
|
||||
|
||||
Child Entity: Child to Vegetation Entity has the following components:
|
||||
Box Shape (size: <10, 10, 10>)
|
||||
Gradient Transform Modifier
|
||||
Constant Gradient
|
||||
Child Entity: Child to Vegetation Entity has the following components:
|
||||
Box Shape (size: <10, 10, 10>)
|
||||
Gradient Transform Modifier
|
||||
Constant Gradient
|
||||
|
||||
Expected Behavior: The vegetation area adjusts rotation based on the Constant Gradient component
|
||||
and the min and max values for each component. Min max of each axis is checked
|
||||
Expected Behavior: The vegetation area adjusts rotation based on the Constant Gradient component
|
||||
and the min and max values for each component. Min max of each axis is checked
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Set up vegetation entities
|
||||
3) X-axis Check
|
||||
4) Y-axis Check
|
||||
5) Z-axis Check
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Set up vegetation entities
|
||||
3) X-axis Check
|
||||
4) Y-axis Check
|
||||
5) Z-axis Check
|
||||
|
||||
Note:
|
||||
- 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.
|
||||
Note:
|
||||
- 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
|
||||
"""
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# Test Constants
|
||||
LEVEL_CENTER = math.Vector3(512.0, 512.0, 32.0)
|
||||
constant_gradient_value = 0.15
|
||||
import os
|
||||
|
||||
# Helper Functions
|
||||
def change_range_max(axis, value):
|
||||
spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Max", value)
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.areasystem as areasystem
|
||||
|
||||
def change_range_min(axis, value):
|
||||
spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Min", value)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
def get_expected_rotation(min, max, gradient_value):
|
||||
return min + ((max - min) * gradient_value)
|
||||
# Test Constants
|
||||
LEVEL_CENTER = math.Vector3(512.0, 512.0, 32.0)
|
||||
constant_gradient_value = 0.15
|
||||
|
||||
def validate_rotation(center, radius, num_expected, rot_degrees_vector):
|
||||
# Verify that every instance in the given area has the expected rotation.
|
||||
box = math.Aabb_CreateCenterRadius(center, radius)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
num_found = len(instances)
|
||||
result = (num_found == num_expected)
|
||||
print(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
|
||||
for instance in instances:
|
||||
result = result and instance.rotation.IsClose(expected_rotation)
|
||||
print(f'instance rotation validation: {result} (rotation={instance.rotation} expected={expected_rotation})')
|
||||
return result
|
||||
# Helper Functions
|
||||
def change_range_max(axis, value):
|
||||
spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Max", value)
|
||||
|
||||
def change_range_min(axis, value):
|
||||
spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Min", value)
|
||||
|
||||
# Main Script
|
||||
# 1) Create Level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
def get_expected_rotation(min, max, gradient_value):
|
||||
return min + ((max - min) * gradient_value)
|
||||
|
||||
def validate_rotation(center, radius, num_expected, rot_degrees_vector):
|
||||
# Verify that every instance in the given area has the expected rotation.
|
||||
box = math.Aabb_CreateCenterRadius(center, radius)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
num_found = len(instances)
|
||||
result = (num_found == num_expected)
|
||||
Report.info(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
|
||||
for instance in instances:
|
||||
result = result and instance.rotation.IsClose(expected_rotation)
|
||||
Report.info(f'instance rotation validation: {result} (rotation={instance.rotation} expected={expected_rotation})')
|
||||
return result
|
||||
|
||||
# Main Script
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 2) Set up vegetation entities
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", LEVEL_CENTER, 2.0, 2.0, 2.0, asset_path)
|
||||
|
||||
additional_components = [
|
||||
"Vegetation Rotation Modifier"
|
||||
]
|
||||
for component in additional_components:
|
||||
spawner_entity.add_component(component)
|
||||
|
||||
# Create surface to spawn vegetation on
|
||||
dynveg.create_surface_entity("Surface Entity", LEVEL_CENTER, 10.0, 10.0, 1.0)
|
||||
|
||||
# Create Gradient Entity
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
LEVEL_CENTER,
|
||||
["Constant Gradient"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
Report.critical_result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
|
||||
gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
|
||||
|
||||
# Vegetation Rotation Modifier
|
||||
for axis in ["X", "Y", "Z"]:
|
||||
spawner_entity.get_set_test(
|
||||
3, f"Configuration|Rotation {axis}|Gradient|Gradient Entity Id", gradient_entity.id
|
||||
)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 2) Set up vegetation entities
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", LEVEL_CENTER, 2.0, 2.0, 2.0, asset_path)
|
||||
# Set up constants used across all the rotation checks
|
||||
|
||||
additional_components = [
|
||||
"Vegetation Rotation Modifier"
|
||||
]
|
||||
for component in additional_components:
|
||||
spawner_entity.add_component(component)
|
||||
# Choose an area large enough to contain all of the instances we spawned.
|
||||
area_center = LEVEL_CENTER
|
||||
area_radius = 20.0
|
||||
# We're spawning a 2x2 area, which will have 3 rows of 3 instances due to default vegetation system spacing, so
|
||||
# we should have a total of 9 instances.
|
||||
num_expected = 9
|
||||
|
||||
# Create surface to spawn vegetation on
|
||||
dynveg.create_surface_entity("Surface Entity", LEVEL_CENTER, 10.0, 10.0, 1.0)
|
||||
# 3) X-axis check
|
||||
# baseline, verify that we initially have no rotation
|
||||
change_range_min("Z", 0.0)
|
||||
change_range_max("Z", 0.0)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, 0.0)), 5.0)
|
||||
Report.result(Tests.rotation_baseline, rotation_success)
|
||||
|
||||
# Create Gradient Entity
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
LEVEL_CENTER,
|
||||
["Constant Gradient"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
if gradient_entity.id.IsValid():
|
||||
self.log(f"'{gradient_entity.name}' created")
|
||||
gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
|
||||
# Adjust x-axis range min / max to (-180, 0).
|
||||
# Because we have a constant gradient of 0.25, our actual rotation should be (min + (max - min) * gradient),
|
||||
# or (-180 + (0 - -180) * 0.25)
|
||||
change_range_min("X", -180.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
|
||||
5.0)
|
||||
Report.result(Tests.x_axis_rotation_180, rotation_success)
|
||||
|
||||
# Vegetation Rotation Modifier
|
||||
for axis in ["X", "Y", "Z"]:
|
||||
spawner_entity.get_set_test(
|
||||
3, f"Configuration|Rotation {axis}|Gradient|Gradient Entity Id", gradient_entity.id
|
||||
)
|
||||
# Set the min / max to (0, 90), with an expected result of (0 + (90 - 0) * 0.25)
|
||||
change_range_min("X", 0.0)
|
||||
change_range_max("X", 90.0)
|
||||
rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
|
||||
5.0)
|
||||
Report.result(Tests.x_axis_rotation_90, rotation_success)
|
||||
change_range_max("X", 0.0)
|
||||
|
||||
# Set up constants used across all the rotation checks
|
||||
# 4) Y-axis check
|
||||
change_range_min("Y", -180.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
|
||||
5.0)
|
||||
Report.result(Tests.y_axis_rotation_180, rotation_success)
|
||||
|
||||
# Choose an area large enough to contain all of the instances we spawned.
|
||||
area_center = LEVEL_CENTER
|
||||
area_radius = 20.0
|
||||
# We're spawning a 2x2 area, which will have 3 rows of 3 instances due to default vegetation system spacing, so
|
||||
# we should have a total of 9 instances.
|
||||
num_expected = 9
|
||||
|
||||
# 3) X-axis check
|
||||
general.idle_wait(3.0) # Allow mesh to load
|
||||
change_range_min("Y", 0.0)
|
||||
change_range_max("Y", 90.0)
|
||||
rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
|
||||
5.0)
|
||||
Report.result(Tests.y_axis_rotation_90, rotation_success)
|
||||
change_range_max("Y", 0.0)
|
||||
|
||||
# baseline, verify that we initially have no rotation
|
||||
change_range_min("Z", 0.0)
|
||||
change_range_max("Z", 0.0)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, 0.0)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
# 5) Z-axis check
|
||||
change_range_min("Z", -180.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
Report.result(Tests.z_axis_rotation_180, rotation_success)
|
||||
|
||||
# Adjust x-axis range min / max to (-180, 0).
|
||||
# Because we have a constant gradient of 0.25, our actual rotation should be (min + (max - min) * gradient),
|
||||
# or (-180 + (0 - -180) * 0.25)
|
||||
change_range_min("X", -180.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
|
||||
# Set the min / max to (0, 90), with an expected result of (0 + (90 - 0) * 0.25)
|
||||
change_range_min("X", 0.0)
|
||||
change_range_max("X", 90.0)
|
||||
rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
|
||||
change_range_max("X", 0.0)
|
||||
|
||||
# 4) Y-axis check
|
||||
change_range_min("Y", -180.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
|
||||
change_range_min("Y", 0.0)
|
||||
change_range_max("Y", 90.0)
|
||||
rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
|
||||
change_range_max("Y", 0.0)
|
||||
|
||||
# 5) Z-axis check
|
||||
change_range_min("Z", -180.0)
|
||||
rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
|
||||
change_range_min("Z", 0.0)
|
||||
change_range_max("Z", 90.0)
|
||||
rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
|
||||
rotation_success = self.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
self.test_success = self.test_success and rotation_success
|
||||
change_range_min("Z", 0.0)
|
||||
change_range_max("Z", 90.0)
|
||||
rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
|
||||
rotation_success = helper.wait_for_condition(
|
||||
lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
|
||||
5.0)
|
||||
Report.result(Tests.z_axis_rotation_90, rotation_success)
|
||||
|
||||
|
||||
test = TestRotationModifier_InstancesRotateWithinRange()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(RotationModifier_InstancesRotateWithinRange)
|
||||
|
||||
+132
-130
@@ -5,153 +5,155 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
# Constants
|
||||
CLOSE_ENOUGH_THRESHOLD = 0.01
|
||||
class Tests:
|
||||
gradient_entity_created = (
|
||||
"Successfully created Gradient entity",
|
||||
"Failed to create Gradient entity"
|
||||
)
|
||||
scale_values_set = (
|
||||
"Scale Min and Scale Max are set to 0.1 and 1.0 in Vegetation Asset List",
|
||||
"Scale Min and Scale Max are not set to 0.1 and 1.0 in Vegetation Asset List"
|
||||
)
|
||||
instance_count = (
|
||||
"Found the expected number of instances",
|
||||
"Found an unexpected number of instances"
|
||||
)
|
||||
instances_properly_scaled = (
|
||||
"All instances scaled within appropriate range",
|
||||
"Found instances scaled outside of the appropriate range"
|
||||
)
|
||||
|
||||
|
||||
class TestScaleModifierOverrides_InstancesProperlyScale(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="ScaleModifierOverrides_InstancesProperlyScale", args=["level"])
|
||||
def ScaleModifierOverrides_InstancesProperlyScale():
|
||||
"""
|
||||
Summary:
|
||||
A level is created, then as simple vegetation area is created. Vegetation Scale Modifier component is
|
||||
added to the vegetation area. A new child entity is created with Random Noise Gradient Generator,
|
||||
Gradient Transform Modifier, and Box Shape. Child entity is set as gradient entity id in Vegetation
|
||||
Scale Modifier, and scale of instances is validated to fall within expected range.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A level is created, then as simple vegetation area is created. Vegetation Scale Modifier component is
|
||||
added to the vegetation area. A new child entity is created with Random Noise Gradient Generator,
|
||||
Gradient Transform Modifier, and Box Shape. Child entity is set as gradient entity id in Vegetation
|
||||
Scale Modifier, and scale of instances is validated to fall within expected range.
|
||||
Expected Behavior:
|
||||
Vegetation instances have random scale between Range Min and Range Max applied.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation instances have random scale between Range Min and Range Max applied.
|
||||
Test Steps:
|
||||
1) Open an existing level
|
||||
2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
3) Set a valid mesh asset on the Vegetation Asset List
|
||||
4) Add Vegetation Scale Modifier component to the vegetation and set the values
|
||||
5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
|
||||
6) Create a new child entity and add components
|
||||
7) Add child entity as gradient entity id in Vegetation Scale Modifier
|
||||
8) Validate scale of instances with a few different min/max override values
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
3) Set a valid mesh asset on the Vegetation Asset List
|
||||
4) Add Vegetation Scale Modifier component to the vegetation and set the values
|
||||
5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
|
||||
6) Create a new child entity and add components
|
||||
7) Add child entity as gradient entity id in Vegetation Scale Modifier
|
||||
8) Validate scale of instances with a few different min/max override values
|
||||
Note:
|
||||
- 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.
|
||||
|
||||
Note:
|
||||
- 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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
def set_and_validate_scale(entity, min_scale, max_scale):
|
||||
# Set Range Min/Max
|
||||
entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Min", min_scale)
|
||||
entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Max", max_scale)
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Clear all areas to force a refresh
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Wait for instances to spawn
|
||||
num_expected = 20 * 20
|
||||
self.test_success = self.test_success and self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
# Constants
|
||||
CLOSE_ENOUGH_THRESHOLD = 0.01
|
||||
|
||||
# Validate scale values of instances
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
if len(instances) == num_expected:
|
||||
for instance in instances:
|
||||
if min_scale <= instance.scale <= max_scale:
|
||||
self.log("All instances scaled within appropriate range")
|
||||
return True
|
||||
self.log(f"Instance at {instance.position} scale is {instance.scale}. Expected between "
|
||||
f"{min_scale}/{max_scale}")
|
||||
return False
|
||||
self.log(f"Failed to find all instances! Found {len(instances)}, expected {num_expected}.")
|
||||
return False
|
||||
def set_and_validate_scale(entity, min_scale, max_scale):
|
||||
# Set Range Min/Max
|
||||
entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Min", min_scale)
|
||||
entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Max", max_scale)
|
||||
|
||||
# 1) Create level and set an appropriate view of spawner area
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
# Refresh the planted instances
|
||||
general.run_console("veg_DebugClearAllAreas")
|
||||
|
||||
# Check the initial instance count
|
||||
num_expected = 20 * 20
|
||||
success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.critical_result(Tests.instance_count, success)
|
||||
|
||||
# Validate scale values of instances
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
for instance in instances:
|
||||
if min_scale <= instance.scale <= max_scale:
|
||||
return True
|
||||
return False
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 10.0, asset_path)
|
||||
|
||||
# Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 4) Add Vegetation Scale Modifier component to the vegetation and set the values
|
||||
spawner_entity.add_component("Vegetation Scale Modifier")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
|
||||
# 5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Override Enabled", True)
|
||||
scale_min = float(
|
||||
format(
|
||||
(
|
||||
hydra.get_component_property_value(
|
||||
spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Min"
|
||||
)
|
||||
),
|
||||
".1f",
|
||||
)
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 10.0, asset_path)
|
||||
|
||||
# Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 4) Add Vegetation Scale Modifier component to the vegetation and set the values
|
||||
spawner_entity.add_component("Vegetation Scale Modifier")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
|
||||
# 5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Override Enabled", True)
|
||||
scale_min = float(
|
||||
format(
|
||||
(
|
||||
hydra.get_component_property_value(
|
||||
spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Min"
|
||||
)
|
||||
),
|
||||
".1f",
|
||||
)
|
||||
)
|
||||
scale_max = float(
|
||||
format(
|
||||
(
|
||||
hydra.get_component_property_value(
|
||||
spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Max"
|
||||
)
|
||||
),
|
||||
".1f",
|
||||
)
|
||||
scale_max = float(
|
||||
format(
|
||||
(
|
||||
hydra.get_component_property_value(
|
||||
spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Max"
|
||||
)
|
||||
),
|
||||
".1f",
|
||||
)
|
||||
)
|
||||
if ((scale_max - 1.0) < CLOSE_ENOUGH_THRESHOLD) and ((scale_min - 0.1) < CLOSE_ENOUGH_THRESHOLD):
|
||||
self.log("Scale Min and Scale Max are set to 0.1 and 1.0 in Vegetation Asset List")
|
||||
else:
|
||||
self.log("Scale Min and Scale Max are not set to 0.1 and 1.0 in Vegetation Asset List")
|
||||
)
|
||||
Report.result(Tests.scale_values_set, ((scale_max - 1.0) < CLOSE_ENOUGH_THRESHOLD) and
|
||||
((scale_min - 0.1) < CLOSE_ENOUGH_THRESHOLD))
|
||||
|
||||
# 6) Create a new child entity and add components
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
entity_position,
|
||||
["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
if gradient_entity.id.IsValid():
|
||||
self.log(f"'{gradient_entity.name}' created")
|
||||
# 6) Create a new child entity and add components
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
entity_position,
|
||||
["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
Report.result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
|
||||
|
||||
# 7) Add child entity as gradient entity id in Vegetation Scale Modifier
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
|
||||
# 7) Add child entity as gradient entity id in Vegetation Scale Modifier
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
|
||||
|
||||
# 8) Validate instances are scaled properly via a few different Range Min/Max settings on the override
|
||||
self.test_success = set_and_validate_scale(spawner_entity, 0.1, 1.0) and self.test_success
|
||||
self.test_success = set_and_validate_scale(spawner_entity, 2.0, 2.5) and self.test_success
|
||||
self.test_success = set_and_validate_scale(spawner_entity, 1.0, 5.0) and self.test_success
|
||||
# 8) Validate instances are scaled properly via a few different Range Min/Max settings on the override
|
||||
Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 0.1, 1.0))
|
||||
Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 2.0, 2.5))
|
||||
Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 1.0, 5.0))
|
||||
|
||||
|
||||
test = TestScaleModifierOverrides_InstancesProperlyScale()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(ScaleModifierOverrides_InstancesProperlyScale)
|
||||
|
||||
+99
-99
@@ -5,123 +5,123 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
gradient_entity_created = (
|
||||
"Successfully created Gradient entity",
|
||||
"Failed to create Gradient entity"
|
||||
)
|
||||
instance_count = (
|
||||
"Found the expected number of instances",
|
||||
"Found an unexpected number of instances"
|
||||
)
|
||||
instances_properly_scaled = (
|
||||
"All instances scaled within appropriate range",
|
||||
"Found instances scaled outside of the appropriate range"
|
||||
)
|
||||
|
||||
|
||||
class TestScaleModifier_InstancesProperlyScale(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="ScaleModifier_InstancesProperlyScale", args=["level"])
|
||||
def ScaleModifier_InstancesProperlyScale():
|
||||
"""
|
||||
Summary:
|
||||
A New level is created. A New entity is created with components Vegetation Layer Spawner, Vegetation Asset List,
|
||||
Box Shape and Vegetation Scale Modifier. A New child entity is created with components Random Noise Gradient,
|
||||
Gradient Transform Modifier, and Box Shape. Pin the Random Noise entity to the Gradient Entity Id field for
|
||||
the Gradient group. Range Min and Range Max are set to few values and values are validated. Range Min and Range
|
||||
Max are set to few other values and values are validated.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A New level is created. A New entity is created with components Vegetation Layer Spawner, Vegetation Asset List,
|
||||
Box Shape and Vegetation Scale Modifier. A New child entity is created with components Random Noise Gradient,
|
||||
Gradient Transform Modifier, and Box Shape. Pin the Random Noise entity to the Gradient Entity Id field for
|
||||
the Gradient group. Range Min and Range Max are set to few values and values are validated. Range Min and Range
|
||||
Max are set to few other values and values are validated.
|
||||
Expected Behavior:
|
||||
Vegetation instances are scaled within Range Min/Range Max.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation instances are scaled within Range Min/Range Max.
|
||||
Test Steps:
|
||||
1) Open an existing level
|
||||
2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
|
||||
Vegetation Scale Modifier
|
||||
3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
|
||||
4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
|
||||
5) Range Min/Max is set to few different values on the Vegetation Scale Modifier component and
|
||||
scale of instances is validated
|
||||
|
||||
Test Steps:
|
||||
1) Create level
|
||||
2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
|
||||
Vegetation Scale Modifier
|
||||
3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
|
||||
4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
|
||||
5) Range Min/Max is set to few different values on the Vegetation Scale Modifier component and
|
||||
scale of instances is validated
|
||||
Note:
|
||||
- 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.
|
||||
|
||||
Note:
|
||||
- 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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
def set_and_validate_scale(entity, min_scale, max_scale):
|
||||
# Set Range Min/Max
|
||||
entity.get_set_test(3, "Configuration|Range Min", min_scale)
|
||||
entity.get_set_test(3, "Configuration|Range Max", max_scale)
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Clear all areas to force a refresh
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Wait for instances to spawn
|
||||
num_expected = 20 * 20
|
||||
self.test_success = self.test_success and self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
def set_and_validate_scale(entity, min_scale, max_scale):
|
||||
# Set Range Min/Max
|
||||
entity.get_set_test(3, "Configuration|Range Min", min_scale)
|
||||
entity.get_set_test(3, "Configuration|Range Max", max_scale)
|
||||
|
||||
# Validate scale values of instances
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
if len(instances) == num_expected:
|
||||
for instance in instances:
|
||||
if min_scale <= instance.scale <= max_scale:
|
||||
self.log("All instances scaled within appropriate range")
|
||||
return True
|
||||
self.log(f"Instance at {instance.position} scale is {instance.scale}. Expected between "
|
||||
f"{min_scale}/{max_scale}")
|
||||
return False
|
||||
self.log(f"Failed to find all instances! Found {len(instances)}, expected {num_expected}.")
|
||||
return False
|
||||
# Refresh the planted instances
|
||||
general.run_console("veg_DebugClearAllAreas")
|
||||
|
||||
# 1) Create level and set an appropriate view of spawner area
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
# Check the initial instance count
|
||||
num_expected = 20 * 20
|
||||
success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.critical_result(Tests.instance_count, success)
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
# Validate scale values of instances
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
for instance in instances:
|
||||
if min_scale <= instance.scale <= max_scale:
|
||||
return True
|
||||
return False
|
||||
|
||||
# 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
|
||||
# Vegetation Scale Modifier
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
spawner_entity.add_component("Vegetation Scale Modifier")
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# 3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
entity_position,
|
||||
["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
if gradient_entity.id.IsValid():
|
||||
self.log(f"'{gradient_entity.name}' created")
|
||||
# 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
|
||||
# Vegetation Scale Modifier
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
spawner_entity.add_component("Vegetation Scale Modifier")
|
||||
|
||||
# 4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
|
||||
# Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 5) Set Range Min/Max on the Vegetation Scale Modifier component to diff values, and verify instance scale is
|
||||
# within bounds
|
||||
self.test_success = set_and_validate_scale(spawner_entity, 2.0, 4.0) and self.test_success
|
||||
self.test_success = set_and_validate_scale(spawner_entity, 12.0, 40.0) and self.test_success
|
||||
self.test_success = set_and_validate_scale(spawner_entity, 0.5, 2.5) and self.test_success
|
||||
# 3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
|
||||
gradient_entity = hydra.Entity("Gradient Entity")
|
||||
gradient_entity.create_entity(
|
||||
entity_position,
|
||||
["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
|
||||
parent_id=spawner_entity.id
|
||||
)
|
||||
Report.critical_result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
|
||||
|
||||
# 4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
|
||||
|
||||
# 5) Set Range Min/Max on the Vegetation Scale Modifier component to diff values, and verify instance scale is
|
||||
# within bounds
|
||||
Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 2.0, 4.0))
|
||||
Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 12.0, 40.0))
|
||||
Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 0.5, 2.5))
|
||||
|
||||
|
||||
test = TestScaleModifier_InstancesProperlyScale()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(ScaleModifier_InstancesProperlyScale)
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
instance_count_in_box_shape = (
|
||||
"Only found instances in the configured Box Shape intersection area",
|
||||
"Found instances outside of the configured Box Shape intersection area"
|
||||
)
|
||||
instance_count_in_cylinder_shape = (
|
||||
"Only found instances in the configured Cylinder Shape intersection area",
|
||||
"Found instances outside of the configured Cylinder Shape intersection area"
|
||||
)
|
||||
preprocess_instance_count = (
|
||||
"Found the expected number of instances with preprocessing filter stage",
|
||||
"Found an unexpected number of instances with preprocessing filter stage"
|
||||
)
|
||||
postprocess_instance_count = (
|
||||
"Found the expected number of instances with postprocessing filter stage",
|
||||
"Found an unexpected number of instances with postprocessing filter stage"
|
||||
)
|
||||
|
||||
|
||||
def ShapeIntersectionFilter_FilterStageToggle():
|
||||
"""
|
||||
Summary:
|
||||
Filter Stage toggle affects final vegetation position
|
||||
|
||||
Expected Result:
|
||||
Vegetation instances plant differently depending on the Filter Stage setting. With PreProcess, some vegetation
|
||||
instances can appear on slopes outside the filtered values. With PostProcess, vegetation instances only appear on
|
||||
the correct slope values.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# Add a Vegetation Shape Intersection Filter to the vegetation area entity
|
||||
vegetation.add_component("Vegetation Shape Intersection Filter")
|
||||
|
||||
# Create a new entity as a child of the vegetation area entity with Box Shape
|
||||
box = hydra.Entity("box")
|
||||
box.create_entity(position, ["Box Shape"])
|
||||
box.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(8.0, 8.0, 1.0))
|
||||
|
||||
# Create a new entity as a child of the vegetation area entity with Cylinder Shape.
|
||||
cylinder = hydra.Entity("cylinder")
|
||||
cylinder.create_entity(position, ["Cylinder Shape"])
|
||||
cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
|
||||
cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
|
||||
box.set_test_parent_entity(vegetation)
|
||||
cylinder.set_test_parent_entity(vegetation)
|
||||
|
||||
# On the Shape Intersection Filter component, click the crosshair button, and add child entities one by one
|
||||
vegetation.get_set_test(3, "Configuration|Shape Entity Id", box.id)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0, 100), 2.0)
|
||||
Report.result(Tests.instance_count_in_box_shape, result)
|
||||
vegetation.get_set_test(3, "Configuration|Shape Entity Id", cylinder.id)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 100), 2.0)
|
||||
Report.result(Tests.instance_count_in_cylinder_shape, result)
|
||||
|
||||
# Create a new entity as a child of the area entity with Random Noise Gradient, Gradient Transform Modifier,
|
||||
# and Box Shape component
|
||||
random_noise = hydra.Entity("random_noise")
|
||||
random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
|
||||
random_noise.set_test_parent_entity(vegetation)
|
||||
|
||||
# Add a Vegetation Position Modifier to the vegetation area entity
|
||||
vegetation.add_component("Vegetation Position Modifier")
|
||||
|
||||
# Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
|
||||
vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
|
||||
|
||||
# Toggle between PreProcess and PostProcess
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 117), 2.0)
|
||||
Report.result(Tests.preprocess_instance_count, result)
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
|
||||
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 122), 2.0)
|
||||
Report.result(Tests.postprocess_instance_count, result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(ShapeIntersectionFilter_FilterStageToggle)
|
||||
+103
-101
@@ -5,124 +5,126 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
C4874094: Shape reference can be replaced/removed
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
instance_count_in_box_shape = (
|
||||
"Only found instances in the configured Box Shape intersection area",
|
||||
"Found instances outside of the configured Box Shape intersection area"
|
||||
)
|
||||
instance_count_in_cylinder_shape = (
|
||||
"Only found instances in the configured Cylinder Shape intersection area",
|
||||
"Found instances outside of the configured Cylinder Shape intersection area"
|
||||
)
|
||||
unfiltered_instance_count = (
|
||||
"Found instances in the entire Spawner area with no filter set",
|
||||
"Failed to find all expected instances in the Spawner area with no filter set"
|
||||
)
|
||||
|
||||
|
||||
class TestShapeIntersectionFilter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="ShapeIntersectionFilter_InstancePlanting", args=["level"])
|
||||
def ShapeIntersectionFilter_InstancesPlantInAssignedShape():
|
||||
"""
|
||||
Summary:
|
||||
A spawner area is created with a Vegetation Shape Intersection Filter. 2 different shape entities are created,
|
||||
pinned to the Shape Intersection Filter, and instance counts are verified.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A spawner area is created with a Vegetation Shape Intersection Filter. 2 different shape entities are created,
|
||||
pinned to the Shape Intersection Filter, and instance counts are verified.
|
||||
Expected Behavior:
|
||||
The Shape Entity Id reference can be successfully set/updated. Instances spawn only in the specified shape area.
|
||||
|
||||
Expected Behavior:
|
||||
The Shape Entity Id reference can be successfully set/updated. Instances spawn only in the specified shape area.
|
||||
Test Steps:
|
||||
1) Open an existing level, and set view for visual debugging
|
||||
2) Create an instance spawner and planting surface
|
||||
3) Create child entity with Box Shape
|
||||
4) Create child entity with Cylinder Shape
|
||||
5) Assign the Intersection Filter to the Box Shape and validate instance counts
|
||||
6) Assign the Intersection Filter to the Cylinder Shape and validate instance counts
|
||||
7) Remove the shape reference on the Intersection Filter and validate instance counts
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level, and set view for visual debugging
|
||||
2) Create an instance spawner and planting surface
|
||||
3) Create child entity with Box Shape
|
||||
4) Create child entity with Cylinder Shape
|
||||
5) Assign the Intersection Filter to the Box Shape and validate instance counts
|
||||
6) Assign the Intersection Filter to the Cylinder Shape and validate instance counts
|
||||
7) Remove the shape reference on the Intersection Filter and validate instance counts
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import os
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
# 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0,
|
||||
asset_path)
|
||||
spawner_entity.add_component("Vegetation Shape Intersection Filter")
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Create a planting surface
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# 3) Create a child entity with Box Shape
|
||||
components_to_add = ["Box Shape"]
|
||||
box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
|
||||
box = hydra.Entity("Box", box_id)
|
||||
box.components = []
|
||||
for component in components_to_add:
|
||||
box.components.append(hydra.add_component(component, box_id))
|
||||
new_box_dimension = math.Vector3(5.0, 5.0, 5.0)
|
||||
hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 4) Create a child entity with Cylinder Shape
|
||||
components_to_add = ["Cylinder Shape"]
|
||||
cylinder_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
|
||||
cylinder = hydra.Entity("Cylinder", cylinder_id)
|
||||
cylinder.components = []
|
||||
for component in components_to_add:
|
||||
cylinder.components.append(hydra.add_component(component, cylinder_id))
|
||||
hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
|
||||
# 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0,
|
||||
asset_path)
|
||||
spawner_entity.add_component("Vegetation Shape Intersection Filter")
|
||||
|
||||
# 5) Set the Intersection Filter's Shape Entity Id to the Box Shape entity
|
||||
spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", box_id)
|
||||
# Create a planting surface
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# Validate instance counts. Instances should only plant in the Box Shape area
|
||||
num_expected = 49
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
|
||||
# 6) Set the Intersection Filter's Shape Entity Id to the Cylinder Shape entity
|
||||
spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", cylinder_id)
|
||||
# 3) Create a child entity with Box Shape
|
||||
components_to_add = ["Box Shape"]
|
||||
box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
|
||||
box = hydra.Entity("Box", box_id)
|
||||
box.components = []
|
||||
for component in components_to_add:
|
||||
box.components.append(hydra.add_component(component, box_id))
|
||||
new_box_dimension = math.Vector3(5.0, 5.0, 5.0)
|
||||
hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
|
||||
|
||||
# Validate instance counts. Instances should only plant in the Cylinder Shape area
|
||||
num_expected = 121
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
# 4) Create a child entity with Cylinder Shape
|
||||
components_to_add = ["Cylinder Shape"]
|
||||
cylinder_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
|
||||
cylinder = hydra.Entity("Cylinder", cylinder_id)
|
||||
cylinder.components = []
|
||||
for component in components_to_add:
|
||||
cylinder.components.append(hydra.add_component(component, cylinder_id))
|
||||
hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
|
||||
|
||||
# 7) Clear the Intersection Filter's Shape Entity Id reference
|
||||
spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", None)
|
||||
# 5) Set the Intersection Filter's Shape Entity Id to the Box Shape entity
|
||||
spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", box_id)
|
||||
|
||||
# Validate instance counts. Instances should now fill the entire spawner_entity's area
|
||||
num_expected = 20 * 20
|
||||
success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
self.test_success = success and self.test_success
|
||||
# Validate instance counts. Instances should only plant in the Box Shape area
|
||||
num_expected = 49
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.instance_count_in_box_shape, success)
|
||||
|
||||
# 6) Set the Intersection Filter's Shape Entity Id to the Cylinder Shape entity
|
||||
spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", cylinder_id)
|
||||
|
||||
# Validate instance counts. Instances should only plant in the Cylinder Shape area
|
||||
num_expected = 121
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.instance_count_in_cylinder_shape, success)
|
||||
|
||||
# 7) Clear the Intersection Filter's Shape Entity Id reference
|
||||
spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", None)
|
||||
|
||||
# Validate instance counts. Instances should now fill the entire spawner_entity's area
|
||||
num_expected = 20 * 20
|
||||
success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
|
||||
num_expected), 5.0)
|
||||
Report.result(Tests.unfiltered_instance_count, success)
|
||||
|
||||
|
||||
test = TestShapeIntersectionFilter()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(ShapeIntersectionFilter_InstancesPlantInAssignedShape)
|
||||
|
||||
+107
-96
@@ -5,121 +5,132 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
from math import radians
|
||||
import sys
|
||||
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
surface_entity_created = (
|
||||
"Successfully created Surface entity",
|
||||
"Failed to create Surface entity"
|
||||
)
|
||||
instance_count = (
|
||||
"Found the expected number of instances",
|
||||
"Unexpected number of instances found"
|
||||
)
|
||||
instances_aligned_0 = (
|
||||
"All instances are pointed straight up",
|
||||
"Found instances not aligned to surface pointing straight up"
|
||||
)
|
||||
instances_aligned_1 = (
|
||||
"All instances are planted perpendicularly to the surface",
|
||||
"Found instances not aligned to surface perpendicularly"
|
||||
)
|
||||
|
||||
|
||||
class TestSlopeAlignmentModifierOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SlopeAlignmentModifierOverrides", args=["level"])
|
||||
def SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment():
|
||||
"""
|
||||
Summary:
|
||||
Verifies instances properly align to surfaces based on configuration of descriptor overrides of the
|
||||
Vegetation Slope Alignment Modifier component.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
C4814459 Verifies instances properly align to surfaces based on configuration of descriptor overrides of the
|
||||
Vegetation Slope Alignment Modifier component.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
from math import radians
|
||||
|
||||
def verify_proper_alignment(instance, rot_degrees_vec):
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
|
||||
if instance.alignment.IsClose(expected_rotation):
|
||||
return True
|
||||
self.log(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
|
||||
return False
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Create empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
def verify_proper_alignment(instance, rot_degrees_vec):
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
|
||||
if instance.alignment.IsClose(expected_rotation):
|
||||
return True
|
||||
Report.info(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
|
||||
return False
|
||||
|
||||
# Create a spawner entity setup with all needed components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Create a sloped mesh surface for the instances to plant on
|
||||
center_point = math.Vector3(502.0, 512.0, 24.0)
|
||||
mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
|
||||
mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
|
||||
False)
|
||||
rotation = math.Vector3(0.0, radians(45.0), 0.0)
|
||||
surface_entity = hydra.Entity("Surface Entity")
|
||||
surface_entity.create_entity(
|
||||
center_point,
|
||||
["Mesh", "Mesh Surface Tag Emitter"]
|
||||
)
|
||||
if surface_entity.id.IsValid():
|
||||
print(f"'{surface_entity.name}' created")
|
||||
hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Add a Vegetation Debugger component to allow refreshing instances
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
# Create a spawner entity setup with all needed components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
|
||||
|
||||
# Add Vegetation Slope Alignment Modifier to the spawner entity and toggle on Allow Per-Item Overrides
|
||||
spawner_entity.add_component("Vegetation Slope Alignment Modifier")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
# Create a sloped mesh surface for the instances to plant on
|
||||
center_point = math.Vector3(502.0, 512.0, 24.0)
|
||||
mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
|
||||
mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
|
||||
False)
|
||||
rotation = math.Vector3(0.0, radians(45.0), 0.0)
|
||||
surface_entity = hydra.Entity("Surface Entity")
|
||||
surface_entity.create_entity(
|
||||
center_point,
|
||||
["Mesh", "Mesh Surface Tag Emitter"]
|
||||
)
|
||||
Report.critical_result(Tests.surface_entity_created, surface_entity.id.IsValid())
|
||||
hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
|
||||
|
||||
# Toggle on Surface Slope Alignment Override Enabled on the Vegetation Asset List component
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Override Enabled",
|
||||
True)
|
||||
# Add a Vegetation Debugger component to allow refreshing instances
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# Set Surface Slope Alignment Override Min and Max to 0 and validate instance alignment
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
|
||||
# Add Vegetation Slope Alignment Modifier to the spawner entity and toggle on Allow Per-Item Overrides
|
||||
spawner_entity.add_component("Vegetation Slope Alignment Modifier")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
|
||||
# Verify instances are have planted and are aligned to slope as expected
|
||||
num_expected = 20 * 20
|
||||
self.test_success = self.test_success and self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
# Toggle on Surface Slope Alignment Override Enabled on the Vegetation Asset List component
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Override Enabled",
|
||||
True)
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
# Set Surface Slope Alignment Override Min and Max to 0 and validate instance alignment
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
|
||||
|
||||
if self.test_success and num_expected == len(instances):
|
||||
for instance in instances:
|
||||
self.test_success = verify_proper_alignment(instance,
|
||||
math.Vector3(0.0, 0.0, 0.0)) and self.test_success
|
||||
# Verify instances are have planted and are aligned to slope as expected
|
||||
num_expected = 20 * 20
|
||||
instances_planted = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.critical_result(Tests.instance_count, instances_planted)
|
||||
|
||||
# Set Surface Slope Alignment Min and Max to 1 and validate instance alignment
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Min", 1.0)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 1.0)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
self.test_success = self.test_success and self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
success = True
|
||||
for instance in instances:
|
||||
success = verify_proper_alignment(instance, math.Vector3(0.0, 0.0, 0.0))
|
||||
Report.result(Tests.instances_aligned_0, success)
|
||||
|
||||
if self.test_success and num_expected == len(instances):
|
||||
for instance in instances:
|
||||
self.test_success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0)) and \
|
||||
self.test_success
|
||||
# Set Surface Slope Alignment Min and Max to 1 and validate instance alignment
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Min", 1.0)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 1.0)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
instances_planted = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.critical_result(Tests.instance_count, instances_planted)
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
|
||||
success = True
|
||||
for instance in instances:
|
||||
success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0))
|
||||
Report.result(Tests.instances_aligned_1, success)
|
||||
|
||||
|
||||
test = TestSlopeAlignmentModifierOverrides()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment)
|
||||
|
||||
+113
-101
@@ -5,127 +5,139 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
from math import radians
|
||||
import sys
|
||||
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
surface_entity_created = (
|
||||
"Successfully created Surface entity",
|
||||
"Failed to create Surface entity"
|
||||
)
|
||||
instance_count = (
|
||||
"Found the expected number of instances",
|
||||
"Unexpected number of instances found"
|
||||
)
|
||||
instances_aligned_1 = (
|
||||
"All instances are planted perpendicularly to the surface",
|
||||
"Found instances not aligned to surface perpendicularly"
|
||||
)
|
||||
instances_aligned_0 = (
|
||||
"All instances are pointed straight up",
|
||||
"Found instances not aligned to surface pointing straight up"
|
||||
)
|
||||
|
||||
|
||||
class TestSlopeAlignmentModifier(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SlopeAlignmentModifier", args=["level"])
|
||||
def SlopeAlignmentModifier_InstanceSurfaceAlignment():
|
||||
"""
|
||||
Summary:
|
||||
Verifies instances properly align to surfaces based on configuration of the Vegetation Slope Alignment
|
||||
Modifier.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
C4896941 Verifies instances properly align to surfaces based on configuration of the Vegetation Slope Alignment
|
||||
Modifier.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
from math import radians
|
||||
|
||||
def verify_proper_alignment(instance, rot_degrees_vec):
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
|
||||
if instance.alignment.IsClose(expected_rotation):
|
||||
return True
|
||||
self.log(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
|
||||
return False
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Create empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
def verify_proper_alignment(instance, rot_degrees_vec):
|
||||
expected_rotation = math.Quaternion()
|
||||
expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
|
||||
if instance.alignment.IsClose(expected_rotation):
|
||||
return True
|
||||
Report.info(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
|
||||
return False
|
||||
|
||||
# Create a spawner entity setup with all needed components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Create a sloped mesh surface for the instances to plant on
|
||||
center_point = math.Vector3(502.0, 512.0, 24.0)
|
||||
mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
|
||||
mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
|
||||
False)
|
||||
rotation = math.Vector3(0.0, radians(45.0), 0.0)
|
||||
surface_entity = hydra.Entity("Surface Entity")
|
||||
surface_entity.create_entity(
|
||||
center_point,
|
||||
["Mesh", "Mesh Surface Tag Emitter"]
|
||||
)
|
||||
if surface_entity.id.IsValid():
|
||||
print(f"'{surface_entity.name}' created")
|
||||
hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Add a Vegetation Debugger component to allow refreshing instances
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
# Create a spawner entity setup with all needed components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
|
||||
|
||||
# Add Vegetation Slope Alignment Modifier to the spawner entity
|
||||
spawner_entity.add_component("Vegetation Slope Alignment Modifier")
|
||||
# Create a sloped mesh surface for the instances to plant on
|
||||
center_point = math.Vector3(502.0, 512.0, 24.0)
|
||||
mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
|
||||
mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
|
||||
False)
|
||||
rotation = math.Vector3(0.0, radians(45.0), 0.0)
|
||||
surface_entity = hydra.Entity("Surface Entity")
|
||||
surface_entity.create_entity(
|
||||
center_point,
|
||||
["Mesh", "Mesh Surface Tag Emitter"]
|
||||
)
|
||||
Report.critical_result(Tests.surface_entity_created, surface_entity.id.IsValid())
|
||||
hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
|
||||
|
||||
# Set Alignment Coefficient Min/Max to 1 on the Slope Alignment Modifier
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 1.0)
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 1.0)
|
||||
# Add a Vegetation Debugger component to allow refreshing instances
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# Create new child entity with a Constant Gradient
|
||||
child_vegetation_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
|
||||
child_vegetation = hydra.Entity("Child Vegetation Entity", child_vegetation_id)
|
||||
components_to_add = ["Constant Gradient"]
|
||||
child_vegetation.components = []
|
||||
for component in components_to_add:
|
||||
child_vegetation.components.append(hydra.add_component(component, child_vegetation_id))
|
||||
# Add Vegetation Slope Alignment Modifier to the spawner entity
|
||||
spawner_entity.add_component("Vegetation Slope Alignment Modifier")
|
||||
|
||||
# Reference the Constant Gradient on the Slope Alignment Modifier component
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", child_vegetation_id)
|
||||
# Set Alignment Coefficient Min/Max to 1 on the Slope Alignment Modifier
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 1.0)
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 1.0)
|
||||
|
||||
# Verify instances are have planted and are aligned to slope as expected
|
||||
num_expected = 20 * 20
|
||||
self.test_success = self.test_success and self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
# Create new child entity with a Constant Gradient
|
||||
child_vegetation_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
|
||||
child_vegetation = hydra.Entity("Child Vegetation Entity", child_vegetation_id)
|
||||
components_to_add = ["Constant Gradient"]
|
||||
child_vegetation.components = []
|
||||
for component in components_to_add:
|
||||
child_vegetation.components.append(hydra.add_component(component, child_vegetation_id))
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
# Reference the Constant Gradient on the Slope Alignment Modifier component
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", child_vegetation_id)
|
||||
|
||||
if self.test_success and num_expected == len(instances):
|
||||
for instance in instances:
|
||||
self.test_success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0)) and \
|
||||
self.test_success
|
||||
# Verify instances are have planted and are aligned to slope as expected
|
||||
num_expected = 20 * 20
|
||||
instances_planted = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.critical_result(Tests.instance_count, instances_planted)
|
||||
|
||||
# Change Min/Max to 0.0 and verify proper alignment
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 0.0)
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 0.0)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
self.test_success = self.test_success and self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
success = True
|
||||
for instance in instances:
|
||||
success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0))
|
||||
Report.result(Tests.instances_aligned_1, success)
|
||||
|
||||
if self.test_success and num_expected == len(instances):
|
||||
for instance in instances:
|
||||
self.test_success = verify_proper_alignment(instance, math.Vector3(0.0, 0.0, 0.0)) and self.test_success
|
||||
# Change Min/Max to 0.0 and verify proper alignment
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 0.0)
|
||||
spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 0.0)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
instances_planted = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.critical_result(Tests.instance_count, instances_planted)
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
|
||||
success = True
|
||||
for instance in instances:
|
||||
success = verify_proper_alignment(instance, math.Vector3(0.0, 0.0, 0.0))
|
||||
Report.result(Tests.instances_aligned_0, success)
|
||||
|
||||
|
||||
test = TestSlopeAlignmentModifier()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(SlopeAlignmentModifier_InstanceSurfaceAlignment)
|
||||
|
||||
+97
-96
@@ -5,121 +5,122 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
C4874096 - Slope Min/Max properties can be set, and properly affect planted vegetation
|
||||
C4814464 - Slope Filter overrides function as expected
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
prefilter_instance_count = (
|
||||
"Found the expected number of instances before applying the Slope Filter",
|
||||
"Found an unexpected number of instances before applying the Slope Filter"
|
||||
)
|
||||
postfilter_instance_count = (
|
||||
"Found the expected number of instances after applying the Slope Filter",
|
||||
"Found an unexpected number of instances after applying the Slope Filter"
|
||||
)
|
||||
postfilter_overrides_instance_count = (
|
||||
"Found the expected number of instances after applying descriptor overrides to the Slope Filter",
|
||||
"Found an unexpected number of instances after applying descriptor overrides to the Slope Filter"
|
||||
)
|
||||
|
||||
|
||||
class TestSlopeFilterComponentAndOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SlopeFilter_InstancesPlantOnValidSlope", args=["level"])
|
||||
def SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes():
|
||||
"""
|
||||
Summary:
|
||||
An existing level is opened. A spawner entity is added, along with a flat planting surface at 32 on Z, and sphere
|
||||
mesh at 38 on Z to provide a sloped surface. A Slope Filter is added to the spawner entity, and Slope Min/Max
|
||||
values are set. Instance counts are validated. The same test is then performed for Slope Filter overrides.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. A spawner entity is added, along with a flat planting surface at 32 on Z, and sphere
|
||||
mesh at 38 on Z to provide a sloped surface. A Slope Filter is added to the spawner entity, and Slope Min/Max
|
||||
values are set. Instance counts are validated. The same test is then performed for Slope Filter overrides.
|
||||
Expected Behavior:
|
||||
Instances plant only on surfaces that fall between the Slope Filter Min/Max settings
|
||||
|
||||
Expected Behavior:
|
||||
Instances plant only on surfaces that fall between the Slope Filter Min/Max settings
|
||||
Test Steps:
|
||||
1) Open an existing level
|
||||
2) Create an instance spawner entity
|
||||
3) Create surfaces to plant on, one at 32 on Z and another sloped surface at 38 on Z.
|
||||
4) Initial instance counts pre-filter are verified.
|
||||
5) Slope Min/Max values are set on the Slope Filter component
|
||||
6) Instance counts are validated
|
||||
7) Setup for overrides tests
|
||||
8) Slope Min/Max values are set on the descriptor overrides
|
||||
9) Instance counts are validated
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level
|
||||
2) Create an instance spawner entity
|
||||
3) Create surfaces to plant on, one at 32 on Z and another sloped surface at 38 on Z.
|
||||
4) Initial instance counts pre-filter are verified.
|
||||
5) Slope Min/Max values are set on the Slope Filter component
|
||||
6) Instance counts are validated
|
||||
7) Setup for overrides tests
|
||||
8) Slope Min/Max values are set on the descriptor overrides
|
||||
9) Instance counts are validated
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 475.0, 38.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Add a Vegetation Slope Filter
|
||||
spawner_entity.add_component("Vegetation Slope Filter")
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 475.0, 38.0)
|
||||
|
||||
# 3) Add surfaces to plant on. This will include a flat surface and a sphere mesh to provide a sloped surface
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
sloped_surface_center = math.Vector3(512.0, 512.0, 38.0)
|
||||
dynveg.create_mesh_surface_entity_with_slopes("Sloped Planting Surface", sloped_surface_center, 10.0)
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
|
||||
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
# Add a Vegetation Slope Filter
|
||||
spawner_entity.add_component("Vegetation Slope Filter")
|
||||
|
||||
# 4) Validate instance counts pre-filter
|
||||
num_expected_flat_surface = 40 * 40 # 20x20 instances per 16m
|
||||
num_expected_slopes_pre_filter = 120 # Unfiltered planting on the top of the sphere mesh
|
||||
num_expected = num_expected_flat_surface + num_expected_slopes_pre_filter
|
||||
initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
|
||||
spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = initial_success and self.test_success
|
||||
# 3) Add surfaces to plant on. This will include a flat surface and a sphere mesh to provide a sloped surface
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
sloped_surface_center = math.Vector3(512.0, 512.0, 38.0)
|
||||
dynveg.create_mesh_surface_entity_with_slopes("Sloped Planting Surface", sloped_surface_center, 10.0)
|
||||
|
||||
# 5) Change Slope Min/Max on the Vegetation Slope Filter component
|
||||
spawner_entity.get_set_test(3, "Configuration|Slope Min", 20)
|
||||
spawner_entity.get_set_test(3, "Configuration|Slope Max", 45)
|
||||
# Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
|
||||
'Configuration|Area System Settings|Sector Point Snap Mode', 1)
|
||||
|
||||
# 6) Validate instance counts post-filter: instances should only plant on slopes between 20-45 degrees
|
||||
num_expected_slopes_post_filter = 48
|
||||
slope_min_max_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
|
||||
spawner_entity.id, num_expected_slopes_post_filter), 5.0)
|
||||
self.test_success = slope_min_max_success and self.test_success
|
||||
# 4) Validate instance counts pre-filter
|
||||
num_expected_flat_surface = 40 * 40 # 20x20 instances per 16m
|
||||
num_expected_slopes_pre_filter = 120 # Unfiltered planting on the top of the sphere mesh
|
||||
num_expected = num_expected_flat_surface + num_expected_slopes_pre_filter
|
||||
initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
|
||||
spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.prefilter_instance_count, initial_success)
|
||||
|
||||
# 7) Setup for overrides on the Slope Filter component and the spawner entity's descriptor
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Override Enabled", True)
|
||||
# 5) Change Slope Min/Max on the Vegetation Slope Filter component
|
||||
spawner_entity.get_set_test(3, "Configuration|Slope Min", 20)
|
||||
spawner_entity.get_set_test(3, "Configuration|Slope Max", 45)
|
||||
|
||||
# 8) Set Slope Filter Min/Max overrides on the spawner entity's descriptor
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Min", 5)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Max", 20)
|
||||
# 6) Validate instance counts post-filter: instances should only plant on slopes between 20-45 degrees
|
||||
num_expected_slopes_post_filter = 48
|
||||
slope_min_max_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
|
||||
spawner_entity.id, num_expected_slopes_post_filter), 5.0)
|
||||
Report.result(Tests.postfilter_instance_count, slope_min_max_success)
|
||||
|
||||
# 9) Validate instance counts post-filter: instances should only plant on slopes between 5-20 degrees
|
||||
num_expected_slopes_post_filter_overrides = 12
|
||||
overrides_min_max_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
|
||||
spawner_entity.id, num_expected_slopes_post_filter_overrides), 5.0)
|
||||
self.test_success = overrides_min_max_success and self.test_success
|
||||
# 7) Setup for overrides on the Slope Filter component and the spawner entity's descriptor
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Override Enabled", True)
|
||||
|
||||
# 8) Set Slope Filter Min/Max overrides on the spawner entity's descriptor
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Min", 5)
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Max", 20)
|
||||
|
||||
# 9) Validate instance counts post-filter: instances should only plant on slopes between 5-20 degrees
|
||||
num_expected_slopes_post_filter_overrides = 12
|
||||
overrides_min_max_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
|
||||
spawner_entity.id, num_expected_slopes_post_filter_overrides), 5.0)
|
||||
Report.result(Tests.postfilter_overrides_instance_count, overrides_min_max_success)
|
||||
|
||||
|
||||
test = TestSlopeFilterComponentAndOverrides()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes)
|
||||
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import azlmbr.math as math
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.paths
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.components as components
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
class TestSlopeFilterFilterStageToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SlopeFilter_FilterStageToggle", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Filter Stage toggle affects final vegetation position
|
||||
|
||||
Expected Result:
|
||||
Vegetation instances plant differently depending on the Filter Stage setting. With PreProcess, some vegetation instances can
|
||||
appear on slopes outside the filtered values. With PostProcess, vegetation instances only appear on the correct slope values.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# Create empty level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# Add a Vegetation Shape Intersection Filter to the vegetation area entity
|
||||
vegetation.add_component("Vegetation Shape Intersection Filter")
|
||||
|
||||
# Create a new entity as a child of the vegetation area entity with Box Shape
|
||||
box = hydra.Entity("box")
|
||||
box.create_entity(position, ["Box Shape"])
|
||||
box.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(8.0, 8.0, 1.0))
|
||||
|
||||
# Create a new entity as a child of the vegetation area entity with Cylinder Shape.
|
||||
cylinder = hydra.Entity("cylinder")
|
||||
cylinder.create_entity(position, ["Cylinder Shape"])
|
||||
cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
|
||||
cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
|
||||
box.set_test_parent_entity(vegetation)
|
||||
cylinder.set_test_parent_entity(vegetation)
|
||||
|
||||
# # On the Vegetation Shape Intersection Filter component, click the crosshair button, and add child entities one by one
|
||||
vegetation.get_set_test(3, "Configuration|Shape Entity Id", box.id)
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0, 100), 2.0)
|
||||
self.log(f"Vegetation plant only in the areas where the Box overlaps with the vegetation area's boundaries: {result}")
|
||||
vegetation.get_set_test(3, "Configuration|Shape Entity Id", cylinder.id)
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 100), 2.0)
|
||||
self.log(f"Vegetation plant only in the areas where the Cylinder overlaps with the vegetation area's boundaries: {result}")
|
||||
|
||||
# Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient Transform Modifier,
|
||||
# and Box Shape component
|
||||
random_noise = hydra.Entity("random_noise")
|
||||
random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
|
||||
random_noise.set_test_parent_entity(vegetation)
|
||||
|
||||
# Add a Vegetation Position Modifier to the vegetation area entity
|
||||
vegetation.add_component("Vegetation Position Modifier")
|
||||
|
||||
# Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
|
||||
vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
|
||||
|
||||
# Toggle between PreProcess and PostProcess
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 117), 2.0)
|
||||
self.log(f"Vegetation instances count equal to expected value for PREPROCESS filter stage: {result}")
|
||||
vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
|
||||
result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 122), 2.0)
|
||||
self.log(f"Vegetation instances count equal to expected value for POSTPROCESS filter stage: {result}")
|
||||
|
||||
test = TestSlopeFilterFilterStageToggle()
|
||||
test.run()
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
spawner_slice_created = (
|
||||
"Spawner slice created successfully",
|
||||
"Failed to create Spawner slice"
|
||||
)
|
||||
instance_count_unhidden = (
|
||||
"Initial instance counts are as expected",
|
||||
"Found an unexpected number of initial instances"
|
||||
)
|
||||
instance_count_hidden = (
|
||||
"Instance counts upon hiding the Spawner slice are as expected",
|
||||
"Unexpectedly found instances with the Spawner slice hidden"
|
||||
)
|
||||
blender_slice_created = (
|
||||
"Blender slice created successfully",
|
||||
"Failed to create Blender slice"
|
||||
)
|
||||
|
||||
|
||||
def SpawnerSlices_SliceCreationAndVisibilityToggleWorks():
|
||||
"""
|
||||
Summary:
|
||||
C2627900 Verifies if a slice containing the component can be created.
|
||||
C2627905 A slice containing the Vegetation Layer Blender component can be created.
|
||||
C2627904: Hiding a slice containing the component clears any visuals from the Viewport.
|
||||
|
||||
Expected Result:
|
||||
C2627900, C2627905: Slice is created, and is properly processed in the Asset Processor.
|
||||
C2627904: Vegetation area visuals are hidden from the Viewport.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.slice as slice
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.asset as asset
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
def path_is_valid_asset(asset_path):
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False)
|
||||
return asset_id.invoke("IsValid")
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# 2) C2627900 Verifies if a slice containing the Vegetation Layer Spawner component can be created.
|
||||
# 2.1) Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
veg_1 = dynveg.create_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# 2.2) Create slice from the entity
|
||||
slice_path = os.path.join("slices", "TestSlice_1.slice")
|
||||
slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", veg_1.id, slice_path)
|
||||
|
||||
# 2.3) Verify if the slice has been created successfully
|
||||
spawner_slice_success = helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
|
||||
Report.result(Tests.spawner_slice_created, spawner_slice_success)
|
||||
|
||||
# 3) C2627904: Hiding a slice containing the component clears any visuals from the Viewport
|
||||
# 3.1) Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# 3.2) Initially verify instance count before hiding slice
|
||||
initial_count_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400), 5.0)
|
||||
Report.result(Tests.instance_count_unhidden, initial_count_success)
|
||||
|
||||
# 3.3) Hide the slice and verify instance count
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, False)
|
||||
hidden_instance_count = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 0), 5.0)
|
||||
Report.result(Tests.instance_count_hidden, hidden_instance_count)
|
||||
|
||||
# 3.4) Unhide the slice
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, True)
|
||||
|
||||
# 4) C2627905 A slice containing the Vegetation Layer Blender component can be created.
|
||||
# 4.1) Create another vegetation entity to add to blender component
|
||||
veg_2 = dynveg.create_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0, "")
|
||||
|
||||
# 4.2) Create entity with Vegetation Layer Blender
|
||||
components_to_add = ["Box Shape", "Vegetation Layer Blender"]
|
||||
blender_entity = hydra.Entity("blender_entity")
|
||||
blender_entity.create_entity(position, components_to_add)
|
||||
|
||||
# 4.3) Pin both the vegetation areas to the blender entity
|
||||
pte = hydra.get_property_tree(blender_entity.components[1])
|
||||
path = "Configuration|Vegetation Areas"
|
||||
pte.update_container_item(path, 0, veg_1.id)
|
||||
pte.add_container_item(path, 1, veg_2.id)
|
||||
|
||||
# 4.4) Drag the simple vegetation areas under the Vegetation Layer Blender entity to create an entity hierarchy.
|
||||
veg_1.set_test_parent_entity(blender_entity)
|
||||
veg_2.set_test_parent_entity(blender_entity)
|
||||
|
||||
# 4.5) Create slice from blender entity
|
||||
slice_path = os.path.join("slices", "TestSlice_2.slice")
|
||||
slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", blender_entity.id, slice_path)
|
||||
|
||||
# 4.6) Verify if the slice has been created successfully
|
||||
blender_slice_success = helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
|
||||
Report.result(Tests.blender_slice_created, blender_slice_success)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(SpawnerSlices_SliceCreationAndVisibilityToggleWorks)
|
||||
+88
-90
@@ -5,99 +5,97 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
class Tests:
|
||||
editor_remains_stable = (
|
||||
"Editor did not crash following rapid surface data updates",
|
||||
"Editor crashed"
|
||||
)
|
||||
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
def SurfaceDataRefreshes_RemainsStable():
|
||||
"""
|
||||
Summary:
|
||||
The Vegetation Area System can intermittently crash when updating surface data and moving the camera
|
||||
around rapidly. The situation occurs across multiple frames - the surface data updates, which triggers a bunch
|
||||
of sector updates getting added to the update queue. Then in a subsequent frame, there is no active vegetation
|
||||
area or surface data updates, which triggers "delete all sectors". The "delete all" wasn't deleting entries from
|
||||
the update queue, so any unprocessed updates would continue to get processed. If any of those updates referenced
|
||||
a sector that no longer exists, because the camera changed position, then it would assert and crash.
|
||||
|
||||
To repro this bug, this test loads an empty level with a large box shape emitting a surface, and then runs a tight
|
||||
loop of camera movements and "surface changed" events that invalidate all surface points. Because this is a timing
|
||||
issue, there's no guarantee that the test below will successfully cause the condition to occur, but it successfully
|
||||
crashed every time it was tested locally prior to the bugfix.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
world_center = math.Vector3(512.0, 512.0, 32.0)
|
||||
|
||||
# Add an entity with a 1024 x 1024 box centered at 512,512.
|
||||
surface_entity = dynveg.create_surface_entity("Surface Data", world_center, 1024.0, 1024.0, 1.0)
|
||||
|
||||
# Move the camera to the world center
|
||||
general.set_current_view_position(world_center.x, world_center.y, world_center.z)
|
||||
|
||||
# 2) Perform the test. Since the conditions are extremely timing related, and every machine
|
||||
# running the test can have different timing conditions, we run through a set of different
|
||||
# combinations to try and cause the crash under as many scenarios as possible
|
||||
|
||||
loops_per_surface_changed = [3, 5, 5]
|
||||
loops_per_camera_reset = [20, 20, 20]
|
||||
camera_speed_per_loop = [10.0, 10.0, 15.0]
|
||||
|
||||
# Setting test success to false to make sure the toggle at the end accurately conveys the loop being successful
|
||||
test_success = False
|
||||
|
||||
# Loop through all our attempted timing test cases to cause the crash pretty consistently.
|
||||
for test_case in range(0,3):
|
||||
Report.info(f'Starting test case {test_case}')
|
||||
Report.info(f'Loops per surface changed: {loops_per_surface_changed[test_case]}')
|
||||
Report.info(f'Loops per camera reset: {loops_per_camera_reset[test_case]}')
|
||||
Report.info(f'Camera speed per loop: {camera_speed_per_loop[test_case]}')
|
||||
for test_counter in range(0, 100):
|
||||
|
||||
# Every N loops, invalidate the entire set of surface data. It's mostly just important for this
|
||||
# not to happen *every* iteration, since we need the vegetation system to bounce between having
|
||||
# dirty surface points that cause sectors to be refreshed, and having no dirty surface points or
|
||||
# active surface areas to trigger a "delete all sectors" condition.
|
||||
if (test_counter % loops_per_surface_changed[test_case]) == 0:
|
||||
azlmbr.surface_data.SurfaceDataSystemNotificationBus(azlmbr.bus.Broadcast,
|
||||
'OnSurfaceChanged',
|
||||
surface_entity.id,
|
||||
azlmbr.math.Aabb(),
|
||||
azlmbr.math.Aabb())
|
||||
|
||||
# Move the camera back and forth along the X axis at just the right speed to invalidate sectors that are
|
||||
# queued for updating but haven't updated yet, so that when they try to update they crash.
|
||||
x_pos = world_center.x + ((test_counter % loops_per_camera_reset[test_case]) * camera_speed_per_loop[test_case])
|
||||
general.set_current_view_position(x_pos, world_center.y, world_center.z)
|
||||
|
||||
Report.info(f'{test_counter}: {x_pos}')
|
||||
|
||||
# Give a little processing time each iteration.
|
||||
general.idle_wait(0.01)
|
||||
|
||||
# If we haven't crashed, then we've succeeded.
|
||||
test_success = True
|
||||
Report.result(Tests.editor_remains_stable, test_success)
|
||||
|
||||
|
||||
class TestSurfaceDataRefreshes_RemainsStable(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SurfaceDataRefreshes_RemainsStable", args=["level"])
|
||||
if __name__ == "__main__":
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
The Vegetation Area System can intermittently crash when updating surface data and moving the camera
|
||||
around rapidly. The situation occurs across multiple frames - the surface data updates, which triggers a bunch
|
||||
of sector updates getting added to the update queue. Then in a subsequent frame, there is no active vegetation
|
||||
area or surface data updates, which triggers "delete all sectors". The "delete all" wasn't deleting entries from
|
||||
the update queue, so any unprocessed updates would continue to get processed. If any of those updates referenced
|
||||
a sector that no longer exists, because the camera changed position, then it would assert and crash.
|
||||
|
||||
To repro this bug, this test creates an empty level with a large box shape emitting a surface, and then runs a tight
|
||||
loop of camera movements and "surface changed" events that invalidate all surface points. Because this is a timing
|
||||
issue, there's no guarantee that the test below will successfully cause the condition to occur, but it successfully
|
||||
crashed every time it was tested locally prior to the bugfix.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
# 1) Create a test level with the needed test setup
|
||||
self.test_success = self.create_level(
|
||||
self.get_arg('level'),
|
||||
heightmap_resolution=128,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=128,
|
||||
use_terrain=False)
|
||||
|
||||
world_center = math.Vector3(512.0, 512.0, 32.0)
|
||||
|
||||
# Add an entity with a 1024 x 1024 box centered at 512,512.
|
||||
surface_entity = dynveg.create_surface_entity("Surface Data", world_center, 1024.0, 1024.0, 1.0)
|
||||
|
||||
# Move the camera to the world center
|
||||
general.set_current_view_position(world_center.x, world_center.y, world_center.z)
|
||||
|
||||
# 2) Perform the test. Since the conditions are extremely timing related, and every machine
|
||||
# running the test can have different timing conditions, we run through a set of different
|
||||
# combinations to try and cause the crash under as many scenarios as possible
|
||||
|
||||
loops_per_surface_changed = [3, 5, 5]
|
||||
loops_per_camera_reset = [20, 20, 20]
|
||||
camera_speed_per_loop = [10.0, 10.0, 15.0]
|
||||
|
||||
# Setting test success to false to make sure the toggle at the end accurately conveys the loop being successful
|
||||
self.test_success = False
|
||||
|
||||
# Loop through all our attempted timing test cases to cause the crash pretty consistently.
|
||||
for test_case in range(0,3):
|
||||
self.log(f'Starting test case {test_case}')
|
||||
self.log(f'Loops per surface changed: {loops_per_surface_changed[test_case]}')
|
||||
self.log(f'Loops per camera reset: {loops_per_camera_reset[test_case]}')
|
||||
self.log(f'Camera speed per loop: {camera_speed_per_loop[test_case]}')
|
||||
for test_counter in range (0,100):
|
||||
|
||||
# Every N loops, invalidate the entire set of surface data. It's mostly just important for this
|
||||
# not to happen *every* iteration, since we need the vegetation system to bounce between having
|
||||
# dirty surface points that cause sectors to be refreshed, and having no dirty surface points or
|
||||
# active surface areas to trigger a "delete all sectors" condition.
|
||||
if (test_counter % loops_per_surface_changed[test_case]) == 0:
|
||||
azlmbr.surface_data.SurfaceDataSystemNotificationBus(azlmbr.bus.Broadcast,
|
||||
'OnSurfaceChanged',
|
||||
surface_entity.id,
|
||||
azlmbr.math.Aabb(),
|
||||
azlmbr.math.Aabb())
|
||||
|
||||
# Move the camera back and forth along the X axis at just the right speed to invalidate sectors that are
|
||||
# queued for updating but haven't updated yet, so that when they try to update they crash.
|
||||
x_pos = world_center.x + ((test_counter % loops_per_camera_reset[test_case]) * camera_speed_per_loop[test_case])
|
||||
general.set_current_view_position(x_pos, world_center.y, world_center.z)
|
||||
|
||||
self.log(f'{test_counter}: {x_pos}')
|
||||
|
||||
# Give a little processing time each iteration.
|
||||
general.idle_wait(0.01)
|
||||
|
||||
# If we haven't crashed, then we've succeeded.
|
||||
self.test_success = True
|
||||
|
||||
|
||||
test = TestSurfaceDataRefreshes_RemainsStable()
|
||||
test.run()
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(SurfaceDataRefreshes_RemainsStable)
|
||||
|
||||
+132
-125
@@ -5,153 +5,160 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
C3711666: Multiple Descriptors with different Surface Mask Filter overrides plant as expected.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
class Tests:
|
||||
initial_surface_validation = (
|
||||
"Found all expected instances on all surfaces with initial setup",
|
||||
"Found an unexpected number of instances on all surfaces with initial setup"
|
||||
)
|
||||
surface_a_validation = (
|
||||
"Found the expected number of instances on Surface A",
|
||||
"Found an unexpected number of instances on Surface A"
|
||||
)
|
||||
surface_b_validation = (
|
||||
"Found the expected number of instances on Surface B",
|
||||
"Found an unexpected number of instances on Surface B"
|
||||
)
|
||||
surface_c_validation = (
|
||||
"Found the expected number of instances on Surface C",
|
||||
"Found an unexpected number of instances on Surface C"
|
||||
)
|
||||
|
||||
|
||||
class TestSurfaceMaskFilterMultipleOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SurfaceMaskFilter_MultipleDescriptorOverrides", args=["level"])
|
||||
def SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected():
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. An instance spawner with 3 descriptors is created. 3 planting surfaces of different
|
||||
sizes are created and different surface tags are applied to each. Descriptor surface mask filter overrides are
|
||||
set and instance counts are validated.
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
A new level is created. An instance spawner with 3 descriptors is created. 3 planting surfaces of different
|
||||
sizes are created and different surface tags are applied to each. Descriptor surface mask filter overrides are
|
||||
set and instance counts are validated.
|
||||
Expected Behavior:
|
||||
Instances plant on surfaces based on surface mask filter overrides.
|
||||
|
||||
Expected Behavior:
|
||||
Instances plant on surfaces based on surface mask filter overrides.
|
||||
Test Steps:
|
||||
1) Open an existing level
|
||||
2) An instance spawner with 3 descriptors is created, and a Surface Mask Filter is added to the entity
|
||||
3) 3 surfaces of different sizes are created, and set to emit different tags
|
||||
4) Pre-test validation of instances
|
||||
5) Test 1 setup and validation: Inclusion tag matching surface a is set on a single descriptor
|
||||
6) Test 2 setup and validation: Inclusion tag matching surface b is set on a single descriptor
|
||||
7) Test 3 setup and validation: Inclusion tag matching surface c is set on a single descriptor
|
||||
|
||||
Test Steps:
|
||||
1) A new level is created
|
||||
2) An instance spawner with 3 descriptors is created, and a Surface Mask Filter is added to the entity
|
||||
3) 3 surfaces of different sizes are created, and set to emit different tags
|
||||
4) Pre-test validation of instances
|
||||
5) Test 1 setup and validation: Inclusion tag matching surface a is set on a single descriptor
|
||||
6) Test 2 setup and validation: Inclusion tag matching surface b is set on a single descriptor
|
||||
7) Test 3 setup and validation: Inclusion tag matching surface c is set on a single descriptor
|
||||
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.
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
:return: None
|
||||
"""
|
||||
surface_tag_list = [surface_data.SurfaceTag("test_tag"), surface_data.SurfaceTag("test_tag2"),
|
||||
surface_data.SurfaceTag("test_tag3")]
|
||||
import os
|
||||
|
||||
# 1) Create a new, temporary level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
asset_list_component = spawner_entity.components[2]
|
||||
desc_asset = hydra.get_component_property_value(asset_list_component,
|
||||
"Configuration|Embedded Assets")[0]
|
||||
desc_list = [desc_asset, desc_asset, desc_asset]
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
|
||||
|
||||
# Add a Surface Mask Filter component to the spawner entity and toggle on Allow Overrides
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
surface_tag_list = [surface_data.SurfaceTag("test_tag"), surface_data.SurfaceTag("test_tag2"),
|
||||
surface_data.SurfaceTag("test_tag3")]
|
||||
|
||||
# 3) Create 3 surfaces for planting, spaced out vertically, and set expected instance counts for each surface
|
||||
surface_entity_a = dynveg.create_surface_entity("Surface Entity A", math.Vector3(512.0, 512.0, 32.0),
|
||||
16.0, 16.0, 1.0)
|
||||
num_expected_surface_a = 20 * 20 # 20x20 instances on a 16x16 meter surface
|
||||
surface_entity_b = dynveg.create_surface_entity("Surface Entity B", math.Vector3(512.0, 512.0, 35.0),
|
||||
12.0, 12.0, 1.0)
|
||||
num_expected_surface_b = 15 * 15 # 15x15 instances on a 12x12 meter surface
|
||||
surface_entity_c = dynveg.create_surface_entity("Surface Entity C", math.Vector3(512.0, 512.0, 38.0),
|
||||
8.0, 8.0, 1.0)
|
||||
num_expected_surface_c = 10 * 10 # 10x10 instances on a 8x8 meter surface
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
# Set each surface to emit a different tag
|
||||
surface_entity_a.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[0]])
|
||||
surface_entity_b.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[1]])
|
||||
surface_entity_c.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[2]])
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 500.0, 38.0)
|
||||
general.set_current_view_rotation(-20.0, 0.0, 0.0)
|
||||
|
||||
# 4) Initial Validation: Validate instance count in the spawner area. Instances should plant on all surfaces
|
||||
num_expected = num_expected_surface_a + num_expected_surface_b + num_expected_surface_c
|
||||
initial_success = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
self.test_success = initial_success and self.test_success
|
||||
# 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors
|
||||
spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
|
||||
asset_path)
|
||||
asset_list_component = spawner_entity.components[2]
|
||||
desc_asset = hydra.get_component_property_value(asset_list_component,
|
||||
"Configuration|Embedded Assets")[0]
|
||||
desc_list = [desc_asset, desc_asset, desc_asset]
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
|
||||
|
||||
# 5)
|
||||
# Test #1 Setup: Set test_tag to inclusion list for descriptor 1. Set other descriptors to exclude all surfaces
|
||||
# Add a Surface Mask Filter component to the spawner entity and toggle on Allow Overrides
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
|
||||
|
||||
# Toggle on Display Per-Item Overrides and Surface Mask Filter Override for each descriptor
|
||||
for index in range(3):
|
||||
spawner_entity.get_set_test(2, f"Configuration|Embedded Assets|[{index}]|Display Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2,
|
||||
f"Configuration|Embedded Assets|[{index}]|Surface Mask Filter|Override Mode", 1)
|
||||
# 3) Create 3 surfaces for planting, spaced out vertically, and set expected instance counts for each surface
|
||||
surface_entity_a = dynveg.create_surface_entity("Surface Entity A", math.Vector3(512.0, 512.0, 32.0),
|
||||
16.0, 16.0, 1.0)
|
||||
num_expected_surface_a = 20 * 20 # 20x20 instances on a 16x16 meter surface
|
||||
surface_entity_b = dynveg.create_surface_entity("Surface Entity B", math.Vector3(512.0, 512.0, 35.0),
|
||||
12.0, 12.0, 1.0)
|
||||
num_expected_surface_b = 15 * 15 # 15x15 instances on a 12x12 meter surface
|
||||
surface_entity_c = dynveg.create_surface_entity("Surface Entity C", math.Vector3(512.0, 512.0, 38.0),
|
||||
8.0, 8.0, 1.0)
|
||||
num_expected_surface_c = 10 * 10 # 10x10 instances on a 8x8 meter surface
|
||||
|
||||
# Set each surface to emit a different tag
|
||||
surface_entity_a.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[0]])
|
||||
surface_entity_b.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[1]])
|
||||
surface_entity_c.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[2]])
|
||||
|
||||
# 4) Initial Validation: Validate instance count in the spawner area. Instances should plant on all surfaces
|
||||
num_expected = num_expected_surface_a + num_expected_surface_b + num_expected_surface_c
|
||||
initial_success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
|
||||
Report.result(Tests.initial_surface_validation, initial_success)
|
||||
|
||||
# 5)
|
||||
# Test #1 Setup: Set test_tag to inclusion list for descriptor 1. Set other descriptors to exclude all surfaces
|
||||
|
||||
# Toggle on Display Per-Item Overrides and Surface Mask Filter Override for each descriptor
|
||||
for index in range(3):
|
||||
spawner_entity.get_set_test(2, f"Configuration|Embedded Assets|[{index}]|Display Per-Item Overrides", True)
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
|
||||
[surface_tag_list[0]])
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[1]|Surface Mask Filter|Exclusion Tags",
|
||||
surface_tag_list)
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[2]|Surface Mask Filter|Exclusion Tags",
|
||||
surface_tag_list)
|
||||
f"Configuration|Embedded Assets|[{index}]|Surface Mask Filter|Override Mode", 1)
|
||||
|
||||
# Test #1 Validation: Validate instance count. Should only plant on a single surface for 400 instances
|
||||
test_1_success = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_a), 5.0)
|
||||
self.test_success = test_1_success and self.test_success
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
|
||||
[surface_tag_list[0]])
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[1]|Surface Mask Filter|Exclusion Tags",
|
||||
surface_tag_list)
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[2]|Surface Mask Filter|Exclusion Tags",
|
||||
surface_tag_list)
|
||||
|
||||
# 6)
|
||||
# Test #2 Setup: Set test_tag2 to inclusion for descriptor 1.
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
|
||||
[surface_tag_list[1]])
|
||||
# Test #1 Validation: Validate instance count. Should only plant on a single surface for 400 instances
|
||||
test_1_success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_a), 5.0)
|
||||
Report.result(Tests.surface_a_validation, test_1_success)
|
||||
|
||||
# Test #2 Validation: Validate instance count. Should only plant on a single surface for 225 instances
|
||||
test_2_success = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_b), 5.0)
|
||||
self.test_success = test_2_success and self.test_success
|
||||
# 6)
|
||||
# Test #2 Setup: Set test_tag2 to inclusion for descriptor 1.
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
|
||||
[surface_tag_list[1]])
|
||||
|
||||
# 7)
|
||||
# Test #3 Setup: Set test_tag3 to inclusion for descriptor 1.
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
|
||||
[surface_tag_list[2]])
|
||||
# Test #2 Validation: Validate instance count. Should only plant on a single surface for 225 instances
|
||||
test_2_success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_b), 5.0)
|
||||
Report.result(Tests.surface_b_validation, test_2_success)
|
||||
|
||||
# Test #3 Validation: Validate instance count. Should only plant on a single surface for 100 instances
|
||||
test_3_success = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_c), 5.0)
|
||||
self.test_success = test_3_success and self.test_success
|
||||
# 7)
|
||||
# Test #3 Setup: Set test_tag3 to inclusion for descriptor 1.
|
||||
spawner_entity.get_set_test(2,
|
||||
"Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
|
||||
[surface_tag_list[2]])
|
||||
|
||||
# Test #3 Validation: Validate instance count. Should only plant on a single surface for 100 instances
|
||||
test_3_success = helper.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_c), 5.0)
|
||||
Report.result(Tests.surface_c_validation, test_3_success)
|
||||
|
||||
|
||||
test = TestSurfaceMaskFilterMultipleOverrides()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected)
|
||||
|
||||
+49
-54
@@ -5,66 +5,61 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
class Tests:
|
||||
tags_same_value_equal = (
|
||||
"Two Surface Tags of the same value evaluated as equal",
|
||||
"Two Surface Tags of the same value unexpectedly evaluated as unequal"
|
||||
)
|
||||
tags_different_value_unequal = (
|
||||
"Two Surface Tags of different values evaluated as unequal",
|
||||
"Two Surface Tags of different values unexpectedly evaluated as equal"
|
||||
)
|
||||
|
||||
|
||||
class TestSurfaceMaskFilter_BasicSurfaceTagCreation(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="TestSurfaceMaskFilter_BasicSurfaceTagCreation", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verifies basic surface tag value equality
|
||||
def SurfaceMaskFilter_BasicSurfaceTagCreation():
|
||||
"""
|
||||
Summary:
|
||||
Verifies basic surface tag value equality
|
||||
|
||||
Expected Behavior:
|
||||
Surface tags of the same name are equal, and different names aren't.
|
||||
Expected Behavior:
|
||||
Surface tags of the same name are equal, and different names aren't.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create 2 new surface tags of identical names and verify they resolve as equal.
|
||||
3) Create another new tag of a different name and verify they resolve as different.
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create 2 new surface tags of identical names and verify they resolve as equal.
|
||||
3) Create another new tag of a different name and verify they resolve as different.
|
||||
|
||||
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.
|
||||
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
|
||||
"""
|
||||
self.log("SurfaceTag test started")
|
||||
|
||||
# Create a level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
|
||||
tag1 = surface_data.SurfaceTag()
|
||||
tag2 = surface_data.SurfaceTag()
|
||||
|
||||
# Test 1: Verify that two tags with the same value are equal
|
||||
tag1.SetTag('equal_test')
|
||||
tag2.SetTag('equal_test')
|
||||
self.log("SurfaceTag equal tag comparison is {} expected True".format(tag1.Equal(tag2)))
|
||||
self.test_success = self.test_success and tag1.Equal(tag2)
|
||||
|
||||
# Test 2: Verify that two tags with different values are not equal
|
||||
tag2.SetTag('not_equal_test')
|
||||
self.log("SurfaceTag not equal tag comparison is {} expected False".format(tag1.Equal(tag2)))
|
||||
self.test_success = self.test_success and not tag1.Equal(tag2)
|
||||
|
||||
self.log("SurfaceTag test finished")
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.surface_data as surface_data
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
|
||||
tag1 = surface_data.SurfaceTag()
|
||||
tag2 = surface_data.SurfaceTag()
|
||||
|
||||
# Test 1: Verify that two tags with the same value are equal
|
||||
tag1.SetTag('equal_test')
|
||||
tag2.SetTag('equal_test')
|
||||
Report.result(Tests.tags_same_value_equal, tag1.Equal(tag2))
|
||||
|
||||
# Test 2: Verify that two tags with different values are not equal
|
||||
tag2.SetTag('not_equal_test')
|
||||
Report.result(Tests.tags_different_value_unequal, not tag1.Equal(tag2))
|
||||
|
||||
|
||||
test = TestSurfaceMaskFilter_BasicSurfaceTagCreation()
|
||||
test.run()
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(SurfaceMaskFilter_BasicSurfaceTagCreation)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user