Optimize surface providers (#7631)

* Add comparison operators to SurfaceTagWeight.

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

* Changed AddSurfaceTagWeight to always combine weights.
This simplifies the API a bit and defines the behavior if someone ever tries to add a duplicate tag.

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

* Added benchmarks for measuring the performance-critical APIs.

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

* Changed SurfaceTagWeights to a fixed_vector.

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

* Add inPosition to AddSurfacePoint.
This will be used to detect which input the surface point is associated with.

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

* Add inPositionIndex to the appropriate APIs.

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

* Switched Gradient Surface benchmarks to use actual surface components.
The gradient unit tests and benchmarks were previously using a mock surface data system, which led to misleading benchmark results. Now, the actual SurfaceData system gets constructed, and the tests use a mock provider, but the benchmarks use actual shape providers for more realistic benchmarking.

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

* Fixed unit tests to have better query ranges.
Half of each previous range was querying outside the surface provider's data.

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

* First attempt at removing SurfacePointLists.
This currently runs significantly slower than the previous code but passes the unit tests.

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

* Another attempt at optimization.
This one runs faster than the previous, but still slow.

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

* Fix the cmake dependency so that the gradient tests rebuild SurfaceData.dll when run.

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

* Switch SurfaceAltitudeGradient over to the new bulk API.
Also, optimized the non-bulk API by having it reuse the SurfacePointList to avoid the repeated allocation / deallocation cost.

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

* Switched to using an indirect index so that all allocations are consecutive in our reserved buffer.

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

* Switched back to SurfaceTagWeight again.

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

* Added runtime dependency to LmbrCentral for unit tests.

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

* Switched code over to use the full EnumeratePoints in most cases.

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

* Added knowledge of max surface point creation into the system.

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

* Add generic GetSurfacePointsFromList API implementation for surface providers.

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

* Fixed implementation to use the correct maximum number of input points based on the surface providers being queried.

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

* Fix out-of-bounds references on empty lists.

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

* Fix memory allocation that caused benchmark runs to crash.

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

* Starting to clean up the API.

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

* Move SurfacePointList into separate files for easier maintainability.

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

* Fixed bug where too many points were filtered out due to using the position Z as a part of the AABB check.

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

* Made FilterPoints an internal part of SurfacePointList so we can choose when and how to perform the filtering.

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

* Final cleanup / comments.

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

* Added includes for non-unity builds.

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

* Optimized GetValues() implementations.
Also consolidated GetValue() and GetValues() down to a single implementation under the covers for easier maintenance.

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

* Changed how unit tests initialize the mock lists to try and fix the linux errors.

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

* Switch to explicit span declarations to help ensure this works with linux.

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

* Fixed compile error.

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

* Make the bulk terrain APIs take in const Vector instead of non-const.

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

* Optimize the surface data providers for bulk queries.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
monroegm-disable-blank-issue-2
Mike Balfour 4 years ago committed by GitHub
parent 1413977aca
commit 0e328afcdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -140,28 +140,28 @@ namespace AzFramework
//! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each //! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each
//! XY coordinate in the list. //! XY coordinate in the list.
virtual void ProcessHeightsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessHeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessNormalsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessNormalsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfaceWeightsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessSurfaceWeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfacePointsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessSurfacePointsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessHeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessHeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessNormalsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessNormalsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0; Sampler sampleFilter = Sampler::DEFAULT) const = 0;
@ -272,42 +272,42 @@ namespace AzFramework
//! Asynchronous versions of the various 'Process*' API functions declared above. //! Asynchronous versions of the various 'Process*' API functions declared above.
//! It's the responsibility of the caller to ensure all callbacks are threadsafe. //! It's the responsibility of the caller to ensure all callbacks are threadsafe.
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync( virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync( virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync( virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync( virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async( virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async( virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async( virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async( virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback, SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;

@ -77,21 +77,21 @@ namespace UnitTest
MOCK_CONST_METHOD5( MOCK_CONST_METHOD5(
GetSurfacePointFromFloats, void(float, float, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*)); GetSurfacePointFromFloats, void(float, float, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessHeightsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessHeightsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessNormalsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessNormalsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessSurfaceWeightsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessSurfaceWeightsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessSurfacePointsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessSurfacePointsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessHeightsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessHeightsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessNormalsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessNormalsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessSurfaceWeightsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessSurfaceWeightsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3( MOCK_CONST_METHOD3(
ProcessSurfacePointsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); ProcessSurfacePointsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD2( MOCK_CONST_METHOD2(
GetNumSamplesFromRegion, AZStd::pair<size_t, size_t>(const AZ::Aabb&, const AZ::Vector2&)); GetNumSamplesFromRegion, AZStd::pair<size_t, size_t>(const AZ::Aabb&, const AZ::Vector2&));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
@ -107,21 +107,21 @@ namespace UnitTest
MOCK_CONST_METHOD1( MOCK_CONST_METHOD1(
GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&)); GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessHeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessHeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessNormalsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessNormalsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessSurfaceWeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessSurfaceWeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessSurfacePointsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessSurfacePointsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessHeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessHeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessNormalsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessNormalsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessSurfaceWeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessSurfaceWeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4( MOCK_CONST_METHOD4(
ProcessSurfacePointsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessSurfacePointsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD5( MOCK_CONST_METHOD5(
ProcessHeightsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>)); ProcessHeightsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD5( MOCK_CONST_METHOD5(

@ -144,43 +144,45 @@ namespace SurfaceData
return false; return false;
} }
bool SurfaceDataMeshComponent::DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const void SurfaceDataMeshComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
{ {
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex); GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
}
// test AABB as first pass to claim the point
const AZ::Vector3 testPosition = AZ::Vector3(
inPosition.GetX(),
inPosition.GetY(),
(m_meshBounds.GetMax().GetZ() + m_meshBounds.GetMin().GetZ()) * 0.5f);
if (!m_meshBounds.Contains(testPosition)) void SurfaceDataMeshComponent::GetSurfacePointsFromList(
AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
{ {
return false; AZ::Vector3 hitPosition;
} AZ::Vector3 hitNormal;
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZ::RPI::ModelAsset* mesh = m_meshAssetData.GetAs<AZ::RPI::ModelAsset>(); AZ::RPI::ModelAsset* mesh = m_meshAssetData.GetAs<AZ::RPI::ModelAsset>();
if (!mesh) if (!mesh)
{ {
return false; return;
} }
const AZ::Vector3 rayStart = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding); for (auto& inPosition : inPositions)
const AZ::Vector3 rayEnd = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMin().GetZ() - s_rayAABBHeightPadding);
return GetMeshRayIntersection(
*mesh, m_meshWorldTM, m_meshWorldTMInverse, m_meshNonUniformScale, rayStart, rayEnd, outPosition, outNormal);
}
void SurfaceDataMeshComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
{ {
AZ::Vector3 hitPosition; // test AABB as first pass to claim the point
AZ::Vector3 hitNormal; if (SurfaceData::AabbContains2D(m_meshBounds, inPosition))
if (DoRayTrace(inPosition, hitPosition, hitNormal)) {
const AZ::Vector3 rayStart =
AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
const AZ::Vector3 rayEnd =
AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMin().GetZ() - s_rayAABBHeightPadding);
bool rayHit = GetMeshRayIntersection(
*mesh, m_meshWorldTM, m_meshWorldTMInverse, m_meshNonUniformScale, rayStart, rayEnd, hitPosition, hitNormal);
if (rayHit)
{ {
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights); surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights);
} }
} }
}
}
AZ::Aabb SurfaceDataMeshComponent::GetSurfaceAabb() const AZ::Aabb SurfaceDataMeshComponent::GetSurfaceAabb() const
{ {

@ -80,9 +80,9 @@ namespace SurfaceData
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// SurfaceDataProviderRequestBus // SurfaceDataProviderRequestBus
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override; void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
void GetSurfacePointsFromList(AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const override;
private: private:
bool DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const;
void UpdateMeshData(); void UpdateMeshData();
void OnCompositionChanged(); void OnCompositionChanged();

@ -108,29 +108,9 @@ namespace GradientSignal
void AddTag(AZStd::string tag) override; void AddTag(AZStd::string tag) override;
private: private:
static float CalculateAltitudeRatio(const SurfaceData::SurfacePointList& points, size_t inPositionIndex, float altitudeMin, float altitudeMax)
{
if (points.IsEmpty(inPositionIndex))
{
return 0.0f;
}
// GetSurfacePoints (which was used to populate the points list) always returns points in decreasing height order, so the
// first point in the list contains the highest altitude.
const float highestAltitude = points.GetHighestSurfacePoint(inPositionIndex).m_position.GetZ();
// Turn the absolute altitude value into a 0-1 value by returning the % of the given altitude range that it falls at.
return GetRatio(altitudeMin, altitudeMax, highestAltitude);
}
mutable AZStd::shared_mutex m_cacheMutex; mutable AZStd::shared_mutex m_cacheMutex;
SurfaceAltitudeGradientConfig m_configuration; SurfaceAltitudeGradientConfig m_configuration;
LmbrCentral::DependencyMonitor m_dependencyMonitor; LmbrCentral::DependencyMonitor m_dependencyMonitor;
AZStd::atomic_bool m_dirty{ false }; AZStd::atomic_bool m_dirty{ false };
// m_surfacePointList exists here because it will more efficiently reuse memory across GetValue() calls if it stays constructed.
// The mutex exists to ensure that we don't try to use it from GetValue() in multiple threads at once.
mutable AZStd::recursive_mutex m_surfacePointListMutex;
mutable SurfaceData::SurfacePointList m_surfacePointList;
}; };
} }

@ -82,25 +82,6 @@ namespace GradientSignal
void AddTag(AZStd::string tag) override; void AddTag(AZStd::string tag) override;
private: private:
static float GetMaxSurfaceWeight(const SurfaceData::SurfacePointList& points)
{
float result = 0.0f;
points.EnumeratePoints([&result](
[[maybe_unused]] size_t inPositionIndex, [[maybe_unused]] const AZ::Vector3& position,
[[maybe_unused]] const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool
{
masks.EnumerateWeights(
[&result]([[maybe_unused]] AZ::Crc32 surfaceType, float weight) -> bool
{
result = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), result);
return true;
});
return true;
});
return result;
}
SurfaceMaskGradientConfig m_configuration; SurfaceMaskGradientConfig m_configuration;
LmbrCentral::DependencyMonitor m_dependencyMonitor; LmbrCentral::DependencyMonitor m_dependencyMonitor;
}; };

@ -124,39 +124,6 @@ namespace GradientSignal
void SetFallOffMidpoint(float midpoint) override; void SetFallOffMidpoint(float midpoint) override;
private: private:
float GetSlopeRatio(const SurfaceData::SurfacePointList& points, float angleMin, float angleMax) const
{
constexpr size_t inPositionIndex = 0;
if (points.IsEmpty(inPositionIndex))
{
return 0.0f;
}
// Assuming our surface normal vector is actually normalized, we can get the slope
// by just grabbing the Z value. It's the same thing as normal.Dot(AZ::Vector3::CreateAxisZ()).
auto highestSurfacePoint = points.GetHighestSurfacePoint(inPositionIndex);
AZ_Assert(
highestSurfacePoint.m_normal.GetNormalized().IsClose(highestSurfacePoint.m_normal),
"Surface normals are expected to be normalized");
const float slope = highestSurfacePoint.m_normal.GetZ();
// Convert slope back to an angle so that we can lerp in "angular space", not "slope value space".
// (We want our 0-1 range to be linear across the range of angles)
const float slopeAngle = acosf(slope);
switch (m_configuration.m_rampType)
{
case SurfaceSlopeGradientConfig::RampType::SMOOTH_STEP:
return m_configuration.m_smoothStep.GetSmoothedValue(GetRatio(angleMin, angleMax, slopeAngle));
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_UP:
// For ramp up, linearly interpolate from min to max.
return GetRatio(angleMin, angleMax, slopeAngle);
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_DOWN:
default:
// For ramp down, linearly interpolate from max to min.
return GetRatio(angleMax, angleMin, slopeAngle);
}
}
SurfaceSlopeGradientConfig m_configuration; SurfaceSlopeGradientConfig m_configuration;
}; };
} }

