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
//! 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,
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,
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,
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,
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,
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,
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,
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,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
@ -272,42 +272,42 @@ namespace AzFramework
//! Asynchronous versions of the various 'Process*' API functions declared above.
//! It's the responsibility of the caller to ensure all callbacks are threadsafe.
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;

@ -77,21 +77,21 @@ namespace UnitTest
MOCK_CONST_METHOD5(
GetSurfacePointFromFloats, void(float, float, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*));
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(
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(
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(
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(
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(
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(
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(
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(
GetNumSamplesFromRegion, AZStd::pair<size_t, size_t>(const AZ::Aabb&, const AZ::Vector2&));
MOCK_CONST_METHOD4(
@ -107,21 +107,21 @@ namespace UnitTest
MOCK_CONST_METHOD1(
GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&));
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(
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(
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(
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(
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(
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(
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(
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(
ProcessHeightsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD5(

@ -144,44 +144,46 @@ namespace SurfaceData
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);
void SurfaceDataMeshComponent::GetSurfacePointsFromList(
AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
{
AZ::Vector3 hitPosition;
AZ::Vector3 hitNormal;
if (!m_meshBounds.Contains(testPosition))
{
return false;
}
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZ::RPI::ModelAsset* mesh = m_meshAssetData.GetAs<AZ::RPI::ModelAsset>();
if (!mesh)
{
return false;
return;
}
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);
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;
AZ::Vector3 hitNormal;
if (DoRayTrace(inPosition, hitPosition, hitNormal))
for (auto& inPosition : inPositions)
{
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights);
// test AABB as first pass to claim the point
if (SurfaceData::AabbContains2D(m_meshBounds, inPosition))
{
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);
}
}
}
}
AZ::Aabb SurfaceDataMeshComponent::GetSurfaceAabb() const
{
return m_meshBounds;

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

@ -108,29 +108,9 @@ namespace GradientSignal
void AddTag(AZStd::string tag) override;
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;
SurfaceAltitudeGradientConfig m_configuration;
LmbrCentral::DependencyMonitor m_dependencyMonitor;
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;
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;
LmbrCentral::DependencyMonitor m_dependencyMonitor;
};

@ -124,39 +124,6 @@ namespace GradientSignal
void SetFallOffMidpoint(float midpoint) override;
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;
};
}

@ -202,18 +202,9 @@ namespace GradientSignal
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
// and deallocation across GetValue() calls. However, this also means we can only use it from one thread at a time, so lock a
// mutex to ensure no other threads call GetValue() at the same time.
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);
float result = 0.0f;
GetValues(AZStd::span<const AZ::Vector3>(&sampleParams.m_position, 1), AZStd::span<float>(&result, 1));
return result;
}
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,
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.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
}
else
{
// 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++)
if (!points.IsEmpty(index))
{
// 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
{
outValues[index] = CalculateAltitudeRatio(points, index, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax);
outValues[index] = 0.0f;
}
}
}

@ -162,16 +162,7 @@ namespace GradientSignal
float SurfaceMaskGradientComponent::GetValue(const GradientSampleParams& params) const
{
float result = 0.0f;
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);
}
GetValues(AZStd::span<const AZ::Vector3>(&params.m_position, 1), AZStd::span<float>(&result, 1));
return result;
}
@ -183,34 +174,31 @@ namespace GradientSignal
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())
{
// 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::SurfacePointList points;
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(
[this, positions, &outValues, &valuesFound](SurfaceData::SurfaceDataSystemRequestBus::Events* surfaceDataRequests)
&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagList,
points);
// 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
{
// 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;
for (size_t index = 0; index < positions.size(); index++)
{
points.Clear();
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagList, points);
outValues[index] = GetMaxSurfaceWeight(points);
}
masks.EnumerateWeights(
[inPositionIndex, &outValues]([[maybe_unused]] AZ::Crc32 surfaceType, float weight) -> bool
{
outValues[inPositionIndex] = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), outValues[inPositionIndex]);
return true;
});
return true;
});
}
if (!valuesFound)
{
// No surface tags, so no output values.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
}
}
size_t SurfaceMaskGradientComponent::GetNumTags() const

@ -205,14 +205,9 @@ namespace GradientSignal
float SurfaceSlopeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
SurfaceData::SurfacePointList points;
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
sampleParams.m_position, m_configuration.m_surfaceTagsToSample, points);
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);
float result = 0.0f;
GetValues(AZStd::span<const AZ::Vector3>(&sampleParams.m_position, 1), AZStd::span<float>(&result, 1));
return result;
}
void SurfaceSlopeGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
@ -223,32 +218,49 @@ namespace GradientSignal
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::SurfacePointList points;
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::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 angleMax = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMax, 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));
for (size_t index = 0; index < positions.size(); index++)
for (size_t index = 0; index < positions.size(); index++)
{
if (points.IsEmpty(index))
{
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);
switch (m_configuration.m_rampType)
{
points.Clear();
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagsToSample, points);
outValues[index] = GetSlopeRatio(points, angleMin, angleMax);
case SurfaceSlopeGradientConfig::RampType::SMOOTH_STEP:
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;
}
});
if (!valuesFound)
{
// No surface tags, so no output values.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
}
}
}

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

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

