Merge branch 'development' of https://github.com/aws-lumberyard-dev/o3de into mnaumov/FixingEOOrdering_signofffix

Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>
monroegm-disable-blank-issue-2
Mikhail Naumov 4 years ago
commit f599a30fae

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<path d="M3.145,8.433c0-1.47,1.196-2.666,2.666-2.666h9.544c-0.158-0.819-0.88-1.443-1.744-1.443H3.487
c-0.978,0-1.778,0.8-1.778,1.778v5.356c0,0.861,0.62,1.582,1.436,1.743V8.433z" fill="#FFFFFF"/>
<g>
<path d="M6.833,11.654c0-1.47,1.196-2.666,2.666-2.666h9.069c-0.158-0.819-0.88-1.443-1.744-1.443H6.7
c-0.978,0-1.778,0.8-1.778,1.778v5.356c0,0.978,0.8,1.778,1.778,1.778h0.133V11.654z" fill="#FFFFFF"/>
</g>
<path d="M20.513,10.765H10.388c-0.978,0-1.778,0.8-1.778,1.777v5.356c0,0.978,0.8,1.778,1.778,1.778h10.125
c0.978,0,1.778-0.8,1.778-1.778v-5.356C22.29,11.565,21.49,10.765,20.513,10.765z M19.332,15.967h-7.763
c-0.264,0-0.478-0.355-0.478-0.793c0-0.438,0.214-0.793,0.478-0.793h7.763c0.264,0,0.478,0.355,0.478,0.793
C19.81,15.612,19.597,15.967,19.332,15.967z" fill="#FFFFFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -9,87 +9,20 @@ import os
import pytest
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
from Atom.atom_utils.atom_constants import LIGHT_TYPES
logger = logging.getLogger(__name__)
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("level", ["auto_test"])
class TestAtomEditorComponentsMain(object):
"""Holds tests for Atom components."""
@pytest.mark.test_case_id("C34525095")
def test_AtomEditorComponents_LightComponent(
self, request, editor, workspace, project, launcher_platform, level):
"""
Please review the hydra script run by this test for more specific test info.
Tests that the Light component has the expected property options available to it.
"""
cfg_args = [level]
expected_lines = [
"light_entity Entity successfully created",
"Entity has a Light component",
"light_entity_test: Component added to the entity: True",
f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}",
"Controller|Configuration|Shadows|Enable shadow set to True",
"light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS",
"Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF
"Controller|Configuration|Shadows|Filtering sample count set to 4",
"Controller|Configuration|Shadows|Filtering sample count set to 64",
"Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM
"Controller|Configuration|Shadows|ESM exponent set to 50.0",
"Controller|Configuration|Shadows|ESM exponent set to 5000.0",
"Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF
f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}",
f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}",
f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}",
"light_entity Controller|Configuration|Fast approximation: SUCCESS",
"light_entity Controller|Configuration|Both directions: SUCCESS",
f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}",
f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} "
f"which matches {LIGHT_TYPES['simple_point']}",
"Controller|Configuration|Attenuation radius|Mode set to 0",
"Controller|Configuration|Attenuation radius|Radius set to 100.0",
f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} "
f"which matches {LIGHT_TYPES['simple_spot']}",
"Controller|Configuration|Shutters|Outer angle set to 45.0",
"Controller|Configuration|Shutters|Outer angle set to 90.0",
"light_entity_test: Component added to the entity: True",
"Light component test (non-GPU) completed.",
]
unexpected_lines = ["Traceback (most recent call last):"]
hydra.launch_and_validate_results(
request,
TEST_DIRECTORY,
editor,
"hydra_AtomEditorComponents_LightComponent.py",
timeout=120,
expected_lines=expected_lines,
unexpected_lines=unexpected_lines,
halt_on_unexpected=True,
null_renderer=True,
cfg_args=cfg_args,
enable_prefab_system=False,
)
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAutomation(EditorTestSuite):
enable_prefab_system = False
#this test is intermittently timing out without ever having executed. sandboxing while we investigate cause.
# this test is intermittently timing out without ever having executed. sandboxing while we investigate cause.
@pytest.mark.test_case_id("C36525660")
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module

