Another batch of GetValues() overrides. (#6915)

* Another batch of GetValues() overrides.

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

* Added missing headers.

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

* Addressed PR feedback.

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 3a3aa20545
commit 4b9e53e623
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -99,6 +99,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override;
protected:
@ -110,6 +111,34 @@ namespace GradientSignal
MixedGradientLayer* GetLayer(int layerIndex) override;
private:
static float PerformMixingOperation(MixedGradientLayer::MixingOperation operation, float prevValue, float currentUnpremultiplied)
{
switch (operation)
{
case MixedGradientLayer::MixingOperation::Initialize:
return currentUnpremultiplied;
case MixedGradientLayer::MixingOperation::Multiply:
return prevValue * currentUnpremultiplied;
case MixedGradientLayer::MixingOperation::Add:
return prevValue + currentUnpremultiplied;
case MixedGradientLayer::MixingOperation::Subtract:
return prevValue - currentUnpremultiplied;
case MixedGradientLayer::MixingOperation::Min:
return AZStd::min(prevValue, currentUnpremultiplied);
case MixedGradientLayer::MixingOperation::Max:
return AZStd::max(prevValue, currentUnpremultiplied);
case MixedGradientLayer::MixingOperation::Average:
return (prevValue + currentUnpremultiplied) / 2.0f;
case MixedGradientLayer::MixingOperation::Normal:
return currentUnpremultiplied;
case MixedGradientLayer::MixingOperation::Overlay:
return (prevValue >= 0.5f) ? (1.0f - (2.0f * (1.0f - prevValue) * (1.0f - currentUnpremultiplied)))
: (2.0f * prevValue * currentUnpremultiplied);
default:
return currentUnpremultiplied;
}
}
MixedGradientConfig m_configuration;
LmbrCentral::DependencyMonitor m_dependencyMonitor;
};

@ -73,6 +73,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override;
protected:
@ -86,6 +87,39 @@ namespace GradientSignal
GradientSampler& GetGradientSampler() override;
private:
static float PosterizeValue(float input, float bands, PosterizeGradientConfig::ModeType mode)
{
const float clampedInput = AZ::GetClamp(input, 0.0f, 1.0f);
float output = 0.0f;
// "quantize" the input down to a number that goes from 0 to (bands-1)
const float band = AZ::GetMin(floorf(clampedInput * bands), bands - 1.0f);
// Given our quantized band, produce the right output for that band range.
switch (mode)
{
default:
case PosterizeGradientConfig::ModeType::Floor:
// Floor: the output range should be the lowest value of each band, or (0 to bands-1) / bands
output = (band + 0.0f) / bands;
break;
case PosterizeGradientConfig::ModeType::Round:
// Round: the output range should be the midpoint of each band, or (0.5 to bands-0.5) / bands
output = (band + 0.5f) / bands;
break;
case PosterizeGradientConfig::ModeType::Ceiling:
// Ceiling: the output range should be the highest value of each band, or (1 to bands) / bands
output = (band + 1.0f) / bands;
break;
case PosterizeGradientConfig::ModeType::Ps:
// Ps: the output range should be equally distributed from 0-1, or (0 to bands-1) / (bands-1)
output = band / (bands - 1.0f);
break;
}
return AZ::GetMin(output, 1.0f);
}
PosterizeGradientConfig m_configuration;
LmbrCentral::DependencyMonitor m_dependencyMonitor;
};

@ -64,6 +64,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override;
protected:

@ -71,6 +71,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override;
protected:

