Integrating latest 47acbe8
This commit is contained in:
+127
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestAltitudeFilterComponentAndOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AltitudeFilterComponentAndOverrides", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# Add a Vegetation Altitude Filter
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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 = 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
|
||||
|
||||
|
||||
test = TestAltitudeFilterComponentAndOverrides()
|
||||
test.run()
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AltitudeFilter_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.
|
||||
PostProcess should cause some number of plants that appear above and below the desired altitude range to disappear.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
PREPROCESS_INSTANCE_COUNT = 16
|
||||
POSTPROCESS_INSTANCE_COUNT = 13
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# Add a Vegetation Altitude Filter to the vegetation area entity
|
||||
vegetation.add_component("Vegetation Altitude Filter")
|
||||
|
||||
# Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# Add entity with Mesh to replicate creation of hills
|
||||
dynveg.create_mesh_surface_entity_with_slopes("hill", position, 40.0, 40.0, 40.0)
|
||||
|
||||
# Increase Box Shape size to encompass the hills
|
||||
vegetation.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(100.0, 100.0, 100.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)
|
||||
|
||||
# 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 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}")
|
||||
|
||||
|
||||
test = TestAltitudeFilterFilterStageToggle()
|
||||
test.run()
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestAltitudeFilterShapeSample(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AltitudeFilterShapeSample", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# Add a Vegetation Altitude Filter
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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 = 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
|
||||
|
||||
|
||||
test = TestAltitudeFilterShapeSample()
|
||||
test.run()
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.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,
|
||||
)
|
||||
|
||||
# 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()
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestAssetListCombiner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AssetListCombiner_CombinedDescriptors", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
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 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
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
test = TestAssetListCombiner()
|
||||
test.run()
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestAssetWeightSelectorSortByWeight(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="AssetWeightSelector_SortByWeight", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# Add an Asset Weight Selector component to the spawner entity
|
||||
spawner_entity.add_component("Vegetation Asset Weight Selector")
|
||||
|
||||
# 3) Create a planting surface
|
||||
dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 1.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)
|
||||
|
||||
# 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 = 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
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
test = TestAssetWeightSelectorSortByWeight()
|
||||
test.run()
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestDebuggerDebugCVarsWorks(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="Debugger_DebugCVarsWorks", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
C2789148 Vegetation Debug CVars are enabled when the Debugger component is present
|
||||
|
||||
Expected Result:
|
||||
The following commands are available in the Editor only when the Vegetation Debugger Level component is present:
|
||||
veg_debugDumpReport (Command)
|
||||
veg_debugRefreshAllAreas (Command)
|
||||
|
||||
: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,
|
||||
)
|
||||
|
||||
# Initially run the command in console without Debugger component
|
||||
general.run_console("veg_debugDumpReport")
|
||||
|
||||
# Add the Vegetation Debugger component to the Level Inspector
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# Run a command again after adding the Vegetation debugger
|
||||
general.run_console("veg_debugRefreshAllAreas")
|
||||
|
||||
|
||||
test = TestDebuggerDebugCVarsWorks()
|
||||
test.run()
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestDistanceBetweenFilterComponentOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DistanceBetweenFilterComponentOverrides", args=["level"])
|
||||
|
||||
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) 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 Lumberyard 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
|
||||
"""
|
||||
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)
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# Add a Vegetation Debugger component to allow area refreshes
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 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)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
self.test_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 2), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 2), 5.0) and \
|
||||
self.test_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)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
self.test_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0) and \
|
||||
self.test_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)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
self.test_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0) and \
|
||||
self.test_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)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
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
|
||||
|
||||
|
||||
test = TestDistanceBetweenFilterComponentOverrides()
|
||||
test.run()
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestDistanceBetweenFilterComponent(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DistanceBetweenFilterComponent", args=["level"])
|
||||
|
||||
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) 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 Lumberyard 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
|
||||
"""
|
||||
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)
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# Add a Vegetation Debugger component to allow area refreshes
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 5) Add a Vegetation Distance Between Filter and verify initial instance counts are accurate
|
||||
spawner_entity.add_component("Vegetation Distance Between Filter")
|
||||
self.test_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 2), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 2), 5.0) and \
|
||||
self.test_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)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
self.test_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0) and \
|
||||
self.test_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)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
self.test_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0) and \
|
||||
self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0) and \
|
||||
self.test_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)
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
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
|
||||
|
||||
|
||||
test = TestDistanceBetweenFilterComponent()
|
||||
test.run()
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestDynamicSliceInstanceSpawner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawner", args=["level"])
|
||||
|
||||
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,
|
||||
)
|
||||
general.idle_wait(1.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')
|
||||
# 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}')
|
||||
|
||||
# 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}')
|
||||
|
||||
# 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}')
|
||||
|
||||
### 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"]
|
||||
)
|
||||
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)
|
||||
general.idle_wait(1.0)
|
||||
num_expected_instances = 20 * 20
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
property_tree_success = property_tree_success and (num_found == num_expected_instances)
|
||||
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)
|
||||
general.idle_wait(1.0)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
self.log(f'Allow Empty Assets test: Found {num_found} instances -- Expected {num_expected_instances} instances')
|
||||
allow_empty_assets_success = allow_empty_assets_success and (num_found == num_expected_instances)
|
||||
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)
|
||||
general.idle_wait(1.0)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
self.log(f'Spawn dynamic slices test: Found {num_found} instances -- Expected {num_expected_instances} instances')
|
||||
spawns_slices_success = spawns_slices_success and (num_found == num_expected_instances)
|
||||
self.test_success = self.test_success and spawns_slices_success
|
||||
self.log(f'Spawn dynamic slices test: {spawns_slices_success}')
|
||||
|
||||
|
||||
test = TestDynamicSliceInstanceSpawner()
|
||||
test.run()
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.entity as EntityId
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestDynamicSliceInstanceSpawnerEmbeddedEditor(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawnerEmbeddedEditor", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 3) Create a surface to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 128.0, 128.0, 1.0)
|
||||
|
||||
# 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
|
||||
|
||||
# 5) Create a new entity with a Camera component for testing in the launcher
|
||||
cam_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
camera_component = ["Camera"]
|
||||
new_entity_id2 = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", cam_position, EntityId.EntityId()
|
||||
)
|
||||
if new_entity_id2.IsValid():
|
||||
self.log("Camera entity created")
|
||||
camera_entity = hydra.Entity("Camera Entity", new_entity_id2)
|
||||
camera_entity.components = []
|
||||
for component in camera_component:
|
||||
camera_entity.components.append(hydra.add_component(component, new_entity_id2))
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.idle_wait(1.0)
|
||||
general.export_to_engine()
|
||||
general.idle_wait(1.0)
|
||||
|
||||
|
||||
test = TestDynamicSliceInstanceSpawnerEmbeddedEditor()
|
||||
test.run()
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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.entity as EntityId
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestDynamicSliceInstanceSpawnerExternalEditor(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawnerExternalEditor", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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, EntityId.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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 3) Create a surface to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", entity_position, 128.0, 128.0, 1.0)
|
||||
|
||||
# 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
|
||||
|
||||
# 5) Create a new entity with a Camera component for testing in the launcher
|
||||
entity_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
camera_component = ["Camera"]
|
||||
new_entity_id2 = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
if new_entity_id2.IsValid():
|
||||
self.log("Camera entity created")
|
||||
camera_entity = hydra.Entity("Camera Entity", new_entity_id2)
|
||||
camera_entity.components = []
|
||||
for component in camera_component:
|
||||
camera_entity.components.append(hydra.add_component(component, new_entity_id2))
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.idle_wait(1.0)
|
||||
general.export_to_engine()
|
||||
general.idle_wait(1.0)
|
||||
|
||||
|
||||
test = TestDynamicSliceInstanceSpawnerExternalEditor()
|
||||
test.run()
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestEmptyInstanceSpawner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="EmptyInstanceSpawner", args=["level"])
|
||||
|
||||
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,
|
||||
)
|
||||
general.idle_wait(1.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')
|
||||
self.test_success = self.test_success and behavior_context_test_success
|
||||
self.log(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')
|
||||
self.test_success = self.test_success and spawner_type_test_success
|
||||
self.log(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')
|
||||
self.test_success = self.test_success and spawner_test_success
|
||||
self.log(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"]
|
||||
)
|
||||
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
|
||||
general.idle_wait(2.0)
|
||||
num_expected_instances = 20 * 20
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
property_tree_success = property_tree_success and (num_found == num_expected_instances)
|
||||
self.test_success = self.test_success and property_tree_success
|
||||
self.log(f'Found {num_found} instances -- Expected {num_expected_instances} instances')
|
||||
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)
|
||||
general.idle_wait(2.0)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
allow_empty_assets_success = allow_empty_assets_success and (num_found == num_expected_instances)
|
||||
self.test_success = self.test_success and allow_empty_assets_success
|
||||
self.log(f'Allow Empty Assets test: {allow_empty_assets_success}')
|
||||
|
||||
|
||||
test = TestEmptyInstanceSpawner()
|
||||
test.run()
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestInstanceSpawnerPriority(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="InstanceSpawnerPriority", args=["level"])
|
||||
|
||||
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
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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 = 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
|
||||
|
||||
# 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 = 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 = TestInstanceSpawnerPriority()
|
||||
test.run()
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
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.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestVegLayerBlenderCreated(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerBlender_E2E_Editor", args=["level"])
|
||||
self.screenshot_count = 0
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
general.set_current_view_position(500.49, 498.69, 46.66)
|
||||
general.set_current_view_rotation(-42.05, 0.00, -36.33)
|
||||
|
||||
# 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)
|
||||
|
||||
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)
|
||||
|
||||
base_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
dynveg.create_surface_entity("Surface Entity",
|
||||
base_position,
|
||||
16.0, 16.0, 1.0)
|
||||
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 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")
|
||||
|
||||
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)
|
||||
|
||||
# 4) Verify instances in blender area are equally represented by both descriptors
|
||||
|
||||
# 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)
|
||||
|
||||
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
|
||||
|
||||
# 5) Create a new entity with a Camera component for testing in the launcher
|
||||
entity_position = math.Vector3(500.0, 500.0, 47.0)
|
||||
rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
|
||||
camera_component = ["Camera"]
|
||||
camera_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
if camera_id.IsValid():
|
||||
self.log("Camera entity created")
|
||||
camera_entity = hydra.Entity("Camera Entity", camera_id)
|
||||
camera_entity.components = []
|
||||
for component in camera_component:
|
||||
camera_entity.components.append(hydra.add_component(component, camera_id))
|
||||
azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", camera_id, rot_degrees_vector)
|
||||
|
||||
# 6) Save and export level
|
||||
general.save_level()
|
||||
general.idle_wait(1.0)
|
||||
general.export_to_engine()
|
||||
general.idle_wait(1.0)
|
||||
|
||||
|
||||
test = TestVegLayerBlenderCreated()
|
||||
test.run()
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 3) Create surface for planting on
|
||||
dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# 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 = 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) 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 = 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
|
||||
|
||||
|
||||
test = TestLayerBlocker()
|
||||
test.run()
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerSpawner_FilterStageToggle", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
PREPROCESS_INSTANCE_COUNT = 16
|
||||
POSTPROCESS_INSTANCE_COUNT = 19
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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, 10.0, asset_path)
|
||||
vegetation_entity.add_component("Vegetation Slope Filter")
|
||||
vegetation_entity.add_component("Vegetation Position Modifier")
|
||||
|
||||
# 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)
|
||||
|
||||
# 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 min and max values for Slope Filter
|
||||
vegetation_entity.get_set_test(3, "Configuration|Slope Min", 25)
|
||||
vegetation_entity.get_set_test(3, "Configuration|Slope Max", 35)
|
||||
|
||||
# Add entity with Mesh to replicate creation of hills
|
||||
dynveg.create_mesh_surface_entity_with_slopes("hill", position, 5.0, 5.0, 5.0)
|
||||
|
||||
# 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}")
|
||||
|
||||
|
||||
test = TestLayerSpawnerFilterStageToggle()
|
||||
test.run()
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestLayerSpawnerInheritBehavior(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerSpawner_InheritBehavior", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
SURFACE_TAG = "test_tag"
|
||||
|
||||
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)
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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 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 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 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
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)}"
|
||||
)
|
||||
|
||||
|
||||
test = TestLayerSpawnerInheritBehavior()
|
||||
test.run()
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestLayerSpawner_AllShapesPlant(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="TestLayerSpawner_AllShapesPlant", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
Expected Behavior:
|
||||
Vegetation properly plants in areas of any shape.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
# 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")
|
||||
|
||||
# Create surface for planting on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 60.0, 60.0, 1.0)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
test = TestLayerSpawner_AllShapesPlant()
|
||||
test.run()
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestLayerSpawnerInstanceCameraRefresh(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="LayerSpawner_InstanceCameraRefresh", args=["level"])
|
||||
|
||||
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
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
test = TestLayerSpawnerInstanceCameraRefresh()
|
||||
test.run()
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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.math as math
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class test_MeshBlocker_InstancesBlockedByMesh(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshBlocker_InstancesBlockedByMesh", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
blocker_entity = hydra.Entity("Blocker Entity")
|
||||
blocker_entity.create_entity(entity_position,
|
||||
["Mesh", "Vegetation Layer Blocker (Mesh)"])
|
||||
if blocker_entity.id.IsValid():
|
||||
print(f"'{blocker_entity.name}' created")
|
||||
|
||||
cubeId = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "default", "primitive_cube.cgf"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(0, "MeshComponentRenderNode|Mesh asset", cubeId)
|
||||
|
||||
# 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 1m 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
|
||||
|
||||
|
||||
test = test_MeshBlocker_InstancesBlockedByMesh()
|
||||
test.run()
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
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.math as math
|
||||
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshBlocker_InstancesBlockedByMeshHeightTuning", args=["level"])
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
# 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 cube mesh
|
||||
entity_position = math.Vector3(512.0, 512.0, 36.0)
|
||||
blocker_entity = hydra.Entity("Blocker Entity")
|
||||
blocker_entity.create_entity(entity_position,
|
||||
["Mesh", "Vegetation Layer Blocker (Mesh)"])
|
||||
if blocker_entity.id.IsValid():
|
||||
print(f"'{blocker_entity.name}' created")
|
||||
|
||||
sphereId = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "default", "primitive_sphere.cgf"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(0, "MeshComponentRenderNode|Mesh asset", sphereId)
|
||||
components.TransformBus(bus.Event, "SetLocalScale", blocker_entity.id, math.Vector3(5.0, 5.0, 5.0))
|
||||
|
||||
# 5) Adjust the height Max percentage values of blocker
|
||||
blocker_entity.get_set_test(1, "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 sphere at
|
||||
# 80% max height factored in.
|
||||
num_expected = 117
|
||||
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
|
||||
|
||||
|
||||
test = test_MeshBlocker_InstancesBlockedByMeshHeightTuning()
|
||||
test.run()
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestMeshSurfaceTagEmitter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshSurfaceTagEmitter_DependentOnMeshComponent", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
def is_component_enabled(EntityComponentIdPair):
|
||||
return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair)
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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")
|
||||
|
||||
# 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")
|
||||
|
||||
# 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])
|
||||
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")
|
||||
|
||||
|
||||
test = TestMeshSurfaceTagEmitter()
|
||||
test.run()
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestMeshSurfaceTagEmitter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSucessfully",
|
||||
args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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 = 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()}")
|
||||
|
||||
|
||||
test = TestMeshSurfaceTagEmitter()
|
||||
test.run()
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="PhysXColliderSurfaceTagEmitter_E2E_Editor", args=["level"])
|
||||
|
||||
def validate_behavior_context(self):
|
||||
# Verify that we can create the component through the BehaviorContext
|
||||
behavior_context_test_success = True
|
||||
test_component = azlmbr.surface_data.SurfaceDataColliderComponent()
|
||||
behavior_context_test_success = behavior_context_test_success and (test_component is not None)
|
||||
behavior_context_test_success = behavior_context_test_success and (test_component.typename ==
|
||||
'SurfaceDataColliderComponent')
|
||||
|
||||
# Verify that we can get/set the tags through the BehaviorContext
|
||||
provider_tag1 = azlmbr.surface_data.SurfaceTag('provider_tag1')
|
||||
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}')
|
||||
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.
|
||||
|
||||
: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:
|
||||
self.test_success = self.test_success and self.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_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_path = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("levels", "physics",
|
||||
"c4044697_material_perfacematerialvalidation",
|
||||
"test.pxmesh"), math.Uuid(), False)
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Shape", 7)
|
||||
hydra.get_set_test(collider_entity, 0, "Shape Configuration|Asset|PhysX Mesh", test_physx_mesh_asset_path)
|
||||
|
||||
# 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(0, "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)
|
||||
self.log("Starting PhysX Mesh Collider Test")
|
||||
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_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 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, 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, 0), 5.0)
|
||||
self.test_success = self.test_success and baseline_success
|
||||
|
||||
|
||||
test = TestPhysXColliderSurfaceTagEmitter()
|
||||
test.run()
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestPositionModifierAutoSnapToSurface(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="PositionModifier_AutoSnapToSurface", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 3) Create a spherical planting surface
|
||||
dynveg.create_mesh_surface_entity_with_slopes("Planting Surface", spawner_center_point, 5.0, 5.0, 5.0)
|
||||
|
||||
# 4) Verify initial instance counts pre-filter
|
||||
num_expected = 121 # 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
|
||||
|
||||
# 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)
|
||||
|
||||
# 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 5 on the x-axis
|
||||
spawner_entity.get_set_test(3, position_modifier_paths[0], 5)
|
||||
spawner_entity.get_set_test(3, position_modifier_paths[1], 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, 33.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
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
test = TestPositionModifierAutoSnapToSurface()
|
||||
test.run()
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestPositionModifierComponentAndOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="PositionModifierComponentAndOverrides_InstanceOffset", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
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']
|
||||
|
||||
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']
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(16.0, -5.0, 32.0)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 3) Add flat surface to plant on
|
||||
dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 0.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
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
for offset in offsets_to_test:
|
||||
if self.test_success:
|
||||
set_offset_and_verify_instance_counts(offset, spawner_center_point, is_override=True)
|
||||
|
||||
|
||||
test = TestPositionModifierComponentAndOverrides()
|
||||
test.run()
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestRotationModifierOverrides_InstancesRotateWithinRange(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="RotationModifierOverrides_InstancesRotateWithinRange", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
# 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.run_console("e_WaterOcean=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
|
||||
|
||||
# Create surface to spawn on
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 16.0, 16.0, 1.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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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 = 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
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
test = TestRotationModifierOverrides_InstancesRotateWithinRange()
|
||||
test.run()
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestRotationModifier_InstancesRotateWithinRange(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="RotationModifier_InstancesRotateWithinRange", args=["level"])
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
Test Steps:
|
||||
1) Create 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.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# Test Constants
|
||||
LEVEL_CENTER = math.Vector3(512.0, 512.0, 32.0)
|
||||
constant_gradient_value = 0.15
|
||||
|
||||
# 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)
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
|
||||
# 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,
|
||||
)
|
||||
general.run_console("e_WaterOcean=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
|
||||
)
|
||||
if gradient_entity.id.IsValid():
|
||||
self.log(f"'{gradient_entity.name}' created")
|
||||
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
|
||||
)
|
||||
|
||||
# Set up constants used across all the rotation checks
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
test = TestRotationModifier_InstancesRotateWithinRange()
|
||||
test.run()
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
# Constants
|
||||
CLOSE_ENOUGH_THRESHOLD = 0.01
|
||||
|
||||
|
||||
class TestScaleModifierOverrides_InstancesProperlyScale(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="ScaleModifierOverrides_InstancesProperlyScale", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
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)
|
||||
|
||||
# Clear all areas to force a refresh
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
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",
|
||||
)
|
||||
)
|
||||
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")
|
||||
|
||||
# 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")
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
test = TestScaleModifierOverrides_InstancesProperlyScale()
|
||||
test.run()
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestScaleModifier_InstancesProperlyScale(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="ScaleModifier_InstancesProperlyScale", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
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)
|
||||
|
||||
# Clear all areas to force a refresh
|
||||
general.run_console('veg_debugClearAllAreas')
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
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 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")
|
||||
|
||||
# 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")
|
||||
|
||||
# 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")
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
|
||||
test = TestScaleModifier_InstancesProperlyScale()
|
||||
test.run()
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestShapeIntersectionFilter(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="ShapeIntersectionFilter_InstancePlanting", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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")
|
||||
|
||||
# Create a planting surface
|
||||
dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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 = 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
|
||||
|
||||
|
||||
test = TestShapeIntersectionFilter()
|
||||
test.run()
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestSlopeAlignmentModifierOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SlopeAlignmentModifierOverrides", args=["level"])
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# Create a sloped mesh surface for the instances to plant on
|
||||
mesh_asset_path = os.path.join("Objects", "default", "primitive_plane.cgf")
|
||||
mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
|
||||
False)
|
||||
rotation = math.Vector3(0.0, radians(45.0), 0.0)
|
||||
scale = math.Vector3(30.0, 30.0, 30.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, "MeshComponentRenderNode|Mesh asset", mesh_asset)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
|
||||
components.TransformBus(bus.Event, "SetLocalScale", surface_entity.id, scale)
|
||||
|
||||
# Add a Vegetation Debugger component to allow refreshing instances
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
|
||||
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
|
||||
|
||||
# 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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
test = TestSlopeAlignmentModifierOverrides()
|
||||
test.run()
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestSlopeAlignmentModifier(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SlopeAlignmentModifier", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
C4896941 Verifies instances properly align to surfaces based on configuration of the Vegetation Slope Alignment
|
||||
Modifier.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
# 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 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)
|
||||
|
||||
# Create a sloped mesh surface for the instances to plant on
|
||||
mesh_asset_path = os.path.join("Objects", "default", "primitive_plane.cgf")
|
||||
mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
|
||||
False)
|
||||
rotation = math.Vector3(0.0, radians(45.0), 0.0)
|
||||
scale = math.Vector3(30.0, 30.0, 30.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, "MeshComponentRenderNode|Mesh asset", mesh_asset)
|
||||
components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
|
||||
components.TransformBus(bus.Event, "SetLocalScale", surface_entity.id, scale)
|
||||
|
||||
# Add a Vegetation Debugger component to allow refreshing instances
|
||||
hydra.add_level_component("Vegetation Debugger")
|
||||
|
||||
# Add Vegetation Slope Alignment Modifier to the spawner entity
|
||||
spawner_entity.add_component("Vegetation Slope Alignment Modifier")
|
||||
|
||||
# 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)
|
||||
|
||||
# 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))
|
||||
|
||||
# Reference the Constant Gradient on the Slope Alignment Modifier component
|
||||
spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", child_vegetation_id)
|
||||
|
||||
# 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)
|
||||
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
|
||||
|
||||
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
|
||||
|
||||
# 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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
test = TestSlopeAlignmentModifier()
|
||||
test.run()
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestSlopeFilterComponentAndOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SlopeFilter_InstancesPlantOnValidSlope", args=["level"])
|
||||
|
||||
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
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
general.set_current_view_position(512.0, 475.0, 38.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)
|
||||
|
||||
# Add a Vegetation Slope Filter
|
||||
spawner_entity.add_component("Vegetation Slope Filter")
|
||||
|
||||
# 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, 5.0, 5.0, 5.0)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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)
|
||||
|
||||
# 6) Validate instance counts post-filter: instances should only plant on slopes between 20-45 degrees
|
||||
num_expected_slopes_post_filter = 44
|
||||
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
|
||||
|
||||
# 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 = 16
|
||||
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
|
||||
|
||||
|
||||
test = TestSlopeFilterComponentAndOverrides()
|
||||
test.run()
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.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,
|
||||
)
|
||||
|
||||
# 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()
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestSurfaceDataRefreshes_RemainsStable(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SurfaceDataRefreshes_RemainsStable", args=["level"])
|
||||
|
||||
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()
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
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 automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestSurfaceMaskFilterMultipleOverrides(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SurfaceMaskFilter_MultipleDescriptorOverrides", args=["level"])
|
||||
|
||||
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.
|
||||
|
||||
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 Lumberyard 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
|
||||
"""
|
||||
surface_tag_list = [surface_data.SurfaceTag("test_tag"), surface_data.SurfaceTag("test_tag2"),
|
||||
surface_data.SurfaceTag("test_tag3")]
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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 = 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
|
||||
|
||||
# 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,
|
||||
f"Configuration|Embedded Assets|[{index}]|Surface Mask Filter|Override Mode", 1)
|
||||
|
||||
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)
|
||||
|
||||
# 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
|
||||
|
||||
# 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 #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
|
||||
|
||||
# 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 = 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
|
||||
|
||||
|
||||
test = TestSurfaceMaskFilterMultipleOverrides()
|
||||
test.run()
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestSurfaceMaskFilter_BasicSurfaceTagCreation(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="TestSurfaceMaskFilter_BasicSurfaceTagCreation", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
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")
|
||||
|
||||
|
||||
test = TestSurfaceMaskFilter_BasicSurfaceTagCreation()
|
||||
test.run()
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
"""
|
||||
C2561342: Exclusive Surface Masks tags function
|
||||
"""
|
||||
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.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.shape as shape
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestExclusiveSurfaceMasksTag(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SurfaceMaskFilter_ExclusionList", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
New level is created and set up with surface shapes with varying surface tags. A simple vegetation area has been
|
||||
created and Vegetation Surface Mask Filter component is added to entity with terrain hole exclusion tag.
|
||||
|
||||
Expected Behavior:
|
||||
With default Exclusion settings, vegetation does not plant over the terrain holes.
|
||||
With Exclusion Weight Max below 1.0, vegetation plants over the terrain holes.
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level.
|
||||
2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
3) Add a Vegetation Surface Mask Filter component to the entity.
|
||||
4) Create 2 surface entities to represent terrain and terrain hole surfaces
|
||||
5) Add an Exclusion List tag to the component, and set it to terrainHole.
|
||||
6) Check spawn count with default Exclusion Weights
|
||||
7) Check spawn count with Exclusion Weight Max set below 1.0
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
def update_surface_tag_exclusion_list(Entity, component_index, surface_tag):
|
||||
tag_list = [surface_data.SurfaceTag()]
|
||||
|
||||
# assign list with one surface tag to exclusion list
|
||||
hydra.get_set_test(Entity, component_index, "Configuration|Exclusion|Surface Tags", tag_list)
|
||||
|
||||
# set that one surface tag element to required surface tag
|
||||
component = Entity.components[component_index]
|
||||
path = "Configuration|Exclusion|Surface Tags|[0]|Surface Tag"
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
|
||||
new_value = hydra.get_component_property_value(component, path)
|
||||
|
||||
if new_value == surface_tag:
|
||||
self.log(f"Exclusive surface mask filter of {surface_tag} is added successfully")
|
||||
else:
|
||||
self.log(f"Failed to add an Exclusive surface mask filter of {surface_tag}")
|
||||
|
||||
def update_generated_surface_tag(Entity, component_index, surface_tag):
|
||||
tag_list = [surface_data.SurfaceTag()]
|
||||
|
||||
# assign list with one surface tag to Generated Tags list
|
||||
hydra.get_set_test(Entity, component_index, "Configuration|Generated Tags", tag_list)
|
||||
|
||||
# set that one surface tag element to required surface tag
|
||||
component = Entity.components[component_index]
|
||||
path = "Configuration|Generated Tags|[0]|Surface Tag"
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
|
||||
new_value = hydra.get_component_property_value(component, path)
|
||||
|
||||
if new_value == surface_tag:
|
||||
self.log(f"Generated surface tag of {surface_tag} is added successfully")
|
||||
else:
|
||||
self.log(f"Failed to add Generated surface tag of {surface_tag}")
|
||||
|
||||
# 1) 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,
|
||||
)
|
||||
|
||||
# 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) Add a Vegetation Surface Mask Filter component to the entity.
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
|
||||
# 4) Create 2 surface entities to represent terrain and terrain hole surfaces
|
||||
surface_tags: dict = {"terrainHole": 1327698037, "terrain": 3363197873}
|
||||
entity_position = math.Vector3(510.0, 512.0, 32.0)
|
||||
surface_entity_1 = dynveg.create_surface_entity("Surface Entity 1",
|
||||
entity_position,
|
||||
10.0, 10.0, 1.0)
|
||||
update_generated_surface_tag(surface_entity_1, 1, surface_tags["terrainHole"])
|
||||
|
||||
entity_position = math.Vector3(520.0, 512.0, 32.0)
|
||||
surface_entity_2 = dynveg.create_surface_entity("Surface Entity 2",
|
||||
entity_position,
|
||||
10.0, 10.0, 1.0)
|
||||
update_generated_surface_tag(surface_entity_2, 1, surface_tags["terrain"])
|
||||
|
||||
# 5) Add an Exclusion List tag to the component, and set it to "terrainHole".
|
||||
update_surface_tag_exclusion_list(spawner_entity, 3, surface_tags["terrainHole"])
|
||||
|
||||
# 6) Check spawn count with default Exclusion Weights
|
||||
general.idle_wait(2.0) # Allow a few seconds for instances to spawn
|
||||
num_expected_instances = 39
|
||||
box = shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = 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
|
||||
|
||||
# 7) Check spawn count with Exclusion Weight Max set below 1.0
|
||||
hydra.get_set_test(spawner_entity, 3, "Configuration|Exclusion|Weight Max", 0.9)
|
||||
general.idle_wait(2.0) # Allow a few seconds for instances to spawn
|
||||
num_expected_instances = 169
|
||||
num_found = 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
|
||||
|
||||
|
||||
test = TestExclusiveSurfaceMasksTag()
|
||||
test.run()
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
"""
|
||||
C2561341: Inclusive Surface Masks tags function
|
||||
"""
|
||||
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.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.shape as shape
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestInclusiveSurfaceMasksTag(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SurfaceMaskFilter_InclusionList", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
New level is created and set up with surface shapes with varying surface tags. A simple vegetation area has been
|
||||
created and Vegetation Surface Mask Filter component is added to entity with terrain hole inclusion tag.
|
||||
|
||||
Expected Behavior:
|
||||
With default Inclusion Weights, vegetation draws over the terrain holes.
|
||||
With Inclusion Weight Max set below 1.0, vegetation stops drawing over the terrain holes.
|
||||
|
||||
Test Steps:
|
||||
1) Create a new level
|
||||
2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
3) Add a Vegetation Surface Mask Filter component to the entity.
|
||||
4) Create 2 surface entities to represent terrain and terrain hole surfaces
|
||||
5) Add an Inclusion List tag to the component, and set it to "terrainHole".
|
||||
6) Check spawn count with default Inclusion Weights
|
||||
7) Check spawn count with Inclusion Weight Max set below 1.0
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
def update_surface_tag_inclusion_list(Entity, component_index, surface_tag):
|
||||
tag_list = [surface_data.SurfaceTag()]
|
||||
|
||||
# assign list with one surface tag to inclusion list
|
||||
hydra.get_set_test(Entity, component_index, "Configuration|Inclusion|Surface Tags", tag_list)
|
||||
|
||||
# set that one surface tag element to required surface tag
|
||||
component = Entity.components[component_index]
|
||||
path = "Configuration|Inclusion|Surface Tags|[0]|Surface Tag"
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
|
||||
new_value = hydra.get_component_property_value(component, path)
|
||||
|
||||
if new_value == surface_tag:
|
||||
print("Inclusive surface mask filter of terrainHole is added successfully")
|
||||
else:
|
||||
print("Failed to add an Inclusive surface mask filter of terrainHole")
|
||||
general.idle_wait(2.0)
|
||||
|
||||
def update_generated_surface_tag(Entity, component_index, surface_tag):
|
||||
tag_list = [surface_data.SurfaceTag()]
|
||||
|
||||
# assign list with one surface tag to Generated Tags list
|
||||
hydra.get_set_test(Entity, component_index, "Configuration|Generated Tags", tag_list)
|
||||
|
||||
# set that one surface tag element to required surface tag
|
||||
component = Entity.components[component_index]
|
||||
path = "Configuration|Generated Tags|[0]|Surface Tag"
|
||||
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
|
||||
new_value = hydra.get_component_property_value(component, path)
|
||||
|
||||
if new_value == surface_tag:
|
||||
self.log(f"Generated surface tag of {surface_tag} is added successfully")
|
||||
else:
|
||||
self.log(f"Failed to add Generated surface tag of {surface_tag}")
|
||||
|
||||
# 1) 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,
|
||||
)
|
||||
|
||||
# 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) Add a Vegetation Surface Mask Filter component to the entity.
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
|
||||
# 4) Create 2 surface entities to represent terrain and terrain hole surfaces
|
||||
surface_tags: dict = {"terrainHole": 1327698037, "terrain": 3363197873}
|
||||
entity_position = math.Vector3(510.0, 512.0, 32.0)
|
||||
surface_entity_1 = dynveg.create_surface_entity("Surface Entity 1",
|
||||
entity_position,
|
||||
10.0, 10.0, 1.0)
|
||||
update_generated_surface_tag(surface_entity_1, 1, surface_tags["terrainHole"])
|
||||
|
||||
entity_position = math.Vector3(520.0, 512.0, 32.0)
|
||||
surface_entity_2 = dynveg.create_surface_entity("Surface Entity 2",
|
||||
entity_position,
|
||||
10.0, 10.0, 1.0)
|
||||
update_generated_surface_tag(surface_entity_2, 1, surface_tags["terrain"])
|
||||
|
||||
# 5) Add an Inclusion List tag to the component, and set it to "terrainHole".
|
||||
update_surface_tag_inclusion_list(spawner_entity, 3, surface_tags["terrainHole"])
|
||||
|
||||
# 6) Check spawn count with default Inclusion Weights
|
||||
general.idle_wait(2.0) # Allow a few seconds for instances to spawn
|
||||
num_expected_instances = 130
|
||||
box = shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = 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
|
||||
|
||||
# 7) Check spawn count with Inclusion Weight Max set below 1.0
|
||||
hydra.get_set_test(spawner_entity, 3, "Configuration|Inclusion|Weight Max", 0.9)
|
||||
general.idle_wait(2.0) # Allow a few seconds for instances to update
|
||||
num_expected_instances = 0
|
||||
num_found = 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
|
||||
|
||||
|
||||
test = TestInclusiveSurfaceMasksTag()
|
||||
test.run()
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestSystemSettingsSectorPointDensity(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SystemSettings_SectorPointDensity", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Sector Point Density increases/reduces the number of vegetation points within a sector
|
||||
|
||||
Expected Result:
|
||||
Default value for Sector Point Density is 20.
|
||||
20 vegetation meshes appear on each side of the established vegetation area with the default value.
|
||||
When altered, the specified number of vegetation meshes along a side of a vegetation area matches the value set
|
||||
in Sector Point Density.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
INSTANCE_COUNT_BEFORE_DENSITY_CHANGE = 400
|
||||
INSTANCE_COUNT_AFTER_DENSITY_CHANGE = 100
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
|
||||
dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
|
||||
dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# Count the number of vegetation meshes along one side of the new vegetation area. #
|
||||
result = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count(position, 8.0, INSTANCE_COUNT_BEFORE_DENSITY_CHANGE), 2.0
|
||||
)
|
||||
self.log(f"Vegetation instances count equal to expected value before changing sector point density: {result}")
|
||||
|
||||
# Add the Vegetation Debugger component to the Level Inspector
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
|
||||
# Change Sector Point Density to 10
|
||||
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",
|
||||
10,
|
||||
)
|
||||
|
||||
# Count the number of vegetation meshes along one side of the new vegetation area.
|
||||
result = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count(position, 8.0, INSTANCE_COUNT_AFTER_DENSITY_CHANGE), 2.0
|
||||
)
|
||||
self.log(f"Vegetation instances count equal to expected value after changing sector point density: {result}")
|
||||
|
||||
|
||||
test = TestSystemSettingsSectorPointDensity()
|
||||
test.run()
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
import automatedtesting_shared.hydra_editor_utils as hydra
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestSystemSettingsSectorSize(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="SystemSettings_SectorSize", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Sector Size In Meters increases/reduces the size of a sector
|
||||
|
||||
Expected Result:
|
||||
The number of spawned vegetation meshes inside the vegetation area is identical after updating the Sector Size
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
VEGETATION_INSTANCE_COUNT = 400
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
# 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, 1.0, asset_path)
|
||||
dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
|
||||
|
||||
# Add the Vegetation Debugger component to the Level Inspector
|
||||
veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
|
||||
|
||||
# Count the number of vegetation meshes along one side of the new vegetation area.
|
||||
result = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count(position, 8.0, VEGETATION_INSTANCE_COUNT), 2.0
|
||||
)
|
||||
self.log(f"Vegetation instances count equal to expected value before changing sector size: {result}")
|
||||
|
||||
# Change Sector Size in Meters to 10.
|
||||
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 Size In Meters",
|
||||
10,
|
||||
)
|
||||
|
||||
# Alter the Box Shape to be 10,10,1
|
||||
vegetation.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(10.0, 10.0, 1.0))
|
||||
|
||||
# Count the number of vegetation meshes along one side of the new vegetation area.
|
||||
result = self.wait_for_condition(
|
||||
lambda: dynveg.validate_instance_count(position, 5.0, VEGETATION_INSTANCE_COUNT), 2.0
|
||||
)
|
||||
self.log(f"Vegetation instances count equal to expected value after changing sector size: {result}")
|
||||
|
||||
|
||||
test = TestSystemSettingsSectorSize()
|
||||
test.run()
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
This script tests for regressions of "vegetation instances don't despawn correctly
|
||||
when the camera moves beyond the range of all active vegetation areas".
|
||||
|
||||
This creates a new level and a vegetation area with 400 instances.
|
||||
The expectation is that we will have 400 instances in that area when the camera is centered on it,
|
||||
and 0 instances when the camera is moved sufficiently far away.
|
||||
"""
|
||||
|
||||
import sys, os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
|
||||
|
||||
class TestVegetationInstances_DespawnWhenOutOfRange(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix='VegetationInstances_DespawnWhenOutOfRange', args=['level'])
|
||||
|
||||
def run_test(self):
|
||||
|
||||
# Create a new level
|
||||
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)
|
||||
|
||||
# Create vegetation layer spawner
|
||||
world_center = math.Vector3(512.0, 512.0, 32.0)
|
||||
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
|
||||
spawner_entity = dynveg.create_vegetation_area("Spawner Instance", world_center, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# Create a surface to spawn on
|
||||
dynveg.create_surface_entity("Spawner Entity", world_center, 16.0, 16.0, 1.0)
|
||||
|
||||
# Get the root position of our veg area and use it to position our camera.
|
||||
# This is useful both to ensure that vegetation is spawned where we're querying and to
|
||||
# visually verify the number of instances in each box
|
||||
position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", spawner_entity.id)
|
||||
general.set_current_view_position(position.x, position.y, position.z + 30.0)
|
||||
general.set_current_view_rotation(-90.0, 0.0, 0.0)
|
||||
|
||||
# When centered over the veg area, we expect to find 400 instances.
|
||||
# (16x16 area, 20 points per 16 meters)
|
||||
num_expected = 400
|
||||
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
|
||||
|
||||
# Move sufficiently far away from the veg area that it should all despawn.
|
||||
general.set_current_view_position(position.x - 1000.0, position.y - 1000.0, position.z + 30.0)
|
||||
|
||||
# We now expect to find 0 instances. If the bug exists, we will find 400 still.
|
||||
num_expected = 0
|
||||
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
|
||||
|
||||
|
||||
test = TestVegetationInstances_DespawnWhenOutOfRange()
|
||||
test.run()
|
||||
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
Reference in New Issue
Block a user