|
|
|
|
@ -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)
|
|
|
|
|
|