Преглед на файлове

[LYN-3099] Fixed some issues with vegetation planting on surfaces (#1554)

* [LYN-3099] Fix vegetation raycasts to use bounded ray queries instead of FLT_MAX.
Raycasts with a distance of FLT_MAX sometimes overflowed deep in IntersectSegmentTriangleCCW, so it's better to have strict start/end positional queries.  We have specific starts and ends anyways, so it's a safer approach anyways.
This also adds support for Non-Uniform Scale for meshes, since it was clearly not working correctly in vegetation when testing various scaled meshes.

* Addressed PR feedback
Mike Balfour преди 4 години
родител
ревизия
c873ddac45

+ 17 - 3
Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp

@@ -73,8 +73,14 @@ namespace SurfaceData
         }
         }
     }
     }
 
 
+    SurfaceDataMeshComponent::SurfaceDataMeshComponent()
+        : m_nonUniformScaleChangedHandler([this]([[maybe_unused]] const AZ::Vector3& scale) { this->OnCompositionChanged(); })
+    {
+    }
+
     SurfaceDataMeshComponent::SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration)
     SurfaceDataMeshComponent::SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration)
         : m_configuration(configuration)
         : m_configuration(configuration)
+        , m_nonUniformScaleChangedHandler([this]([[maybe_unused]] const AZ::Vector3& scale) { this->OnCompositionChanged(); })
     {
     {
     }
     }
 
 
@@ -83,6 +89,9 @@ namespace SurfaceData
         AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
         AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
         AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
         AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
 
 
+        AZ::NonUniformScaleRequestBus::Event(
+            GetEntityId(), &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, m_nonUniformScaleChangedHandler);
+
         m_providerHandle = InvalidSurfaceDataRegistryHandle;
         m_providerHandle = InvalidSurfaceDataRegistryHandle;
         m_refresh = false;
         m_refresh = false;
 
 
@@ -98,6 +107,7 @@ namespace SurfaceData
             m_providerHandle = InvalidSurfaceDataRegistryHandle;
             m_providerHandle = InvalidSurfaceDataRegistryHandle;
         }
         }
 
 
+        m_nonUniformScaleChangedHandler.Disconnect();
         SurfaceDataProviderRequestBus::Handler::BusDisconnect();
         SurfaceDataProviderRequestBus::Handler::BusDisconnect();
         AZ::TickBus::Handler::BusDisconnect();
         AZ::TickBus::Handler::BusDisconnect();
         AZ::TransformNotificationBus::Handler::BusDisconnect();
         AZ::TransformNotificationBus::Handler::BusDisconnect();
@@ -157,9 +167,10 @@ namespace SurfaceData
             return false;
             return false;
         }
         }
 
 
-        const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
-        const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
-        return GetMeshRayIntersection(*mesh, m_meshWorldTM, m_meshWorldTMInverse, rayOrigin, rayDirection, outPosition, outNormal);
+        const AZ::Vector3 rayStart = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
+        const AZ::Vector3 rayEnd = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMin().GetZ() - s_rayAABBHeightPadding);
+        return GetMeshRayIntersection(
+            *mesh, m_meshWorldTM, m_meshWorldTMInverse, m_meshNonUniformScale, rayStart, rayEnd, outPosition, outNormal);
     }
     }
 
 
 
 
@@ -241,6 +252,9 @@ namespace SurfaceData
             AZ::TransformBus::EventResult(m_meshWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
             AZ::TransformBus::EventResult(m_meshWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
             m_meshWorldTMInverse = m_meshWorldTM.GetInverse();
             m_meshWorldTMInverse = m_meshWorldTM.GetInverse();
 
 
+            m_meshNonUniformScale = AZ::Vector3::CreateOne();
+            AZ::NonUniformScaleRequestBus::EventResult(m_meshNonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
+
             meshValidAfterUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
             meshValidAfterUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
         }
         }
 
 

+ 5 - 1
Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.h

@@ -9,6 +9,7 @@
 
 
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Component/Component.h>
 #include <AzCore/Component/Component.h>
+#include <AzCore/Component/NonUniformScaleBus.h>
 #include <AzCore/Component/TickBus.h>
 #include <AzCore/Component/TickBus.h>
 #include <AzCore/Component/TransformBus.h>
 #include <AzCore/Component/TransformBus.h>
 #include <AzCore/std/containers/unordered_map.h>
 #include <AzCore/std/containers/unordered_map.h>
@@ -52,7 +53,7 @@ namespace SurfaceData
         static void Reflect(AZ::ReflectContext* context);
         static void Reflect(AZ::ReflectContext* context);
 
 
         SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration);
         SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration);