@ -15,6 +15,7 @@
#include <SurfaceData/SurfaceDataTypes.h>
#include <LmbrCentral/Dependency/DependencyNotificationBus.h>
#include <AzCore/Component/TickBus.h>
#include <GradientSignal/Util.h>
namespace LmbrCentral
{
@ -89,6 +90,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
protected:
//////////////////////////////////////////////////////////////////////////
@ -105,7 +107,22 @@ namespace GradientSignal
void AddTag(AZStd::string tag) override;
private:
mutable AZStd::recursive_mutex m_cacheMutex;
static float CalculateAltitudeRatio(const SurfaceData::SurfacePointList& points, float altitudeMin, float altitudeMax)
{
if (points.empty())
{
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.front().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 };

@ -70,6 +70,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
protected:
//////////////////////////////////////////////////////////////////////////
@ -80,6 +81,21 @@ namespace GradientSignal
void AddTag(AZStd::string tag) override;
private:
static float GetMaxSurfaceWeight(const SurfaceData::SurfacePointList& points)
{
float result = 0.0f;
for (const auto& point : points)
{
for (const auto& [maskId, weight] : point.m_masks)
{
result = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), result);
}
}
return result;
}
SurfaceMaskGradientConfig m_configuration;
LmbrCentral::DependencyMonitor m_dependencyMonitor;
};

@ -14,6 +14,7 @@
#include <GradientSignal/Ebuses/SurfaceSlopeGradientRequestBus.h>
#include <SurfaceData/SurfaceDataTypes.h>
#include <GradientSignal/SmoothStep.h>
#include <GradientSignal/Util.h>
namespace LmbrCentral
{
@ -91,6 +92,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
protected:
//////////////////////////////////////////////////////////////////////////
@ -121,6 +123,37 @@ namespace GradientSignal
void SetFallOffMidpoint(float midpoint) override;
private:
float GetSlopeRatio(const SurfaceData::SurfacePointList& points, float angleMin, float angleMax) const
{
if (points.empty())
{
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()).
AZ_Assert(
points.front().m_normal.GetNormalized().IsClose(points.front().m_normal),
"Surface normals are expected to be normalized");
const float slope = points.front().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;
};
}

@ -65,6 +65,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
float GetValue(const GradientSampleParams& sampleParams) const override;
void GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const override;
bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override;
protected:

@ -152,7 +152,7 @@ namespace GradientSignal
auto ClearOutputValues = [](AZStd::span<float> outValues)
{
// If we don't have a valid gradient (or it is fully transparent), clear out all the output values.
memset(outValues.data(), 0, outValues.size() * sizeof(float));
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
};
if (m_opacity <= 0.0f || !m_gradientId.IsValid())

@ -13,6 +13,7 @@
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/std/containers/span.h>
#include <GradientSignal/GradientSampler.h>
#include <GradientSignal/Util.h>
@ -26,29 +27,46 @@ namespace GradientSignal
static void Reflect(AZ::ReflectContext* context);
inline float GetSmoothedValue(float inputValue) const;
inline void GetSmoothedValues(AZStd::span<float> inOutValues) const;
float m_falloffMidpoint = 0.5f;
float m_falloffRange = 0.5f;
float m_falloffStrength = 0.25f;
private:
inline float CalculateSmoothedValue(float min, float max, float valueFalloffStrength, float inputValue) const;
};
inline float SmoothStep::GetSmoothedValue(float inputValue) const
inline float SmoothStep::CalculateSmoothedValue(float min, float max, float valueFalloffStrength, float inputValue) const
{
float output = 0.0f;
const float value = AZ::GetClamp(inputValue, 0.0f, 1.0f);
const float valueFalloffStrength = AZ::GetClamp(m_falloffStrength, 0.0f, 1.0f);
float min = m_falloffMidpoint - m_falloffRange / 2.0f;
float max = m_falloffMidpoint + m_falloffRange / 2.0f;
float result1 = GetRatio(min, min + valueFalloffStrength, value);
result1 = GetSmoothStep(result1);
float result2 = GetRatio(max - valueFalloffStrength, max, value);
result2 = GetSmoothStep(result2);
output = result1 * (1.0f - result2);
return result1 * (1.0f - result2);
}
inline float SmoothStep::GetSmoothedValue(float inputValue) const
{
const float min = m_falloffMidpoint - m_falloffRange / 2.0f;
const float max = m_falloffMidpoint + m_falloffRange / 2.0f;
const float valueFalloffStrength = AZ::GetClamp(m_falloffStrength, 0.0f, 1.0f);
return CalculateSmoothedValue(min, max, valueFalloffStrength, inputValue);
}
inline void SmoothStep::GetSmoothedValues(AZStd::span<float> inOutValues) const
{
const float min = m_falloffMidpoint - m_falloffRange / 2.0f;
const float max = m_falloffMidpoint + m_falloffRange / 2.0f;
const float valueFalloffStrength = AZ::GetClamp(m_falloffStrength, 0.0f, 1.0f);
return output;
for (auto& inOutValue : inOutValues)
{
inOutValue = CalculateSmoothedValue(min, max, valueFalloffStrength, inOutValue);
}
}
}
} // namespace GradientSignal

