diff --git a/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudComponentControllerConfigurationBus.h b/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudComponentControllerConfigurationBus.h index 7f4d970..6f2fdbd 100644 --- a/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudComponentControllerConfigurationBus.h +++ b/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudComponentControllerConfigurationBus.h @@ -15,6 +15,7 @@ namespace Pointcloud virtual void SetPointcloudAsset(AZ::Data::Asset asset) = 0; virtual void SetPointSize(float pointSize) = 0; virtual void SetVisibility(bool visible) = 0; + virtual AZ::Aabb GetBounds() const = 0; }; using PointcloudConfigurationBus = AZ::EBus; diff --git a/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudFeatureProcessorInterface.h b/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudFeatureProcessorInterface.h index 54dba92..447d5fa 100644 --- a/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudFeatureProcessorInterface.h +++ b/Gems/Pointcloud/Code/Include/Pointcloud/PointcloudFeatureProcessorInterface.h @@ -10,9 +10,11 @@ #include #include +#include #include #include #include + namespace Pointcloud { class Pointcloud; @@ -61,5 +63,9 @@ namespace Pointcloud //! Get the number of points in a pointcloud //! @param handle The handle of the pointcloud obtained from AcquirePointcloud virtual uint32_t GetPointCount(const PointcloudHandle& handle) const = 0; + + //! Get the bounds of a pointcloud + //! @param handle The handle of the pointcloud obtained from AcquirePointcloud + virtual AZStd::optional GetBounds(const PointcloudHandle& handle) const = 0; }; } // namespace Pointcloud \ No newline at end of file diff --git a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp index 1f67c81..c65ff9b 100644 --- a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp +++ b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp @@ -118,6 +118,15 @@ namespace Pointcloud m_modelMatrixIndex.Reset(); } + // Update bounds + AZ::Aabb aabb = AZ::Aabb::CreateNull(); + for (const auto& vertex : cloudVertexData) + { + AZ::Vector3 position = AZ::Vector3(vertex.m_position[0], vertex.m_position[1], vertex.m_position[2]); + aabb.AddPoint(position); + } + pcData.m_bounds = aabb; + UpdateDrawPacket(); } @@ -348,4 +357,13 @@ namespace Pointcloud } return 0; } + + AZStd::optional PointcloudFeatureProcessor::GetBounds(const PointcloudHandle& handle) const + { + if (auto it = m_pointcloudData.find(handle); it != m_pointcloudData.end()) + { + return it->second.m_bounds; + } + return AZStd::nullopt; + } } // namespace Pointcloud \ No newline at end of file diff --git a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h index be8ca82..0e6f559 100644 --- a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h +++ b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h @@ -43,6 +43,7 @@ namespace Pointcloud void SetVisibility(const PointcloudHandle& handle, bool visible) override; void ReleasePointcloud(const PointcloudHandle& handle) override; uint32_t GetPointCount(const PointcloudHandle& handle) const override; + AZStd::optional GetBounds(const PointcloudHandle& handle) const override; protected: // RPI::SceneNotificationBus overrides @@ -69,6 +70,7 @@ namespace Pointcloud AZ::Data::Instance m_drawSrg = nullptr; bool m_visible = true; bool m_needSrgUpdate = true; + AZ::Aabb m_bounds = AZ::Aabb::CreateNull(); AZ::Data::AssetId m_assetId; //! AssetId of the pointcloud asset, if pointcloud was acquired from an asset AZ::Data::Asset m_assetData; //! Pointcloud asset data, if pointcloud was acquired from an asset }; diff --git a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp index 1e5a2f6..e77f72c 100644 --- a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp +++ b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp @@ -203,4 +203,17 @@ namespace Pointcloud } } + AZ::Aabb PointcloudComponentController::GetBounds() const + { + if (m_featureProcessor) + { + auto bounds = m_featureProcessor->GetBounds(m_config.m_pointcloudHandle); + if (bounds.has_value()) + { + return bounds.value(); + } + } + return AZ::Aabb::CreateNull(); + } + } // namespace Pointcloud diff --git a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.h b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.h index 02468ed..a512eef 100644 --- a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.h +++ b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.h @@ -8,6 +8,8 @@ #pragma once +#include "AzCore/Math/Aabb.h" + #include #include #include @@ -68,6 +70,7 @@ namespace Pointcloud void SetPointcloudAsset(AZ::Data::Asset asset) override; void SetPointSize(float pointSize) override; void SetVisibility(bool visible) override; + AZ::Aabb GetBounds() const override; AZ::Crc32 OnSetPointSize(); AZ::Crc32 OnAssetChanged(); diff --git a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.cpp b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.cpp index cdca786..34667d1 100644 --- a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.cpp +++ b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.cpp @@ -48,18 +48,144 @@ namespace Pointcloud AzToolsFramework::EditorEntityInfoRequestBus::EventResult( visible, GetEntityId(), &AzToolsFramework::EditorEntityInfoRequestBus::Events::IsVisible); m_controller.SetVisibility(visible); + AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId()); + AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId()); } void PointcloudEditorComponent::Deactivate() { PointcloudEditorComponentBase::Deactivate(); AzToolsFramework::EditorEntityInfoNotificationBus::Handler::BusDisconnect(); + AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect(); + AzFramework::BoundsRequestBus::Handler::BusDisconnect(); } bool PointcloudEditorComponent::ShouldActivateController() const { return false; } + AZ::Aabb PointcloudEditorComponent::GetWorldBounds() const + { + AZ::Transform transform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM); + AZ::Aabb bounds = m_controller.GetBounds(); + bounds.ApplyTransform(transform); + return bounds; + } + + AZ::Aabb PointcloudEditorComponent::GetLocalBounds() const + { + AZ::Transform transform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformBus::Events::GetLocalTM); + AZ::Aabb bounds = m_controller.GetBounds(); + bounds.ApplyTransform(transform); + return bounds; + } + + AZ::Aabb PointcloudEditorComponent::GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) + { + return GetWorldBounds(); + } + + // Based on https://github.com/erich666/GraphicsGems/blob/master/gems/RayBox.c + bool PointcloudEditorComponent::EditorSelectionIntersectRayViewport( + const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) + { + bool inside = true; + bool quadrant[3]; + int whichPlane; + AZ::Vector3 minB = m_controller.GetBounds().GetMin(); + AZ::Vector3 maxB = m_controller.GetBounds().GetMax(); + AZ::Vector3 origin = src; + AZ::Vector3 candidatePlane; + AZ::Vector3 maxT; + AZ::Vector3 coord; + + for (int i = 0; i < 3; i++) + { + if (origin.GetElement(i) < minB.GetElement(i)) + { + quadrant[i] = false; + candidatePlane.SetElement(i, minB.GetElement(i)); + inside = false; + } + else if (origin.GetElement(i) > maxB.GetElement(i)) + { + quadrant[i] = true; + candidatePlane.SetElement(i, maxB.GetElement(i)); + inside = false; + } + else + { + quadrant[i] = true; + } + } + + if (inside) + { + coord = origin; + // When inside the bounding box, compute distance from ray origin to a point on the box + distance = (origin - (minB + (maxB - minB) * 0.5f)).GetLength(); + return true; + } + + for (int i = 0; i < 3; i++) + { + if (!quadrant[i] && dir.GetElement(i) != 0) + { + maxT.SetElement(i, (candidatePlane.GetElement(i) - origin.GetElement(i)) / dir.GetElement(i)); + } + else + { + maxT.SetElement(i, -1); + } + } + + whichPlane = 0; + for (int i = 1; i < 3; i++) + { + if (maxT.GetElement(whichPlane) < maxT.GetElement(i)) + { + whichPlane = i; + } + } + + if (maxT.GetElement(whichPlane) < 0) + { + return false; + } + + for (int i = 0; i < 3; i++) + { + if (whichPlane != i) + { + coord.SetElement(i, origin.GetElement(i) + maxT.GetElement(whichPlane) * dir.GetElement(i)); + if (coord.GetElement(i) < minB.GetElement(i) || coord.GetElement(i) > maxB.GetElement(i)) + { + return false; + } + } + else + { + coord.SetElement(i, candidatePlane.GetElement(i)); + } + } + + // Compute distance from ray origin to intersection point + distance = (coord - origin).GetLength(); + + return true; + } + + bool PointcloudEditorComponent::SupportsEditorRayIntersect() + { + return true; + } + bool PointcloudEditorComponent::SupportsEditorRayIntersectViewport(const AzFramework::ViewportInfo& viewportInfo) + { + return true; + } + void PointcloudEditorComponent::OnEntityInfoUpdatedVisibility(AZ::EntityId entityId, bool visible) { m_controller.OnEntityInfoUpdatedVisibility(entityId, visible); diff --git a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.h b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.h index c7b7cfc..1d25c88 100644 --- a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.h +++ b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudEditorComponent.h @@ -3,6 +3,10 @@ #include "PointcloudComponentController.h" #include "../../Clients/PointcloudComponent.h" +#include + +#include + #include #include #include @@ -27,6 +31,8 @@ namespace Pointcloud : public PointcloudEditorComponentBase , private AZ::TransformNotificationBus::Handler , private AzToolsFramework::EditorEntityInfoNotificationBus::Handler + , public AzFramework::BoundsRequestBus::Handler + , public AzToolsFramework::EditorComponentSelectionRequestsBus::Handler { public: AZ_EDITOR_COMPONENT( @@ -43,6 +49,16 @@ namespace Pointcloud void Deactivate() override; bool ShouldActivateController() const override; + AZ::Aabb GetWorldBounds() const override; + AZ::Aabb GetLocalBounds() const override; + + AZ::Aabb GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) override; + bool EditorSelectionIntersectRayViewport( + const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) override; + + bool SupportsEditorRayIntersect() override; + bool SupportsEditorRayIntersectViewport(const AzFramework::ViewportInfo& viewportInfo) override; + private: // AZ::TransformNotificationBus::Handler overrides ... void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;