@ -1,213 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import sys
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.math as math
import azlmbr.paths
import azlmbr.legacy.general as general
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from Atom.atom_utils.atom_constants import LIGHT_TYPES
LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type'
SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES = [
("Controller|Configuration|Shadows|Enable shadow", True),
("Controller|Configuration|Shadows|Shadowmap size", 0), # 256
("Controller|Configuration|Shadows|Shadowmap size", 1), # 512
("Controller|Configuration|Shadows|Shadowmap size", 2), # 1024
("Controller|Configuration|Shadows|Shadowmap size", 3), # 2048
("Controller|Configuration|Shadows|Shadow filter method", 1), # PCF
("Controller|Configuration|Shadows|Filtering sample count", 4.0),
("Controller|Configuration|Shadows|Filtering sample count", 64.0),
("Controller|Configuration|Shadows|Shadow filter method", 2), # ECM
("Controller|Configuration|Shadows|ESM exponent", 50),
("Controller|Configuration|Shadows|ESM exponent", 5000),
("Controller|Configuration|Shadows|Shadow filter method", 3), # ESM+PCF
]
QUAD_LIGHT_PROPERTIES = [
("Controller|Configuration|Both directions", True),
("Controller|Configuration|Fast approximation", True),
]
SIMPLE_POINT_LIGHT_PROPERTIES = [
("Controller|Configuration|Attenuation radius|Mode", 0),
("Controller|Configuration|Attenuation radius|Radius", 100.0),
]
SIMPLE_SPOT_LIGHT_PROPERTIES = [
("Controller|Configuration|Shutters|Inner angle", 45.0),
("Controller|Configuration|Shutters|Outer angle", 90.0),
]
def verify_required_component_property_value(entity_name, component, property_path, expected_property_value):
"""
Compares the property value of component against the expected_property_value.
:param entity_name: name of the entity to use (for test verification purposes).
:param component: component to check on a given entity for its current property value.
:param property_path: the path to the property inside the component.
:param expected_property_value: The value expected from the value inside property_path.
:return: None, but prints to general.log() which the test uses to verify against.
"""
property_value = editor.EditorComponentAPIBus(
bus.Broadcast, "GetComponentProperty", component, property_path).GetValue()
general.log(f"{entity_name}_test: Property value is {property_value} "
f"which matches {expected_property_value}")
def run():
"""
Test Case - Light Component
1. Creates a "light_entity" Entity and attaches a "Light" component to it.
2. Updates the Light component to each light type option from the LIGHT_TYPES constant.
3. The test will check the Editor log to ensure each light type was selected.
4. Prints the string "Light component test (non-GPU) completed" after completion.
Tests will fail immediately if any of these log lines are found:
1. Trace::Assert
2. Trace::Error
3. Traceback (most recent call last):
:return: None
"""
# Create a "light_entity" entity with "Light" component.
light_entity_name = "light_entity"
light_component = "Light"
light_entity = hydra.Entity(light_entity_name)
light_entity.create_entity(math.Vector3(-1.0, -2.0, 3.0), [light_component])
general.log(
f"{light_entity_name}_test: Component added to the entity: "
f"{hydra.has_components(light_entity.id, [light_component])}")
# Populate the light_component_id_pair value so that it can be used to select all Light component options.
light_component_id_pair = None
component_type_id_list = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', [light_component], 0)
if len(component_type_id_list) < 1:
general.log(f"ERROR: A component class with name {light_component} doesn't exist")
light_component_id_pair = None
elif len(component_type_id_list) > 1:
general.log(f"ERROR: Found more than one component classes with same name: {light_component}")
light_component_id_pair = None
entity_component_id_pair = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'GetComponentOfType', light_entity.id, component_type_id_list[0])
if entity_component_id_pair.IsSuccess():
light_component_id_pair = entity_component_id_pair.GetValue()
# Test each Light component option can be selected and it's properties updated.
# Point (sphere) light type checks.
light_type_property_test(
light_type=LIGHT_TYPES['sphere'],
light_properties=SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES,
light_component_id_pair=light_component_id_pair,
light_entity_name=light_entity_name,
light_entity=light_entity
)
# Spot (disk) light type checks.
light_type_property_test(
light_type=LIGHT_TYPES['spot_disk'],
light_properties=SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES,
light_component_id_pair=light_component_id_pair,
light_entity_name=light_entity_name,
light_entity=light_entity
)
# Capsule light type checks.
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
light_component_id_pair,
LIGHT_TYPE_PROPERTY,
LIGHT_TYPES['capsule']
)
verify_required_component_property_value(
entity_name=light_entity_name,
component=light_entity.components[0],
property_path=LIGHT_TYPE_PROPERTY,
expected_property_value=LIGHT_TYPES['capsule']
)
# Quad light type checks.
light_type_property_test(
light_type=LIGHT_TYPES['quad'],
light_properties=QUAD_LIGHT_PROPERTIES,
light_component_id_pair=light_component_id_pair,
light_entity_name=light_entity_name,
light_entity=light_entity
)
# Polygon light type checks.
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
light_component_id_pair,
LIGHT_TYPE_PROPERTY,
LIGHT_TYPES['polygon']
)
verify_required_component_property_value(
entity_name=light_entity_name,
component=light_entity.components[0],
property_path=LIGHT_TYPE_PROPERTY,
expected_property_value=LIGHT_TYPES['polygon']
)
# Point (simple punctual) light type checks.
light_type_property_test(
light_type=LIGHT_TYPES['simple_point'],
light_properties=SIMPLE_POINT_LIGHT_PROPERTIES,
light_component_id_pair=light_component_id_pair,
light_entity_name=light_entity_name,
light_entity=light_entity
)
# Spot (simple punctual) light type checks.
light_type_property_test(
light_type=LIGHT_TYPES['simple_spot'],
light_properties=SIMPLE_SPOT_LIGHT_PROPERTIES,
light_component_id_pair=light_component_id_pair,
light_entity_name=light_entity_name,
light_entity=light_entity
)
general.log("Light component test (non-GPU) completed.")
def light_type_property_test(light_type, light_properties, light_component_id_pair, light_entity_name, light_entity):
"""
Updates the current light type and modifies its properties, then verifies they are accurate to what was set.
:param light_type: The type of light to update, must match a value in LIGHT_TYPES
:param light_properties: List of tuples detailing properties to modify with update values.
:param light_component_id_pair: Entity + component ID pair for updating the light component on a given entity.
:param light_entity_name: the name of the Entity holding the light component.
:param light_entity: the Entity object containing the light component.
:return: None
"""
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
light_component_id_pair,
LIGHT_TYPE_PROPERTY,
light_type
)
verify_required_component_property_value(
entity_name=light_entity_name,
component=light_entity.components[0],
property_path=LIGHT_TYPE_PROPERTY,
expected_property_value=light_type
)
for light_property in light_properties:
light_entity.get_set_test(0, light_property[0], light_property[1])
if __name__ == "__main__":
run()

@ -68,7 +68,7 @@ def ShapeIntersectionFilter_FilterStageToggle():
# 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))
box.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(5.0, 5.0, 1.0))
# Create a new entity as a child of the vegetation area entity with Cylinder Shape.
cylinder = hydra.Entity("cylinder")
@ -80,10 +80,10 @@ def ShapeIntersectionFilter_FilterStageToggle():
# On the Shape Intersection Filter component, click the crosshair button, and add child entities one by one
vegetation.get_set_test(3, "Configuration|Shape Entity Id", box.id)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0, 100), 2.0)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 49), 2.0)
Report.result(Tests.instance_count_in_box_shape, result)
vegetation.get_set_test(3, "Configuration|Shape Entity Id", cylinder.id)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 100), 2.0)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 121), 2.0)
Report.result(Tests.instance_count_in_cylinder_shape, result)
# Create a new entity as a child of the area entity with Random Noise Gradient, Gradient Transform Modifier,
@ -98,12 +98,13 @@ def ShapeIntersectionFilter_FilterStageToggle():
# 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
# Toggle between PreProcess and PostProcess and validate instances. Validate in a 0.3m wider radius due to position
# offsets
vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 117), 2.0)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.3, 121), 2.0)
Report.result(Tests.preprocess_instance_count, result)
vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 122), 2.0)
result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.3, 122), 2.0)
Report.result(Tests.postprocess_instance_count, result)

@ -131,7 +131,6 @@ class TestAutomation_PrefabNotEnabled(EditorTestSuite):
class test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(EditorParallelTest):
from .EditorScripts import ShapeIntersectionFilter_InstancesPlantInAssignedShape as test_module
@pytest.mark.skip("https://github.com/o3de/o3de/issues/6973")
class test_ShapeIntersectionFilter_FilterStageToggle(EditorParallelTest):
from .EditorScripts import ShapeIntersectionFilter_FilterStageToggle as test_module

