Change gradients to use cached GradientTransform instance (#6591)

* Change flow so that TerrainSystem stops responding during deactivation.
Some systems might accidentally try to call back to the TerrainSystem inside a DestroyBegin notification, so make sure it stops listening before sending out the notification.

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

* Change gradients to cache and use a GradientTransform instance.
In my local test case, calling EBus on every call took 337 ms, using a lambda to wrap the calls took 197 ms, and using the fully cached version took 170 ms.

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

* Remove the wrappingTransform function and go back to the switch statement.
There was a bit of overhead to each function call due to using AZStd::function that just isn't necessary for this use case.

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

* Add profile markers to the heightfield updates so that they're more visible.

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

* Cleared state while component is deactivated.
The state was getting refreshed even while the component was in a deactivated state, which meant that it wasn't properly notifying of state changes when it became active since it wasn't detecting an actual change.  By clearing the state when deactivated, and ensuring the state isn't getting refreshed *while* deactivated, the notifications work properly.

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

* Fixed compile warning on unit test.

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

* Addressed PR feedback - changed comments, reduced mutex scope

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2021-12-30 12:43:00 -06:00
committed by GitHub
parent 2f1346c719
commit 48260486fb
17 changed files with 245 additions and 144 deletions
@@ -249,6 +249,9 @@ namespace FastNoiseGem
void FastNoiseGradientComponent::Activate()
{
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
GradientSignal::GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
// Some platforms require random seeds to be > 0. Clamp to a positive range to ensure we're always safe.
m_generator.SetSeed(AZ::GetMax(m_configuration.m_seed, 1));
m_generator.SetFrequency(m_configuration.m_frequency);
@@ -272,6 +275,7 @@ namespace FastNoiseGem
{
GradientSignal::GradientRequestBus::Handler::BusDisconnect();
FastNoiseGradientRequestBus::Handler::BusDisconnect();
GradientSignal::GradientTransformNotificationBus::Handler::BusDisconnect();
}
bool FastNoiseGradientComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
@@ -294,13 +298,21 @@ namespace FastNoiseGem
return false;
}
void FastNoiseGradientComponent::OnGradientTransformChanged(const GradientSignal::GradientTransform& newTransform)
{
AZStd::unique_lock<decltype(m_transformMutex)> lock(m_transformMutex);
m_gradientTransform = newTransform;
}
float FastNoiseGradientComponent::GetValue(const GradientSignal::GradientSampleParams& sampleParams) const
{
AZ::Vector3 uvw = sampleParams.m_position;
bool wasPointRejected = false;
GradientSignal::GradientTransformRequestBus::Event(
GetEntityId(), &GradientSignal::GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, wasPointRejected);
{
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
}
if (!wasPointRejected)
{
@@ -12,6 +12,7 @@
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
#include <FastNoise/Ebuses/FastNoiseGradientRequestBus.h>
#include <External/FastNoise/FastNoise.h>
@@ -67,6 +68,7 @@ namespace FastNoiseGem
: public AZ::Component
, private GradientSignal::GradientRequestBus::Handler
, private FastNoiseGradientRequestBus::Handler
, private GradientSignal::GradientTransformNotificationBus::Handler
{
public:
friend class EditorFastNoiseGradientComponent;
@@ -80,23 +82,25 @@ namespace FastNoiseGem
FastNoiseGradientComponent(const FastNoiseGradientConfig& configuration);
FastNoiseGradientComponent() = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
// AZ::Component overrides...
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
// GradientRequestBus overrides...
float GetValue(const GradientSignal::GradientSampleParams& sampleParams) const override;
protected:
FastNoiseGradientConfig m_configuration;
FastNoise m_generator;
GradientSignal::GradientTransform m_gradientTransform;
mutable AZStd::shared_mutex m_transformMutex;
/////////////////////////////////////////////////////////////////////////
// FastNoiseGradientRequest overrides
// GradientTransformNotificationBus overrides...
void OnGradientTransformChanged(const GradientSignal::GradientTransform& newTransform) override;
// FastNoiseGradientRequest overrides...
int GetRandomSeed() const override;
void SetRandomSeed(int seed) override;
+4 -9
View File
@@ -46,17 +46,10 @@ public:
////////////////////////////////////////////////////////////////////////////
//// GradientTransformRequestBus
void TransformPositionToUVW([[maybe_unused]] const AZ::Vector3& inPosition, [[maybe_unused]] AZ::Vector3& outUVW, [[maybe_unused]] bool& wasPointRejected) const override {}
void TransformPositionToUVWNormalized(
[[maybe_unused]] const AZ::Vector3& inPosition,
[[maybe_unused]] AZ::Vector3& outUVW,
[[maybe_unused]] bool& wasPointRejected) const override
const GradientSignal::GradientTransform& GetGradientTransform() const override
{
return m_gradientTransform;
}
void GetGradientLocalBounds([[maybe_unused]] AZ::Aabb& bounds) const override
{
}
void GetGradientEncompassingBounds([[maybe_unused]] AZ::Aabb& bounds) const override {}
//////////////////////////////////////////////////////////////////////////
// GradientTransformModifierRequestBus
@@ -104,6 +97,8 @@ public:
bool GetAdvancedMode() const override { return false; }
void SetAdvancedMode([[maybe_unused]] bool value) override {}
GradientSignal::GradientTransform m_gradientTransform;
};
TEST(FastNoiseTest, ComponentsWithComponentApplication)
@@ -11,6 +11,7 @@
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/Math/Vector3.h>
#include <GradientSignal/GradientTransform.h>
namespace GradientSignal
{
@@ -22,16 +23,56 @@ namespace GradientSignal
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
//! allows multiple threads to call shape requests
//! allows multiple threads to call gradient transform requests
using MutexType = AZStd::recursive_mutex;
virtual ~GradientTransformRequests() = default;
virtual void TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const = 0;
virtual void TransformPositionToUVWNormalized(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const = 0;
virtual void GetGradientLocalBounds(AZ::Aabb& bounds) const = 0;
virtual void GetGradientEncompassingBounds(AZ::Aabb& bounds) const = 0;
//! Get the GradientTransform that's been configured by the bus listener.
//! \return the GradientTransform instance that can be used to transform world points into gradient lookup space.
virtual const GradientTransform& GetGradientTransform() const = 0;
};
using GradientTransformRequestBus = AZ::EBus<GradientTransformRequests>;
/**
* Notifies about changes to the GradientTransform configuration
*/
class GradientTransformNotifications
: public AZ::EBusTraits
{
public:
////////////////////////////////////////////////////////////////////////
// EBusTraits
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
using MutexType = AZStd::recursive_mutex;
////////////////////////////////////////////////////////////////////////
//! Notify listeners that the GradientTransform configuration has changed.
//! \return the GradientTransform instance that can be used to transform world points into gradient lookup space.
virtual void OnGradientTransformChanged(const GradientTransform& newTransform) = 0;
//! Connection policy that auto-calls OnGradientTransformChanged on connection with the current GradientTransform data.
template<class Bus>
struct ConnectionPolicy : public AZ::EBusConnectionPolicy<Bus>
{
static void Connect(
typename Bus::BusPtr& busPtr,
typename Bus::Context& context,
typename Bus::HandlerNode& handler,
typename Bus::Context::ConnectLockGuard& connectLock,
const typename Bus::BusIdType& id = 0)
{
AZ::EBusConnectionPolicy<Bus>::Connect(busPtr, context, handler, connectLock, id);
GradientTransform transform;
GradientTransformRequestBus::EventResult(transform, id, &GradientTransformRequests::GetGradientTransform);
handler->OnGradientTransformChanged(transform);
}
};
};
using GradientTransformNotificationBus = AZ::EBus<GradientTransformNotifications>;
} //namespace GradientSignal
@@ -111,7 +111,6 @@ namespace GradientSignal
private:
//! These are the various transformations that will be performed, based on wrapping type.
using WrappingTransformFunction = AZStd::function<AZ::Vector3(const AZ::Vector3& point, const AZ::Aabb& bounds)>;
static AZ::Vector3 NoTransform(const AZ::Vector3& point, const AZ::Aabb& bounds);
static AZ::Vector3 GetUnboundedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
static AZ::Vector3 GetClampedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
@@ -144,7 +143,6 @@ namespace GradientSignal
//! How the gradient should repeat itself outside of the shape bounds.
WrappingType m_wrappingType = WrappingType::None;
WrappingTransformFunction m_wrappingTransform = NoTransform;
/**
* Cached reciprocal for performing an inverse lerp back to shape bounds.
@@ -276,24 +276,29 @@ namespace GradientSignal
void GradientTransformComponent::Activate()
{
m_dirty = false;
m_gradientTransform = GradientTransform();
// Update our GradientTransform to be configured correctly. We don't need to notify dependents of the change though.
// If anyone is listening, they're already getting notified below.
const bool notifyDependentsOfChange = false;
UpdateFromShape(notifyDependentsOfChange);
GradientTransformRequestBus::Handler::BusConnect(GetEntityId());
LmbrCentral::DependencyNotificationBus::Handler::BusConnect(GetEntityId());
AZ::TickBus::Handler::BusConnect();
GradientTransformModifierRequestBus::Handler::BusConnect(GetEntityId());
m_dirty = false;
m_dependencyMonitor.Reset();
m_dependencyMonitor.ConnectOwner(GetEntityId());
m_dependencyMonitor.ConnectDependency(GetEntityId());
m_dependencyMonitor.ConnectDependency(GetShapeEntityId());
UpdateFromShape();
}
void GradientTransformComponent::Deactivate()
{
m_dirty = false;
m_gradientTransform = GradientTransform();
m_dependencyMonitor.Reset();
GradientTransformRequestBus::Handler::BusDisconnect();
@@ -322,28 +327,10 @@ namespace GradientSignal
return false;
}
void GradientTransformComponent::TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const
const GradientTransform& GradientTransformComponent::GetGradientTransform() const
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
m_gradientTransform.TransformPositionToUVW(inPosition, outUVW, wasPointRejected);
}
void GradientTransformComponent::TransformPositionToUVWNormalized(
const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
m_gradientTransform.TransformPositionToUVWNormalized(inPosition, outUVW, wasPointRejected);
}
void GradientTransformComponent::GetGradientLocalBounds(AZ::Aabb& bounds) const
{
bounds = m_shapeBounds;
}
void GradientTransformComponent::GetGradientEncompassingBounds(AZ::Aabb& bounds) const
{
bounds = m_shapeBounds;
bounds.ApplyMatrix3x4(m_shapeTransformInverse.GetInverseFull());
return m_gradientTransform;
}
void GradientTransformComponent::OnCompositionChanged()
@@ -355,25 +342,16 @@ namespace GradientSignal
{
if (m_dirty)
{
const auto configurationOld = m_configuration;
const auto shapeBoundsOld = m_shapeBounds;
const auto shapeTransformInverseOld = m_shapeTransformInverse;
// Updating on tick to query transform bus on main thread.
// Also, if the GradientTransform configuration changes, notify listeners so they can refresh themselves.
const bool notifyDependentsOfChange = true;
UpdateFromShape(notifyDependentsOfChange);
//updating on tick to query transform bus on main thread
UpdateFromShape();
//notify observers if content has changed
if (configurationOld != m_configuration ||
shapeBoundsOld != m_shapeBounds ||
shapeTransformInverseOld != m_shapeTransformInverse)
{
LmbrCentral::DependencyNotificationBus::Event(GetEntityId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
}
m_dirty = false;
}
}
void GradientTransformComponent::UpdateFromShape()
void GradientTransformComponent::UpdateFromShape(bool notifyDependentsOfChange)
{
AZ_PROFILE_FUNCTION(Entity);
@@ -385,6 +363,10 @@ namespace GradientSignal
return;
}
const GradientTransform oldGradientTransform = m_gradientTransform;
AZ::Aabb shapeBounds = AZ::Aabb::CreateNull();
AZ::Matrix3x4 shapeTransformInverse = AZ::Matrix3x4::CreateIdentity();
AZ::Transform shapeTransform = AZ::Transform::CreateIdentity();
switch (m_configuration.m_transformType)
{
@@ -428,10 +410,10 @@ namespace GradientSignal
if (!m_configuration.m_advancedMode || !m_configuration.m_overrideBounds)
{
// If we have a shape reference, grab its local space bounds and (inverse) transform into that local space
GetObbParamsFromShape(shapeReference, m_shapeBounds, m_shapeTransformInverse);
if (m_shapeBounds.IsValid())
GetObbParamsFromShape(shapeReference, shapeBounds, shapeTransformInverse);
if (shapeBounds.IsValid())
{
m_configuration.m_bounds = m_shapeBounds.GetExtents();
m_configuration.m_bounds = shapeBounds.GetExtents();
}
}
@@ -453,19 +435,34 @@ namespace GradientSignal
//rebuild bounds from parameters
m_configuration.m_bounds = m_configuration.m_bounds.GetAbs();
m_shapeBounds = AZ::Aabb::CreateFromMinMax(-m_configuration.m_bounds * 0.5f, m_configuration.m_bounds * 0.5f);
shapeBounds = AZ::Aabb::CreateFromMinMax(-m_configuration.m_bounds * 0.5f, m_configuration.m_bounds * 0.5f);
//rebuild transform from parameters
AZ::Matrix3x4 shapeTransformFinal;
shapeTransformFinal.SetFromEulerDegrees(m_configuration.m_rotate);
shapeTransformFinal.SetTranslation(m_configuration.m_translate);
shapeTransformFinal.MultiplyByScale(m_configuration.m_scale);
m_shapeTransformInverse = shapeTransformFinal.GetInverseFull();
shapeTransformInverse = shapeTransformFinal.GetInverseFull();
// Set everything up on the Gradient Transform
const bool use3dGradients = m_configuration.m_advancedMode && m_configuration.m_is3d;
m_gradientTransform = GradientTransform(
m_shapeBounds, shapeTransformFinal, use3dGradients, m_configuration.m_frequencyZoom, m_configuration.m_wrappingType);
shapeBounds, shapeTransformFinal, use3dGradients, m_configuration.m_frequencyZoom, m_configuration.m_wrappingType);
// If the transform has changed, send out notifications.
if (oldGradientTransform != m_gradientTransform)
{
// Always notify on the GradientTransformNotificationBus.
GradientTransformNotificationBus::Event(
GetEntityId(), &GradientTransformNotificationBus::Events::OnGradientTransformChanged, m_gradientTransform);
// Only notify the DependencyNotificationBus when requested by the caller.
if (notifyDependentsOfChange)
{
LmbrCentral::DependencyNotificationBus::Event(
GetEntityId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
}
}
}
AZ::EntityId GradientTransformComponent::GetShapeEntityId() const
@@ -101,10 +101,7 @@ namespace GradientSignal
//////////////////////////////////////////////////////////////////////////
// GradientTransformRequestBus
void TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const override;
void TransformPositionToUVWNormalized(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const override;
void GetGradientLocalBounds(AZ::Aabb& bounds) const override;
void GetGradientEncompassingBounds(AZ::Aabb& bounds) const override;
const GradientTransform& GetGradientTransform() const override;
//////////////////////////////////////////////////////////////////////////
// DependencyNotificationBus
@@ -114,7 +111,7 @@ namespace GradientSignal
// AZ::TickBus::Handler
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
void UpdateFromShape();
void UpdateFromShape(bool notifyDependentsOfChange);
AZ::EntityId GetShapeEntityId() const;
@@ -169,8 +166,6 @@ namespace GradientSignal
private:
mutable AZStd::recursive_mutex m_cacheMutex;
GradientTransformConfig m_configuration;
AZ::Aabb m_shapeBounds = AZ::Aabb::CreateNull();
AZ::Matrix3x4 m_shapeTransformInverse = AZ::Matrix3x4::CreateIdentity();
LmbrCentral::DependencyMonitor m_dependencyMonitor;
AZStd::atomic_bool m_dirty{ false };
GradientTransform m_gradientTransform;
@@ -129,6 +129,9 @@ namespace GradientSignal
void ImageGradientComponent::Activate()
{
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
SetupDependencies();
ImageGradientRequestBus::Handler::BusConnect(GetEntityId());
@@ -144,6 +147,7 @@ namespace GradientSignal
AZ::Data::AssetBus::Handler::BusDisconnect();
GradientRequestBus::Handler::BusDisconnect();
ImageGradientRequestBus::Handler::BusDisconnect();
GradientTransformNotificationBus::Handler::BusDisconnect();
m_dependencyMonitor.Reset();
@@ -189,18 +193,27 @@ namespace GradientSignal
m_configuration.m_imageAsset = asset;
}
void ImageGradientComponent::OnGradientTransformChanged(const GradientTransform& newTransform)
{
AZStd::unique_lock<decltype(m_imageMutex)> lock(m_imageMutex);
m_gradientTransform = newTransform;
}
float ImageGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
AZ::Vector3 uvw = sampleParams.m_position;
bool wasPointRejected = false;
GradientTransformRequestBus::Event(
GetEntityId(), &GradientTransformRequestBus::Events::TransformPositionToUVWNormalized, sampleParams.m_position, uvw, wasPointRejected);
if (!wasPointRejected)
{
AZStd::shared_lock<decltype(m_imageMutex)> imageLock(m_imageMutex);
return GetValueFromImageAsset(m_configuration.m_imageAsset, uvw, m_configuration.m_tilingX, m_configuration.m_tilingY, 0.0f);
m_gradientTransform.TransformPositionToUVWNormalized(sampleParams.m_position, uvw, wasPointRejected);
if (!wasPointRejected)
{
return GetValueFromImageAsset(
m_configuration.m_imageAsset, uvw, m_configuration.m_tilingX, m_configuration.m_tilingY, 0.0f);
}
}
return 0.0f;
@@ -11,6 +11,7 @@
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
#include <GradientSignal/Ebuses/ImageGradientRequestBus.h>
#include <GradientSignal/ImageAsset.h>
#include <GradientSignal/Util.h>
@@ -46,6 +47,7 @@ namespace GradientSignal
, private AZ::Data::AssetBus::Handler
, private GradientRequestBus::Handler
, private ImageGradientRequestBus::Handler
, private GradientTransformNotificationBus::Handler
{
public:
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
@@ -59,29 +61,27 @@ namespace GradientSignal
ImageGradientComponent() = default;
~ImageGradientComponent() = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
// AZ::Component overrides...
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
// GradientRequestBus overrides...
float GetValue(const GradientSampleParams& sampleParams) const override;
//////////////////////////////////////////////////////////////////////////
// AZ::Data::AssetBus::Handler
// AZ::Data::AssetBus overrides...
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void OnAssetMoved(AZ::Data::Asset<AZ::Data::AssetData> asset, void* oldDataPointer) override;
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
protected:
// GradientTransformNotificationBus overrides...
void OnGradientTransformChanged(const GradientTransform& newTransform) override;
void SetupDependencies();
//////////////////////////////////////////////////////////////////////////
// ImageGradientRequestBus
// ImageGradientRequestBus overrides...
AZStd::string GetImageAssetPath() const override;
void SetImageAssetPath(const AZStd::string& assetPath) override;
@@ -95,5 +95,6 @@ namespace GradientSignal
ImageGradientConfig m_configuration;
LmbrCentral::DependencyMonitor m_dependencyMonitor;
mutable AZStd::shared_mutex m_imageMutex;
GradientTransform m_gradientTransform;
};
}
@@ -138,6 +138,9 @@ namespace GradientSignal
void PerlinGradientComponent::Activate()
{
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
m_perlinImprovedNoise.reset(aznew PerlinImprovedNoise(AZ::GetMax(m_configuration.m_randomSeed, 1)));
GradientRequestBus::Handler::BusConnect(GetEntityId());
PerlinGradientRequestBus::Handler::BusConnect(GetEntityId());
@@ -148,6 +151,7 @@ namespace GradientSignal
m_perlinImprovedNoise.reset();
GradientRequestBus::Handler::BusDisconnect();
PerlinGradientRequestBus::Handler::BusDisconnect();
GradientTransformNotificationBus::Handler::BusDisconnect();
}
bool PerlinGradientComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
@@ -170,21 +174,29 @@ namespace GradientSignal
return false;
}
void PerlinGradientComponent::OnGradientTransformChanged(const GradientTransform& newTransform)
{
AZStd::unique_lock<decltype(m_transformMutex)> lock(m_transformMutex);
m_gradientTransform = newTransform;
}
float PerlinGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
AZ_PROFILE_FUNCTION(Entity);
if (m_perlinImprovedNoise)
{
AZ::Vector3 uvw = sampleParams.m_position;
bool wasPointRejected = false;
GradientTransformRequestBus::Event(
GetEntityId(), &GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, wasPointRejected);
{
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
}
if (!wasPointRejected)
{
return m_perlinImprovedNoise->GenerateOctaveNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ(), m_configuration.m_octave, m_configuration.m_amplitude, m_configuration.m_frequency);
return m_perlinImprovedNoise->GenerateOctaveNoise(
uvw.GetX(), uvw.GetY(), uvw.GetZ(), m_configuration.m_octave, m_configuration.m_amplitude,
m_configuration.m_frequency);
}
}
@@ -12,6 +12,7 @@
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
#include <GradientSignal/Ebuses/PerlinGradientRequestBus.h>
#include <GradientSignal/PerlinImprovedNoise.h>
@@ -47,6 +48,7 @@ namespace GradientSignal
: public AZ::Component
, private GradientRequestBus::Handler
, private PerlinGradientRequestBus::Handler
, private GradientTransformNotificationBus::Handler
{
public:
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
@@ -60,23 +62,25 @@ namespace GradientSignal
PerlinGradientComponent() = default;
~PerlinGradientComponent() = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
// AZ::Component overrides...
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
// GradientRequestBus overrides...
float GetValue(const GradientSampleParams& sampleParams) const override;
private:
PerlinGradientConfig m_configuration;
AZStd::unique_ptr<PerlinImprovedNoise> m_perlinImprovedNoise;
GradientTransform m_gradientTransform;
mutable AZStd::shared_mutex m_transformMutex;
/////////////////////////////////////////////////////////////////////////
//PerlinGradientRequest overrides
// GradientTransformNotificationBus overrides...
void OnGradientTransformChanged(const GradientTransform& newTransform) override;
// PerlinGradientRequestBus overrides...
int GetRandomSeed() const override;
void SetRandomSeed(int seed) override;
@@ -105,6 +105,9 @@ namespace GradientSignal
void RandomGradientComponent::Activate()
{
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
GradientRequestBus::Handler::BusConnect(GetEntityId());
RandomGradientRequestBus::Handler::BusConnect(GetEntityId());
}
@@ -113,6 +116,7 @@ namespace GradientSignal
{
GradientRequestBus::Handler::BusDisconnect();
RandomGradientRequestBus::Handler::BusDisconnect();
GradientTransformNotificationBus::Handler::BusDisconnect();
}
bool RandomGradientComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
@@ -135,15 +139,22 @@ namespace GradientSignal
return false;
}
void RandomGradientComponent::OnGradientTransformChanged(const GradientTransform& newTransform)
{
AZStd::unique_lock<decltype(m_transformMutex)> lock(m_transformMutex);
m_gradientTransform = newTransform;
}
float RandomGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
{
AZ_PROFILE_FUNCTION(Entity);
AZ::Vector3 uvw = sampleParams.m_position;
bool wasPointRejected = false;
GradientTransformRequestBus::Event(
GetEntityId(), &GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, wasPointRejected);
{
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
}
if (!wasPointRejected)
{
@@ -10,6 +10,7 @@
#include <AzCore/Component/Component.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
#include <GradientSignal/Ebuses/RandomGradientRequestBus.h>
namespace LmbrCentral
@@ -38,6 +39,7 @@ namespace GradientSignal
: public AZ::Component
, private GradientRequestBus::Handler
, private RandomGradientRequestBus::Handler
, private GradientTransformNotificationBus::Handler
{
public:
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
@@ -51,22 +53,24 @@ namespace GradientSignal
RandomGradientComponent() = default;
~RandomGradientComponent() = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
// AZ::Component overrides...
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// GradientRequestBus
// GradientRequestBus overrides...
float GetValue(const GradientSampleParams& sampleParams) const override;
private:
RandomGradientConfig m_configuration;
GradientTransform m_gradientTransform;
mutable AZStd::shared_mutex m_transformMutex;
/////////////////////////////////////////////////////////////////////////
// RandomGradientRequest overrides
// GradientTransformNotificationBus overrides...
void OnGradientTransformChanged(const GradientTransform& newTransform) override;
// RandomGradientRequestBus overrides...
int GetRandomSeed() const override;
void SetRandomSeed(int seed) override;
};
@@ -55,9 +55,13 @@ namespace GradientSignal
void EditorGradientTransformComponent::UpdateFromShape()
{
// Update config from shape on game component, copy that back to our config
m_component.UpdateFromShape();
m_component.WriteOutConfig(&m_configuration);
SetDirty();
if (m_runtimeComponentActive)
{
// Update config from shape on game component, copy that back to our config.
bool notifyDependentsOfChange = true;
m_component.UpdateFromShape(notifyDependentsOfChange);
m_component.WriteOutConfig(&m_configuration);
SetDirty();
}
}
} //namespace GradientSignal
@@ -20,7 +20,6 @@ namespace GradientSignal
, m_inverseTransform(transform.GetInverseFull())
, m_frequencyZoom(frequencyZoom)
, m_wrappingType(wrappingType)
, m_wrappingTransform(NoTransform)
, m_alwaysAcceptPoint(true)
{
// If we want this to be a 2D gradient lookup, we always want to set the W result in the output to 0.
@@ -30,31 +29,17 @@ namespace GradientSignal
m_inverseTransform.SetRow(2, AZ::Vector4::CreateZero());
}
// Set up the appropriate wrapping transform function for the the given wrapping type.
// Also note that ClampToZero is the only wrapping type that allows us to return a "pointIsRejected" result
// for points that fall outside the shape bounds.
if (m_shapeBounds.IsValid())
// If we have invalid shape bounds, reset the wrapping type back to None. Wrapping won't work without valid bounds.
if (!m_shapeBounds.IsValid())
{
switch (wrappingType)
{
default:
case WrappingType::None:
m_wrappingTransform = GetUnboundedPointInAabb;
break;
case WrappingType::ClampToEdge:
m_wrappingTransform = GetClampedPointInAabb;
break;
case WrappingType::ClampToZero:
m_alwaysAcceptPoint = false;
m_wrappingTransform = GetClampedPointInAabb;
break;
case WrappingType::Mirror:
m_wrappingTransform = GetMirroredPointInAabb;
break;
case WrappingType::Repeat:
m_wrappingTransform = GetWrappedPointInAabb;
break;
}
m_wrappingType = WrappingType::None;
}
// ClampToZero is the only wrapping type that allows us to return a "pointIsRejected" result for points that fall
// outside the shape bounds.
if (m_wrappingType == WrappingType::ClampToZero)
{
m_alwaysAcceptPoint = false;
}
m_normalizeExtentsReciprocal = AZ::Vector3(
@@ -76,7 +61,26 @@ namespace GradientSignal
(outUVW.IsGreaterEqualThan(m_shapeBounds.GetMin()) && outUVW.IsLessThan(m_shapeBounds.GetMax()));
wasPointRejected = !wasPointAccepted;
outUVW = m_wrappingTransform(outUVW, m_shapeBounds);
switch (m_wrappingType)
{
default:
case WrappingType::None:
outUVW = GetUnboundedPointInAabb(outUVW, m_shapeBounds);
break;
case WrappingType::ClampToEdge:
outUVW = GetClampedPointInAabb(outUVW, m_shapeBounds);
break;
case WrappingType::ClampToZero:
outUVW = GetClampedPointInAabb(outUVW, m_shapeBounds);
break;
case WrappingType::Mirror:
outUVW = GetMirroredPointInAabb(outUVW, m_shapeBounds);
break;
case WrappingType::Repeat:
outUVW = GetWrappedPointInAabb(outUVW, m_shapeBounds);
break;
}
outUVW *= m_frequencyZoom;
}
@@ -121,7 +125,7 @@ namespace GradientSignal
* [min, max) : value
* [max, min) : max - value - epsilon
* ...
* The epsilon is because we always want to keep our output values in the [min, max) range. We apply the epsilon to all
* The epsilon is because we always want to keep our output values in the [min, max) range. We apply the epsilon to all
* the mirrored values so that we get consistent spacing between the values.
*/
@@ -255,6 +255,8 @@ namespace Terrain
void TerrainPhysicsColliderComponent::GenerateHeightsInBounds(AZStd::vector<float>& heights) const
{
AZ_PROFILE_FUNCTION(Entity);
const AZ::Vector2 gridResolution = GetHeightfieldGridSpacing();
AZ::Aabb worldSize = GetHeightfieldAabb();
@@ -315,6 +317,8 @@ namespace Terrain
void TerrainPhysicsColliderComponent::GenerateHeightsAndMaterialsInBounds(
AZStd::vector<Physics::HeightMaterialPoint>& heightMaterials) const
{
AZ_PROFILE_FUNCTION(Entity);
const AZ::Vector2 gridResolution = GetHeightfieldGridSpacing();
AZ::Aabb worldSize = GetHeightfieldAabb();
@@ -105,11 +105,13 @@ void TerrainSystem::Activate()
void TerrainSystem::Deactivate()
{
// Stop listening to the bus even before we signal DestroyBegin so that way any calls to the terrain system as a *result* of
// calling DestroyBegin will fail to reach the terrain system.
AzFramework::Terrain::TerrainDataRequestBus::Handler::BusDisconnect();
AzFramework::Terrain::TerrainDataNotificationBus::Broadcast(
&AzFramework::Terrain::TerrainDataNotificationBus::Events::OnTerrainDataDestroyBegin);
AzFramework::Terrain::TerrainDataRequestBus::Handler::BusDisconnect();
{
AZStd::unique_lock<AZStd::shared_mutex> lock(m_areaMutex);
m_registeredAreas.clear();