-        SurfaceDataMeshComponent() = default;
+        SurfaceDataMeshComponent();
         ~SurfaceDataMeshComponent() = default;
         ~SurfaceDataMeshComponent() = default;
 
 
         //////////////////////////////////////////////////////////////////////////
         //////////////////////////////////////////////////////////////////////////
@@ -86,6 +87,8 @@ namespace SurfaceData
         AZ::Aabb GetSurfaceAabb() const;
         AZ::Aabb GetSurfaceAabb() const;
         SurfaceTagVector GetSurfaceTags() const;
         SurfaceTagVector GetSurfaceTags() const;
 
 
+        AZ::NonUniformScaleChangedEvent::Handler m_nonUniformScaleChangedHandler; ///< Responds to changes in non-uniform scale.
+
         SurfaceDataMeshConfig m_configuration;
         SurfaceDataMeshConfig m_configuration;
 
 
         SurfaceDataRegistryHandle m_providerHandle = InvalidSurfaceDataRegistryHandle;
         SurfaceDataRegistryHandle m_providerHandle = InvalidSurfaceDataRegistryHandle;
@@ -96,6 +99,7 @@ namespace SurfaceData
         AZ::Data::Asset<AZ::Data::AssetData> m_meshAssetData;
         AZ::Data::Asset<AZ::Data::AssetData> m_meshAssetData;
         AZ::Transform m_meshWorldTM = AZ::Transform::CreateIdentity();
         AZ::Transform m_meshWorldTM = AZ::Transform::CreateIdentity();
         AZ::Transform m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
         AZ::Transform m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
+        AZ::Vector3 m_meshNonUniformScale = AZ::Vector3::CreateOne();
         AZ::Aabb m_meshBounds = AZ::Aabb::CreateNull();
         AZ::Aabb m_meshBounds = AZ::Aabb::CreateNull();
     };
     };
 }
 }

+ 3 - 3
Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h