@ -191,6 +191,7 @@ void AssetImporterManager::OnBrowseDestinationFilePath(QLineEdit* destinationLin
fileDialog.setViewMode(QFileDialog::List);
fileDialog.setWindowModality(Qt::WindowModality::ApplicationModal);
fileDialog.setWindowTitle(tr("Select import destination"));
fileDialog.setFileMode(QFileDialog::Directory);
QSettings settings;
QString currentDestination = settings.value(AssetImporterManagerPrivate::g_selectDestinationFilesPath).toString();

@ -32,6 +32,15 @@ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView);
namespace AzToolsFramework
{
namespace AssetBrowser
{
static constexpr const char* CollapseAllIcon = "Assets/Editor/Icons/AssetBrowser/Collapse_All.svg";
static constexpr const char* MenuIcon = ":/Menu/menu.svg";
} // namespace AssetBrowser
} // namespace AzToolsFramework
class ListenerForShowAssetEditorEvent
: public QObject
, private AzToolsFramework::EditorEvents::Bus::Handler
@ -87,10 +96,21 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent)
m_assetBrowserModel->SetFilterModel(m_filterModel.data());
m_ui->m_collapseAllButton->setAutoRaise(true); // hover highlight
m_ui->m_collapseAllButton->setIcon(QIcon(AzAssetBrowser::CollapseAllIcon));
connect(
m_ui->m_collapseAllButton, &QToolButton::clicked, this,
[this]()
{
m_ui->m_assetBrowserTreeViewWidget->collapseAll();
});
if (ed_useNewAssetBrowserTableView)
{
m_ui->m_toggleDisplayViewBtn->setVisible(true);
m_ui->m_toggleDisplayViewBtn->setIcon(QIcon(":/Menu/menu.svg"));
m_ui->m_toggleDisplayViewBtn->setAutoRaise(true);
m_ui->m_toggleDisplayViewBtn->setIcon(QIcon(AzAssetBrowser::MenuIcon));
m_tableModel->setFilterRole(Qt::DisplayRole);
m_tableModel->setSourceModel(m_filterModel.data());

@ -72,6 +72,22 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_collapseAllButton">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string extracomment="Collapse All"/>
</property>
<property name="toolTipDuration">
<number>3</number>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -143,15 +159,6 @@
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>

@ -408,7 +408,7 @@ namespace O3DE::ProjectManager
}
// check if engine path is registered
auto allEngines = m_manifest.attr("get_engines")();
auto allEngines = m_manifest.attr("get_manifest_engines")();
if (pybind11::isinstance<pybind11::list>(allEngines))
{
const AZ::IO::FixedMaxPath enginePathFixed(Py_To_String(enginePath));
@ -891,7 +891,7 @@ namespace O3DE::ProjectManager
bool result = ExecuteWithLock([&] {
// external projects
for (auto path : m_manifest.attr("get_projects")())
for (auto path : m_manifest.attr("get_manifest_projects")())
{
projects.push_back(ProjectInfoFromPath(path));
}

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Image processing for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Atom Bootstrap",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Debug Camera component for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Common features for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "DX12 RHI for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Metal RHI for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Atom Null RHI",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Vulcan RHI for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "RHI for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "RPI for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Tools Framework for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Atom Bridge",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Font Rendering for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Tool",
"summary": "",
"summary": "ImGui tools for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Viewport display icons for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Viewport Display Information for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Common features for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "EmotionFX for Atom",
"canonical_tags": [
"Gem"
],

@ -6,7 +6,7 @@
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "ImGui support for Atom",
"canonical_tags": [
"Gem"
],

@ -104,7 +104,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
NAME FastNoise.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
fastnoise_tests_files.cmake
fastnoise_editor_tests_files.cmake
COMPILE_DEFINITIONS
PUBLIC
FASTNOISE_EDITOR
@ -120,23 +120,31 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_googletest(
NAME Gem::FastNoise.Editor.Tests
)
else()
ly_add_target(
NAME FastNoise.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
fastnoise_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
Gem::FastNoise.Static
Gem::LmbrCentral
)
ly_add_googletest(
NAME Gem::FastNoise.Tests
)
endif()
ly_add_target(
NAME FastNoise.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
fastnoise_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
Gem::FastNoise.Static
Gem::GradientSignal
Gem::GradientSignal.Tests.Static
Gem::LmbrCentral
)
ly_add_googletest(
NAME Gem::FastNoise.Tests
)
ly_add_googlebenchmark(
NAME Gem::FastNoise.Benchmarks
TARGET Gem::FastNoise.Tests
)
endif()

@ -54,6 +54,21 @@ namespace FastNoiseGem
return AZ::Edit::PropertyVisibility::Hide;
}
bool FastNoiseGradientConfig::operator==(const FastNoiseGradientConfig& rhs) const
{
return (m_cellularDistanceFunction == rhs.m_cellularDistanceFunction)
&& (m_cellularJitter == rhs.m_cellularJitter)
&& (m_cellularReturnType == rhs.m_cellularReturnType)
&& (m_fractalType == rhs.m_fractalType)
&& (m_frequency == rhs.m_frequency)
&& (m_gain == rhs.m_gain)
&& (m_interp == rhs.m_interp)
&& (m_lacunarity == rhs.m_lacunarity)
&& (m_noiseType == rhs.m_noiseType)
&& (m_octaves == rhs.m_octaves)
&& (m_seed == rhs.m_seed);
}
void FastNoiseGradientConfig::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
@ -306,7 +321,7 @@ namespace FastNoiseGem
float FastNoiseGradientComponent::GetValue(const GradientSignal::GradientSampleParams& sampleParams) const
{
AZ::Vector3 uvw = sampleParams.m_position;
AZ::Vector3 uvw;
bool wasPointRejected = false;
{
@ -314,13 +329,34 @@ namespace FastNoiseGem
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
}
if (!wasPointRejected)
// Generator returns a range between [-1, 1], map that to [0, 1]
return wasPointRejected ?
0.0f :
AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f);
}
void FastNoiseGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
// Generator returns a range between [-1, 1], map that to [0, 1]
return AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f);
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
return 0.0f;
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
AZ::Vector3 uvw;
for (size_t index = 0; index < positions.size(); index++)
{
bool wasPointRejected = false;
m_gradientTransform.TransformPositionToUVW(positions[index], uvw, wasPointRejected);
// Generator returns a range between [-1, 1], map that to [0, 1]
outValues[index] = wasPointRejected ?
0.0f :
AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f);
}
}
template <typename TValueType, TValueType FastNoiseGradientConfig::*TConfigMember, void (FastNoise::*TMethod)(TValueType)>

