From 48260486fb606020f4715f4299e46b26faa0c0cd Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 30 Dec 2021 12:43:00 -0600 Subject: [PATCH] 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> --- .../Source/FastNoiseGradientComponent.cpp | 18 +++- .../Code/Source/FastNoiseGradientComponent.h | 16 ++-- Gems/FastNoise/Code/Tests/FastNoiseTest.cpp | 13 +-- .../Ebuses/GradientTransformRequestBus.h | 51 +++++++++-- .../GradientSignal/GradientTransform.h | 2 - .../Components/GradientTransformComponent.cpp | 85 +++++++++---------- .../Components/GradientTransformComponent.h | 9 +- .../Components/ImageGradientComponent.cpp | 23 +++-- .../Components/ImageGradientComponent.h | 17 ++-- .../Components/PerlinGradientComponent.cpp | 24 ++++-- .../Components/PerlinGradientComponent.h | 16 ++-- .../Components/RandomGradientComponent.cpp | 19 ++++- .../Components/RandomGradientComponent.h | 16 ++-- .../EditorGradientTransformComponent.cpp | 12 ++- .../Code/Source/GradientTransform.cpp | 58 +++++++------ .../TerrainPhysicsColliderComponent.cpp | 4 + .../Source/TerrainSystem/TerrainSystem.cpp | 6 +- 17 files changed, 245 insertions(+), 144 deletions(-) diff --git a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp index bb4c337299..4cea2efcc8 100644 --- a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp +++ b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp @@ -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 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 lock(m_transformMutex); + m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected); + } if (!wasPointRejected) { diff --git a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h index da972743ec..dd19049ee6 100644 --- a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h +++ b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp b/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp index 620f538c71..f0d5a9d1bd 100644 --- a/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp +++ b/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp @@ -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) diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientTransformRequestBus.h b/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientTransformRequestBus.h index ac2f1a9cb1..3b674d0bd5 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientTransformRequestBus.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientTransformRequestBus.h @@ -11,6 +11,7 @@ #include #include #include +#include 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; + + /** + * 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 + struct ConnectionPolicy : public AZ::EBusConnectionPolicy + { + 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::Connect(busPtr, context, handler, connectLock, id); + + GradientTransform transform; + GradientTransformRequestBus::EventResult(transform, id, &GradientTransformRequests::GetGradientTransform); + handler->OnGradientTransformChanged(transform); + } + }; + }; + + using GradientTransformNotificationBus = AZ::EBus; + } //namespace GradientSignal diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/GradientTransform.h b/Gems/GradientSignal/Code/Include/GradientSignal/GradientTransform.h index c8073c2f4f..b191ea245a 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/GradientTransform.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/GradientTransform.h @@ -111,7 +111,6 @@ namespace GradientSignal private: //! These are the various transformations that will be performed, based on wrapping type. - using WrappingTransformFunction = AZStd::function; 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. diff --git a/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.cpp b/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.cpp index 8cd7dc56a1..5b2ce4d4cf 100644 --- a/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.cpp @@ -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 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 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 diff --git a/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.h b/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.h index 50ae6fe475..805fba9e74 100644 --- a/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.h +++ b/Gems/GradientSignal/Code/Source/Components/GradientTransformComponent.h @@ -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; diff --git a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp index 2d594a201c..4bf709755b 100644 --- a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp @@ -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 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 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; diff --git a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.h b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.h index e73c8d0c4a..8214436f83 100644 --- a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.h +++ b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ namespace GradientSignal , private AZ::Data::AssetBus::Handler , private GradientRequestBus::Handler , private ImageGradientRequestBus::Handler + , private GradientTransformNotificationBus::Handler { public: template 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 asset) override; void OnAssetMoved(AZ::Data::Asset asset, void* oldDataPointer) override; void OnAssetReloaded(AZ::Data::Asset 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; }; } diff --git a/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp index d5e846b9ef..8f9d40387b 100644 --- a/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp @@ -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 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 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); } } diff --git a/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.h b/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.h index 9fda45c716..ef171f5319 100644 --- a/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.h +++ b/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,7 @@ namespace GradientSignal : public AZ::Component , private GradientRequestBus::Handler , private PerlinGradientRequestBus::Handler + , private GradientTransformNotificationBus::Handler { public: template 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 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; diff --git a/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp index d320dbeb3d..fc2ccbef70 100644 --- a/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp @@ -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 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 lock(m_transformMutex); + m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected); + } if (!wasPointRejected) { diff --git a/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.h b/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.h index 299b9dadfe..b0dbd964a0 100644 --- a/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.h +++ b/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace LmbrCentral @@ -38,6 +39,7 @@ namespace GradientSignal : public AZ::Component , private GradientRequestBus::Handler , private RandomGradientRequestBus::Handler + , private GradientTransformNotificationBus::Handler { public: template 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; }; diff --git a/Gems/GradientSignal/Code/Source/Editor/EditorGradientTransformComponent.cpp b/Gems/GradientSignal/Code/Source/Editor/EditorGradientTransformComponent.cpp index 4517c30711..850faf19df 100644 --- a/Gems/GradientSignal/Code/Source/Editor/EditorGradientTransformComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Editor/EditorGradientTransformComponent.cpp @@ -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 diff --git a/Gems/GradientSignal/Code/Source/GradientTransform.cpp b/Gems/GradientSignal/Code/Source/GradientTransform.cpp index acf9e2f150..ffaa8f7e6a 100644 --- a/Gems/GradientSignal/Code/Source/GradientTransform.cpp +++ b/Gems/GradientSignal/Code/Source/GradientTransform.cpp @@ -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. */ diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 1299403659..8c2c0e80b6 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -255,6 +255,8 @@ namespace Terrain void TerrainPhysicsColliderComponent::GenerateHeightsInBounds(AZStd::vector& 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& heightMaterials) const { + AZ_PROFILE_FUNCTION(Entity); + const AZ::Vector2 gridResolution = GetHeightfieldGridSpacing(); AZ::Aabb worldSize = GetHeightfieldAabb(); diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index 1b2dedd469..7c8b6021af 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -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 lock(m_areaMutex); m_registeredAreas.clear();