@ -202,18 +202,9 @@ namespace GradientSignal
float SurfaceAltitudeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const float SurfaceAltitudeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{ {
// For GetValue(), we reuse our SurfacePointList for the GetSurfacePoints query to avoid the repeated cost of memory allocation float result = 0.0f;
// and deallocation across GetValue() calls. However, this also means we can only use it from one thread at a time, so lock a GetValues(AZStd::span<const AZ::Vector3>(&sampleParams.m_position, 1), AZStd::span<float>(&result, 1));
// mutex to ensure no other threads call GetValue() at the same time. return result;
AZStd::unique_lock<decltype(m_surfacePointListMutex)> surfacePointLock(m_surfacePointListMutex);
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
sampleParams.m_position, m_configuration.m_surfaceTagsToSample, m_surfacePointList);
constexpr size_t inPositionIndex = 0;
return CalculateAltitudeRatio(m_surfacePointList, inPositionIndex, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax);
} }
void SurfaceAltitudeGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const void SurfaceAltitudeGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
@ -231,17 +222,20 @@ namespace GradientSignal
&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagsToSample, &SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagsToSample,
points); points);
if (points.IsEmpty()) // For each position, turn the height into a 0-1 value based on our min/max altitudes.
for (size_t index = 0; index < positions.size(); index++)
{ {
// No surface data, so no output values. if (!points.IsEmpty(index))
AZStd::fill(outValues.begin(), outValues.end(), 0.0f); {
// Get the point with the highest Z value and use that for the altitude.
const float highestAltitude = points.GetHighestSurfacePoint(index).m_position.GetZ();
// Turn the absolute altitude value into a 0-1 value by returning the % of the given altitude range that it falls at.
outValues[index] = GetRatio(m_configuration.m_altitudeMin, m_configuration.m_altitudeMax, highestAltitude);
} }
else else
{ {
// For each position, turn the height into a 0-1 value based on our min/max altitudes. outValues[index] = 0.0f;
for (size_t index = 0; index < positions.size(); index++)
{
outValues[index] = CalculateAltitudeRatio(points, index, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax);
} }
} }
} }