@ -47,6 +47,8 @@ namespace FastNoiseGem
AZ::u32 GetFrequencyParameterVisbility() const;
AZ::u32 GetInterpParameterVisibility() const;
bool operator==(const FastNoiseGradientConfig& rhs) const;
int m_seed = 1;
float m_frequency = 1.f;
FastNoise::Interp m_interp = FastNoise::Interp::Quintic;
@ -90,6 +92,7 @@ namespace FastNoiseGem
// GradientRequestBus overrides...
float GetValue(const GradientSignal::GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const override;
protected:
FastNoiseGradientConfig m_configuration;

@ -0,0 +1,116 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifdef HAVE_BENCHMARK
#include <AzTest/AzTest.h>
#include <AzCore/Math/Vector3.h>
#include <FastNoiseGradientComponent.h>
#include <FastNoiseTest.h>
#include <GradientSignalTestHelpers.h>
#include <GradientSignal/Components/GradientTransformComponent.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformModifierRequestBus.h>
#include <GradientSignal/GradientSampler.h>
#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
namespace UnitTest
{
class FastNoiseGetValues
: public ::benchmark::Fixture
{
public:
void RunGetValueOrGetValuesBenchmark(benchmark::State& state, FastNoise::NoiseType noiseType)
{
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
// Set up a FastNoise component with the requested noise type
FastNoiseGem::FastNoiseGradientConfig cfg;
cfg.m_frequency = 0.01f;
cfg.m_noiseType = noiseType;
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>(cfg);
noiseEntity->Init();
noiseEntity->Activate();
UnitTest::GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, noiseEntity->GetId());
}
};
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Value)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Value);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_ValueFractal)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::ValueFractal);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Perlin)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Perlin);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_PerlinFractal)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::PerlinFractal);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Simplex)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Simplex);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_SimplexFractal)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::SimplexFractal);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Cellular)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Cellular);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_WhiteNoise)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::WhiteNoise);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Cubic)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Cubic);
}
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_CubicFractal)(benchmark::State& state)
{
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::CubicFractal);
}
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Value);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_ValueFractal);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Perlin);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_PerlinFractal);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Simplex);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_SimplexFractal);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Cellular);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_WhiteNoise);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Cubic);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_CubicFractal);
#endif
}

@ -0,0 +1,44 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzTest/AzTest.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <EditorFastNoiseGradientComponent.h>
#include <FastNoiseTest.h>
class FastNoiseEditorTestApp : public ::testing::Test
{
};
TEST_F(FastNoiseEditorTestApp, FastNoise_EditorCreateGameEntity)
{
AZStd::unique_ptr<AZ::Entity> noiseEntity(aznew AZ::Entity("editor_noise_entity"));
ASSERT_TRUE(noiseEntity != nullptr);
FastNoiseGem::EditorFastNoiseGradientComponent editor;
auto* editorBase = static_cast<AzToolsFramework::Components::EditorComponentBase*>(&editor);
editorBase->BuildGameEntity(noiseEntity.get());
// the new game entity's FastNoise component should look like the default one
FastNoiseGem::FastNoiseGradientConfig defaultConfig;
FastNoiseGem::FastNoiseGradientConfig gameComponentConfig;
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
// Change a value in the gameComponentConfig just to verify that it got overwritten instead of simply matching the default.
gameComponentConfig.m_seed++;
noiseComp->WriteOutConfig(&gameComponentConfig);
ASSERT_EQ(defaultConfig, gameComponentConfig);
}
// This uses custom test / benchmark hooks so that we can load LmbrCentral and GradientSignal Gems.
AZ_UNIT_TEST_HOOK(new UnitTest::FastNoiseTestEnvironment, UnitTest::FastNoiseBenchmarkEnvironment);