@@ -83,9 +83,9 @@ namespace SurfaceData
 
 
     bool GetMeshRayIntersection(
     bool GetMeshRayIntersection(
         const AZ::RPI::ModelAsset& meshAsset, const AZ::Transform& meshTransform,
         const AZ::RPI::ModelAsset& meshAsset, const AZ::Transform& meshTransform,
-        const AZ::Transform& meshTransformInverse, const AZ::Vector3& rayOrigin,
-        const AZ::Vector3& rayDirection, AZ::Vector3& outPosition,
-        AZ::Vector3& outNormal);
+        const AZ::Transform& meshTransformInverse, const AZ::Vector3& nonUniformScale,
+        const AZ::Vector3& rayStart, const AZ::Vector3& rayEnd,
+        AZ::Vector3& outPosition, AZ::Vector3& outNormal);
 
 
     AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& masks, const AZ::Crc32 tag, const float value)
     AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& masks, const AZ::Crc32 tag, const float value)
     {
     {

+ 13 - 8
Gems/SurfaceData/Code/Source/SurfaceDataUtility.cpp

@@ -11,23 +11,28 @@
 namespace SurfaceData
 namespace SurfaceData
 {
 {
     bool GetMeshRayIntersection(
     bool GetMeshRayIntersection(
-        const AZ::RPI::ModelAsset& meshAsset, const AZ::Transform& meshTransform, const AZ::Transform& meshTransformInverse,
-        const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, AZ::Vector3& outPosition, AZ::Vector3& outNormal)
+        const AZ::RPI::ModelAsset& meshAsset, const AZ::Transform& meshTransform,
+        const AZ::Transform& meshTransformInverse, const AZ::Vector3& nonUniformScale,
+        const AZ::Vector3& rayStart, const AZ::Vector3& rayEnd, 
+        AZ::Vector3& outPosition, AZ::Vector3& outNormal)
     {
     {
         AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
         AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
 
 
+        const AZ::Vector3 clampedScale = nonUniformScale.GetMax(AZ::Vector3(AZ::MinTransformScale));
+
         // Transform everything into model space
         // Transform everything into model space
-        const AZ::Vector3 rayOriginLocal = meshTransformInverse.TransformPoint(rayOrigin);
-        const AZ::Vector3 rayDirectionLocal = meshTransformInverse.TransformVector(rayDirection).GetNormalized();
-        float distance = FLT_MAX;
+        const AZ::Vector3 rayStartLocal = meshTransformInverse.TransformPoint(rayStart) / clampedScale;
+        const AZ::Vector3 rayEndLocal = meshTransformInverse.TransformPoint(rayEnd) / clampedScale;
+        const AZ::Vector3 rayDirectionLocal = (rayEndLocal - rayStartLocal).GetNormalized();
+        float distance = rayEndLocal.GetDistance(rayStartLocal);
 
 
         AZ::Vector3 normalLocal;
         AZ::Vector3 normalLocal;
 
 
-        if (meshAsset.LocalRayIntersectionAgainstModel(rayOriginLocal, rayDirectionLocal, distance, normalLocal))
+        if (meshAsset.LocalRayIntersectionAgainstModel(rayStartLocal, rayDirectionLocal, distance, normalLocal))
         {
         {
             // Transform everything back to world space
             // Transform everything back to world space
-            outPosition = meshTransform.TransformPoint(rayOriginLocal + (rayDirectionLocal * distance));
-            outNormal = meshTransform.TransformVector(normalLocal);
+            outPosition = meshTransform.TransformPoint((rayStartLocal + (rayDirectionLocal * distance)) * clampedScale);
+            outNormal = meshTransform.TransformVector(normalLocal * clampedScale);
             return true;
             return true;
         }
         }
 
 

+ 20 - 5
Gems/Vegetation/Code/Source/Components/MeshBlockerComponent.cpp

@@ -129,9 +129,16 @@ namespace Vegetation
         }
         }
     }
     }
 
 
+    MeshBlockerComponent::MeshBlockerComponent()
+        : AreaComponentBase()
+        , m_nonUniformScaleChangedHandler([this]([[maybe_unused]] const AZ::Vector3& scale) { this->OnCompositionChanged(); })
+    {
+    }
+
     MeshBlockerComponent::MeshBlockerComponent(const MeshBlockerConfig& configuration)
     MeshBlockerComponent::MeshBlockerComponent(const MeshBlockerConfig& configuration)
         : AreaComponentBase(configuration)
         : AreaComponentBase(configuration)
         , m_configuration(configuration)
         , m_configuration(configuration)
+        , m_nonUniformScaleChangedHandler([this]([[maybe_unused]] const AZ::Vector3& scale) { this->OnCompositionChanged(); })
     {
     {
     }
     }
 
 
@@ -139,6 +146,9 @@ namespace Vegetation
     {
     {
         AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
         AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
 
 
+        AZ::NonUniformScaleRequestBus::Event(
+            GetEntityId(), &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, m_nonUniformScaleChangedHandler);
+
         UpdateMeshData();
         UpdateMeshData();
         m_refresh = false;
         m_refresh = false;
 
 
@@ -153,6 +163,7 @@ namespace Vegetation
     {
     {
         AreaComponentBase::Deactivate(); //must deactivate base first to ensure AreaRequestBus disconnect waits for other threads
         AreaComponentBase::Deactivate(); //must deactivate base first to ensure AreaRequestBus disconnect waits for other threads
 
 
+        m_nonUniformScaleChangedHandler.Disconnect();
         SurfaceData::SurfaceDataSystemNotificationBus::Handler::BusDisconnect();
         SurfaceData::SurfaceDataSystemNotificationBus::Handler::BusDisconnect();
 
 
         m_refresh = false;
         m_refresh = false;
@@ -260,9 +271,10 @@ namespace Vegetation
 
 
         AZ::Vector3 outPosition;
         AZ::Vector3 outPosition;
         AZ::Vector3 outNormal;
         AZ::Vector3 outNormal;
-        const AZ::Vector3 rayOrigin(point.m_position.GetX(), point.m_position.GetY(), m_meshBoundsForIntersection.GetMax().GetZ());
-        const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
-        bool intersected = SurfaceData::GetMeshRayIntersection(*mesh, m_meshWorldTM, m_meshWorldTMInverse, rayOrigin, rayDirection, outPosition, outNormal) &&
+        const AZ::Vector3 rayStart(point.m_position.GetX(), point.m_position.GetY(), m_meshBoundsForIntersection.GetMax().GetZ());
+        const AZ::Vector3 rayEnd(point.m_position.GetX(), point.m_position.GetY(), m_meshBoundsForIntersection.GetMin().GetZ());
+        bool intersected = SurfaceData::GetMeshRayIntersection(
+            *mesh, m_meshWorldTM, m_meshWorldTMInverse, m_meshNonUniformScale, rayStart, rayEnd, outPosition, outNormal) &&
             m_meshBoundsForIntersection.Contains(outPosition);
             m_meshBoundsForIntersection.Contains(outPosition);
         m_cachedRayHits[point.m_handle] = intersected;
         m_cachedRayHits[point.m_handle] = intersected;
         return intersected;
         return intersected;
@@ -377,10 +389,10 @@ namespace Vegetation
                 m_meshBoundsForIntersection.GetMin().GetZ() + m_meshBoundsForIntersection.GetExtents().GetZ() * m_configuration.m_meshHeightPercentMax);
                 m_meshBoundsForIntersection.GetMin().GetZ() + m_meshBoundsForIntersection.GetExtents().GetZ() * m_configuration.m_meshHeightPercentMax);
 
 
             AZ::Vector3 cornerMin = m_meshBoundsForIntersection.GetMin();
             AZ::Vector3 cornerMin = m_meshBoundsForIntersection.GetMin();
-            cornerMin.SetZ(heights.first);
+            cornerMin.SetZ(heights.first - s_rayAABBHeightPadding);
 
 
             AZ::Vector3 cornerMax = m_meshBoundsForIntersection.GetMax();
             AZ::Vector3 cornerMax = m_meshBoundsForIntersection.GetMax();
-            cornerMax.SetZ(heights.second);
+            cornerMax.SetZ(heights.second + s_rayAABBHeightPadding);
 
 
             m_meshBoundsForIntersection.Set(cornerMin, cornerMax);
             m_meshBoundsForIntersection.Set(cornerMin, cornerMax);
         }
         }
@@ -392,6 +404,9 @@ namespace Vegetation
         AZ::TransformBus::EventResult(m_meshWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
         AZ::TransformBus::EventResult(m_meshWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
         m_meshWorldTMInverse = m_meshWorldTM.GetInverse();
         m_meshWorldTMInverse = m_meshWorldTM.GetInverse();
 
 
+        m_meshNonUniformScale = AZ::Vector3::CreateOne();
+        AZ::NonUniformScaleRequestBus::EventResult(m_meshNonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
+
         AreaComponentBase::OnCompositionChanged();
         AreaComponentBase::OnCompositionChanged();
     }
     }
 
 

+ 7 - 1
Gems/Vegetation/Code/Source/Components/MeshBlockerComponent.h

@@ -9,6 +9,7 @@
 
 
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Component/Component.h>
 #include <AzCore/Component/Component.h>
+#include <AzCore/Component/NonUniformScaleBus.h>
 #include <AzCore/Component/TickBus.h>
 #include <AzCore/Component/TickBus.h>
 #include <Vegetation/Ebuses/AreaRequestBus.h>
 #include <Vegetation/Ebuses/AreaRequestBus.h>
 #include <Vegetation/Ebuses/MeshBlockerRequestBus.h>
 #include <Vegetation/Ebuses/MeshBlockerRequestBus.h>
@@ -62,7 +63,7 @@ namespace Vegetation
         static void Reflect(AZ::ReflectContext* context);
         static void Reflect(AZ::ReflectContext* context);
 
 
         MeshBlockerComponent(const MeshBlockerConfig& configuration);
         MeshBlockerComponent(const MeshBlockerConfig& configuration);
-        MeshBlockerComponent() = default;
+        MeshBlockerComponent();
         ~MeshBlockerComponent() = default;
         ~MeshBlockerComponent() = default;
 
 
         //////////////////////////////////////////////////////////////////////////
         //////////////////////////////////////////////////////////////////////////
@@ -122,6 +123,8 @@ namespace Vegetation
         MeshBlockerConfig m_configuration;
         MeshBlockerConfig m_configuration;
         AZStd::atomic_bool m_refresh{ false };
         AZStd::atomic_bool m_refresh{ false };
 
 
+        AZ::NonUniformScaleChangedEvent::Handler m_nonUniformScaleChangedHandler; ///< Responds to changes in non-uniform scale.
+
         // cached data
         // cached data
         mutable AZStd::recursive_mutex m_cacheMutex;
         mutable AZStd::recursive_mutex m_cacheMutex;
         AZ::Data::Asset<AZ::Data::AssetData> m_meshAssetData;
         AZ::Data::Asset<AZ::Data::AssetData> m_meshAssetData;
@@ -129,9 +132,12 @@ namespace Vegetation
         AZ::Transform m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
         AZ::Transform m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
         AZ::Aabb m_meshBounds = AZ::Aabb::CreateNull();
         AZ::Aabb m_meshBounds = AZ::Aabb::CreateNull();
         AZ::Aabb m_meshBoundsForIntersection = AZ::Aabb::CreateNull();
         AZ::Aabb m_meshBoundsForIntersection = AZ::Aabb::CreateNull();
+        AZ::Vector3 m_meshNonUniformScale = AZ::Vector3::CreateOne();
         bool m_meshVisible = false;
         bool m_meshVisible = false;
 
 
         using CachedRayHits = AZStd::unordered_map<ClaimHandle, bool>;
         using CachedRayHits = AZStd::unordered_map<ClaimHandle, bool>;
         CachedRayHits m_cachedRayHits;
         CachedRayHits m_cachedRayHits;
+
+        static constexpr float s_rayAABBHeightPadding = 0.1f;
     };
     };
 }
 }