@ -162,16 +162,7 @@ namespace GradientSignal
float SurfaceMaskGradientComponent::GetValue(const GradientSampleParams& params) const float SurfaceMaskGradientComponent::GetValue(const GradientSampleParams& params) const
{ {
float result = 0.0f; float result = 0.0f;
GetValues(AZStd::span<const AZ::Vector3>(&params.m_position, 1), AZStd::span<float>(&result, 1));
if (!m_configuration.m_surfaceTagList.empty())
{
SurfaceData::SurfacePointList points;
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
params.m_position, m_configuration.m_surfaceTagList, points);
result = GetMaxSurfaceWeight(points);
}
return result; return result;
} }
@ -183,34 +174,31 @@ namespace GradientSignal
return; return;
} }
bool valuesFound = false; // Initialize all our output values to 0.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
if (!m_configuration.m_surfaceTagList.empty()) if (!m_configuration.m_surfaceTagList.empty())
{ {
// Rather than calling GetSurfacePoints on the EBus repeatedly in a loop, we instead pass a lambda into the EBus that contains
// the loop within it so that we can avoid the repeated EBus-calling overhead.
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(
[this, positions, &outValues, &valuesFound](SurfaceData::SurfaceDataSystemRequestBus::Events* surfaceDataRequests)
{
// It's possible that there's nothing connected to the EBus, so keep track of the fact that we have valid results.
valuesFound = true;
SurfaceData::SurfacePointList points; SurfaceData::SurfacePointList points;
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(
&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagList,
points);
for (size_t index = 0; index < positions.size(); index++) // For each position, get the max surface weight that matches our filter and that appears at that position.
points.EnumeratePoints(
[&outValues](
size_t inPositionIndex, [[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& normal,
const SurfaceData::SurfaceTagWeights& masks) -> bool
{ {
points.Clear(); masks.EnumerateWeights(
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagList, points); [inPositionIndex, &outValues]([[maybe_unused]] AZ::Crc32 surfaceType, float weight) -> bool
outValues[index] = GetMaxSurfaceWeight(points);
}
});
}
if (!valuesFound)
{ {
// No surface tags, so no output values. outValues[inPositionIndex] = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), outValues[inPositionIndex]);
AZStd::fill(outValues.begin(), outValues.end(), 0.0f); return true;
});
return true;
});
} }
} }
size_t SurfaceMaskGradientComponent::GetNumTags() const size_t SurfaceMaskGradientComponent::GetNumTags() const

