Unit tests and benchmarks for GetValues() (#6823)

* Benchmarks and tests for Image and Constant GetValues

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Verify GetValues for Perlin and Random Gradients

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Standardized the assert format for GetValues().

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* More GetValues unit tests and test cleanup

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Fixed typos

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* GetValues() unit tests for surface gradients.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Benchmarks for ShapeAreaFalloff Gradient

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Added benchmarks for all remaining gradients and cleaned up the helper methods.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Renamed class for better report formatting.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Added missing Mocks dependencies for the Editor tests.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2022-01-12 08:46:10 -06:00
committed by GitHub
parent f51c845cbb
commit ffa9cc3a66
14 changed files with 907 additions and 386 deletions
+3
View File
@@ -141,6 +141,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
AZ::AzTestShared
Gem::GradientSignal.Static
Gem::LmbrCentral
Gem::LmbrCentral.Mocks
Gem::GradientSignal.Mocks
)
@@ -160,6 +161,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
Gem::GradientSignal.Tests.Static
Gem::GradientSignal.Static
Gem::LmbrCentral
Gem::LmbrCentral.Mocks
Gem::GradientSignal.Mocks
)
ly_add_googletest(
@@ -190,6 +192,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
Gem::GradientSignal.Static
Gem::GradientSignal.Editor.Static
Gem::LmbrCentral.Editor
Gem::LmbrCentral.Mocks
)
ly_add_googletest(
NAME Gem::GradientSignal.Editor.Tests
@@ -62,22 +62,21 @@ namespace GradientSignal
// Reference implementation of GetValues for any gradients that don't have their own optimized implementations.
// This is 10%-60% faster than calling GetValue via EBus many times due to the per-call EBus overhead.
AZ_Assert(
positions.size() == outValues.size(), "input and output lists are different sizes (%zu vs %zu).",
positions.size(), outValues.size());
if (positions.size() == outValues.size())
if (positions.size() != outValues.size())
{
GradientSampleParams sampleParams;
for (size_t index = 0; index < positions.size(); index++)
{
sampleParams.m_position = positions[index];
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
// The const_cast is necessary for now since array_view currently only supports const entries.
// If/when array_view is fixed to support non-const, or AZStd::span gets created, the const_cast can get removed.
auto& outValue = const_cast<float&>(outValues[index]);
outValue = GetValue(sampleParams);
}
GradientSampleParams sampleParams;
for (size_t index = 0; index < positions.size(); index++)
{
sampleParams.m_position = positions[index];
// The const_cast is necessary for now since array_view currently only supports const entries.
// If/when array_view is fixed to support non-const, or AZStd::span gets created, the const_cast can get removed.
auto& outValue = const_cast<float&>(outValues[index]);
outValue = GetValue(sampleParams);
}
}
@@ -120,7 +120,7 @@ namespace GradientSignal
if (m_isRequestInProgress)
{
AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependences with gradient entity references");
AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependencies with gradient entity references");
}
else
{
@@ -197,7 +197,7 @@ namespace GradientSignal
if (m_isRequestInProgress)
{
AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependences with gradient entity references");
AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependencies with gradient entity references");
ClearOutputValues(outValues);
return;
}
@@ -16,162 +16,337 @@
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <GradientSignal/Components/ImageGradientComponent.h>
#include <GradientSignal/Components/PerlinGradientComponent.h>
#include <GradientSignal/Components/RandomGradientComponent.h>
#include <GradientSignal/Components/GradientTransformComponent.h>
namespace UnitTest
{
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValue)(benchmark::State& state)
class GradientGetValues : public GradientSignalBenchmarkFixture
{
CreateTestImageGradient(m_testEntity.get());
RunEBusGetValueBenchmark(state);
}
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,
};
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValue)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
// 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);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValues)(benchmark::State& state)
// --------------------------------------------------------------------------------------
// Base Gradients
BENCHMARK_DEFINE_F(GradientGetValues, BM_ConstantGradient)(benchmark::State& state)
{
CreateTestImageGradient(m_testEntity.get());
RunEBusGetValuesBenchmark(state);
auto entity = BuildTestConstantGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValues)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValue)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_ImageGradient)(benchmark::State& state)
{
CreateTestImageGradient(m_testEntity.get());
RunSamplerGetValueBenchmark(state);
auto entity = BuildTestImageGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValue)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValues)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_PerlinGradient)(benchmark::State& state)
{
CreateTestImageGradient(m_testEntity.get());
RunSamplerGetValuesBenchmark(state);
auto entity = BuildTestPerlinGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValues)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValue)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_RandomGradient)(benchmark::State& state)
{
CreateTestPerlinGradient(m_testEntity.get());
RunEBusGetValueBenchmark(state);
auto entity = BuildTestRandomGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValue)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValues)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_ShapeAreaFalloffGradient)(benchmark::State& state)
{
CreateTestPerlinGradient(m_testEntity.get());
RunEBusGetValuesBenchmark(state);
auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValues)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ConstantGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ImageGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_PerlinGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_RandomGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ShapeAreaFalloffGradient);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValue)(benchmark::State& state)
// --------------------------------------------------------------------------------------
// Gradient Modifiers
BENCHMARK_DEFINE_F(GradientGetValues, BM_DitherGradient)(benchmark::State& state)
{
CreateTestPerlinGradient(m_testEntity.get());
RunSamplerGetValueBenchmark(state);
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValue)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValues)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_InvertGradient)(benchmark::State& state)
{
CreateTestPerlinGradient(m_testEntity.get());
RunSamplerGetValuesBenchmark(state);
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValues)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValue)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_LevelsGradient)(benchmark::State& state)
{
CreateTestRandomGradient(m_testEntity.get());
RunEBusGetValueBenchmark(state);
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValue)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValues)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_MixedGradient)(benchmark::State& state)
{
CreateTestRandomGradient(m_testEntity.get());
RunEBusGetValuesBenchmark(state);
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds);
auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValues)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValue)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_PosterizeGradient)(benchmark::State& state)
{
CreateTestRandomGradient(m_testEntity.get());
RunSamplerGetValueBenchmark(state);
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValue)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValues)(benchmark::State& state)
BENCHMARK_DEFINE_F(GradientGetValues, BM_ReferenceGradient)(benchmark::State& state)
{
CreateTestRandomGradient(m_testEntity.get());
RunSamplerGetValuesBenchmark(state);
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId());
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValues)
->Args({ 1024, 1024 })
->Args({ 2048, 2048 })
->Args({ 4096, 4096 })
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(GradientGetValues, BM_SmoothStepGradient)(benchmark::State& state)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId());
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());
}
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_DitherGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_InvertGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_LevelsGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_MixedGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_PosterizeGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ReferenceGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SmoothStepGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ThresholdGradient);
// --------------------------------------------------------------------------------------
// Surface Gradients
BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceAltitudeGradient)(benchmark::State& state)
{
auto mockSurfaceDataSystem =
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceMaskGradient)(benchmark::State& state)
{
auto mockSurfaceDataSystem =
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceSlopeGradient)(benchmark::State& state)
{
auto mockSurfaceDataSystem =
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds);
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
}
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceAltitudeGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceMaskGradient);
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceSlopeGradient);
#endif
}
@@ -0,0 +1,182 @@
/*
* 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/GradientSignalTestFixtures.h>
#include <AzTest/AzTest.h>
namespace UnitTest
{
struct GradientSignalGetValuesTestsFixture
: public GradientSignalTest
{
// 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_EQ instead of EXPECT_EQ 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_EQ(value, results[positionIndex]);
}
}
};
TEST_F(GradientSignalGetValuesTestsFixture, ImageGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestImageGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, PerlinGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestPerlinGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, RandomGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestRandomGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, ConstantGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestConstantGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, ShapeAreaFalloffGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, DitherGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, InvertGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestInvertGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, LevelsGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, MixedGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds);
auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, PosterizeGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, ReferenceGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, SmoothStepGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, ThresholdGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId());
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceAltitudeGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto mockSurfaceDataSystem =
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceMaskGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto mockSurfaceDataSystem =
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceSlopeGradientComponent_VerifyGetValueAndGetValuesMatch)
{
auto mockSurfaceDataSystem =
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds);
CompareGetValueAndGetValues(entity->GetId());
}
}
@@ -417,7 +417,6 @@ namespace UnitTest
TestFixedDataSampler(expectedOutput, dataSize, entity->GetId());
}
}
}
@@ -371,12 +371,9 @@ namespace UnitTest
const AZ::EntityId id = mockReference->GetId();
MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize);
GradientSignal::ReferenceGradientConfig config;
config.m_gradientSampler.m_gradientId = mockReference->GetId();
auto entity = CreateEntity();
CreateComponent<GradientSignal::ReferenceGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
// Create a reference gradient with an arbitrary box shape on it.
const float HalfBounds = 64.0f;
auto entity = BuildTestReferenceGradient(HalfBounds, mockReference->GetId());
TestFixedDataSampler(expectedOutput, dataSize, entity->GetId());
}
@@ -385,10 +382,9 @@ namespace UnitTest
{
// Verify that gradient references can validate and disconnect cyclic connections
auto constantGradientEntity = CreateEntity();
GradientSignal::ConstantGradientConfig constantGradientConfig;
CreateComponent<GradientSignal::ConstantGradientComponent>(constantGradientEntity.get(), constantGradientConfig);
ActivateEntity(constantGradientEntity.get());
// Create a constant gradient with an arbitrary box shape on it.
const float HalfBounds = 64.0f;
auto constantGradientEntity = BuildTestConstantGradient(HalfBounds);
// Verify cyclic reference test passes when pointing to gradient generator entity
auto referenceGradientEntity1 = CreateEntity();
@@ -212,12 +212,9 @@ namespace UnitTest
const AZ::EntityId id = entityMock->GetId();
UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize);
GradientSignal::InvertGradientConfig config;
config.m_gradientSampler.m_gradientId = entityMock->GetId();
auto entity = CreateEntity();
CreateComponent<GradientSignal::InvertGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
// Create the entity with an arbitrarily-sized box.
const float HalfBounds = 64.0f;
auto entity = BuildTestInvertGradient(HalfBounds, entityMock->GetId());
TestFixedDataSampler(expectedOutput, dataSize, entity->GetId());
}
@@ -9,10 +9,30 @@
#include <Tests/GradientSignalTestFixtures.h>
#include <AzFramework/Components/TransformComponent.h>
#include <GradientSignal/Components/GradientTransformComponent.h>
// Base gradient components
#include <GradientSignal/Components/ConstantGradientComponent.h>
#include <GradientSignal/Components/ImageGradientComponent.h>
#include <GradientSignal/Components/PerlinGradientComponent.h>
#include <GradientSignal/Components/RandomGradientComponent.h>
#include <GradientSignal/Components/ShapeAreaFalloffGradientComponent.h>
// Gradient modifier components
#include <GradientSignal/Components/DitherGradientComponent.h>
#include <GradientSignal/Components/InvertGradientComponent.h>
#include <GradientSignal/Components/LevelsGradientComponent.h>
#include <GradientSignal/Components/MixedGradientComponent.h>
#include <GradientSignal/Components/PosterizeGradientComponent.h>
#include <GradientSignal/Components/ReferenceGradientComponent.h>
#include <GradientSignal/Components/SmoothStepGradientComponent.h>
#include <GradientSignal/Components/ThresholdGradientComponent.h>
// Gradient surface data components
#include <GradientSignal/Components/SurfaceAltitudeGradientComponent.h>
#include <GradientSignal/Components/SurfaceMaskGradientComponent.h>
#include <GradientSignal/Components/SurfaceSlopeGradientComponent.h>
namespace UnitTest
{
@@ -32,12 +52,18 @@ namespace UnitTest
AZ::Data::AssetManager::Create(desc);
m_mockHandler = new ImageAssetMockAssetHandler();
AZ::Data::AssetManager::Instance().RegisterHandler(m_mockHandler, azrtti_typeid<GradientSignal::ImageAsset>());
m_mockShapeHandlers = new AZStd::vector<AZStd::unique_ptr<testing::NiceMock<UnitTest::MockShapeComponentRequests>>>();
}
void GradientSignalBaseFixture::TearDownCoreSystems()
{
// Clear any mock shape handlers that we've created for our test entities.
delete m_mockShapeHandlers;
AZ::Data::AssetManager::Instance().UnregisterHandler(m_mockHandler);
delete m_mockHandler; // delete after removing from the asset manager
AzFramework::LegacyAssetEventBus::ClearQueuedEvents();
AZ::Data::AssetManager::Destroy();
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
@@ -47,6 +73,338 @@ namespace UnitTest
m_systemEntity = nullptr;
}
AZStd::unique_ptr<testing::NiceMock<UnitTest::MockShapeComponentRequests>> GradientSignalBaseFixture::CreateMockShape(
const AZ::Aabb& spawnerBox, const AZ::EntityId& shapeEntityId)
{
AZStd::unique_ptr<testing::NiceMock<UnitTest::MockShapeComponentRequests>> mockShape =
AZStd::make_unique<testing::NiceMock<UnitTest::MockShapeComponentRequests>>(shapeEntityId);
ON_CALL(*mockShape, GetEncompassingAabb).WillByDefault(testing::Return(spawnerBox));
ON_CALL(*mockShape, GetTransformAndLocalBounds)
.WillByDefault(
[spawnerBox](AZ::Transform& transform, AZ::Aabb& bounds)
{
transform = AZ::Transform::CreateTranslation(spawnerBox.GetCenter());
bounds = spawnerBox.GetTranslated(-spawnerBox.GetCenter());
});
ON_CALL(*mockShape, IsPointInside)
.WillByDefault(
[spawnerBox](const AZ::Vector3& point) -> bool
{
return spawnerBox.Contains(point);
});
return mockShape;
}
AZStd::unique_ptr<MockSurfaceDataSystem> GradientSignalBaseFixture::CreateMockSurfaceDataSystem(const AZ::Aabb& spawnerBox)
{
SurfaceData::SurfacePoint point;
AZStd::unique_ptr<MockSurfaceDataSystem> mockSurfaceDataSystem = AZStd::make_unique<MockSurfaceDataSystem>();
// Give the mock surface data a bunch of fake point values to return.
for (float y = spawnerBox.GetMin().GetY(); y < spawnerBox.GetMax().GetY(); y+= 1.0f)
{
for (float x = spawnerBox.GetMin().GetX(); x < spawnerBox.GetMax().GetX(); x += 1.0f)
{
// Use our x distance into the spawnerBox as an arbitrary percentage value that we'll use to calculate
// our other arbitrary values below.
float arbitraryPercentage = AZStd::abs(x / spawnerBox.GetExtents().GetX());
// Create a position that's between min and max Z of the box.
point.m_position = AZ::Vector3(x, y, AZ::Lerp(spawnerBox.GetMin().GetZ(), spawnerBox.GetMax().GetZ(), arbitraryPercentage));
// Create an arbitrary normal value.
point.m_normal = point.m_position.GetNormalized();
// Create an arbitrary surface value.
point.m_masks[AZ_CRC_CE("test_mask")] = arbitraryPercentage;
mockSurfaceDataSystem->m_GetSurfacePoints[AZStd::make_pair(x, y)] = { { point } };
}
}
return mockSurfaceDataSystem;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::CreateTestEntity(float shapeHalfBounds)
{
// Create the base entity
AZStd::unique_ptr<AZ::Entity> testEntity = CreateEntity();
// Create a mock Shape component that describes the bounds that we're using to map our gradient into world space.
CreateComponent<MockShapeComponent>(testEntity.get());
// Create and keep a reference to a mock shape handler that will respond to shape requests for the mock shape.
auto mockShapeHandler =
CreateMockShape(AZ::Aabb::CreateCenterRadius(AZ::Vector3(shapeHalfBounds), shapeHalfBounds), testEntity->GetId());
m_mockShapeHandlers->push_back(AZStd::move(mockShapeHandler));
// Create a transform that locates our gradient in the center of our desired mock Shape.
auto transform = CreateComponent<AzFramework::TransformComponent>(testEntity.get());
transform->SetLocalTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds)));
transform->SetWorldTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds)));
return testEntity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestConstantGradient(float shapeHalfBounds)
{
// Create a Constant Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::ConstantGradientConfig config;
config.m_value = 0.75f;
CreateComponent<GradientSignal::ConstantGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestImageGradient(float shapeHalfBounds)
{
// Create an Image Gradient Component with arbitrary sizes and parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::ImageGradientConfig config;
const uint32_t imageSize = 4096;
const int32_t imageSeed = 12345;
config.m_imageAsset = ImageAssetMockAssetHandler::CreateImageAsset(imageSize, imageSize, imageSeed);
config.m_tilingX = 1.0f;
config.m_tilingY = 1.0f;
CreateComponent<GradientSignal::ImageGradientComponent>(entity.get(), config);
// Create a Gradient Transform Component with arbitrary parameters.
GradientSignal::GradientTransformConfig gradientTransformConfig;
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
CreateComponent<GradientSignal::GradientTransformComponent>(entity.get(), gradientTransformConfig);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestPerlinGradient(float shapeHalfBounds)
{
// Create a Perlin Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::PerlinGradientConfig config;
config.m_amplitude = 1.0f;
config.m_frequency = 1.1f;
config.m_octave = 4;
config.m_randomSeed = 12345;
CreateComponent<GradientSignal::PerlinGradientComponent>(entity.get(), config);
// Create a Gradient Transform Component with arbitrary parameters.
GradientSignal::GradientTransformConfig gradientTransformConfig;
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
CreateComponent<GradientSignal::GradientTransformComponent>(entity.get(), gradientTransformConfig);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestRandomGradient(float shapeHalfBounds)
{
// Create a Random Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::RandomGradientConfig config;
config.m_randomSeed = 12345;
CreateComponent<GradientSignal::RandomGradientComponent>(entity.get(), config);
// Create a Gradient Transform Component with arbitrary parameters.
GradientSignal::GradientTransformConfig gradientTransformConfig;
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
CreateComponent<GradientSignal::GradientTransformComponent>(entity.get(), gradientTransformConfig);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestShapeAreaFalloffGradient(float shapeHalfBounds)
{
// Create a Shape Area Falloff Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::ShapeAreaFalloffGradientConfig config;
config.m_shapeEntityId = entity->GetId();
config.m_falloffWidth = 16.0f;
config.m_falloffType = GradientSignal::FalloffType::InnerOuter;
CreateComponent<GradientSignal::ShapeAreaFalloffGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestDitherGradient(
float shapeHalfBounds, const AZ::EntityId& inputGradientId)
{
// Create a Dither Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::DitherGradientConfig config;
config.m_gradientSampler.m_gradientId = inputGradientId;
config.m_useSystemPointsPerUnit = false;
config.m_pointsPerUnit = 1.0f;
config.m_patternOffset = AZ::Vector3::CreateZero();
config.m_patternType = GradientSignal::DitherGradientConfig::BayerPatternType::PATTERN_SIZE_4x4;
CreateComponent<GradientSignal::DitherGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestInvertGradient(
float shapeHalfBounds, const AZ::EntityId& inputGradientId)
{
// Create an Invert Gradient Component.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::InvertGradientConfig config;
config.m_gradientSampler.m_gradientId = inputGradientId;
CreateComponent<GradientSignal::InvertGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestLevelsGradient(
float shapeHalfBounds, const AZ::EntityId& inputGradientId)
{
// Create a Levels Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::LevelsGradientConfig config;
config.m_gradientSampler.m_gradientId = inputGradientId;
config.m_inputMin = 0.1f;
config.m_inputMid = 0.3f;
config.m_inputMax = 0.9f;
config.m_outputMin = 0.0f;
config.m_outputMax = 1.0f;
CreateComponent<GradientSignal::LevelsGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestMixedGradient(
float shapeHalfBounds, const AZ::EntityId& baseGradientId, const AZ::EntityId& mixedGradientId)
{
// Create a Mixed Gradient Component that mixes two input gradients together in arbitrary ways.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::MixedGradientConfig config;
GradientSignal::MixedGradientLayer layer;
layer.m_enabled = true;
layer.m_operation = GradientSignal::MixedGradientLayer::MixingOperation::Initialize;
layer.m_gradientSampler.m_gradientId = baseGradientId;
layer.m_gradientSampler.m_opacity = 1.0f;
config.m_layers.push_back(layer);
layer.m_operation = GradientSignal::MixedGradientLayer::MixingOperation::Overlay;
layer.m_gradientSampler.m_gradientId = mixedGradientId;
layer.m_gradientSampler.m_opacity = 0.75f;
config.m_layers.push_back(layer);
CreateComponent<GradientSignal::MixedGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestPosterizeGradient(
float shapeHalfBounds, const AZ::EntityId& inputGradientId)
{
// Create a Posterize Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::PosterizeGradientConfig config;
config.m_gradientSampler.m_gradientId = inputGradientId;
config.m_mode = GradientSignal::PosterizeGradientConfig::ModeType::Ps;
config.m_bands = 5;
CreateComponent<GradientSignal::PosterizeGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestReferenceGradient(
float shapeHalfBounds, const AZ::EntityId& inputGradientId)
{
// Create a Reference Gradient Component.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::ReferenceGradientConfig config;
config.m_gradientSampler.m_gradientId = inputGradientId;
config.m_gradientSampler.m_ownerEntityId = entity->GetId();
CreateComponent<GradientSignal::ReferenceGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestSmoothStepGradient(
float shapeHalfBounds, const AZ::EntityId& inputGradientId)
{
// Create a Smooth Step Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::SmoothStepGradientConfig config;
config.m_gradientSampler.m_gradientId = inputGradientId;
config.m_smoothStep.m_falloffMidpoint = 0.75f;
config.m_smoothStep.m_falloffRange = 0.125f;
config.m_smoothStep.m_falloffStrength = 0.25f;
CreateComponent<GradientSignal::SmoothStepGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestThresholdGradient(
float shapeHalfBounds, const AZ::EntityId& inputGradientId)
{
// Create a Threshold Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::ThresholdGradientConfig config;
config.m_gradientSampler.m_gradientId = inputGradientId;
config.m_threshold = 0.75f;
CreateComponent<GradientSignal::ThresholdGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestSurfaceAltitudeGradient(float shapeHalfBounds)
{
// Create a Surface Altitude Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::SurfaceAltitudeGradientConfig config;
config.m_altitudeMin = -5.0f;
config.m_altitudeMax = 15.0f;
CreateComponent<GradientSignal::SurfaceAltitudeGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestSurfaceMaskGradient(float shapeHalfBounds)
{
// Create a Surface Mask Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::SurfaceMaskGradientConfig config;
config.m_surfaceTagList.push_back(AZ_CRC_CE("test_mask"));
CreateComponent<GradientSignal::SurfaceMaskGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
AZStd::unique_ptr<AZ::Entity> GradientSignalBaseFixture::BuildTestSurfaceSlopeGradient(float shapeHalfBounds)
{
// Create a Surface Slope Gradient Component with arbitrary parameters.
auto entity = CreateTestEntity(shapeHalfBounds);
GradientSignal::SurfaceSlopeGradientConfig config;
config.m_slopeMin = 5.0f;
config.m_slopeMax = 50.0f;
config.m_rampType = GradientSignal::SurfaceSlopeGradientConfig::RampType::SMOOTH_STEP;
config.m_smoothStep.m_falloffMidpoint = 0.75f;
config.m_smoothStep.m_falloffRange = 0.125f;
config.m_smoothStep.m_falloffStrength = 0.25f;
CreateComponent<GradientSignal::SurfaceSlopeGradientComponent>(entity.get(), config);
ActivateEntity(entity.get());
return entity;
}
void GradientSignalTest::TestFixedDataSampler(const AZStd::vector<float>& expectedOutput, int size, AZ::EntityId gradientEntityId)
{
GradientSignal::GradientSampler gradientSampler;
@@ -67,209 +425,5 @@ namespace UnitTest
}
}
}
#ifdef HAVE_BENCHMARK
void GradientSignalBenchmarkFixture::CreateTestEntity(float shapeHalfBounds)
{
// Create the base entity
m_testEntity = CreateEntity();
// Create a mock Shape component that describes the bounds that we're using to map our gradient into world space.
CreateComponent<MockShapeComponent>(m_testEntity.get());
MockShapeComponentHandler mockShapeHandler(m_testEntity->GetId());
mockShapeHandler.m_GetLocalBounds = AZ::Aabb::CreateCenterRadius(AZ::Vector3(shapeHalfBounds), shapeHalfBounds);
// Create a mock Transform component that locates our gradient in the center of our desired mock Shape.
MockTransformHandler mockTransformHandler;
mockTransformHandler.m_GetLocalTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds));
mockTransformHandler.m_GetWorldTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds));
mockTransformHandler.BusConnect(m_testEntity->GetId());
}
void GradientSignalBenchmarkFixture::DestroyTestEntity()
{
m_testEntity.reset();
}
void GradientSignalBenchmarkFixture::CreateTestImageGradient(AZ::Entity* entity)
{
// Create the Image Gradient Component with some default sizes and parameters.
GradientSignal::ImageGradientConfig config;
const uint32_t imageSize = 4096;
const int32_t imageSeed = 12345;
config.m_imageAsset = ImageAssetMockAssetHandler::CreateImageAsset(imageSize, imageSize, imageSeed);
config.m_tilingX = 1.0f;
config.m_tilingY = 1.0f;
CreateComponent<GradientSignal::ImageGradientComponent>(entity, config);
// Create the Gradient Transform Component with some default parameters.
GradientSignal::GradientTransformConfig gradientTransformConfig;
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
CreateComponent<GradientSignal::GradientTransformComponent>(entity, gradientTransformConfig);
}
void GradientSignalBenchmarkFixture::CreateTestPerlinGradient(AZ::Entity* entity)
{
// Create the Perlin Gradient Component with some default sizes and parameters.
GradientSignal::PerlinGradientConfig config;
config.m_amplitude = 1.0f;
config.m_frequency = 1.1f;
config.m_octave = 4;
config.m_randomSeed = 12345;
CreateComponent<GradientSignal::PerlinGradientComponent>(entity, config);
// Create the Gradient Transform Component with some default parameters.
GradientSignal::GradientTransformConfig gradientTransformConfig;
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
CreateComponent<GradientSignal::GradientTransformComponent>(entity, gradientTransformConfig);
}
void GradientSignalBenchmarkFixture::CreateTestRandomGradient(AZ::Entity* entity)
{
// Create the Random Gradient Component with some default parameters.
GradientSignal::RandomGradientConfig config;
config.m_randomSeed = 12345;
CreateComponent<GradientSignal::RandomGradientComponent>(entity, config);
// Create the Gradient Transform Component with some default parameters.
GradientSignal::GradientTransformConfig gradientTransformConfig;
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
CreateComponent<GradientSignal::GradientTransformComponent>(entity, gradientTransformConfig);
}
void GradientSignalBenchmarkFixture::RunSamplerGetValueBenchmark(benchmark::State& state)
{
AZ_PROFILE_FUNCTION(Entity);
// All components are created, so activate the entity
ActivateEntity(m_testEntity.get());
// Create a gradient sampler and run through a series of points to see if they match expectations.
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = m_testEntity->GetId();
// Get the height and width ranges for querying from our benchmark parameters
float height = aznumeric_cast<float>(state.range(0));
float width = aznumeric_cast<float>(state.range(1));
// Call GetValue() 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 GradientSignalBenchmarkFixture::RunSamplerGetValuesBenchmark(benchmark::State& state)
{
AZ_PROFILE_FUNCTION(Entity);
// All components are created, so activate the entity
ActivateEntity(m_testEntity.get());
// Create a gradient sampler and run through a series of points to see if they match expectations.
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = m_testEntity->GetId();
// Get the height and width ranges for querying from our benchmark parameters
float height = aznumeric_cast<float>(state.range(0));
float width = aznumeric_cast<float>(state.range(1));
int64_t totalQueryPoints = state.range(0) * state.range(1);
// Call GetValues() for every height and width in our ranges.
for (auto _ : state)
{
// Set up our vector of query positions.
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
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);
}
}
// Query and get the results.
AZStd::vector<float> results(totalQueryPoints);
gradientSampler.GetValues(positions, results);
}
}
void GradientSignalBenchmarkFixture::RunEBusGetValueBenchmark(benchmark::State& state)
{
AZ_PROFILE_FUNCTION(Entity);
// All components are created, so activate the entity
ActivateEntity(m_testEntity.get());
GradientSignal::GradientSampleParams params;
// Get the height and width ranges for querying from our benchmark parameters
float height = aznumeric_cast<float>(state.range(0));
float width = aznumeric_cast<float>(state.range(1));
// Call GetValue() 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, m_testEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValue, params);
benchmark::DoNotOptimize(value);
}
}
}
}
void GradientSignalBenchmarkFixture::RunEBusGetValuesBenchmark(benchmark::State& state)
{
AZ_PROFILE_FUNCTION(Entity);
// All components are created, so activate the entity
ActivateEntity(m_testEntity.get());
GradientSignal::GradientSampler gradientSampler;
gradientSampler.m_gradientId = m_testEntity->GetId();
// Get the height and width ranges for querying from our benchmark parameters
float height = aznumeric_cast<float>(state.range(0));
float width = aznumeric_cast<float>(state.range(1));
int64_t totalQueryPoints = state.range(0) * state.range(1);
// Call GetValues() for every height and width in our ranges.
for (auto _ : state)
{
// Set up our vector of query positions.
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
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);
}
}
// Query and get the results.
AZStd::vector<float> results(totalQueryPoints);
GradientSignal::GradientRequestBus::Event(
m_testEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValues, positions, results);
}
}
#endif
}
@@ -8,6 +8,7 @@
#pragma once
#include <Tests/GradientSignalTestMocks.h>
#include <LmbrCentral/Shape/MockShapes.h>
namespace UnitTest
{
@@ -30,22 +31,56 @@ namespace UnitTest
}
template<typename Component, typename Configuration>
AZ::Component* CreateComponent(AZ::Entity* entity, const Configuration& config)
Component* CreateComponent(AZ::Entity* entity, const Configuration& config)
{
m_app->RegisterComponentDescriptor(Component::CreateDescriptor());
return entity->CreateComponent<Component>(config);
}
template<typename Component>
AZ::Component* CreateComponent(AZ::Entity* entity)
Component* CreateComponent(AZ::Entity* entity)
{
m_app->RegisterComponentDescriptor(Component::CreateDescriptor());
return entity->CreateComponent<Component>();
}
// Create a mock shape that will respond to the shape bus with proper responses for the given input box.
AZStd::unique_ptr<testing::NiceMock<UnitTest::MockShapeComponentRequests>> CreateMockShape(
const AZ::Aabb& spawnerBox, const AZ::EntityId& shapeEntityId);
// Create a mock SurfaceDataSystem that will respond to requests for surface points with mock responses for points inside
// the given input box.
AZStd::unique_ptr<MockSurfaceDataSystem> CreateMockSurfaceDataSystem(const AZ::Aabb& spawnerBox);
// Create an entity with a mock shape and a transform. It won't be activated yet though, because we expect a gradient component
// to also get added to it first before activation.
AZStd::unique_ptr<AZ::Entity> CreateTestEntity(float shapeHalfBounds);
// Create and activate an entity with a gradient component of the requested type, initialized with test data.
AZStd::unique_ptr<AZ::Entity> BuildTestConstantGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::Entity> BuildTestImageGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::Entity> BuildTestPerlinGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::Entity> BuildTestRandomGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::Entity> BuildTestShapeAreaFalloffGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::Entity> BuildTestDitherGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestInvertGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestLevelsGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestMixedGradient(
float shapeHalfBounds, const AZ::EntityId& baseGradientId, const AZ::EntityId& mixedGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestPosterizeGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestReferenceGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestSmoothStepGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestThresholdGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId);
AZStd::unique_ptr<AZ::Entity> BuildTestSurfaceAltitudeGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::Entity> BuildTestSurfaceMaskGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::Entity> BuildTestSurfaceSlopeGradient(float shapeHalfBounds);
AZStd::unique_ptr<AZ::ComponentApplication> m_app;
AZ::Entity* m_systemEntity = nullptr;
ImageAssetMockAssetHandler* m_mockHandler = nullptr;
AZStd::vector<AZStd::unique_ptr<testing::NiceMock<UnitTest::MockShapeComponentRequests>>>* m_mockShapeHandlers = nullptr;
};
struct GradientSignalTest
@@ -80,33 +115,15 @@ namespace UnitTest
AZ::Debug::TraceMessageBus::Handler::BusConnect();
UnitTest::AllocatorsBenchmarkFixture::SetUp(state);
SetupCoreSystems();
// Create a default test entity with bounds of 256 m x 256 m x 256 m.
const float shapeHalfBounds = 128.0f;
CreateTestEntity(shapeHalfBounds);
}
void internalTearDown(const benchmark::State& state)
{
DestroyTestEntity();
TearDownCoreSystems();
UnitTest::AllocatorsBenchmarkFixture::TearDown(state);
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
}
void CreateTestEntity(float shapeHalfBounds);
void DestroyTestEntity();
void CreateTestImageGradient(AZ::Entity* entity);
void CreateTestPerlinGradient(AZ::Entity* entity);
void CreateTestRandomGradient(AZ::Entity* entity);
void RunSamplerGetValueBenchmark(benchmark::State& state);
void RunSamplerGetValuesBenchmark(benchmark::State& state);
void RunEBusGetValueBenchmark(benchmark::State& state);
void RunEBusGetValuesBenchmark(benchmark::State& state);
protected:
void SetUp(const benchmark::State& state) override
{
@@ -125,8 +142,6 @@ namespace UnitTest
{
internalTearDown(state);
}
AZStd::unique_ptr<AZ::Entity> m_testEntity;
};
#endif
}
@@ -8,6 +8,7 @@
set(FILES
Tests/GradientSignalBenchmarks.cpp
Tests/GradientSignalGetValuesTests.cpp
Tests/GradientSignalImageTests.cpp
Tests/GradientSignalReferencesTests.cpp
Tests/GradientSignalServicesTests.cpp
@@ -190,7 +190,7 @@ namespace LmbrCentral
{
AZ::Crc32 result = {};
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -205,7 +205,7 @@ namespace LmbrCentral
{
AZ::Aabb result = AZ::Aabb::CreateNull();
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -221,7 +221,7 @@ namespace LmbrCentral
transform = AZ::Transform::CreateIdentity();
bounds = AZ::Aabb::CreateNull();
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -234,7 +234,7 @@ namespace LmbrCentral
{
bool result = false;
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -249,7 +249,7 @@ namespace LmbrCentral
{
float result = FLT_MAX;
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -264,7 +264,7 @@ namespace LmbrCentral
{
float result = FLT_MAX;
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -279,7 +279,7 @@ namespace LmbrCentral
{
AZ::Vector3 result = AZ::Vector3::CreateZero();
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -294,7 +294,7 @@ namespace LmbrCentral
{
bool result = false;
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references");
if (AllowRequest())
{
m_isRequestInProgress = true;
@@ -160,7 +160,7 @@ namespace Terrain
{
float maxSample = 0.0f;
terrainExists = false;
AZ_WarningOnce("Terrain", !m_isRequestInProgress, "Detected cyclic dependences with terrain height entity references");
AZ_WarningOnce("Terrain", !m_isRequestInProgress, "Detected cyclic dependencies with terrain height entity references");
if (!m_isRequestInProgress)
{
m_isRequestInProgress = true;
@@ -224,7 +224,7 @@ namespace Vegetation
bool result = true;
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references");
if (!m_isRequestInProgress)
{
m_isRequestInProgress = true;
@@ -264,7 +264,7 @@ namespace Vegetation
return;
}
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references");
if (!m_isRequestInProgress)
{
m_isRequestInProgress = true;
@@ -295,7 +295,7 @@ namespace Vegetation
{
AZ_PROFILE_FUNCTION(Entity);
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references");
if (!m_isRequestInProgress)
{
m_isRequestInProgress = true;
@@ -320,7 +320,7 @@ namespace Vegetation
LmbrCentral::ShapeComponentRequestsBus::EventResult(bounds, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
}
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references");
if (!m_isRequestInProgress)
{
m_isRequestInProgress = true;
@@ -344,7 +344,7 @@ namespace Vegetation
AZ::u32 count = 0;
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references");
AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references");
if (!m_isRequestInProgress)
{
m_isRequestInProgress = true;