Files
o3de/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h
T
Mike Balfour dc050d4acd Terrain System bugfixes (#4180)
* Remove the "TEST_SUPPORTED" traits.
Terrain unit tests should be usable on all platforms, so they shouldn't need a platform-specific trait to enable/disable.

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

* Fix a few misc terrain bugs.
* Change Activate/Deactivate to happen immediately instead of deferring.  There were too many order-of-operation bugs caused by trying to defer this.
* Added implementation for calculating normals.
* Fixed bug where GetHeightSynchronous wasn't stopping at the highest-priority layer.
* Added locks for SurfaceData bus to help ensure we lock our mutexes in the correct order and avoid deadlocks.

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

* Add trivial TerrainSystem tests.
Tests construction, Activate(), Deactivate(), and destruction.

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

* Unified Terrain system calls on single bus.

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

* Added mock for TerrainDataNotificationBus listener.
Also added unit tests to verify the listener, and added in missing notification events.

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

* Removed extra Sampler class.
Fixed up APIs to correctly pass Sampler and terrainExistsPtr around.

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

* Switched MockTerrainSystem to be proper gmock.
This makes it for flexible to use and easier to reuse from other test environments.

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

* Fix settings bug caused by bad order of operations that occurred when the methods moved to a different bus.

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

* Eliminate extra EBus by simplifying area initialization.
Previously, there was a back-and-forth ebus signal used for the terrain system to find any terrain spawners that were created prior to the terrain system activation.  Now it uses the more simple technique of just grabbing all the spawners that are currently hooked up to the spawner ebus.

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

* Switch to NiceMock so that "uninteresting" mock calls get ignored.

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

* Addressed PR feedback.
Filled in terrainExistsPtr at the end, and added it to GetNormal as well.

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

* Fixed shader height calculation.
It was off by half a pixel, and it was interpolating, both of which were wrong.

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

* Create initial LmbrCentral mocks that other Gems can use.
To help improve mock maintenance over time, this creates mocks in the same Gem as the systems being mocked, instead of the other Gems that need to use mocked systems during testing.  This way, the mocks should more easily stay in sync with the interface that they mock out.

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

* Null-guard any uses of Atom to make the class easier to unit test.

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

* Add more mocked terrain services

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

* Moved Terrain mocks to publicly-available Mocks directory.  Also added more unit tests.

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

* Change debug code to use EXACT instead of BILINEAR height sampling, because it's specifically using the terrain grid.

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

* Added support for the sampler filters.

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

* Fix bad merge.

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

* Add unit test to verify terrain layers define terrain regions.

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

* Moved the AABB component mock into a private terrain header, since it's a specialized mock just for the terrain tests.

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

* Moved sampler and normal calculations into TerrainSystem so that they can work across multiple adjacent areas.

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

* Missed a couple of unit test changes.

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

* Removed normal query as well, that needs a seprate unit test.

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

* Removed unused variable that was only caught in Linux/Android builds.

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

* Addressed PR feedback
Made the parameter names consistently listed in MockShapes.h.
Added comments to TerrainHeightGradientListComponent explaining why terrainExists is always true when a gradient exists.
Also fixed a bug where terrainExists should technically be *false* if no gradient exists.

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

* Added more descriptive comments and names for ClampPosition.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
2021-09-17 12:59:25 -05:00

124 lines
5.7 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/containers/fixed_vector.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/parallel/shared_mutex.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/Math/Color.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Jobs/JobManagerBus.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
#include <TerrainSystem/TerrainSystemBus.h>
namespace Terrain
{
struct TerrainLayerPriorityComparator
{
bool operator()(const AZ::EntityId& layer1id, const AZ::EntityId& layer2id) const;
};
class TerrainSystem
: public AzFramework::Terrain::TerrainDataRequestBus::Handler
, private Terrain::TerrainSystemServiceRequestBus::Handler
, private AZ::TickBus::Handler
{
public:
TerrainSystem();
~TerrainSystem();
///////////////////////////////////////////
// TerrainSystemServiceRequestBus::Handler Impl
void Activate() override;
void Deactivate() override;
void RegisterArea(AZ::EntityId areaId) override;
void UnregisterArea(AZ::EntityId areaId) override;
void RefreshArea(AZ::EntityId areaId) override;
///////////////////////////////////////////
// TerrainDataRequestBus::Handler Impl
AZ::Vector2 GetTerrainHeightQueryResolution() const override;
void SetTerrainHeightQueryResolution(AZ::Vector2 queryResolution) override;
AZ::Aabb GetTerrainAabb() const override;
void SetTerrainAabb(const AZ::Aabb& worldBounds) override;
//! 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.
float GetHeight(AZ::Vector3 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.
//! @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.
AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight(
AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override;
AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats(
float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override;
//! 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.
const char* GetMaxSurfaceName(
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 GetIsHoleFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR) const override;
// 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.
AZ::Vector3 GetNormal(
AZ::Vector3 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;
private:
void ClampPosition(float x, float y, AZ::Vector2& outPosition, AZ::Vector2& normalizedDelta) 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::TickBus::Handler overrides ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
struct TerrainSystemSettings
{
AZ::Aabb m_worldBounds;
AZ::Vector2 m_heightQueryResolution{ 1.0f };
bool m_systemActive{ false };
};
TerrainSystemSettings m_currentSettings;
TerrainSystemSettings m_requestedSettings;
bool m_terrainSettingsDirty = true;
bool m_terrainHeightDirty = false;
AZ::Aabb m_dirtyRegion;
mutable AZStd::shared_mutex m_areaMutex;
AZStd::map<AZ::EntityId, AZ::Aabb, TerrainLayerPriorityComparator> m_registeredAreas;
};
} // namespace Terrain