From 2fe4524458556e717d7cd6d9c98807bbb6a1ee74 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Fri, 22 Oct 2021 14:22:57 -0500 Subject: [PATCH] Terrain API cleanups (#4914) * Terrain API fixups Moved SurfaceData definitions in AzFramework out of terrain into separate files. Added some missing API calls: Get*FromVector2, GetSurfacePoint* Changed OrderedSurfaceTagWeightSet to SurfaceTagWeightList Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * PR feedback - remove IsClose check. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed PhysX test compile failures by redcoding a bunch of "dummy terrain" implementation that's unused. It was originally added for the PhysX Terrain component, but that component is long gone and has been superceded by the more generic PhysX Heightfield Collider. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed up failing terrain unit tests. Added API changes, and changed the assumption on where the surface weight sort is taking place. The component is no longer expected to provide the sorted list, it only needs to be sorted at the end coming out of the terrain system, so the unit tests have been modified to reflect that. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../AzFramework/Application/Application.cpp | 3 + .../AzFramework/SurfaceData/SurfaceData.cpp | 59 +++++++++ .../AzFramework/SurfaceData/SurfaceData.h | 72 +++++++++++ .../Terrain/TerrainDataRequestBus.cpp | 71 ++++------- .../Terrain/TerrainDataRequestBus.h | 116 +++++++++--------- .../AzFramework/azframework_files.cmake | 2 + .../Benchmarks/PhysXBenchmarksCommon.cpp | 4 - .../Tests/Benchmarks/PhysXBenchmarksCommon.h | 1 - Gems/PhysX/Code/Tests/EditorTestUtilities.cpp | 4 - Gems/PhysX/Code/Tests/EditorTestUtilities.h | 1 - Gems/PhysX/Code/Tests/PhysXTestFixtures.cpp | 4 - Gems/PhysX/Code/Tests/PhysXTestFixtures.h | 1 - Gems/PhysX/Code/Tests/PhysXTestUtil.h | 64 ---------- .../Ebuses/TerrainAreaSurfaceRequestBus.h | 4 +- Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h | 29 +++-- .../MockTerrainAreaSurfaceRequestBus.h | 2 +- .../TerrainSurfaceDataSystemComponent.cpp | 14 ++- .../TerrainSurfaceGradientListComponent.cpp | 7 +- .../TerrainSurfaceGradientListComponent.h | 2 +- .../Source/TerrainSystem/TerrainSystem.cpp | 111 ++++++++++------- .../Code/Source/TerrainSystem/TerrainSystem.h | 41 +++++-- .../Tests/TerrainSurfaceGradientListTests.cpp | 16 +-- Gems/Terrain/Code/Tests/TerrainSystemTest.cpp | 47 ++++--- 23 files changed, 390 insertions(+), 285 deletions(-) create mode 100644 Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.cpp create mode 100644 Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.h diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 1f99a594fa..f8d0ea8bb1 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -278,6 +279,8 @@ namespace AzFramework AzFramework::RemoteStorageDriveConfig::Reflect(context); Physics::ReflectionUtils::ReflectPhysicsApi(context); + AzFramework::SurfaceData::SurfaceTagWeight::Reflect(context); + AzFramework::SurfaceData::SurfacePoint::Reflect(context); AzFramework::Terrain::TerrainDataRequests::Reflect(context); if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) diff --git a/Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.cpp b/Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.cpp new file mode 100644 index 0000000000..55fec57bb6 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.cpp @@ -0,0 +1,59 @@ +/* + * 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 +#include +#include + +namespace AzFramework::SurfaceData +{ + void SurfaceTagWeight::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("m_surfaceType", &SurfaceTagWeight::m_surfaceType) + ->Field("m_weight", &SurfaceTagWeight::m_weight) + ; + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Category, "SurfaceData") + ->Constructor() + ->Property("surfaceType", BehaviorValueProperty(&SurfaceTagWeight::m_surfaceType)) + ->Property("weight", BehaviorValueProperty(&SurfaceTagWeight::m_weight)) + ; + } + } + + void SurfacePoint::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("m_position", &SurfacePoint::m_position) + ->Field("m_normal", &SurfacePoint::m_normal) + ->Field("m_surfaceTags", &SurfacePoint::m_surfaceTags) + ; + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AzFramework::SurfaceData::SurfacePoint") + ->Attribute(AZ::Script::Attributes::Category, "SurfaceData") + ->Constructor() + ->Property("position", BehaviorValueProperty(&SurfacePoint::m_position)) + ->Property("normal", BehaviorValueProperty(&SurfacePoint::m_normal)) + ->Property("surfaceTags", BehaviorValueProperty(&SurfacePoint::m_surfaceTags)) + ; + } + } + +} // namespace AzFramework::SurfaceData diff --git a/Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.h b/Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.h new file mode 100644 index 0000000000..77d9ae4239 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/SurfaceData/SurfaceData.h @@ -0,0 +1,72 @@ +/* + * 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 +#include +#include +#include + +namespace AzFramework::SurfaceData +{ + namespace Constants + { + static constexpr const char* s_unassignedTagName = "(unassigned)"; + } + + struct SurfaceTagWeight + { + AZ_TYPE_INFO(SurfaceTagWeight, "{EA14018E-E853-4BF5-8E13-D83BB99A54CC}"); + SurfaceTagWeight() = default; + SurfaceTagWeight(AZ::Crc32 surfaceType, float weight) + : m_surfaceType(surfaceType) + , m_weight(weight) + { + } + + AZ::Crc32 m_surfaceType = AZ::Crc32(Constants::s_unassignedTagName); + float m_weight = 0.0f; //! A Value in the range [0.0f .. 1.0f] + + static void Reflect(AZ::ReflectContext* context); + }; + + struct SurfaceTagWeightComparator + { + bool operator()(const SurfaceTagWeight& tagWeight1, const SurfaceTagWeight& tagWeight2) const + { + // Return a deterministic sort order for surface tags from highest to lowest weight, with the surface types sorted + // in a predictable order when the weights are equal. The surface type sort order is meaningless since it is sorting CRC + // values, it's really just important for it to be stable. + // For the floating-point weight comparisons we use exact instead of IsClose value comparisons for a similar reason - we + // care about being sorted highest to lowest, but there's no inherent meaning in sorting surface types with *similar* weights + // together. + + if (tagWeight1.m_weight != tagWeight2.m_weight) + { + return tagWeight1.m_weight > tagWeight2.m_weight; + } + else + { + return tagWeight1.m_surfaceType > tagWeight2.m_surfaceType; + } + } + }; + + using SurfaceTagWeightList = AZStd::vector; + + struct SurfacePoint final + { + AZ_TYPE_INFO(SurfacePoint, "{331A3D0E-BB1D-47BF-96A2-249FAA0D720D}"); + + AZ::Vector3 m_position; + AZ::Vector3 m_normal; + SurfaceTagWeightList m_surfaceTags; + + static void Reflect(AZ::ReflectContext* context); + }; +} // namespace AzFramework::SurfaceData diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.cpp b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.cpp index 1fb29cfa30..561408db20 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.cpp +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.cpp @@ -8,56 +8,33 @@ #include "TerrainDataRequestBus.h" #include +#include -namespace AzFramework +namespace AzFramework::Terrain { - namespace SurfaceData + void TerrainDataRequests::Reflect(AZ::ReflectContext* context) { - void SurfaceTagWeight::Reflect(AZ::ReflectContext* context) + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Field("m_surfaceType", &SurfaceTagWeight::m_surfaceType) - ->Field("m_weight", &SurfaceTagWeight::m_weight) - ; - } - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->Class("SurfaceTagWeight") - ->Property("m_surfaceType", BehaviorValueProperty(&SurfaceTagWeight::m_surfaceType)) - ->Property("m_weight", BehaviorValueProperty(&SurfaceTagWeight::m_weight)) - ; - } - } - } //namespace SurfaceData - - namespace Terrain - { - void TerrainDataRequests::Reflect(AZ::ReflectContext* context) - { - AzFramework::SurfaceData::SurfaceTagWeight::Reflect(context); - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->EBus("TerrainDataRequestBus") - ->Attribute(AZ::Script::Attributes::Category, "Terrain") - ->Event("GetHeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeight) - ->Event("GetHeightFromFloats", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeightFromFloats) - ->Event("GetMaxSurfaceWeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetMaxSurfaceWeight) - ->Event("GetMaxSurfaceWeightFromFloats", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetMaxSurfaceWeightFromFloats) - ->Event("GetIsHoleFromFloats", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetIsHoleFromFloats) - ->Event("GetNormal", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetNormal) - ->Event("GetNormalFromFloats", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetNormalFromFloats) - ->Event("GetTerrainAabb", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainAabb) - ->Event("GetTerrainHeightQueryResolution", - &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainHeightQueryResolution) - ; - - } - + behaviorContext->EBus("TerrainDataRequestBus") + ->Attribute(AZ::Script::Attributes::Category, "Terrain") + ->Event("GetHeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeight) + ->Event("GetNormal", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetNormal) + ->Event("GetMaxSurfaceWeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetMaxSurfaceWeight) + ->Event("GetMaxSurfaceWeightFromVector2", + &AzFramework::Terrain::TerrainDataRequestBus::Events::GetMaxSurfaceWeightFromVector2) + ->Event("GetSurfaceWeights", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetSurfaceWeights) + ->Event("GetSurfaceWeightsFromVector2", + &AzFramework::Terrain::TerrainDataRequestBus::Events::GetSurfaceWeightsFromVector2) + ->Event("GetIsHoleFromFloats", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetIsHoleFromFloats) + ->Event("GetSurfacePoint", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetSurfacePoint) + ->Event("GetSurfacePointFromVector2", + &AzFramework::Terrain::TerrainDataRequestBus::Events::GetSurfacePointFromVector2) + ->Event("GetTerrainAabb", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainAabb) + ->Event("GetTerrainHeightQueryResolution", + &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainHeightQueryResolution) + ; } - } //namespace Terrain -} // namespace AzFramework + } +} // namespace AzFramework::Terrain diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h index 3f6a8f0960..30a2f8e044 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h @@ -8,50 +8,13 @@ #pragma once #include -#include #include #include #include -#include +#include namespace AzFramework { - namespace SurfaceData - { - namespace Constants - { - static const char* s_unassignedTagName = "(unassigned)"; - } - - struct SurfaceTagWeight - { - AZ_TYPE_INFO(SurfaceTagWeight, "{EA14018E-E853-4BF5-8E13-D83BB99A54CC}"); - - AZ::Crc32 m_surfaceType = AZ::Crc32(Constants::s_unassignedTagName); - float m_weight = 0.0f; //! A Value in the range [0.0f .. 1.0f] - - //! Don't call this directly. TerrainDataRequests::Reflect is doing it already. - static void Reflect(AZ::ReflectContext* context); - }; - - struct SurfaceTagWeightComparator - { - bool operator()(const SurfaceTagWeight& tagWeight1, const SurfaceTagWeight& tagWeight2) const - { - if (!AZ::IsClose(tagWeight1.m_weight, tagWeight2.m_weight)) - { - return tagWeight1.m_weight > tagWeight2.m_weight; - } - else - { - return tagWeight1.m_surfaceType > tagWeight2.m_surfaceType; - } - } - }; - - using OrderedSurfaceTagWeightSet = AZStd::set; - } //namespace SurfaceData - namespace Terrain { @@ -91,49 +54,82 @@ namespace AzFramework //! Returns terrains height in meters at location x,y. //! @terrainExistsPtr: Can be nullptr. If != nullptr then, if there's no terrain at location x,y or location x,y is inside a terrain HOLE then *terrainExistsPtr will become false, //! otherwise *terrainExistsPtr will become true. - virtual float GetHeight(AZ::Vector3 position, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; - virtual float GetHeightFromFloats(float x, float y, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual float GetHeight(const AZ::Vector3& position, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual float GetHeightFromVector2( + const AZ::Vector2& position, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual float GetHeightFromFloats( + float x, float y, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + + //! Returns true if there's a hole at location x,y. + //! Also returns true if there's no terrain data at location x,y. + virtual bool GetIsHole(const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR) const = 0; + virtual bool GetIsHoleFromVector2(const AZ::Vector2& position, Sampler sampleFilter = Sampler::BILINEAR) const = 0; + virtual bool GetIsHoleFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR) const = 0; + + // Given an XY coordinate, return the surface normal. + //! @terrainExists: Can be nullptr. If != nullptr then, if there's no terrain at location x,y or location x,y is inside a + //! terrain HOLE then *terrainExistsPtr will be set to false, + //! otherwise *terrainExistsPtr will be set to true. + virtual AZ::Vector3 GetNormal( + const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual AZ::Vector3 GetNormalFromVector2( + const AZ::Vector2& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual AZ::Vector3 GetNormalFromFloats( + float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; //! Given an XY coordinate, return the max surface type and weight. //! @terrainExists: Can be nullptr. If != nullptr then, if there's no terrain at location x,y or location x,y is inside a terrain HOLE then *terrainExistsPtr will be set to false, //! otherwise *terrainExistsPtr will be set to true. - virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight(AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; - virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2(const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0; - virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight( + const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2( + const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0; + virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats( + float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; //! Given an XY coordinate, return the set of surface types and weights. The Vector3 input position version is defined to ignore //! the input Z value. virtual void GetSurfaceWeights( const AZ::Vector3& inPosition, - SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0; virtual void GetSurfaceWeightsFromVector2( const AZ::Vector2& inPosition, - SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0; virtual void GetSurfaceWeightsFromFloats( float x, float y, - SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0; //! Convenience function for low level systems that can't do a reverse lookup from Crc to string. Everyone else should use GetMaxSurfaceWeight or GetMaxSurfaceWeightFromFloats. //! Not available in the behavior context. //! Returns nullptr if the position is inside a hole or outside of the terrain boundaries. - virtual const char * GetMaxSurfaceName(AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual const char* GetMaxSurfaceName( + const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; - //! Returns true if there's a hole at location x,y. - //! Also returns true if there's no terrain data at location x,y. - virtual bool GetIsHoleFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR) const = 0; - - // Given an XY coordinate, return the surface normal. - //! @terrainExists: Can be nullptr. If != nullptr then, if there's no terrain at location x,y or location x,y is inside a terrain HOLE then *terrainExistsPtr will be set to false, - //! otherwise *terrainExistsPtr will be set to true. - virtual AZ::Vector3 GetNormal(AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; - virtual AZ::Vector3 GetNormalFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + //! Given an XY coordinate, return all terrain information at that location. The Vector3 input position version is defined + //! to ignore the input Z value. + virtual void GetSurfacePoint( + const AZ::Vector3& inPosition, + SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const = 0; + virtual void GetSurfacePointFromVector2( + const AZ::Vector2& inPosition, + SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const = 0; + virtual void GetSurfacePointFromFloats( + float x, + float y, + SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const = 0; }; using TerrainDataRequestBus = AZ::EBus; @@ -169,6 +165,10 @@ namespace AzFramework } }; using TerrainDataNotificationBus = AZ::EBus; - - } //namespace Terrain + } // namespace Terrain } // namespace AzFramework + +namespace AZ +{ + AZ_TYPE_INFO_SPECIALIZE(AzFramework::Terrain::TerrainDataRequests::Sampler, "{D29BB6D7-3006-4114-858D-355EAA256B86}"); +} // namespace AZ diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index b338dbb0a8..d3196e8517 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -301,6 +301,8 @@ set(FILES Spawnable/SpawnableMonitor.cpp Spawnable/SpawnableSystemComponent.h Spawnable/SpawnableSystemComponent.cpp + SurfaceData/SurfaceData.h + SurfaceData/SurfaceData.cpp Terrain/TerrainDataRequestBus.h Terrain/TerrainDataRequestBus.cpp Thermal/ThermalInfo.h diff --git a/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.cpp b/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.cpp index 70b5aefe14..49dc249d25 100644 --- a/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.cpp +++ b/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.cpp @@ -61,7 +61,6 @@ namespace PhysX::Benchmarks m_defaultScene = physicsSystem->GetScene(m_testSceneHandle); } - m_dummyTerrainComponentDescriptor = DummyTestTerrainComponent::CreateDescriptor(); Physics::DefaultWorldBus::Handler::BusConnect(); } @@ -80,9 +79,6 @@ namespace PhysX::Benchmarks m_testSceneHandle = AzPhysics::InvalidSceneHandle; TestUtils::ResetPhysXSystem(); - - m_dummyTerrainComponentDescriptor->ReleaseDescriptor(); - m_dummyTerrainComponentDescriptor = nullptr; } AzPhysics::SceneHandle PhysXBaseBenchmarkFixture::CreateDefaultTestScene() diff --git a/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.h b/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.h index b32298d484..bde4995e27 100644 --- a/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.h +++ b/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksCommon.h @@ -61,7 +61,6 @@ namespace PhysX::Benchmarks AzPhysics::Scene* m_defaultScene = nullptr; AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle; - AZ::ComponentDescriptor* m_dummyTerrainComponentDescriptor = nullptr; }; } // namespace PhysX::Benchmarks #endif //HAVE_BENCHMARK diff --git a/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp b/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp index 63a689894c..fa794c58a5 100644 --- a/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp +++ b/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp @@ -52,14 +52,10 @@ namespace PhysXEditorTests m_defaultScene = physicsSystem->GetScene(m_defaultSceneHandle); } Physics::DefaultWorldBus::Handler::BusConnect(); - m_dummyTerrainComponentDescriptor = PhysX::DummyTestTerrainComponent::CreateDescriptor(); } void PhysXEditorFixture::TearDown() { - m_dummyTerrainComponentDescriptor->ReleaseDescriptor(); - m_dummyTerrainComponentDescriptor = nullptr; - Physics::DefaultWorldBus::Handler::BusDisconnect(); // prevents warnings from the undo cache on subsequent tests diff --git a/Gems/PhysX/Code/Tests/EditorTestUtilities.h b/Gems/PhysX/Code/Tests/EditorTestUtilities.h index b05a7561fe..9dfe40f366 100644 --- a/Gems/PhysX/Code/Tests/EditorTestUtilities.h +++ b/Gems/PhysX/Code/Tests/EditorTestUtilities.h @@ -51,7 +51,6 @@ namespace PhysXEditorTests // DefaultWorldBus AzPhysics::SceneHandle GetDefaultSceneHandle() const override; - AZ::ComponentDescriptor* m_dummyTerrainComponentDescriptor = nullptr; AzPhysics::SceneHandle m_defaultSceneHandle = AzPhysics::InvalidSceneHandle; AzPhysics::Scene* m_defaultScene = nullptr; diff --git a/Gems/PhysX/Code/Tests/PhysXTestFixtures.cpp b/Gems/PhysX/Code/Tests/PhysXTestFixtures.cpp index b3f233d388..c5fb2d5092 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestFixtures.cpp +++ b/Gems/PhysX/Code/Tests/PhysXTestFixtures.cpp @@ -41,16 +41,12 @@ namespace PhysX } Physics::DefaultWorldBus::Handler::BusConnect(); - - m_dummyTerrainComponentDescriptor = DummyTestTerrainComponent::CreateDescriptor(); } void PhysXDefaultWorldTest::TearDown() { Physics::DefaultWorldBus::Handler::BusDisconnect(); m_defaultScene = nullptr; - m_dummyTerrainComponentDescriptor->ReleaseDescriptor(); - m_dummyTerrainComponentDescriptor = nullptr; //Clean up the Test scene if (auto* physicsSystem = AZ::Interface::Get()) diff --git a/Gems/PhysX/Code/Tests/PhysXTestFixtures.h b/Gems/PhysX/Code/Tests/PhysXTestFixtures.h index 9b00f7d892..6a8325a66f 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestFixtures.h +++ b/Gems/PhysX/Code/Tests/PhysXTestFixtures.h @@ -33,7 +33,6 @@ namespace PhysX // DefaultWorldBus AzPhysics::SceneHandle GetDefaultSceneHandle() const override; - AZ::ComponentDescriptor* m_dummyTerrainComponentDescriptor = nullptr; AzPhysics::Scene* m_defaultScene = nullptr; AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle; }; diff --git a/Gems/PhysX/Code/Tests/PhysXTestUtil.h b/Gems/PhysX/Code/Tests/PhysXTestUtil.h index 1c86768de7..d821fb146b 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestUtil.h +++ b/Gems/PhysX/Code/Tests/PhysXTestUtil.h @@ -63,68 +63,4 @@ namespace PhysX AzPhysics::SimulatedBodyEvents::OnTriggerExit::Handler m_onTriggerExitHandler; }; - - //! Dummy component emulating presence of terrain by connecting to TerrainDataRequestBus - //! PhysX Terrain Component skips activation if there's no terrain present, - //! so in order to test it we also add the DummyTestTerrainComponent. - class DummyTestTerrainComponent - : public AZ::Component - , private AzFramework::Terrain::TerrainDataRequestBus::Handler - { - public: - AZ_COMPONENT(DummyTestTerrainComponent, "{EE4ECA23-9C27-4D5D-9C6F-271A19C0333E}"); - static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) - { - provided.push_back(AZ_CRC_CE("TerrainService")); - } - - private: - //////////////////////////////////////////////////////////////////////// - // AZ::Component interface implementation - void Activate() override - { - AzFramework::Terrain::TerrainDataRequestBus::Handler::BusConnect(); - } - void Deactivate() override - { - AzFramework::Terrain::TerrainDataRequestBus::Handler::BusDisconnect(); - } - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // TerrainDataRequestBus interface dummy implementation - AZ::Vector2 GetTerrainHeightQueryResolution() const override - { - return {}; - } - void SetTerrainHeightQueryResolution([[maybe_unused]] AZ::Vector2 queryResolution) override - { - } - - AZ::Aabb GetTerrainAabb() const override - { - return {}; - } - void SetTerrainAabb([[maybe_unused]] const AZ::Aabb& worldBounds) override - { - } - - float GetHeight(AZ::Vector3, Sampler, bool*) const override - { - return {}; - } - float GetHeightFromFloats(float, float, Sampler, bool*) const override { return {}; } - AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight(AZ::Vector3, Sampler, bool*) const override { return {}; } - AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2(const AZ::Vector2&, Sampler, bool*) const override { return {}; } - AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats(float, float, Sampler, bool*) const override { return {}; } - void GetSurfaceWeights(const AZ::Vector3&, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*) const override {} - void GetSurfaceWeightsFromVector2(const AZ::Vector2&, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*) const override{}; - void GetSurfaceWeightsFromFloats(float, float, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*) const override {} - const char* GetMaxSurfaceName(AZ::Vector3, Sampler, bool*) const override { return {}; } - bool GetIsHoleFromFloats(float, float, Sampler) const override { return {}; } - AZ::Vector3 GetNormal(AZ::Vector3, Sampler, bool*) const override { return {}; } - AZ::Vector3 GetNormalFromFloats(float, float, Sampler, bool*) const override { return {}; } - //////////////////////////////////////////////////////////////////////// - }; - } // namespace PhysX diff --git a/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h b/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h index 4c04cf1e42..ed352b55df 100644 --- a/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h +++ b/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h @@ -27,8 +27,8 @@ namespace Terrain virtual ~TerrainAreaSurfaceRequests() = default; - //! Get the surfaces and weights from a gradient at a given position sorted into descending order of weight. - virtual void GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const = 0; + //! Get the surfaces and weights from a gradient at a given position. + virtual void GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights) const = 0; }; using TerrainAreaSurfaceRequestBus = AZ::EBus; diff --git a/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h b/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h index bb1fa5683a..53d93be8ea 100644 --- a/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h +++ b/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h @@ -107,17 +107,28 @@ namespace UnitTest MOCK_METHOD1(SetTerrainHeightQueryResolution, void(AZ::Vector2)); MOCK_CONST_METHOD0(GetTerrainAabb, AZ::Aabb()); MOCK_METHOD1(SetTerrainAabb, void(const AZ::Aabb&)); - MOCK_CONST_METHOD3(GetHeight, float(AZ::Vector3, Sampler, bool*)); + MOCK_CONST_METHOD3(GetHeight, float(const AZ::Vector3&, Sampler, bool*)); + MOCK_CONST_METHOD3(GetHeightFromVector2, float(const AZ::Vector2&, Sampler, bool*)); MOCK_CONST_METHOD4(GetHeightFromFloats, float(float, float, Sampler, bool*)); - MOCK_CONST_METHOD3(GetMaxSurfaceWeight, AzFramework::SurfaceData::SurfaceTagWeight(AZ::Vector3, Sampler, bool*)); + MOCK_CONST_METHOD2(GetIsHole, bool(const AZ::Vector3&, Sampler)); + MOCK_CONST_METHOD2(GetIsHoleFromVector2, bool(const AZ::Vector2&, Sampler)); + MOCK_CONST_METHOD3(GetIsHoleFromFloats, bool(float, float, Sampler)); + MOCK_CONST_METHOD3(GetNormal, AZ::Vector3(const AZ::Vector3&, Sampler, bool*)); + MOCK_CONST_METHOD3(GetNormalFromVector2, AZ::Vector3(const AZ::Vector2&, Sampler, bool*)); + MOCK_CONST_METHOD4(GetNormalFromFloats, AZ::Vector3(float, float, Sampler, bool*)); + MOCK_CONST_METHOD3(GetMaxSurfaceWeight, AzFramework::SurfaceData::SurfaceTagWeight(const AZ::Vector3&, Sampler, bool*)); MOCK_CONST_METHOD3(GetMaxSurfaceWeightFromVector2, AzFramework::SurfaceData::SurfaceTagWeight(const AZ::Vector2&, Sampler, bool*)); MOCK_CONST_METHOD4(GetMaxSurfaceWeightFromFloats, AzFramework::SurfaceData::SurfaceTagWeight(float, float, Sampler, bool*)); - MOCK_CONST_METHOD4(GetSurfaceWeights, void(const AZ::Vector3&, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*)); - MOCK_CONST_METHOD4(GetSurfaceWeightsFromVector2, void(const AZ::Vector2&, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*)); - MOCK_CONST_METHOD5(GetSurfaceWeightsFromFloats, void(float, float, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*)); - MOCK_CONST_METHOD3(GetMaxSurfaceName, const char*(AZ::Vector3, Sampler, bool*)); - MOCK_CONST_METHOD3(GetIsHoleFromFloats, bool(float, float, Sampler)); - MOCK_CONST_METHOD3(GetNormal, AZ::Vector3(AZ::Vector3, Sampler, bool*)); - MOCK_CONST_METHOD4(GetNormalFromFloats, AZ::Vector3(float, float, Sampler, bool*)); + MOCK_CONST_METHOD4(GetSurfaceWeights, void(const AZ::Vector3&, AzFramework::SurfaceData::SurfaceTagWeightList&, Sampler, bool*)); + MOCK_CONST_METHOD4( + GetSurfaceWeightsFromVector2, void(const AZ::Vector2&, AzFramework::SurfaceData::SurfaceTagWeightList&, Sampler, bool*)); + MOCK_CONST_METHOD5( + GetSurfaceWeightsFromFloats, void(float, float, AzFramework::SurfaceData::SurfaceTagWeightList&, Sampler, bool*)); + MOCK_CONST_METHOD3(GetMaxSurfaceName, const char*(const AZ::Vector3&, Sampler, bool*)); + MOCK_CONST_METHOD4(GetSurfacePoint, void(const AZ::Vector3&, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*)); + MOCK_CONST_METHOD4( + GetSurfacePointFromVector2, void(const AZ::Vector2&, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*)); + MOCK_CONST_METHOD5( + GetSurfacePointFromFloats, void(float, float, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*)); }; } // namespace UnitTest diff --git a/Gems/Terrain/Code/Mocks/Terrain/MockTerrainAreaSurfaceRequestBus.h b/Gems/Terrain/Code/Mocks/Terrain/MockTerrainAreaSurfaceRequestBus.h index c5a04b4265..665bf581bc 100644 --- a/Gems/Terrain/Code/Mocks/Terrain/MockTerrainAreaSurfaceRequestBus.h +++ b/Gems/Terrain/Code/Mocks/Terrain/MockTerrainAreaSurfaceRequestBus.h @@ -28,7 +28,7 @@ namespace UnitTest MOCK_METHOD0(Activate, void()); MOCK_METHOD0(Deactivate, void()); - MOCK_CONST_METHOD2(GetSurfaceWeights, void(const AZ::Vector3&, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&)); + MOCK_CONST_METHOD2(GetSurfaceWeights, void(const AZ::Vector3&, AzFramework::SurfaceData::SurfaceTagWeightList&)); }; } // namespace UnitTest diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp index 0346ff7281..7395e66d06 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp @@ -149,13 +149,17 @@ namespace Terrain if (terrain->GetTerrainAabb().Contains(inPosition)) { bool isTerrainValidAtPoint = false; - const float terrainHeight = terrain->GetHeight(inPosition, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, &isTerrainValidAtPoint); + AzFramework::SurfaceData::SurfacePoint terrainSurfacePoint; + terrain->GetSurfacePoint( + inPosition, terrainSurfacePoint, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, + &isTerrainValidAtPoint); + const bool isHole = !isTerrainValidAtPoint; SurfaceData::SurfacePoint point; point.m_entityId = GetEntityId(); - point.m_position = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), terrainHeight); - point.m_normal = terrain->GetNormal(inPosition); + point.m_position = terrainSurfacePoint.m_position; + point.m_normal = terrainSurfacePoint.m_normal; // Always add a "terrain" or "terrainHole" tag. const AZ::Crc32 terrainTag = @@ -163,9 +167,7 @@ namespace Terrain SurfaceData::AddMaxValueForMasks(point.m_masks, terrainTag, 1.0f); // Add all of the surface tags that the terrain has at this point. - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet surfaceWeights; - terrain->GetSurfaceWeights(point.m_position, surfaceWeights); - for (auto& tag : surfaceWeights) + for (auto& tag : terrainSurfacePoint.m_surfaceTags) { SurfaceData::AddMaxValueForMasks(point.m_masks, tag.m_surfaceType, tag.m_weight); } diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp index 958e175cf3..5b76f15d74 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp @@ -166,7 +166,7 @@ namespace Terrain void TerrainSurfaceGradientListComponent::GetSurfaceWeights( const AZ::Vector3& inPosition, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights) const { outSurfaceWeights.clear(); @@ -178,10 +178,7 @@ namespace Terrain GradientSignal::GradientRequestBus::EventResult(weight, mapping.m_gradientEntityId, &GradientSignal::GradientRequestBus::Events::GetValue, params); - AzFramework::SurfaceData::SurfaceTagWeight tagWeight; - tagWeight.m_surfaceType = mapping.m_surfaceTag; - tagWeight.m_weight = weight; - outSurfaceWeights.emplace(tagWeight); + outSurfaceWeights.emplace_back(mapping.m_surfaceTag, weight); } } diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h index bb30029f35..20851c127f 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h @@ -72,7 +72,7 @@ namespace Terrain bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; // TerrainAreaSurfaceRequestBus - void GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const override; + void GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights) const override; private: ////////////////////////////////////////////////////////////////////////// diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index 821e0bd2e2..fa1d483a5d 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -241,7 +241,12 @@ float TerrainSystem::GetTerrainAreaHeight(float x, float y, bool& terrainExists) return height; } -float TerrainSystem::GetHeight(AZ::Vector3 position, Sampler sampler, bool* terrainExistsPtr) const +float TerrainSystem::GetHeight(const AZ::Vector3& position, Sampler sampler, bool* terrainExistsPtr) const +{ + return GetHeightSynchronous(position.GetX(), position.GetY(), sampler, terrainExistsPtr); +} + +float TerrainSystem::GetHeightFromVector2(const AZ::Vector2& position, Sampler sampler, bool* terrainExistsPtr) const { return GetHeightSynchronous(position.GetX(), position.GetY(), sampler, terrainExistsPtr); } @@ -251,6 +256,20 @@ float TerrainSystem::GetHeightFromFloats(float x, float y, Sampler sampler, bool return GetHeightSynchronous(x, y, sampler, terrainExistsPtr); } +bool TerrainSystem::GetIsHole(const AZ::Vector3& position, Sampler sampler) const +{ + bool terrainExists = false; + GetHeightSynchronous(position.GetX(), position.GetY(), sampler, &terrainExists); + return !terrainExists; +} + +bool TerrainSystem::GetIsHoleFromVector2(const AZ::Vector2& position, Sampler sampler) const +{ + bool terrainExists = false; + GetHeightSynchronous(position.GetX(), position.GetY(), sampler, &terrainExists); + return !terrainExists; +} + bool TerrainSystem::GetIsHoleFromFloats(float x, float y, Sampler sampler) const { bool terrainExists = false; @@ -287,7 +306,12 @@ AZ::Vector3 TerrainSystem::GetNormalSynchronous(float x, float y, Sampler sample return outNormal; } -AZ::Vector3 TerrainSystem::GetNormal(AZ::Vector3 position, Sampler sampler, bool* terrainExistsPtr) const +AZ::Vector3 TerrainSystem::GetNormal(const AZ::Vector3& position, Sampler sampler, bool* terrainExistsPtr) const +{ + return GetNormalSynchronous(position.GetX(), position.GetY(), sampler, terrainExistsPtr); +} + +AZ::Vector3 TerrainSystem::GetNormalFromVector2(const AZ::Vector2& position, Sampler sampler, bool* terrainExistsPtr) const { return GetNormalSynchronous(position.GetX(), position.GetY(), sampler, terrainExistsPtr); } @@ -299,7 +323,7 @@ AZ::Vector3 TerrainSystem::GetNormalFromFloats(float x, float y, Sampler sampler AzFramework::SurfaceData::SurfaceTagWeight TerrainSystem::GetMaxSurfaceWeight( - const AZ::Vector3 position, Sampler sampleFilter, bool* terrainExistsPtr) const + const AZ::Vector3& position, Sampler sampleFilter, bool* terrainExistsPtr) const { return GetMaxSurfaceWeightFromFloats(position.GetX(), position.GetY(), sampleFilter, terrainExistsPtr); } @@ -317,7 +341,7 @@ AzFramework::SurfaceData::SurfaceTagWeight TerrainSystem::GetMaxSurfaceWeightFro *terrainExistsPtr = true; } - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet weightSet; + AzFramework::SurfaceData::SurfaceTagWeightList weightSet; GetOrderedSurfaceWeights(x, y, sampleFilter, weightSet, terrainExistsPtr); @@ -329,6 +353,38 @@ AzFramework::SurfaceData::SurfaceTagWeight TerrainSystem::GetMaxSurfaceWeightFro return *weightSet.begin(); } +void TerrainSystem::GetSurfacePoint( + const AZ::Vector3& inPosition, + AzFramework::SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter, + bool* terrainExistsPtr) const +{ + outSurfacePoint.m_position = inPosition; + outSurfacePoint.m_position.SetZ(GetHeightSynchronous(inPosition.GetX(), inPosition.GetY(), sampleFilter, terrainExistsPtr)); + outSurfacePoint.m_normal = GetNormalSynchronous(inPosition.GetX(), inPosition.GetY(), sampleFilter, nullptr); + GetSurfaceWeights(inPosition, outSurfacePoint.m_surfaceTags, sampleFilter, nullptr); +} + +void TerrainSystem::GetSurfacePointFromVector2( + const AZ::Vector2& inPosition, + AzFramework::SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter, + bool* terrainExistsPtr) const +{ + GetSurfacePoint(AZ::Vector3(inPosition.GetX(), inPosition.GetY(), 0.0f), outSurfacePoint, sampleFilter, terrainExistsPtr); +} + +void TerrainSystem::GetSurfacePointFromFloats( + float x, + float y, + AzFramework::SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter, + bool* terrainExistsPtr) const +{ + GetSurfacePoint(AZ::Vector3(x, y, 0.0f), outSurfacePoint, sampleFilter, terrainExistsPtr); +} + + AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::Aabb& bounds) const { AZ::Vector3 inPosition = AZ::Vector3(x, y, 0); @@ -354,7 +410,7 @@ void TerrainSystem::GetOrderedSurfaceWeights( const float x, const float y, [[maybe_unused]] Sampler sampler, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, bool* terrainExistsPtr) const { AZ::Aabb bounds; @@ -377,54 +433,40 @@ void TerrainSystem::GetOrderedSurfaceWeights( // Get all the surfaces with weights at the given point. Terrain::TerrainAreaSurfaceRequestBus::Event( bestAreaId, &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, inPosition, outSurfaceWeights); + + AZStd::sort(outSurfaceWeights.begin(), outSurfaceWeights.end(), AzFramework::SurfaceData::SurfaceTagWeightComparator()); } void TerrainSystem::GetSurfaceWeights( const AZ::Vector3& inPosition, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter, bool* terrainExistsPtr) const { - if (terrainExistsPtr) - { - *terrainExistsPtr = true; - } - GetOrderedSurfaceWeights(inPosition.GetX(), inPosition.GetY(), sampleFilter, outSurfaceWeights, terrainExistsPtr); } void TerrainSystem::GetSurfaceWeightsFromVector2( const AZ::Vector2& inPosition, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter, bool* terrainExistsPtr) const { - // For now, always set terrainExists to true, as we don't have a way to author data for terrain holes yet. - if (terrainExistsPtr) - { - *terrainExistsPtr = true; - } GetOrderedSurfaceWeights(inPosition.GetX(), inPosition.GetY(), sampleFilter, outSurfaceWeights, terrainExistsPtr); } void TerrainSystem::GetSurfaceWeightsFromFloats( - float x, - float y, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + float x, float y, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter, bool* terrainExistsPtr) const { - // For now, always set terrainExists to true, as we don't have a way to author data for terrain holes yet. - if (terrainExistsPtr) - { - *terrainExistsPtr = true; - } - GetOrderedSurfaceWeights(x, y, sampleFilter, outSurfaceWeights, terrainExistsPtr); } -const char* TerrainSystem::GetMaxSurfaceName([[maybe_unused]] AZ::Vector3 position, [[maybe_unused]] Sampler sampleFilter, [[maybe_unused]] bool* terrainExistsPtr) const +const char* TerrainSystem::GetMaxSurfaceName( + [[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] Sampler sampleFilter, [[maybe_unused]] bool* terrainExistsPtr) const { // For now, always set terrainExists to true, as we don't have a way to author data for terrain holes yet. if (terrainExistsPtr) @@ -436,21 +478,6 @@ const char* TerrainSystem::GetMaxSurfaceName([[maybe_unused]] AZ::Vector3 positi } /* -void TerrainSystem::GetSurfacePoint( - const AZ::Vector3& inPosition, [[maybe_unused]] Sampler sampleFilter, SurfaceData::SurfacePoint& outSurfacePoint) -{ - // TODO: Handle sampleFilter - - float sampleX = inPosition.GetX(); - float sampleY = inPosition.GetY(); - - GetHeight(inPosition, sampleFilter, outSurfacePoint.m_position); - //outSurfacePoint.m_position = AZ::Vector3(sampleX, sampleY, GetHeightSynchronous(sampleX, sampleY)); - outSurfacePoint.m_normal = GetNormalSynchronous(sampleX, sampleY); -} - - - void TerrainSystem::ProcessHeightsFromRegion(const AZ::Aabb& inRegion, const AZ::Vector2 stepSize, Sampler sampleFilter, SurfacePointRegionFillCallback perPositionCallback, TerrainDataReadyCallback onComplete) { diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index 66c48850ef..956424f048 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -62,7 +62,8 @@ namespace Terrain //! @terrainExistsPtr: Can be nullptr. If != nullptr then, if there's no terrain at location x,y or location x,y is inside a terrain //! HOLE then *terrainExistsPtr will become false, //! otherwise *terrainExistsPtr will become true. - float GetHeight(AZ::Vector3 position, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + float GetHeight(const AZ::Vector3& position, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + float GetHeightFromVector2(const AZ::Vector2& position, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; float GetHeightFromFloats(float x, float y, Sampler sampler = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; //! Given an XY coordinate, return the max surface type and weight. @@ -70,7 +71,7 @@ namespace Terrain //! HOLE then *terrainExistsPtr will be set to false, //! otherwise *terrainExistsPtr will be set to true. AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight( - const AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2( const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const override; AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats( @@ -78,18 +79,18 @@ namespace Terrain void GetSurfaceWeights( const AZ::Vector3& inPosition, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const override; void GetSurfaceWeightsFromVector2( const AZ::Vector2& inPosition, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const override; void GetSurfaceWeightsFromFloats( float x, float y, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const override; @@ -97,10 +98,12 @@ namespace Terrain //! GetMaxSurfaceWeight or GetMaxSurfaceWeightFromFloats. Not available in the behavior context. Returns nullptr if the position is //! inside a hole or outside of the terrain boundaries. const char* GetMaxSurfaceName( - AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; //! Returns true if there's a hole at location x,y. //! Also returns true if there's no terrain data at location x,y. + bool GetIsHole(const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR) const override; + bool GetIsHoleFromVector2(const AZ::Vector2& position, Sampler sampleFilter = Sampler::BILINEAR) const override; bool GetIsHoleFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR) const override; // Given an XY coordinate, return the surface normal. @@ -108,10 +111,30 @@ namespace Terrain //! HOLE then *terrainExistsPtr will be set to false, //! otherwise *terrainExistsPtr will be set to true. AZ::Vector3 GetNormal( - AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + const AZ::Vector3& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + AZ::Vector3 GetNormalFromVector2( + const AZ::Vector2& position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; AZ::Vector3 GetNormalFromFloats( float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + void GetSurfacePoint( + const AZ::Vector3& inPosition, + AzFramework::SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const override; + void GetSurfacePointFromVector2( + const AZ::Vector2& inPosition, + AzFramework::SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const override; + void GetSurfacePointFromFloats( + float x, + float y, + AzFramework::SurfaceData::SurfacePoint& outSurfacePoint, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const override; + + private: void ClampPosition(float x, float y, AZ::Vector2& outPosition, AZ::Vector2& normalizedDelta) const; @@ -120,11 +143,11 @@ namespace Terrain const float x, const float y, Sampler sampler, - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights, bool* terrainExistsPtr) const; float GetHeightSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const; float GetTerrainAreaHeight(float x, float y, bool& terrainExists) const; - AZ::Vector3 GetNormalSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const; + AZ::Vector3 GetNormalSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const; // AZ::TickBus::Handler overrides ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; diff --git a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp index 2a645b3f94..dea861bda5 100644 --- a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp @@ -91,10 +91,10 @@ namespace UnitTest } }; - TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientReturnsSurfaceWeightsInOrder) + TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientReturnsSurfaceWeights) { - // When there is more that one surface/weight defined and added to the component, they should all - // be returned in descending weight order. + // When there is more than one surface/weight defined and added to the component, they should all + // be returned. The component isn't required to return them in descending order. AddSurfaceGradientListToEntities(); m_entity->Activate(); @@ -109,15 +109,15 @@ namespace UnitTest NiceMock mockGradientRequests2(m_gradientEntity2->GetId()); ON_CALL(mockGradientRequests2, GetValue).WillByDefault(Return(gradient2Value)); - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet weightSet; + AzFramework::SurfaceData::SurfaceTagWeightList weightList; Terrain::TerrainAreaSurfaceRequestBus::Event( - m_entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightSet); + m_entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightList); - AZ::Crc32 expectedCrcList[] = { AZ::Crc32(surfaceTag2), AZ::Crc32(surfaceTag1) }; - const float expectedWeightList[] = { gradient2Value, gradient1Value }; + AZ::Crc32 expectedCrcList[] = { AZ::Crc32(surfaceTag1), AZ::Crc32(surfaceTag2) }; + const float expectedWeightList[] = { gradient1Value, gradient2Value }; int index = 0; - for (const auto& surfaceWeight : weightSet) + for (const auto& surfaceWeight : weightList) { EXPECT_EQ(surfaceWeight.m_surfaceType, expectedCrcList[index]); EXPECT_NEAR(surfaceWeight.m_weight, expectedWeightList[index], 0.01f); diff --git a/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp b/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp index f273a85e26..4d149e8527 100644 --- a/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp +++ b/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp @@ -475,8 +475,10 @@ namespace UnitTest } } - TEST_F(TerrainSystemTest, GetSurfaceWeightsReturnsAllValidSurfaceWeights) + TEST_F(TerrainSystemTest, GetSurfaceWeightsReturnsAllValidSurfaceWeightsInOrder) { + // When there is more than one surface/weight defined, they should all be returned in descending weight order. + CreateAndActivateTerrainSystem(); const AZ::Aabb aabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3::CreateZero(), AZ::Vector3::CreateOne()); @@ -490,32 +492,41 @@ namespace UnitTest const AZ::Crc32 tag1("tag1"); const AZ::Crc32 tag2("tag2"); + const AZ::Crc32 tag3("tag3"); + const float tag1Weight = 0.8f; + const float tag2Weight = 1.0f; + const float tag3Weight = 0.5f; - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet orderedSurfaceWeights; - - AzFramework::SurfaceData::SurfaceTagWeight tagWeight1; - tagWeight1.m_surfaceType = tag1; - tagWeight1.m_weight = 1.0f; - orderedSurfaceWeights.emplace(tagWeight1); - - AzFramework::SurfaceData::SurfaceTagWeight tagWeight2; - tagWeight2.m_surfaceType = tag2; - tagWeight2.m_weight = 0.8f; - orderedSurfaceWeights.emplace(tagWeight2); + AzFramework::SurfaceData::SurfaceTagWeightList orderedSurfaceWeights + { + { tag1, tag1Weight }, { tag2, tag2Weight }, { tag3, tag3Weight } + }; NiceMock mockSurfaceRequests(entity->GetId()); ON_CALL(mockSurfaceRequests, GetSurfaceWeights).WillByDefault(SetArgReferee<1>(orderedSurfaceWeights)); - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet outSurfaceWeights; + AzFramework::SurfaceData::SurfaceTagWeightList outSurfaceWeights; // Asking for values outside the layer spawner bounds, should result in no results. m_terrainSystem->GetSurfaceWeights(aabb.GetMax() + AZ::Vector3::CreateOne(), outSurfaceWeights); EXPECT_TRUE(outSurfaceWeights.empty()); - // Inside the layer spawner box should give us both the added surface weights. + // Inside the layer spawner box should give us all of the added surface weights. m_terrainSystem->GetSurfaceWeights(aabb.GetCenter(), outSurfaceWeights); - EXPECT_EQ(outSurfaceWeights.size(), 2); + EXPECT_EQ(outSurfaceWeights.size(), 3); + + // The weights should be returned in decreasing order. + AZ::Crc32 expectedCrcList[] = { tag2, tag1, tag3 }; + const float expectedWeightList[] = { tag2Weight, tag1Weight, tag3Weight }; + + int index = 0; + for (const auto& surfaceWeight : outSurfaceWeights) + { + EXPECT_EQ(surfaceWeight.m_surfaceType, expectedCrcList[index]); + EXPECT_NEAR(surfaceWeight.m_weight, expectedWeightList[index], 0.01f); + index++; + } } TEST_F(TerrainSystemTest, GetMaxSurfaceWeightsReturnsBiggestValidSurfaceWeight) @@ -534,17 +545,17 @@ namespace UnitTest const AZ::Crc32 tag1("tag1"); const AZ::Crc32 tag2("tag2"); - AzFramework::SurfaceData::OrderedSurfaceTagWeightSet orderedSurfaceWeights; + AzFramework::SurfaceData::SurfaceTagWeightList orderedSurfaceWeights; AzFramework::SurfaceData::SurfaceTagWeight tagWeight1; tagWeight1.m_surfaceType = tag1; tagWeight1.m_weight = 1.0f; - orderedSurfaceWeights.emplace(tagWeight1); + orderedSurfaceWeights.emplace_back(tagWeight1); AzFramework::SurfaceData::SurfaceTagWeight tagWeight2; tagWeight2.m_surfaceType = tag2; tagWeight2.m_weight = 0.8f; - orderedSurfaceWeights.emplace(tagWeight2); + orderedSurfaceWeights.emplace_back(tagWeight2); NiceMock mockSurfaceRequests(entity->GetId()); ON_CALL(mockSurfaceRequests, GetSurfaceWeights).WillByDefault(SetArgReferee<1>(orderedSurfaceWeights));