@ -10,199 +10,61 @@
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Math/Random.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/Script/ScriptContext.h>
#include <AzCore/std/chrono/clocks.h>
#include <FastNoiseSystemComponent.h>
#include <AzFramework/Components/TransformComponent.h>
#include <FastNoiseGradientComponent.h>
#include <FastNoiseModule.h>
#include <FastNoiseTest.h>
#include <GradientSignalTestHelpers.h>
#include <GradientSignal/Components/GradientTransformComponent.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformModifierRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
#include <GradientSignal/GradientSampler.h>
#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
class MockGradientTransformComponent
: public AZ::Component
, private GradientSignal::GradientTransformRequestBus::Handler
, private GradientSignal::GradientTransformModifierRequestBus::Handler
class FastNoiseTest : public ::testing::Test
{
public:
AZ_COMPONENT(MockGradientTransformComponent, "{464CF47B-7E10-4E1B-BD06-79BD2AC91399}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("GradientTransformService", 0x8c8c5ecc));
}
static void Reflect([[maybe_unused]] AZ::ReflectContext* context) {}
MockGradientTransformComponent() = default;
~MockGradientTransformComponent() = default;
// AZ::Component interface
void Activate() override {}
void Deactivate() override {}
////////////////////////////////////////////////////////////////////////////
//// GradientTransformRequestBus
const GradientSignal::GradientTransform& GetGradientTransform() const override
{
return m_gradientTransform;
}
//////////////////////////////////////////////////////////////////////////
// GradientTransformModifierRequestBus
bool GetAllowReference() const override { return false; }
void SetAllowReference([[maybe_unused]] bool value) override {}
AZ::EntityId GetShapeReference() const override { return AZ::EntityId(); }
void SetShapeReference([[maybe_unused]] AZ::EntityId shapeReference) override {}
bool GetOverrideBounds() const override { return false; }
void SetOverrideBounds([[maybe_unused]] bool value) override {}
AZ::Vector3 GetBounds() const override { return AZ::Vector3(); }
void SetBounds([[maybe_unused]] AZ::Vector3 bounds) override {}
GradientSignal::TransformType GetTransformType() const override { return static_cast<GradientSignal::TransformType>(0); }
void SetTransformType([[maybe_unused]] GradientSignal::TransformType type) override {}
bool GetOverrideTranslate() const override { return false; }
void SetOverrideTranslate([[maybe_unused]] bool value) override {}
AZ::Vector3 GetTranslate() const override { return AZ::Vector3(); }
void SetTranslate([[maybe_unused]] AZ::Vector3 translate) override {}
bool GetOverrideRotate() const override { return false; }
void SetOverrideRotate([[maybe_unused]] bool value) override {}
AZ::Vector3 GetRotate() const override { return AZ::Vector3(); }
void SetRotate([[maybe_unused]] AZ::Vector3 rotate) override {}
bool GetOverrideScale() const override { return false; }
void SetOverrideScale([[maybe_unused]] bool value) override {}
AZ::Vector3 GetScale() const override { return AZ::Vector3(); }
void SetScale([[maybe_unused]] AZ::Vector3 scale) override {}
float GetFrequencyZoom() const override { return false; }
void SetFrequencyZoom([[maybe_unused]] float frequencyZoom) override {}
GradientSignal::WrappingType GetWrappingType() const override { return static_cast<GradientSignal::WrappingType>(0); }
void SetWrappingType([[maybe_unused]] GradientSignal::WrappingType type) override {}
bool GetIs3D() const override { return false; }
void SetIs3D([[maybe_unused]] bool value) override {}
bool GetAdvancedMode() const override { return false; }
void SetAdvancedMode([[maybe_unused]] bool value) override {}
GradientSignal::GradientTransform m_gradientTransform;
};
TEST(FastNoiseTest, ComponentsWithComponentApplication)
TEST_F(FastNoiseTest, FastNoise_ComponentCreatesSuccessfully)
{
AZ::ComponentApplication::Descriptor appDesc;
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL;
appDesc.m_stackRecordLevels = 20;
AZ::ComponentApplication app;
AZ::Entity* systemEntity = app.Create(appDesc);
ASSERT_TRUE(systemEntity != nullptr);
app.RegisterComponentDescriptor(FastNoiseGem::FastNoiseSystemComponent::CreateDescriptor());
systemEntity->CreateComponent<FastNoiseGem::FastNoiseSystemComponent>();
systemEntity->Init();
systemEntity->Activate();
AZ::Entity* noiseEntity = aznew AZ::Entity("fastnoise_entity");
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
app.AddEntity(noiseEntity);
app.Destroy();
ASSERT_TRUE(true);
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
}
class FastNoiseTestApp
: public ::testing::Test
{
public:
FastNoiseTestApp()
: m_application()
, m_systemEntity(nullptr)
{
}
void SetUp() override
{
AZ::ComponentApplication::Descriptor appDesc;
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL;
appDesc.m_stackRecordLevels = 20;
AZ::ComponentApplication::StartupParameters appStartup;
appStartup.m_createStaticModulesCallback =
[](AZStd::vector<AZ::Module*>& modules)
{
modules.emplace_back(new FastNoiseGem::FastNoiseModule);
};
m_systemEntity = m_application.Create(appDesc, appStartup);
m_application.RegisterComponentDescriptor(MockGradientTransformComponent::CreateDescriptor());
m_systemEntity->Init();
m_systemEntity->Activate();
}
void TearDown() override
{
m_application.Destroy();
}
AZ::ComponentApplication m_application;
AZ::Entity* m_systemEntity;
};
//////////////////////////////////////////////////////////////////////////
// testing class to inspect protected data members in the FastNoiseGradientComponent
struct FastNoiseGradientComponentTester : public FastNoiseGem::FastNoiseGradientComponent
{
const FastNoiseGem::FastNoiseGradientConfig& GetConfig() const { return m_configuration; }
void AssertTrue(const FastNoiseGem::FastNoiseGradientConfig& cfg)
{
ASSERT_TRUE(m_configuration.m_cellularDistanceFunction == cfg.m_cellularDistanceFunction);
ASSERT_TRUE(m_configuration.m_cellularJitter == cfg.m_cellularJitter);
ASSERT_TRUE(m_configuration.m_cellularReturnType == cfg.m_cellularReturnType);
ASSERT_TRUE(m_configuration.m_fractalType == cfg.m_fractalType);
ASSERT_TRUE(m_configuration.m_frequency == cfg.m_frequency);
ASSERT_TRUE(m_configuration.m_gain == cfg.m_gain);
ASSERT_TRUE(m_configuration.m_interp == cfg.m_interp);
ASSERT_TRUE(m_configuration.m_lacunarity == cfg.m_lacunarity);
ASSERT_TRUE(m_configuration.m_noiseType == cfg.m_noiseType);
ASSERT_TRUE(m_configuration.m_octaves == cfg.m_octaves);
ASSERT_TRUE(m_configuration.m_seed == cfg.m_seed);
}
};
TEST_F(FastNoiseTestApp, FastNoise_Component)
TEST_F(FastNoiseTest, FastNoise_ComponentMatchesConfiguration)
{
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
m_application.AddEntity(noiseEntity);
FastNoiseGem::FastNoiseGradientConfig cfg;
FastNoiseGem::FastNoiseGradientConfig componentConfig;
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>(cfg);
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
noiseComp->WriteOutConfig(&componentConfig);
ASSERT_EQ(cfg, componentConfig);
}
TEST_F(FastNoiseTestApp, FastNoise_ComponentEbus)
TEST_F(FastNoiseTest, FastNoise_ComponentEbusWorksSuccessfully)
{
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
noiseEntity->CreateComponent<MockGradientTransformComponent>();
noiseEntity->Init();
noiseEntity->Activate();
@ -210,51 +72,39 @@ TEST_F(FastNoiseTestApp, FastNoise_ComponentEbus)
GradientSignal::GradientSampleParams params;
float sample = -1.0f;
GradientSignal::GradientRequestBus::EventResult(sample, noiseEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValue, params);
GradientSignal::GradientRequestBus::EventResult(sample, noiseEntity->GetId(),
&GradientSignal::GradientRequestBus::Events::GetValue, params);
ASSERT_TRUE(sample >= 0.0f);
ASSERT_TRUE(sample <= 1.0f);
}
TEST_F(FastNoiseTestApp, FastNoise_ComponentMatchesConfiguration)
TEST_F(FastNoiseTest, FastNoise_VerifyGetValueAndGetValuesMatch)
{
const float shapeHalfBounds = 128.0f;
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
AZ::SimpleLcgRandom rand(AZStd::GetTimeNowMicroSecond());
// Create a Box Shape to map our gradient into
LmbrCentral::BoxShapeConfig boxConfig(AZ::Vector3(shapeHalfBounds * 2.0f));
auto boxComponent = noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
boxComponent->SetConfiguration(boxConfig);
// Create a Fast Noise component with an adjusted frequency. (The defaults of Perlin noise with frequency=1.0 would cause us
// to always get back the same noise value)
FastNoiseGem::FastNoiseGradientConfig cfg;
cfg.m_frequency = 0.01f;
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>(cfg);
noiseEntity->CreateComponent<MockGradientTransformComponent>();
m_application.AddEntity(noiseEntity);
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
reinterpret_cast<FastNoiseGradientComponentTester*>(noiseComp)->AssertTrue(cfg);
}
#if FASTNOISE_EDITOR
#include <EditorFastNoiseGradientComponent.h>
TEST_F(FastNoiseTestApp, FastNoise_EditorCreateGameEntity)
{
AZStd::unique_ptr<AZ::Entity> noiseEntity(aznew AZ::Entity("editor_noise_entity"));
ASSERT_TRUE(noiseEntity != nullptr);
FastNoiseGem::EditorFastNoiseGradientComponent editor;
auto* editorBase = static_cast<AzToolsFramework::Components::EditorComponentBase*>(&editor);
editorBase->BuildGameEntity(noiseEntity.get());
// the new game entity's ocean component should look like the default one
FastNoiseGem::FastNoiseGradientConfig cfg;
noiseEntity->Init();
noiseEntity->Activate();
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
reinterpret_cast<FastNoiseGradientComponentTester*>(noiseComp)->AssertTrue(cfg);
// Create a gradient sampler and run through a series of points to see if they match expectations.
UnitTest::GradientSignalTestHelpers::CompareGetValueAndGetValues(noiseEntity->GetId(), shapeHalfBounds);
}
#endif
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
// This uses custom test / benchmark hooks so that we can load LmbrCentral and GradientSignal Gems.
AZ_UNIT_TEST_HOOK(new UnitTest::FastNoiseTestEnvironment, UnitTest::FastNoiseBenchmarkEnvironment);