@ -185,8 +185,6 @@ namespace SurfaceData
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
const AZ::Vector3 testPosition = AZ::Vector3(
inPosition.GetX(),
@ -229,18 +227,45 @@ namespace SurfaceData
void SurfaceDataColliderComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
{
AZ::Vector3 hitPosition;
AZ::Vector3 hitNormal;
GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
}
// We want a full raycast, so don't just query the start point.
constexpr bool queryPointOnly = false;
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);
if (DoRayTrace(inPosition, queryPointOnly, hitPosition, hitNormal))
{
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights);
}
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();
AzPhysics::SceneQueryHit result = simBody->RayCast(request);
if (result)
{
surfacePointList.AddSurfacePoint(
GetEntityId(), inPosition, result.m_position, result.m_normal, m_newPointWeights);
}
}
}
});
}
void SurfaceDataColliderComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
{
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
{
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);
if (m_shapeBoundsIsValid && SurfaceData::AabbContains2D(m_shapeBounds, inPosition))
if (!m_shapeBoundsIsValid)
{
const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_shapeBounds.GetMax().GetZ());
const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
float intersectionDistance = 0.0f;
bool hitShape = false;
LmbrCentral::ShapeComponentRequestsBus::EventResult(hitShape, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::IntersectRay, rayOrigin, rayDirection, intersectionDistance);
if (hitShape)
{
AZ::Vector3 position = rayOrigin + intersectionDistance * rayDirection;
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, position, AZ::Vector3::CreateAxisZ(), m_newPointWeights);
}
return;
}
LmbrCentral::ShapeComponentRequestsBus::Event(
GetEntityId(),
[this, inPositions, &surfacePointList](LmbrCentral::ShapeComponentRequestsBus::Events* shape)
{
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;
bool hitShape = shape->IntersectRay(rayOrigin, rayDirection, intersectionDistance);
if (hitShape)
{
AZ::Vector3 position = rayOrigin + intersectionDistance * rayDirection;
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, position, surfacePointNormal, m_newPointWeights);
}
}
}
});
}
void SurfaceDataShapeComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
{
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);