@ -205,14 +205,9 @@ namespace GradientSignal
float SurfaceSlopeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const float SurfaceSlopeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{ {
SurfaceData::SurfacePointList points; float result = 0.0f;
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints, GetValues(AZStd::span<const AZ::Vector3>(&sampleParams.m_position, 1), AZStd::span<float>(&result, 1));
sampleParams.m_position, m_configuration.m_surfaceTagsToSample, points); return result;
const float angleMin = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMin, 0.0f, 90.0f));
const float angleMax = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMax, 0.0f, 90.0f));
return GetSlopeRatio(points, angleMin, angleMax);
} }
void SurfaceSlopeGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const void SurfaceSlopeGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
@ -223,32 +218,49 @@ namespace GradientSignal
return; return;
} }
bool valuesFound = false;
// Rather than calling GetSurfacePoints on the EBus repeatedly in a loop, we instead pass a lambda into the EBus that contains
// the loop within it so that we can avoid the repeated EBus-calling overhead.
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(
[this, positions, &outValues, &valuesFound](SurfaceData::SurfaceDataSystemRequestBus::Events* surfaceDataRequests)
{
// It's possible that there's nothing connected to the EBus, so keep track of the fact that we have valid results.
valuesFound = true;
SurfaceData::SurfacePointList points; SurfaceData::SurfacePointList points;
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(
&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagsToSample,
points);
const float angleMin = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMin, 0.0f, 90.0f)); const float angleMin = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMin, 0.0f, 90.0f));
const float angleMax = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMax, 0.0f, 90.0f)); const float angleMax = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMax, 0.0f, 90.0f));
for (size_t index = 0; index < positions.size(); index++) for (size_t index = 0; index < positions.size(); index++)
{ {
points.Clear(); if (points.IsEmpty(index))
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagsToSample, points); {
outValues[index] = GetSlopeRatio(points, angleMin, angleMax); outValues[index] = 0.0f;
} }
}); else
{
// Assuming our surface normal vector is actually normalized, we can get the slope
// by just grabbing the Z value. It's the same thing as normal.Dot(AZ::Vector3::CreateAxisZ()).
auto highestSurfacePoint = points.GetHighestSurfacePoint(index);
AZ_Assert(
highestSurfacePoint.m_normal.GetNormalized().IsClose(highestSurfacePoint.m_normal),
"Surface normals are expected to be normalized");
const float slope = highestSurfacePoint.m_normal.GetZ();
// Convert slope back to an angle so that we can lerp in "angular space", not "slope value space".
// (We want our 0-1 range to be linear across the range of angles)
const float slopeAngle = acosf(slope);
if (!valuesFound) switch (m_configuration.m_rampType)
{ {
// No surface tags, so no output values. case SurfaceSlopeGradientConfig::RampType::SMOOTH_STEP:
AZStd::fill(outValues.begin(), outValues.end(), 0.0f); outValues[index] = m_configuration.m_smoothStep.GetSmoothedValue(GetRatio(angleMin, angleMax, slopeAngle));
break;
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_UP:
// For ramp up, linearly interpolate from min to max.
outValues[index] = GetRatio(angleMin, angleMax, slopeAngle);
break;
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_DOWN:
default:
// For ramp down, linearly interpolate from max to min.
outValues[index] = GetRatio(angleMax, angleMin, slopeAngle);
break;
}
}
} }
} }