@ -257,62 +257,80 @@ namespace GradientSignal
float MixedGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
AZ_PROFILE_FUNCTION(Entity);
//accumulate the mixed/combined result of all layers and operations
float result = 0.0f;
float operationResult = 0.0f;
for (const auto& layer : m_configuration.m_layers)
{
// added check to prevent opacity of 0.0, which will bust when we unpremultiply the alpha out
if (layer.m_enabled && layer.m_gradientSampler.m_opacity != 0.0f)
{
// Precalculate the inverse opacity that we'll use for blending the current accumulated value with.
// In the one case of "Initialize" blending, force this value to 0 so that we erase any accumulated values.
const float inverseOpacity = (layer.m_operation == MixedGradientLayer::MixingOperation::Initialize)
? 0.0f
: (1.0f - layer.m_gradientSampler.m_opacity);
// this includes leveling and opacity result, we need unpremultiplied opacity to combine properly
float current = layer.m_gradientSampler.GetValue(sampleParams);
// unpremultiplied alpha (we clamp the end result)
float currentUnpremultiplied = current / layer.m_gradientSampler.m_opacity;
switch (layer.m_operation)
{
default:
case MixedGradientLayer::MixingOperation::Initialize:
//reset the result of the mixed/combined layers to the current value
result = 0.0f;
operationResult = currentUnpremultiplied;
break;
case MixedGradientLayer::MixingOperation::Multiply:
operationResult = result * currentUnpremultiplied;
break;
case MixedGradientLayer::MixingOperation::Add:
operationResult = result + currentUnpremultiplied;
break;
case MixedGradientLayer::MixingOperation::Subtract:
operationResult = result - currentUnpremultiplied;
break;
case MixedGradientLayer::MixingOperation::Min:
operationResult = AZStd::min(currentUnpremultiplied, result);
break;
case MixedGradientLayer::MixingOperation::Max:
operationResult = AZStd::max(currentUnpremultiplied, result);
break;
case MixedGradientLayer::MixingOperation::Average:
operationResult = (result + currentUnpremultiplied) / 2.0f;
break;
case MixedGradientLayer::MixingOperation::Normal:
operationResult = currentUnpremultiplied;
break;
case MixedGradientLayer::MixingOperation::Overlay:
operationResult = (result >= 0.5f) ? (1.0f - (2.0f * (1.0f - result) * (1.0f - currentUnpremultiplied))) : (2.0f * result * currentUnpremultiplied);
break;
}
const float currentUnpremultiplied = current / layer.m_gradientSampler.m_opacity;
const float operationResult = PerformMixingOperation(layer.m_operation, result, currentUnpremultiplied);
// blend layers (re-applying opacity, which is why we needed to use unpremultiplied)
result = (result * (1.0f - layer.m_gradientSampler.m_opacity)) + (operationResult * layer.m_gradientSampler.m_opacity);
result = (result * inverseOpacity) + (operationResult * layer.m_gradientSampler.m_opacity);
}
}
return AZ::GetClamp(result, 0.0f, 1.0f);
}
void MixedGradientComponent::GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
// Initialize all of our output data to 0.0f. Layer blends will combine with this, so we need it to have an initial value.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
AZStd::vector<float> layerValues(positions.size());
// accumulate the mixed/combined result of all layers and operations
for (const auto& layer : m_configuration.m_layers)
{
// added check to prevent opacity of 0.0, which will bust when we unpremultiply the alpha out
if (layer.m_enabled && layer.m_gradientSampler.m_opacity != 0.0f)
{
// Precalculate the inverse opacity that we'll use for blending the current accumulated value with.
// In the one case of "Initialize" blending, force this value to 0 so that we erase any accumulated values.
const float inverseOpacity = (layer.m_operation == MixedGradientLayer::MixingOperation::Initialize)
? 0.0f
: (1.0f - layer.m_gradientSampler.m_opacity);
// this includes leveling and opacity result, we need unpremultiplied opacity to combine properly
layer.m_gradientSampler.GetValues(positions, layerValues);
for (size_t index = 0; index < outValues.size(); index++)
{
// unpremultiplied alpha (we clamp the end result)
const float currentUnpremultiplied = layerValues[index] / layer.m_gradientSampler.m_opacity;
const float operationResult = PerformMixingOperation(layer.m_operation, outValues[index], currentUnpremultiplied);
// blend layers (re-applying opacity, which is why we needed to use unpremultiplied)
outValues[index] = (outValues[index] * inverseOpacity) + (operationResult * layer.m_gradientSampler.m_opacity);
}
}
}
for (auto& outValue : outValues)
{
outValue = AZ::GetClamp(outValue, 0.0f, 1.0f);
}
}
bool MixedGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const
{
for (const auto& layer : m_configuration.m_layers)

@ -151,34 +151,28 @@ namespace GradientSignal
float PosterizeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
const float bands = AZ::GetMax(static_cast<float>(m_configuration.m_bands), 2.0f);
const float input = AZ::GetClamp(m_configuration.m_gradientSampler.GetValue(sampleParams), 0.0f, 1.0f);
float output = 0.0f;
const float input = m_configuration.m_gradientSampler.GetValue(sampleParams);
return PosterizeValue(input, bands, m_configuration.m_mode);
}
void PosterizeGradientComponent::GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
const float bands = AZ::GetMax(static_cast<float>(m_configuration.m_bands), 2.0f);
// "quantize" the input down to a number that goes from 0 to (bands-1)
const float band = AZ::GetClamp(floorf(input * bands), 0.0f, bands - 1.0f);
// Fill in the outValues with all of the generated inupt gradient values.
m_configuration.m_gradientSampler.GetValues(positions, outValues);
// Given our quantized band, produce the right output for that band range.
switch (m_configuration.m_mode)
// Run through all the input values and posterize them.
for (auto& outValue : outValues)
{
default:
case PosterizeGradientConfig::ModeType::Floor:
// Floor: the output range should be the lowest value of each band, or (0 to bands-1) / bands
output = (band + 0.0f) / bands;
break;
case PosterizeGradientConfig::ModeType::Round:
// Round: the output range should be the midpoint of each band, or (0.5 to bands-0.5) / bands
output = (band + 0.5f) / bands;
break;
case PosterizeGradientConfig::ModeType::Ceiling:
// Ceiling: the output range should be the highest value of each band, or (1 to bands) / bands
output = (band + 1.0f) / bands;
break;
case PosterizeGradientConfig::ModeType::Ps:
// Ps: the output range should be equally distributed from 0-1, or (0 to bands-1) / (bands-1)
output = band / (bands - 1.0f);
break;
outValue = PosterizeValue(outValue, bands, m_configuration.m_mode);
}
return AZ::GetClamp(output, 0.0f, 1.0f);
}
bool PosterizeGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const