@ -0,0 +1,60 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzFramework/Components/TransformComponent.h>
#include <AzTest/GemTestEnvironment.h>
#include <FastNoiseGradientComponent.h>
#include <FastNoiseSystemComponent.h>
namespace UnitTest
{
// The FastNoise unit tests need to use the GemTestEnvironment to load the GradientSignal and LmbrCentral Gems so that
// GradientTransform components can be used in the unit tests and benchmarks.
class FastNoiseTestEnvironment
: public AZ::Test::GemTestEnvironment
{
public:
void AddGemsAndComponents() override
{
AddDynamicModulePaths({ "GradientSignal" });
AddDynamicModulePaths({ "LmbrCentral" });
AddComponentDescriptors({
AzFramework::TransformComponent::CreateDescriptor(),
FastNoiseGem::FastNoiseSystemComponent::CreateDescriptor(),
FastNoiseGem::FastNoiseGradientComponent::CreateDescriptor()
});
AddRequiredComponents({ FastNoiseGem::FastNoiseSystemComponent::TYPEINFO_Uuid() });
}
};
#ifdef HAVE_BENCHMARK
//! The Benchmark environment is used for one time setup and tear down of shared resources
class FastNoiseBenchmarkEnvironment
: public AZ::Test::BenchmarkEnvironmentBase
, public FastNoiseTestEnvironment
{
protected:
void SetUpBenchmark() override
{
SetupEnvironment();
}
void TearDownBenchmark() override
{
TeardownEnvironment();
}
};
#endif
} // namespace UnitTest

@ -0,0 +1,13 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(FILES
Tests/FastNoiseEditorTest.cpp
Source/FastNoiseModule.h
Source/FastNoiseModule.cpp
)

@ -7,6 +7,7 @@
#
set(FILES
Tests/FastNoiseBenchmarks.cpp
Tests/FastNoiseTest.cpp
Source/FastNoiseModule.h
Source/FastNoiseModule.cpp

@ -9,6 +9,7 @@
#ifdef HAVE_BENCHMARK
#include <Tests/GradientSignalTestFixtures.h>
#include <Tests/GradientSignalTestHelpers.h>
#include <AzTest/AzTest.h>
#include <AzCore/Memory/PoolAllocator.h>
@ -21,220 +22,42 @@ namespace UnitTest
class GradientGetValues : public GradientSignalBenchmarkFixture
{
public:
// We use an enum to list out the different types of GetValue() benchmarks to run so that way we can condense our test cases
// to just take the value in as a benchmark argument and switch on it. Otherwise, we would need to write a different benchmark
// function for each test case for each gradient.
enum GetValuePermutation : int64_t
{
EBUS_GET_VALUE,
EBUS_GET_VALUES,
SAMPLER_GET_VALUE,
SAMPLER_GET_VALUES,
};
// Create an arbitrary size shape for creating our gradients for benchmark runs.
const float TestShapeHalfBounds = 128.0f;
void FillQueryPositions(AZStd::vector<AZ::Vector3>& positions, float height, float width)
{
size_t index = 0;
for (float y = 0.0f; y < height; y += 1.0f)
{
for (float x = 0.0f; x < width; x += 1.0f)
{
positions[index++] = AZ::Vector3(x, y, 0.0f);
}
}
}
void RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
GradientSignal::GradientSampleParams params;
// Get the height and width ranges for querying from our benchmark parameters
const float height = aznumeric_cast<float>(queryRange);
const float width = aznumeric_cast<float>(queryRange);
// Call GetValue() on the EBus for every height and width in our ranges.
for (auto _ : state)
{
for (float y = 0.0f; y < height; y += 1.0f)
{
for (float x = 0.0f; x < width; x += 1.0f)
{
float value = 0.0f;
params.m_position = AZ::Vector3(x, y, 0.0f);
GradientSignal::GradientRequestBus::EventResult(
value, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
benchmark::DoNotOptimize(value);
}
}
}
}
void RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
// Get the height and width ranges for querying from our benchmark parameters
float height = aznumeric_cast<float>(queryRange);
float width = aznumeric_cast<float>(queryRange);
int64_t totalQueryPoints = queryRange * queryRange;
// Call GetValues() for every height and width in our ranges.
for (auto _ : state)
{
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
FillQueryPositions(positions, height, width);
// Query and get the results.
AZStd::vector<float> results(totalQueryPoints);
GradientSignal::GradientRequestBus::Event(
gradientId, &GradientSignal::GradientRequestBus::Events::GetValues, positions, results);
}
}
void RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
// Create a gradient sampler to use for querying our gradient.
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = gradientId;
// Get the height and width ranges for querying from our benchmark parameters
const float height = aznumeric_cast<float>(queryRange);
const float width = aznumeric_cast<float>(queryRange);
// Call GetValue() through the GradientSampler for every height and width in our ranges.
for (auto _ : state)
{
for (float y = 0.0f; y < height; y += 1.0f)
{
for (float x = 0.0f; x < width; x += 1.0f)
{
GradientSignal::GradientSampleParams params;
params.m_position = AZ::Vector3(x, y, 0.0f);
float value = gradientSampler.GetValue(params);
benchmark::DoNotOptimize(value);
}
}
}
}
void RunSamplerGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
// Create a gradient sampler to use for querying our gradient.
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = gradientId;
// Get the height and width ranges for querying from our benchmark parameters
const float height = aznumeric_cast<float>(queryRange);
const float width = aznumeric_cast<float>(queryRange);
const int64_t totalQueryPoints = queryRange * queryRange;
// Call GetValues() through the GradientSampler for every height and width in our ranges.
for (auto _ : state)
{
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
FillQueryPositions(positions, height, width);
// Query and get the results.
AZStd::vector<float> results(totalQueryPoints);
gradientSampler.GetValues(positions, results);
}
}
void RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId)
{
switch (state.range(0))
{
case GetValuePermutation::EBUS_GET_VALUE:
RunEBusGetValueBenchmark(state, gradientId, state.range(1));
break;
case GetValuePermutation::EBUS_GET_VALUES:
RunEBusGetValuesBenchmark(state, gradientId, state.range(1));
break;
case GetValuePermutation::SAMPLER_GET_VALUE:
RunSamplerGetValueBenchmark(state, gradientId, state.range(1));
break;
case GetValuePermutation::SAMPLER_GET_VALUES:
RunSamplerGetValuesBenchmark(state, gradientId, state.range(1));
break;
default:
AZ_Assert(false, "Benchmark permutation type not supported.");
}
}
};
// Because there's no good way to label different enums in the output results (they just appear as integer values), we work around it by
// registering one set of benchmark runs for each enum value and use ArgNames() to give it a friendly name in the results.
#define GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(Fixture, Func) \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 1024 }) \
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 2048 }) \
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 4096 }) \
->ArgNames({ "EbusGetValue", "size" }) \
->Unit(::benchmark::kMillisecond); \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 1024 }) \
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 2048 }) \
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 4096 }) \
->ArgNames({ "EbusGetValues", "size" }) \
->Unit(::benchmark::kMillisecond); \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 1024 }) \
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 2048 }) \
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 4096 }) \
->ArgNames({ "SamplerGetValue", "size" }) \
->Unit(::benchmark::kMillisecond); \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 1024 }) \
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 2048 }) \
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 4096 }) \
->ArgNames({ "SamplerGetValues", "size" }) \
->Unit(::benchmark::kMillisecond);
// --------------------------------------------------------------------------------------
// Base Gradients
BENCHMARK_DEFINE_F(GradientGetValues, BM_ConstantGradient)(benchmark::State& state)
{
auto entity = BuildTestConstantGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_ImageGradient)(benchmark::State& state)
{
auto entity = BuildTestImageGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_PerlinGradient)(benchmark::State& state)
{
auto entity = BuildTestPerlinGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_RandomGradient)(benchmark::State& state)
{
auto entity = BuildTestRandomGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_ShapeAreaFalloffGradient)(benchmark::State& state)
{
auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ConstantGradient);
@ -250,21 +73,21 @@ namespace UnitTest
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_InvertGradient)(benchmark::State& state)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_LevelsGradient)(benchmark::State& state)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_MixedGradient)(benchmark::State& state)
@ -272,35 +95,35 @@ namespace UnitTest
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds);
auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_PosterizeGradient)(benchmark::State& state)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_ReferenceGradient)(benchmark::State& state)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_SmoothStepGradient)(benchmark::State& state)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_ThresholdGradient)(benchmark::State& state)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_DitherGradient);
@ -321,7 +144,7 @@ namespace UnitTest
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceMaskGradient)(benchmark::State& state)
@ -330,7 +153,7 @@ namespace UnitTest
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceSlopeGradient)(benchmark::State& state)
@ -339,7 +162,7 @@ namespace UnitTest
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceAltitudeGradient);

