Prevent infinite recursion with Altitude Gradient.

Using the Altitude Gradient as an input to the Height Gradient List can cause infinite recursion since it is both setting and fetching the same height value.  Added guards to warn if this occurs and gracefully handles the situation.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2021-11-04 15:27:00 -05:00
parent 46d1b19816
commit 5b504086f9
2 changed files with 24 additions and 16 deletions
@@ -151,24 +151,29 @@ namespace Terrain
{
float maxSample = 0.0f;
terrainExists = false;
GradientSignal::GradientSampleParams params(AZ::Vector3(inPosition.GetX(), inPosition.GetY(), 0.0f));
// Right now, when the list contains multiple entries, we will use the highest point from each gradient.
// This is needed in part because gradients don't really have world bounds, so they exist everywhere but generally have a value
// of 0 outside their data bounds if they're using bounded data. We should examine the possibility of extending the gradient API
// to provide actual bounds so that it's possible to detect if the gradient even 'exists' in an area, at which point we could just
// make this list a prioritized list from top to bottom for any points that overlap.
for (auto& gradientId : m_configuration.m_gradientEntities)
AZ_WarningOnce("Terrain", !m_isRequestInProgress, "Detected cyclic dependences with terrain height entity references");
if (!m_isRequestInProgress)
{
// If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain
// to *not* exist at a specific point.
terrainExists = true;
m_isRequestInProgress = true;
GradientSignal::GradientSampleParams params(AZ::Vector3(inPosition.GetX(), inPosition.GetY(), 0.0f));
float sample = 0.0f;
GradientSignal::GradientRequestBus::EventResult(
sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
maxSample = AZ::GetMax(maxSample, sample);
// Right now, when the list contains multiple entries, we will use the highest point from each gradient.
// This is needed in part because gradients don't really have world bounds, so they exist everywhere but generally have a value
// of 0 outside their data bounds if they're using bounded data. We should examine the possibility of extending the gradient
// API to provide actual bounds so that it's possible to detect if the gradient even 'exists' in an area, at which point we
// could just make this list a prioritized list from top to bottom for any points that overlap.
for (auto& gradientId : m_configuration.m_gradientEntities)
{
// If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain
// to *not* exist at a specific point.
terrainExists = true;
float sample = 0.0f;
GradientSignal::GradientRequestBus::EventResult(
sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
maxSample = AZ::GetMax(maxSample, sample);
}
m_isRequestInProgress = false;
}
const float height = AZ::Lerp(m_cachedShapeBounds.GetMin().GetZ(), m_cachedShapeBounds.GetMax().GetZ(), maxSample);
@@ -91,6 +91,9 @@ namespace Terrain
AZ::Vector2 m_cachedHeightQueryResolution{ 1.0f, 1.0f };
AZ::Aabb m_cachedShapeBounds;
// prevent recursion in case user attaches cyclic dependences
mutable bool m_isRequestInProgress{ false };
LmbrCentral::DependencyMonitor m_dependencyMonitor;
};
}