@ -82,6 +82,7 @@ namespace SurfaceData
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// SurfaceDataProviderRequestBus // SurfaceDataProviderRequestBus
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override; void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
void GetSurfacePointsFromList(AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const override;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// SurfaceDataModifierRequestBus // SurfaceDataModifierRequestBus

@ -66,6 +66,7 @@ namespace SurfaceData
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// SurfaceDataProviderRequestBus // SurfaceDataProviderRequestBus
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override; void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
void GetSurfacePointsFromList(AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const override;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// SurfaceDataModifierRequestBus // SurfaceDataModifierRequestBus

@ -185,8 +185,6 @@ namespace SurfaceData
bool SurfaceDataColliderComponent::DoRayTrace(const AZ::Vector3& inPosition, bool queryPointOnly, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const bool SurfaceDataColliderComponent::DoRayTrace(const AZ::Vector3& inPosition, bool queryPointOnly, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const
{ {
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
// test AABB as first pass to claim the point // test AABB as first pass to claim the point
const AZ::Vector3 testPosition = AZ::Vector3( const AZ::Vector3 testPosition = AZ::Vector3(
inPosition.GetX(), inPosition.GetX(),
@ -229,18 +227,45 @@ namespace SurfaceData
void SurfaceDataColliderComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const void SurfaceDataColliderComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
{ {
AZ::Vector3 hitPosition; GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
AZ::Vector3 hitNormal; }
void SurfaceDataColliderComponent::GetSurfacePointsFromList(
AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
{
AzPhysics::SimulatedBodyComponentRequestsBus::Event(
GetEntityId(),
[this, inPositions, &surfacePointList](AzPhysics::SimulatedBodyComponentRequestsBus::Events* simBody)
{
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
AzPhysics::RayCastRequest request;
request.m_direction = -AZ::Vector3::CreateAxisZ();
for (auto& inPosition : inPositions)
{
// test AABB as first pass to claim the point
if (SurfaceData::AabbContains2D(m_colliderBounds, inPosition))
{
// We're casting the ray to look for a collision, so start at the top of the collider and cast downwards
// the full height of the collider.
request.m_start = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_colliderBounds.GetMax().GetZ());
request.m_distance = m_colliderBounds.GetExtents().GetZ();
// We want a full raycast, so don't just query the start point. AzPhysics::SceneQueryHit result = simBody->RayCast(request);
constexpr bool queryPointOnly = false;
if (DoRayTrace(inPosition, queryPointOnly, hitPosition, hitNormal)) if (result)
{ {
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights); surfacePointList.AddSurfacePoint(
GetEntityId(), inPosition, result.m_position, result.m_normal, m_newPointWeights);
}
}
} }
});
} }
void SurfaceDataColliderComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const void SurfaceDataColliderComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
{ {
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex); AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);

@ -143,24 +143,48 @@ namespace SurfaceData
} }
void SurfaceDataShapeComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const void SurfaceDataShapeComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
{
GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
}
void SurfaceDataShapeComponent::GetSurfacePointsFromList(
AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
{ {
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex); AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
if (m_shapeBoundsIsValid && SurfaceData::AabbContains2D(m_shapeBounds, inPosition)) if (!m_shapeBoundsIsValid)
{
return;
}
LmbrCentral::ShapeComponentRequestsBus::Event(
GetEntityId(),
[this, inPositions, &surfacePointList](LmbrCentral::ShapeComponentRequestsBus::Events* shape)
{ {
const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_shapeBounds.GetMax().GetZ());
const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ(); const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
// Shapes don't currently have a way to query normals at a point intersection, so we'll just return a Z-up normal
// until they get support for it.
const AZ::Vector3 surfacePointNormal = AZ::Vector3::CreateAxisZ();
for (auto& inPosition : inPositions)
{
if (SurfaceData::AabbContains2D(m_shapeBounds, inPosition))
{
const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_shapeBounds.GetMax().GetZ());
float intersectionDistance = 0.0f; float intersectionDistance = 0.0f;
bool hitShape = false; bool hitShape = shape->IntersectRay(rayOrigin, rayDirection, intersectionDistance);
LmbrCentral::ShapeComponentRequestsBus::EventResult(hitShape, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::IntersectRay, rayOrigin, rayDirection, intersectionDistance);
if (hitShape) if (hitShape)
{ {
AZ::Vector3 position = rayOrigin + intersectionDistance * rayDirection; AZ::Vector3 position = rayOrigin + intersectionDistance * rayDirection;
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, position, AZ::Vector3::CreateAxisZ(), m_newPointWeights); surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, position, surfacePointNormal, m_newPointWeights);
}
} }
} }
});
} }
void SurfaceDataShapeComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const void SurfaceDataShapeComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
{ {
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex); AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);

@ -145,29 +145,42 @@ namespace Terrain
void TerrainSurfaceDataSystemComponent::GetSurfacePoints( void TerrainSurfaceDataSystemComponent::GetSurfacePoints(
const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const
{
GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
}
void TerrainSurfaceDataSystemComponent::GetSurfacePointsFromList(
AZStd::span<const AZ::Vector3> inPositions, SurfaceData::SurfacePointList& surfacePointList) const
{ {
if (!m_terrainBoundsIsValid) if (!m_terrainBoundsIsValid)
{ {
return; return;
} }
bool isTerrainValidAtPoint = false; size_t inPositionIndex = 0;
AzFramework::SurfaceData::SurfacePoint terrainSurfacePoint;
AzFramework::Terrain::TerrainDataRequestBus::Broadcast(&AzFramework::Terrain::TerrainDataRequestBus::Events::GetSurfacePoint,
inPosition, terrainSurfacePoint, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR,
&isTerrainValidAtPoint);
const bool isHole = !isTerrainValidAtPoint; AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
&AzFramework::Terrain::TerrainDataRequestBus::Events::ProcessSurfacePointsFromList, inPositions,
[this, inPositions, &inPositionIndex, &surfacePointList]
(const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
{
AZ_Assert(inPositionIndex < inPositions.size(), "Too many points returned from ProcessSurfacePointsFromList");
SurfaceData::SurfaceTagWeights weights(terrainSurfacePoint.m_surfaceTags); SurfaceData::SurfaceTagWeights weights(surfacePoint.m_surfaceTags);
// Always add a "terrain" or "terrainHole" tag. // Always add a "terrain" or "terrainHole" tag.
const AZ::Crc32 terrainTag = isHole ? Constants::s_terrainHoleTagCrc : Constants::s_terrainTagCrc; const AZ::Crc32 terrainTag = terrainExists ? Constants::s_terrainTagCrc : Constants::s_terrainHoleTagCrc;
weights.AddSurfaceTagWeight(terrainTag, 1.0f); weights.AddSurfaceTagWeight(terrainTag, 1.0f);
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, terrainSurfacePoint.m_position, terrainSurfacePoint.m_normal, weights); surfacePointList.AddSurfacePoint(
GetEntityId(), inPositions[inPositionIndex], surfacePoint.m_position, surfacePoint.m_normal, weights);
inPositionIndex++;
},
AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR);
} }
AZ::Aabb TerrainSurfaceDataSystemComponent::GetSurfaceAabb() const AZ::Aabb TerrainSurfaceDataSystemComponent::GetSurfaceAabb() const
{ {
auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler(); auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();

@ -59,6 +59,8 @@ namespace Terrain
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// SurfaceDataProviderRequestBus // SurfaceDataProviderRequestBus
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const override; void GetSurfacePoints(const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const override;
void GetSurfacePointsFromList(
AZStd::span<const AZ::Vector3> inPositions, SurfaceData::SurfacePointList& surfacePointList) const override;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// AzFramework::Terrain::TerrainDataNotificationBus // AzFramework::Terrain::TerrainDataNotificationBus

@ -192,7 +192,7 @@ bool TerrainSystem::InWorldBounds(float x, float y) const
} }
// Generate positions to be queried based on the sampler type. // Generate positions to be queried based on the sampler type.
void TerrainSystem::GenerateQueryPositions(const AZStd::span<AZ::Vector3>& inPositions, void TerrainSystem::GenerateQueryPositions(const AZStd::span<const AZ::Vector3>& inPositions,
AZStd::vector<AZ::Vector3>& outPositions, AZStd::vector<AZ::Vector3>& outPositions,
Sampler sampler) const Sampler sampler) const
{ {
@ -253,7 +253,7 @@ AZStd::vector<AZ::Vector3> TerrainSystem::GenerateInputPositionsFromRegion(
} }
void TerrainSystem::MakeBulkQueries( void TerrainSystem::MakeBulkQueries(
const AZStd::span<AZ::Vector3> inPositions, const AZStd::span<const AZ::Vector3> inPositions,
AZStd::span<AZ::Vector3> outPositions, AZStd::span<AZ::Vector3> outPositions,
AZStd::span<bool> outTerrainExists, AZStd::span<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights, AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
@ -296,7 +296,7 @@ void TerrainSystem::MakeBulkQueries(
if (prevAreaId != AZ::EntityId()) if (prevAreaId != AZ::EntityId())
{ {
size_t spanLength = (windowEnd - windowStart) + 1; size_t spanLength = (windowEnd - windowStart) + 1;
queryCallback(AZStd::span<AZ::Vector3>(inPositions.begin() + windowStart, spanLength), queryCallback(AZStd::span<const AZ::Vector3>(inPositions.begin() + windowStart, spanLength),
AZStd::span<AZ::Vector3>(outPositions.begin() + windowStart, spanLength), AZStd::span<AZ::Vector3>(outPositions.begin() + windowStart, spanLength),
AZStd::span<bool>(outTerrainExists.begin() + windowStart, spanLength), AZStd::span<bool>(outTerrainExists.begin() + windowStart, spanLength),
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList>(outSurfaceWeights.begin() + windowStart, spanLength), AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList>(outSurfaceWeights.begin() + windowStart, spanLength),
@ -311,7 +311,7 @@ void TerrainSystem::MakeBulkQueries(
} }
} }
void TerrainSystem::GetHeightsSynchronous(const AZStd::span<AZ::Vector3>& inPositions, Sampler sampler, void TerrainSystem::GetHeightsSynchronous(const AZStd::span<const AZ::Vector3>& inPositions, Sampler sampler,
AZStd::span<float> heights, AZStd::span<bool> terrainExists) const AZStd::span<float> heights, AZStd::span<bool> terrainExists) const
{ {
AZStd::shared_lock<AZStd::shared_mutex> lock(m_areaMutex); AZStd::shared_lock<AZStd::shared_mutex> lock(m_areaMutex);
@ -328,7 +328,7 @@ void TerrainSystem::GetHeightsSynchronous(const AZStd::span<AZ::Vector3>& inPosi
GenerateQueryPositions(inPositions, outPositions, sampler); GenerateQueryPositions(inPositions, outPositions, sampler);
auto callback = []([[maybe_unused]] const AZStd::span<AZ::Vector3> inPositions, auto callback = []([[maybe_unused]] const AZStd::span<const AZ::Vector3> inPositions,
AZStd::span<AZ::Vector3> outPositions, AZStd::span<AZ::Vector3> outPositions,
AZStd::span<bool> outTerrainExists, AZStd::span<bool> outTerrainExists,
[[maybe_unused]] AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights, [[maybe_unused]] AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
@ -516,7 +516,7 @@ bool TerrainSystem::GetIsHoleFromFloats(float x, float y, Sampler sampler) const
return !terrainExists; return !terrainExists;
} }
void TerrainSystem::GetNormalsSynchronous(const AZStd::span<AZ::Vector3>& inPositions, Sampler sampler, void TerrainSystem::GetNormalsSynchronous(const AZStd::span<const AZ::Vector3>& inPositions, Sampler sampler,
AZStd::span<AZ::Vector3> normals, AZStd::span<bool> terrainExists) const AZStd::span<AZ::Vector3> normals, AZStd::span<bool> terrainExists) const
{ {
AZStd::vector<AZ::Vector3> directionVectors; AZStd::vector<AZ::Vector3> directionVectors;
@ -685,7 +685,7 @@ AzFramework::RenderGeometry::RayResult TerrainSystem::GetClosestIntersection(
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessHeightsFromListAsync( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessHeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -695,7 +695,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessNormalsFromListAsync( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessNormalsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -705,7 +705,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfaceWeightsFromListAsync( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfaceWeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -715,7 +715,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfacePointsFromListAsync( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfacePointsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -725,7 +725,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessHeightsFromListOfVector2Async( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessHeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -735,7 +735,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessNormalsFromListOfVector2Async( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessNormalsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -745,7 +745,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfaceWeightsFromListOfVector2Async( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfaceWeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -755,7 +755,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
} }
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfacePointsFromListOfVector2Async( AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfacePointsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -830,7 +830,7 @@ AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::A
} }
void TerrainSystem::GetOrderedSurfaceWeightsFromList( void TerrainSystem::GetOrderedSurfaceWeightsFromList(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
[[maybe_unused]] Sampler sampler, [[maybe_unused]] Sampler sampler,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList, AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList,
AZStd::span<bool> terrainExists) const AZStd::span<bool> terrainExists) const
@ -841,7 +841,7 @@ void TerrainSystem::GetOrderedSurfaceWeightsFromList(
GetHeightsSynchronous(inPositions, AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, heights, terrainExists); GetHeightsSynchronous(inPositions, AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, heights, terrainExists);
} }
auto callback = [](const AZStd::span<AZ::Vector3> inPositions, auto callback = [](const AZStd::span<const AZ::Vector3> inPositions,
[[maybe_unused]] AZStd::span<AZ::Vector3> outPositions, [[maybe_unused]] AZStd::span<AZ::Vector3> outPositions,
[[maybe_unused]] AZStd::span<bool> outTerrainExists, [[maybe_unused]] AZStd::span<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights, AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
@ -929,7 +929,7 @@ const char* TerrainSystem::GetMaxSurfaceName(
} }
void TerrainSystem::ProcessHeightsFromList( void TerrainSystem::ProcessHeightsFromList(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {
@ -953,7 +953,7 @@ void TerrainSystem::ProcessHeightsFromList(
} }
void TerrainSystem::ProcessNormalsFromList( void TerrainSystem::ProcessNormalsFromList(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {
@ -977,7 +977,7 @@ void TerrainSystem::ProcessNormalsFromList(
} }
void TerrainSystem::ProcessSurfaceWeightsFromList( void TerrainSystem::ProcessSurfaceWeightsFromList(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {
@ -1001,7 +1001,7 @@ void TerrainSystem::ProcessSurfaceWeightsFromList(
} }
void TerrainSystem::ProcessSurfacePointsFromList( void TerrainSystem::ProcessSurfacePointsFromList(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {
@ -1034,7 +1034,7 @@ void TerrainSystem::ProcessSurfacePointsFromList(
} }
void TerrainSystem::ProcessHeightsFromListOfVector2( void TerrainSystem::ProcessHeightsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {
@ -1054,7 +1054,7 @@ void TerrainSystem::ProcessHeightsFromListOfVector2(
} }
void TerrainSystem::ProcessNormalsFromListOfVector2( void TerrainSystem::ProcessNormalsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {
@ -1074,7 +1074,7 @@ void TerrainSystem::ProcessNormalsFromListOfVector2(
} }
void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2( void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {
@ -1094,7 +1094,7 @@ void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2(
} }
void TerrainSystem::ProcessSurfacePointsFromListOfVector2( void TerrainSystem::ProcessSurfacePointsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const Sampler sampleFilter) const
{ {

@ -140,28 +140,28 @@ namespace Terrain
//! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each //! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each
//! XY coordinate in the list. //! XY coordinate in the list.
virtual void ProcessHeightsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessHeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
virtual void ProcessNormalsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessNormalsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
virtual void ProcessSurfaceWeightsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessSurfaceWeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
virtual void ProcessSurfacePointsFromList(const AZStd::span<AZ::Vector3>& inPositions, virtual void ProcessSurfacePointsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
virtual void ProcessHeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessHeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
virtual void ProcessNormalsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessNormalsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions, virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const override; Sampler sampleFilter = Sampler::DEFAULT) const override;
@ -194,42 +194,42 @@ namespace Terrain
const AzFramework::RenderGeometry::RayRequest& ray) const override; const AzFramework::RenderGeometry::RayRequest& ray) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync( AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync( AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync( AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync( AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async( AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async( AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async( AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async( AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions, const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
@ -262,7 +262,7 @@ namespace Terrain
template<typename SynchronousFunctionType, typename VectorType> template<typename SynchronousFunctionType, typename VectorType>
AZStd::shared_ptr<TerrainJobContext> ProcessFromListAsync( AZStd::shared_ptr<TerrainJobContext> ProcessFromListAsync(
SynchronousFunctionType synchronousFunction, SynchronousFunctionType synchronousFunction,
const AZStd::span<VectorType>& inPositions, const AZStd::span<const VectorType>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT, Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const; AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const;
@ -291,31 +291,31 @@ namespace Terrain
AZ::Vector3 GetNormalSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const; AZ::Vector3 GetNormalSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const;
typedef AZStd::function<void( typedef AZStd::function<void(
const AZStd::span<AZ::Vector3> inPositions, const AZStd::span<const AZ::Vector3> inPositions,
AZStd::span<AZ::Vector3> outPositions, AZStd::span<AZ::Vector3> outPositions,
AZStd::span<bool> outTerrainExists, AZStd::span<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights, AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
AZ::EntityId areaId)> BulkQueriesCallback; AZ::EntityId areaId)> BulkQueriesCallback;
void GetHeightsSynchronous( void GetHeightsSynchronous(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
Sampler sampler, AZStd::span<float> heights, Sampler sampler, AZStd::span<float> heights,
AZStd::span<bool> terrainExists) const; AZStd::span<bool> terrainExists) const;
void GetNormalsSynchronous( void GetNormalsSynchronous(
const AZStd::span<AZ::Vector3>& inPositions, const AZStd::span<const AZ::Vector3>& inPositions,
Sampler sampler, AZStd::span<AZ::Vector3> normals, Sampler sampler, AZStd::span<AZ::Vector3> normals,
AZStd::span<bool> terrainExists) const; AZStd::span<bool> terrainExists) const;
void GetOrderedSurfaceWeightsFromList( void GetOrderedSurfaceWeightsFromList(
const AZStd::span<AZ::Vector3>& inPositions, Sampler sampler, const AZStd::span<const AZ::Vector3>& inPositions, Sampler sampler,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList, AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList,
AZStd::span<bool> terrainExists) const; AZStd::span<bool> terrainExists) const;
void MakeBulkQueries( void MakeBulkQueries(
const AZStd::span<AZ::Vector3> inPositions, const AZStd::span<const AZ::Vector3> inPositions,
AZStd::span<AZ::Vector3> outPositions, AZStd::span<AZ::Vector3> outPositions,
AZStd::span<bool> outTerrainExists, AZStd::span<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWieghts, AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWieghts,
BulkQueriesCallback queryCallback) const; BulkQueriesCallback queryCallback) const;
void GenerateQueryPositions(const AZStd::span<AZ::Vector3>& inPositions, void GenerateQueryPositions(const AZStd::span<const AZ::Vector3>& inPositions,
AZStd::vector<AZ::Vector3>& outPositions, AZStd::vector<AZ::Vector3>& outPositions,
Sampler sampler) const; Sampler sampler) const;
AZStd::vector<AZ::Vector3> GenerateInputPositionsFromRegion( AZStd::vector<AZ::Vector3> GenerateInputPositionsFromRegion(
@ -361,7 +361,7 @@ namespace Terrain
template<typename SynchronousFunctionType, typename VectorType> template<typename SynchronousFunctionType, typename VectorType>
inline AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessFromListAsync( inline AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessFromListAsync(
SynchronousFunctionType synchronousFunction, SynchronousFunctionType synchronousFunction,
const AZStd::span<VectorType>& inPositions, const AZStd::span<const VectorType>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter, Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -397,7 +397,7 @@ namespace Terrain
const size_t subSpanCount = (i < numJobs - 1) ? numPositionsPerJob : AZStd::dynamic_extent; const size_t subSpanCount = (i < numJobs - 1) ? numPositionsPerJob : AZStd::dynamic_extent;
// Define the job function using the sub span of positions to process. // Define the job function using the sub span of positions to process.
const AZStd::span<VectorType>& positionsToProcess = inPositions.subspan(subSpanOffset, subSpanCount); const AZStd::span<const VectorType>& positionsToProcess = inPositions.subspan(subSpanOffset, subSpanCount);
auto jobFunction = [this, synchronousFunction, positionsToProcess, perPositionCallback, sampleFilter, jobContext, params]() auto jobFunction = [this, synchronousFunction, positionsToProcess, perPositionCallback, sampleFilter, jobContext, params]()
{ {
// Process the sub span of positions, unless the associated job context has been cancelled. // Process the sub span of positions, unless the associated job context has been cancelled.

Loading…
Cancel
Save