@ -8,6 +8,7 @@
#include <Tests/GradientSignalTestFixtures.h>
#include <Tests/GradientSignalTestHelpers.h>
#include <AzTest/AzTest.h>
namespace UnitTest
@ -18,79 +19,36 @@ namespace UnitTest
// Create an arbitrary size shape for comparing values within. It should be large enough that we detect any value anomalies
// but small enough that the tests run quickly.
const float TestShapeHalfBounds = 128.0f;
void CompareGetValueAndGetValues(AZ::EntityId gradientEntityId)
{
// Create a gradient sampler and run through a series of points to see if they match expectations.
const AZ::Aabb queryRegion = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds));
const AZ::Vector2 stepSize(1.0f, 1.0f);
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = gradientEntityId;
const size_t numSamplesX = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetX() / stepSize.GetX()));
const size_t numSamplesY = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetY() / stepSize.GetY()));
// Build up the list of positions to query.
AZStd::vector<AZ::Vector3> positions(numSamplesX * numSamplesY);
size_t index = 0;
for (size_t yIndex = 0; yIndex < numSamplesY; yIndex++)
{
float y = queryRegion.GetMin().GetY() + (stepSize.GetY() * yIndex);
for (size_t xIndex = 0; xIndex < numSamplesX; xIndex++)
{
float x = queryRegion.GetMin().GetX() + (stepSize.GetX() * xIndex);
positions[index++] = AZ::Vector3(x, y, 0.0f);
}
}
// Get the results from GetValues
AZStd::vector<float> results(numSamplesX * numSamplesY);
gradientSampler.GetValues(positions, results);
// For each position, call GetValue and verify that the values match.
for (size_t positionIndex = 0; positionIndex < positions.size(); positionIndex++)
{
GradientSignal::GradientSampleParams params;
params.m_position = positions[positionIndex];
float value = gradientSampler.GetValue(params);
// We use ASSERT_NEAR instead of EXPECT_NEAR because if one value doesn't match, they probably all won't, so there's no
// reason to keep running and printing failures for every value.
ASSERT_NEAR(value, results[positionIndex], 0.000001f);
}
}
};
TEST_F(GradientSignalGetValuesTestsFixture, ImageGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestImageGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, PerlinGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestPerlinGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, RandomGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestRandomGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, ConstantGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestConstantGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, ShapeAreaFalloffGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, DitherGradientComponent_VerifyGetValueAndGetValuesMatch)
@ -98,21 +56,21 @@ namespace UnitTest
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, InvertGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestInvertGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, LevelsGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, MixedGradientComponent_VerifyGetValueAndGetValuesMatch)
@ -120,35 +78,35 @@ namespace UnitTest
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds);
auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, PosterizeGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, ReferenceGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, SmoothStepGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, ThresholdGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceAltitudeGradientComponent_VerifyGetValueAndGetValuesMatch)
@ -157,7 +115,7 @@ namespace UnitTest
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceMaskGradientComponent_VerifyGetValueAndGetValuesMatch)
@ -166,7 +124,7 @@ namespace UnitTest
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceSlopeGradientComponent_VerifyGetValueAndGetValuesMatch)
@ -175,7 +133,7 @@ namespace UnitTest
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
}
}