@ -131,13 +131,18 @@ namespace GradientSignal
float ReferenceGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
AZ_PROFILE_FUNCTION(Entity);
float output = 0.0f;
return m_configuration.m_gradientSampler.GetValue(sampleParams);
}
output = m_configuration.m_gradientSampler.GetValue(sampleParams);
void ReferenceGradientComponent::GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
return output;
m_configuration.m_gradientSampler.GetValues(positions, outValues);
}
bool ReferenceGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const

@ -168,12 +168,20 @@ namespace GradientSignal
float SmoothStepGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
float output = 0.0f;
const float value = m_configuration.m_gradientSampler.GetValue(sampleParams);
return m_configuration.m_smoothStep.GetSmoothedValue(value);
}
const float value = AZ::GetClamp(m_configuration.m_gradientSampler.GetValue(sampleParams), 0.0f, 1.0f);
output = m_configuration.m_smoothStep.GetSmoothedValue(value);
void SmoothStepGradientComponent::GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
return output;
m_configuration.m_gradientSampler.GetValues(positions, outValues);
m_configuration.m_smoothStep.GetSmoothedValues(outValues);
}
bool SmoothStepGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const

@ -202,19 +202,49 @@ namespace GradientSignal
float SurfaceAltitudeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
SurfaceData::SurfacePointList points;
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
sampleParams.m_position, m_configuration.m_surfaceTagsToSample, points);
if (points.empty())
return CalculateAltitudeRatio(points, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax);
}
void SurfaceAltitudeGradientComponent::GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
return 0.0f;
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
const AZ::Vector3& position = points.front().m_position;
return GetRatio(m_configuration.m_altitudeMin, m_configuration.m_altitudeMax, position.GetZ());
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
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;
// For each position, call GetSurfacePoints() and turn the height into a 0-1 value based on our min/max altitudes.
for (size_t index = 0; index < positions.size(); index++)
{
points.clear();
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagsToSample, points);
outValues[index] = CalculateAltitudeRatio(points, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax);
}
});
if (!valuesFound)
{
// No surface data, so no output values.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
}
}
void SurfaceAltitudeGradientComponent::OnCompositionChanged()
@ -246,7 +276,7 @@ namespace GradientSignal
{
AZ_PROFILE_FUNCTION(Entity);
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::unique_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
if (m_configuration.m_shapeEntityId.IsValid())
{

@ -161,8 +161,6 @@ namespace GradientSignal
float SurfaceMaskGradientComponent::GetValue(const GradientSampleParams& params) const
{
AZ_PROFILE_FUNCTION(Entity);
float result = 0.0f;
if (!m_configuration.m_surfaceTagList.empty())
@ -171,18 +169,50 @@ namespace GradientSignal
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
params.m_position, m_configuration.m_surfaceTagList, points);
for (const auto& point : points)
{
for (const auto& maskPair : point.m_masks)
{
result = AZ::GetMax(AZ::GetClamp(maskPair.second, 0.0f, 1.0f), result);
}
}
result = GetMaxSurfaceWeight(points);
}
return result;
}
void SurfaceMaskGradientComponent::GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
bool valuesFound = false;
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;
for (size_t index = 0; index < positions.size(); index++)
{
points.clear();
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagList, points);
outValues[index] = GetMaxSurfaceWeight(points);
}
});
}
if (!valuesFound)
{
// No surface tags, so no output values.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
}
}
size_t SurfaceMaskGradientComponent::GetNumTags() const
{
return m_configuration.GetNumTags();

@ -209,36 +209,50 @@ namespace GradientSignal
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
sampleParams.m_position, m_configuration.m_surfaceTagsToSample, points);
if (points.empty())
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<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
return 0.0f;
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
// 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()).
AZ_Assert(points.front().m_normal.GetNormalized().IsClose(points.front().m_normal), "Surface normals are expected to be normalized");
const float slope = points.front().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);
bool valuesFound = false;
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));
switch (m_configuration.m_rampType)
// 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;
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++)
{
points.clear();
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagsToSample, points);
outValues[index] = GetSlopeRatio(points, angleMin, angleMax);
}
});
if (!valuesFound)
{
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);
// No surface tags, so no output values.
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
}
}
float SurfaceSlopeGradientComponent::GetSlopeMin() const
{
return m_configuration.m_slopeMin;

@ -138,11 +138,22 @@ namespace GradientSignal
float ThresholdGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
float output = 0.0f;
return (m_configuration.m_gradientSampler.GetValue(sampleParams) <= m_configuration.m_threshold) ? 0.0f : 1.0f;
}
output = m_configuration.m_gradientSampler.GetValue(sampleParams) <= m_configuration.m_threshold ? 0.0f : 1.0f;
void ThresholdGradientComponent::GetValues(AZStd::span<AZ::Vector3> positions, AZStd::span<float> outValues) const
{
if (positions.size() != outValues.size())
{
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
return;
}
return output;
m_configuration.m_gradientSampler.GetValues(positions, outValues);
for (auto& outValue : outValues)
{
outValue = (outValue <= m_configuration.m_threshold) ? 0.0f : 1.0f;
}
}
bool ThresholdGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const

Loading…
Cancel
Save