@ -145,29 +145,42 @@ namespace Terrain
void TerrainSurfaceDataSystemComponent::GetSurfacePoints(
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)
{
return;
}
bool isTerrainValidAtPoint = false;
AzFramework::SurfaceData::SurfacePoint terrainSurfacePoint;
AzFramework::Terrain::TerrainDataRequestBus::Broadcast(&AzFramework::Terrain::TerrainDataRequestBus::Events::GetSurfacePoint,
inPosition, terrainSurfacePoint, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR,
&isTerrainValidAtPoint);
size_t inPositionIndex = 0;
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(surfacePoint.m_surfaceTags);
SurfaceData::SurfaceTagWeights weights(terrainSurfacePoint.m_surfaceTags);
// Always add a "terrain" or "terrainHole" tag.
const AZ::Crc32 terrainTag = terrainExists ? Constants::s_terrainTagCrc : Constants::s_terrainHoleTagCrc;
weights.AddSurfaceTagWeight(terrainTag, 1.0f);
// Always add a "terrain" or "terrainHole" tag.
const AZ::Crc32 terrainTag = isHole ? Constants::s_terrainHoleTagCrc : Constants::s_terrainTagCrc;
weights.AddSurfaceTagWeight(terrainTag, 1.0f);
surfacePointList.AddSurfacePoint(
GetEntityId(), inPositions[inPositionIndex], surfacePoint.m_position, surfacePoint.m_normal, weights);
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, terrainSurfacePoint.m_position, terrainSurfacePoint.m_normal, weights);
inPositionIndex++;
},
AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR);
}
AZ::Aabb TerrainSurfaceDataSystemComponent::GetSurfaceAabb() const
{
auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();

@ -59,6 +59,8 @@ namespace Terrain
//////////////////////////////////////////////////////////////////////////
// SurfaceDataProviderRequestBus
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

@ -192,7 +192,7 @@ bool TerrainSystem::InWorldBounds(float x, float y) const
}
// 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,
Sampler sampler) const
{
@ -253,7 +253,7 @@ AZStd::vector<AZ::Vector3> TerrainSystem::GenerateInputPositionsFromRegion(
}
void TerrainSystem::MakeBulkQueries(
const AZStd::span<AZ::Vector3> inPositions,
const AZStd::span<const AZ::Vector3> inPositions,
AZStd::span<AZ::Vector3> outPositions,
AZStd::span<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
@ -296,7 +296,7 @@ void TerrainSystem::MakeBulkQueries(
if (prevAreaId != AZ::EntityId())
{
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<bool>(outTerrainExists.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::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);
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<bool> outTerrainExists,
[[maybe_unused]] AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
@ -516,7 +516,7 @@ bool TerrainSystem::GetIsHoleFromFloats(float x, float y, Sampler sampler) const
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::vector<AZ::Vector3> directionVectors;
@ -685,7 +685,7 @@ AzFramework::RenderGeometry::RayResult TerrainSystem::GetClosestIntersection(
}
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,
Sampler sampleFilter,
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(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
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(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
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(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
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(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
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(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
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(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
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(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -830,7 +830,7 @@ AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::A
}
void TerrainSystem::GetOrderedSurfaceWeightsFromList(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
[[maybe_unused]] Sampler sampler,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList,
AZStd::span<bool> terrainExists) const
@ -841,7 +841,7 @@ void TerrainSystem::GetOrderedSurfaceWeightsFromList(
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<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
@ -929,7 +929,7 @@ const char* TerrainSystem::GetMaxSurfaceName(
}
void TerrainSystem::ProcessHeightsFromList(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const
{
@ -953,7 +953,7 @@ void TerrainSystem::ProcessHeightsFromList(
}
void TerrainSystem::ProcessNormalsFromList(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const
{
@ -977,7 +977,7 @@ void TerrainSystem::ProcessNormalsFromList(
}
void TerrainSystem::ProcessSurfaceWeightsFromList(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const
{
@ -1001,7 +1001,7 @@ void TerrainSystem::ProcessSurfaceWeightsFromList(
}
void TerrainSystem::ProcessSurfacePointsFromList(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const
{
@ -1034,7 +1034,7 @@ void TerrainSystem::ProcessSurfacePointsFromList(
}
void TerrainSystem::ProcessHeightsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const
{
@ -1054,7 +1054,7 @@ void TerrainSystem::ProcessHeightsFromListOfVector2(
}
void TerrainSystem::ProcessNormalsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const
{
@ -1074,7 +1074,7 @@ void TerrainSystem::ProcessNormalsFromListOfVector2(
}
void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter) const
{
@ -1094,7 +1094,7 @@ void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2(
}
void TerrainSystem::ProcessSurfacePointsFromListOfVector2(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
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
//! 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,
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,
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,
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,
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,
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,
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,
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,
Sampler sampleFilter = Sampler::DEFAULT) const override;
@ -194,42 +194,42 @@ namespace Terrain
const AzFramework::RenderGeometry::RayRequest& ray) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
const AZStd::span<const AZ::Vector2>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
@ -262,7 +262,7 @@ namespace Terrain
template<typename SynchronousFunctionType, typename VectorType>
AZStd::shared_ptr<TerrainJobContext> ProcessFromListAsync(
SynchronousFunctionType synchronousFunction,
const AZStd::span<VectorType>& inPositions,
const AZStd::span<const VectorType>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
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;
typedef AZStd::function<void(
const AZStd::span<AZ::Vector3> inPositions,
const AZStd::span<const AZ::Vector3> inPositions,
AZStd::span<AZ::Vector3> outPositions,
AZStd::span<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
AZ::EntityId areaId)> BulkQueriesCallback;
void GetHeightsSynchronous(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
Sampler sampler, AZStd::span<float> heights,
AZStd::span<bool> terrainExists) const;
void GetNormalsSynchronous(
const AZStd::span<AZ::Vector3>& inPositions,
const AZStd::span<const AZ::Vector3>& inPositions,
Sampler sampler, AZStd::span<AZ::Vector3> normals,
AZStd::span<bool> terrainExists) const;
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<bool> terrainExists) const;
void MakeBulkQueries(
const AZStd::span<AZ::Vector3> inPositions,
const AZStd::span<const AZ::Vector3> inPositions,
AZStd::span<AZ::Vector3> outPositions,
AZStd::span<bool> outTerrainExists,
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWieghts,
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,
Sampler sampler) const;
AZStd::vector<AZ::Vector3> GenerateInputPositionsFromRegion(
@ -361,7 +361,7 @@ namespace Terrain
template<typename SynchronousFunctionType, typename VectorType>
inline AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessFromListAsync(
SynchronousFunctionType synchronousFunction,
const AZStd::span<VectorType>& inPositions,
const AZStd::span<const VectorType>& inPositions,
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter,
AZStd::shared_ptr<ProcessAsyncParams> params) const
@ -397,7 +397,7 @@ namespace Terrain
const size_t subSpanCount = (i < numJobs - 1) ? numPositionsPerJob : AZStd::dynamic_extent;
// 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]()
{
// Process the sub span of positions, unless the associated job context has been cancelled.

Loading…
Cancel
Save