@ -0,0 +1,203 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Tests/GradientSignalTestHelpers.h>
#include <AzCore/Math/Aabb.h>
#include <GradientSignal/GradientSampler.h>
namespace UnitTest
{
void GradientSignalTestHelpers::CompareGetValueAndGetValues(AZ::EntityId gradientEntityId, float shapeHalfBounds)
{
// Create a gradient sampler and run through a series of points to see if they match expectations.
const AZ::Aabb queryRegion = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-shapeHalfBounds), AZ::Vector3(shapeHalfBounds));
const AZ::Vector2 stepSize(1.0f, 1.0f);
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = gradientEntityId;
const size_t numSamplesX = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetX() / stepSize.GetX()));
const size_t numSamplesY = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetY() / stepSize.GetY()));
// Build up the list of positions to query.
AZStd::vector<AZ::Vector3> positions(numSamplesX * numSamplesY);
size_t index = 0;
for (size_t yIndex = 0; yIndex < numSamplesY; yIndex++)
{
float y = queryRegion.GetMin().GetY() + (stepSize.GetY() * yIndex);
for (size_t xIndex = 0; xIndex < numSamplesX; xIndex++)
{
float x = queryRegion.GetMin().GetX() + (stepSize.GetX() * xIndex);
positions[index++] = AZ::Vector3(x, y, 0.0f);
}
}
// Get the results from GetValues
AZStd::vector<float> results(numSamplesX * numSamplesY);
gradientSampler.GetValues(positions, results);
// For each position, call GetValue and verify that the values match.
for (size_t positionIndex = 0; positionIndex < positions.size(); positionIndex++)
{
GradientSignal::GradientSampleParams params;
params.m_position = positions[positionIndex];
float value = gradientSampler.GetValue(params);
// We use ASSERT_NEAR instead of EXPECT_NEAR because if one value doesn't match, they probably all won't, so there's no
// reason to keep running and printing failures for every value.
ASSERT_NEAR(value, results[positionIndex], 0.000001f);
}
}
#ifdef HAVE_BENCHMARK
void GradientSignalTestHelpers::FillQueryPositions(AZStd::vector<AZ::Vector3>& positions, float height, float width)
{
size_t index = 0;
for (float y = 0.0f; y < height; y += 1.0f)
{
for (float x = 0.0f; x < width; x += 1.0f)
{
positions[index++] = AZ::Vector3(x, y, 0.0f);
}
}
}
void GradientSignalTestHelpers::RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
GradientSignal::GradientSampleParams params;
// Get the height and width ranges for querying from our benchmark parameters
const float height = aznumeric_cast<float>(queryRange);
const float width = aznumeric_cast<float>(queryRange);
// Call GetValue() on the EBus for every height and width in our ranges.
for (auto _ : state)
{
for (float y = 0.0f; y < height; y += 1.0f)
{
for (float x = 0.0f; x < width; x += 1.0f)
{
float value = 0.0f;
params.m_position = AZ::Vector3(x, y, 0.0f);
GradientSignal::GradientRequestBus::EventResult(
value, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
benchmark::DoNotOptimize(value);
}
}
}
}
void GradientSignalTestHelpers::RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
// Get the height and width ranges for querying from our benchmark parameters
float height = aznumeric_cast<float>(queryRange);
float width = aznumeric_cast<float>(queryRange);
int64_t totalQueryPoints = queryRange * queryRange;
// Call GetValues() for every height and width in our ranges.
for (auto _ : state)
{
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
FillQueryPositions(positions, height, width);
// Query and get the results.
AZStd::vector<float> results(totalQueryPoints);
GradientSignal::GradientRequestBus::Event(
gradientId, &GradientSignal::GradientRequestBus::Events::GetValues, positions, results);
}
}
void GradientSignalTestHelpers::RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
// Create a gradient sampler to use for querying our gradient.
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = gradientId;
// Get the height and width ranges for querying from our benchmark parameters
const float height = aznumeric_cast<float>(queryRange);
const float width = aznumeric_cast<float>(queryRange);
// Call GetValue() through the GradientSampler for every height and width in our ranges.
for (auto _ : state)
{
for (float y = 0.0f; y < height; y += 1.0f)
{
for (float x = 0.0f; x < width; x += 1.0f)
{
GradientSignal::GradientSampleParams params;
params.m_position = AZ::Vector3(x, y, 0.0f);
float value = gradientSampler.GetValue(params);
benchmark::DoNotOptimize(value);
}
}
}
}
void GradientSignalTestHelpers::RunSamplerGetValuesBenchmark(
benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
{
AZ_PROFILE_FUNCTION(Entity);
// Create a gradient sampler to use for querying our gradient.
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = gradientId;
// Get the height and width ranges for querying from our benchmark parameters
const float height = aznumeric_cast<float>(queryRange);
const float width = aznumeric_cast<float>(queryRange);
const int64_t totalQueryPoints = queryRange * queryRange;
// Call GetValues() through the GradientSampler for every height and width in our ranges.
for (auto _ : state)
{
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
FillQueryPositions(positions, height, width);
// Query and get the results.
AZStd::vector<float> results(totalQueryPoints);
gradientSampler.GetValues(positions, results);
}
}
void GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId)
{
switch (state.range(0))
{
case GetValuePermutation::EBUS_GET_VALUE:
RunEBusGetValueBenchmark(state, gradientId, state.range(1));
break;
case GetValuePermutation::EBUS_GET_VALUES:
RunEBusGetValuesBenchmark(state, gradientId, state.range(1));
break;
case GetValuePermutation::SAMPLER_GET_VALUE:
RunSamplerGetValueBenchmark(state, gradientId, state.range(1));
break;
case GetValuePermutation::SAMPLER_GET_VALUES:
RunSamplerGetValuesBenchmark(state, gradientId, state.range(1));
break;
default:
AZ_Assert(false, "Benchmark permutation type not supported.");
}
}
#endif
}

@ -0,0 +1,76 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/EntityId.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/std/containers/vector.h>
#include <AzTest/AzTest.h>
namespace UnitTest
{
class GradientSignalTestHelpers
{
public:
static void CompareGetValueAndGetValues(AZ::EntityId gradientEntityId, float shapeHalfBounds);
#ifdef HAVE_BENCHMARK
// We use an enum to list out the different types of GetValue() benchmarks to run so that way we can condense our test cases
// to just take the value in as a benchmark argument and switch on it. Otherwise, we would need to write a different benchmark
// function for each test case for each gradient.
enum GetValuePermutation : int64_t
{
EBUS_GET_VALUE,
EBUS_GET_VALUES,
SAMPLER_GET_VALUE,
SAMPLER_GET_VALUES,
};
static void FillQueryPositions(AZStd::vector<AZ::Vector3>& positions, float height, float width);
static void RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
static void RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
static void RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
static void RunSamplerGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
static void RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId);
// Because there's no good way to label different enums in the output results (they just appear as integer values), we work around it by
// registering one set of benchmark runs for each enum value and use ArgNames() to give it a friendly name in the results.
#ifndef GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F
#define GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(Fixture, Func) \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 1024 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 2048 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 4096 }) \
->ArgNames({ "EbusGetValue", "size" }) \
->Unit(::benchmark::kMillisecond); \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 1024 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 2048 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 4096 }) \
->ArgNames({ "EbusGetValues", "size" }) \
->Unit(::benchmark::kMillisecond); \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 1024 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 2048 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 4096 }) \
->ArgNames({ "SamplerGetValue", "size" }) \
->Unit(::benchmark::kMillisecond); \
BENCHMARK_REGISTER_F(Fixture, Func) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 1024 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 2048 }) \
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 4096 }) \
->ArgNames({ "SamplerGetValues", "size" }) \
->Unit(::benchmark::kMillisecond);
#endif
#endif
};
}

@ -7,6 +7,8 @@
#
set(FILES
Tests/GradientSignalTestHelpers.cpp
Tests/GradientSignalTestHelpers.h
Tests/GradientSignalTestFixtures.cpp
Tests/GradientSignalTestFixtures.h
Tests/GradientSignalTestMocks.cpp

Loading…
Cancel
Save