Files
UnrealEngine/Engine/Plugins/Enterprise/LidarPointCloud/Source/LidarPointCloudRuntime/Public/LidarPointCloudOctree.h
2025-05-18 13:04:45 +08:00

752 lines
30 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "LidarPointCloudShared.h"
#include "LidarPointCloudSettings.h"
#include "Meshing/LidarPointCloudMeshing.h"
#include "HAL/ThreadSafeCounter64.h"
#include "Misc/ScopeLock.h"
#include "Containers/Queue.h"
#include "ConvexVolume.h"
#include "Interfaces/Interface_CollisionDataProvider.h"
#include "Serialization/BulkData.h"
class ULidarPointCloud;
class FLidarPointCloudOctree;
struct FLidarPointCloudTraversalOctree;
struct FLidarPointCloudTraversalOctreeNode;
class FLidarPointCloudRenderBuffer;
class FLidarPointCloudVertexFactory;
class FLidarPointCloudRayTracingGeometry;
namespace LidarPointCloudMeshing
{
struct FMeshBuffers;
};
/**
* WARNING: Exercise caution when modifying the contents of the Octree, as it may be in use by the Rendering Thread via FPointCloudSceneProxy
* Use the FLidarPointCloudOctree::DataLock prior to such attempt
*/
/**
* Child ordering
* 0 X- Y- Z-
* 1 X- Y- Z+
* 2 X- Y+ Z-
* 3 X- Y+ Z+
* 4 X+ Y- Z-
* 5 X+ Y- Z+
* 6 X+ Y+ Z-
* 7 X+ Y+ Z+
*/
/**
* Represents a single octant in the tree.
*/
struct FLidarPointCloudOctreeNode
{
private:
/** Stores the time, at which the BulkData needs to be released */
float BulkDataLifetime;
/** Depth of this node */
uint8 Depth;
/** Location of this node inside the parent node - see the Child Ordering at the top of the file */
uint8 LocationInParent;
/** Center point of this node. */
FVector3f Center;
/** Stores the children array */
// #todo: Change to TIndirectArray<> - investigate increased memory consumption, ~130 bytes / Node
TArray<FLidarPointCloudOctreeNode*> Children;
/** Pointer to the Tree holding this node */
FLidarPointCloudOctree* Tree;
/** Marks the node for visibility recalculation next time it's necessary */
bool bVisibilityDirty;
/** Marks the node as being used for rendering */
bool bInUse;
/** Marks the node as containing active selection */
bool bHasSelection;
/** Stores the number of visible points */
uint32 NumVisiblePoints;
FCriticalSection MapLock;
/**
* Holds point data allocated to this node
* Can be empty, if the data hasn't been streamed in yet
*/
TArray<FLidarPointCloudPoint> Data;
/**
* Stores the number of points this node contains.
* Needed, since Data may not have been streamed yet, and would return a count of 0.
*/
uint32 NumPoints;
/** True, if the node has its data loaded */
TAtomic<bool> bHasData;
/** Offset in the archive file, where the data for this node is located */
int64 BulkDataOffset;
uint32 BulkDataSize;
/** Holds render data for this node */
TSharedPtr<FLidarPointCloudRenderBuffer> DataCache;
TSharedPtr<FLidarPointCloudVertexFactory> VertexFactory;
TSharedPtr<FLidarPointCloudRayTracingGeometry> RayTracingGeometry;
bool bRenderDataDirty;
/** Used to keep track, which data is available for rendering */
TAtomic<bool> bHasDataPending;
/** This is used to prevent nodes with changed content from being overwritten by consecutive streaming. */
TAtomic<bool> bCanReleaseData;
public:
FORCEINLINE FLidarPointCloudOctreeNode(FLidarPointCloudOctree* Tree, const uint8& Depth) : FLidarPointCloudOctreeNode(Tree, Depth, 0, FVector3f::ZeroVector) {}
FLidarPointCloudOctreeNode(FLidarPointCloudOctree* Tree, const uint8& Depth, const uint8& LocationInParent, const FVector3f& Center);
~FLidarPointCloudOctreeNode();
FLidarPointCloudOctreeNode(const FLidarPointCloudOctreeNode&) = delete;
FLidarPointCloudOctreeNode(FLidarPointCloudOctreeNode&&) = delete;
FLidarPointCloudOctreeNode& operator=(const FLidarPointCloudOctreeNode&) = delete;
FLidarPointCloudOctreeNode& operator=(FLidarPointCloudOctreeNode&&) = delete;
/** Returns a pointer to the point data */
FLidarPointCloudPoint* GetData() const;
/** Returns a pointer to the point data and prevents it from being released */
FLidarPointCloudPoint* GetPersistentData() const;
/** Returns a pointer to the point data */
FORCEINLINE TSharedPtr<FLidarPointCloudRenderBuffer> GetDataCache() { return DataCache; }
/** Return a pointer to the vertex factory containing pre-cached geometry */
FORCEINLINE TSharedPtr<FLidarPointCloudVertexFactory> GetVertexFactory() { return VertexFactory; }
/** Return a pointer to the ray tracing geometry */
FORCEINLINE TSharedPtr<FLidarPointCloudRayTracingGeometry> GetRayTracingGeometry() { return RayTracingGeometry; }
/**
* Builds and updates the necessary render data buffers
* Returns true if successful
*/
bool BuildDataCache(bool bUseStaticBuffers, bool bUseRayTracing);
/** Returns the sum of grid and padding points allocated to this node. */
FORCEINLINE uint32 GetNumPoints() const { return NumPoints; }
/** Returns the sum of visible grid and padding points allocated to this node. */
uint32 GetNumVisiblePoints() const { return NumVisiblePoints; }
/** Calculates and returns the bounds of this node */
FORCEINLINE FBox GetBounds() const;
/** Calculates and returns the sphere bounds of this node */
FORCEINLINE FSphere GetSphereBounds() const;
/** Returns a pointer to the node at the given location, or null if one doesn't exist yet. */
FLidarPointCloudOctreeNode* GetChildNodeAtLocation(const uint8& Location) const;
uint8 GetChildrenBitmask() const;
void UpdateNumVisiblePoints();
/** Attempts to insert given points to this node or passes it to the children, otherwise. */
void InsertPoints(const FLidarPointCloudPoint* Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, const FVector3f& Translation);
void InsertPoints(FLidarPointCloudPoint** Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, const FVector3f& Translation);
/** Removes all points. */
void Empty(bool bRecursive = true);
/** Returns the maximum depth of any children of this node .*/
uint32 GetMaxDepth() const;
/** Returns the amount of memory used by this node */
int64 GetAllocatedSize(bool bRecursive, bool bIncludeBulkData) const;
/** Returns true, if the node has its data loaded */
bool HasData() const { return bHasData; }
/** Returns true, if the node has its data loaded */
bool HasRenderData() const { return DataCache.IsValid() || VertexFactory.IsValid(); }
/**
* Releases the BulkData
* If forced, the node will be released even if persistent
*/
void ReleaseData(bool bForce = false);
/** Releases and removes the render data cache */
void ReleaseDataCache();
/** Convenience function, to add point statistics to the Tree table. */
void AddPointCount(int32 PointCount);
/** Sorts the points by visibility (visible first) to optimize data processing and rendering */
void SortVisiblePoints();
private:
template <typename T>
void InsertPoints_Internal(T Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, const FVector3f& Translation);
void InsertPoints_Dynamic(const FLidarPointCloudPoint* Points, const int64& Count, const FVector3f& Translation);
void InsertPoints_Static(const FLidarPointCloudPoint* Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, const FVector3f& Translation);
void InsertPoints_Dynamic(FLidarPointCloudPoint** Points, const int64& Count, const FVector3f& Translation);
void InsertPoints_Static(FLidarPointCloudPoint** Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, const FVector3f& Translation);
friend FLidarPointCloudOctree;
friend FLidarPointCloudTraversalOctree;
friend FLidarPointCloudTraversalOctreeNode;
friend void LidarPointCloudMeshing::CalculateNormals(FLidarPointCloudOctree*, FThreadSafeBool*, int32, float, TArray64<FLidarPointCloudPoint *>&);
};
/**
* Used for efficient handling of point cloud data.
*/
class LIDARPOINTCLOUDRUNTIME_API FLidarPointCloudOctree
{
public:
/** Stores shared per-LOD node data. */
struct FSharedLODData
{
float Radius;
float RadiusSq;
float GridSize;
FVector3f GridSize3D;
float Size;
float NormalizationMultiplier;
FVector3f Extent;
FSharedLODData() {}
FSharedLODData(const FVector3f& InExtent);
};
public:
/** Maximum allowed depth for any node */
static int32 MaxNodeDepth;
/** Maximum number of unallocated points to keep inside the node before they need to be converted in to a full child node */
static int32 MaxBucketSize;
/** Virtual grid resolution to divide the node into */
static int32 NodeGridResolution;
/** Used for thread safety between rendering and asset operations. */
mutable FCriticalSection DataLock;
/** Used to prevent auto-release of nodes if they are in use by other threads */
FCriticalSection DataReleaseLock;
private:
FLidarPointCloudOctreeNode* Root;
/** Stores shared per-LOD node data. */
TArray<FSharedLODData> SharedData;
/** Stores number of points per each LOD. */
TArray<FThreadSafeCounter64> PointCount;
/** Stores number of nodes per each LOD. */
TArray<FThreadSafeCounter> NodeCount;
/** Extent of this Cloud. */
FVector3f Extent;
/** Used to cache the Allocated Size. */
mutable int32 PreviousNodeCount;
mutable int64 PreviousPointCount;
mutable int64 PreviousAllocatedStructureSize;
mutable int64 PreviousAllocatedSize;
/** Used to notify any linked traversal octrees when they need to re-generate the data. */
TArray<TWeakPtr<FLidarPointCloudTraversalOctree, ESPMode::ThreadSafe>> LinkedTraversalOctrees;
/** Stores collision mesh data */
FTriMeshCollisionData CollisionMesh;
/** Pointer to the owner of this Octree */
ULidarPointCloud* Owner;
IAsyncReadFileHandle* ReadHandle;
FByteBulkData BulkData;
#if WITH_EDITOR
struct FLidarPointCloudBulkData : public FBulkData
{
FSerializeBulkDataElements SerializeElementsCallback;
FLidarPointCloudBulkData(FLidarPointCloudOctree* Octree);
void Serialize(FArchive& Ar, UObject* InOwner);
} SavingBulkData;
#endif
TQueue<FLidarPointCloudOctreeNode*> QueuedNodes;
TArray<FLidarPointCloudOctreeNode*> NodesInUse;
TAtomic<bool> bStreamingBusy;
/** Set to true when the Octree is persistently force-loaded. */
bool bIsFullyLoaded;
public:
FLidarPointCloudOctree() : FLidarPointCloudOctree(nullptr) {}
FLidarPointCloudOctree(ULidarPointCloud* Owner);
~FLidarPointCloudOctree();
FLidarPointCloudOctree(const FLidarPointCloudOctree&) = delete;
FLidarPointCloudOctree(FLidarPointCloudOctree&&) = delete;
FLidarPointCloudOctree& operator=(const FLidarPointCloudOctree&) = delete;
FLidarPointCloudOctree& operator=(FLidarPointCloudOctree&&) = delete;
/** Returns true if the Root node exists and has any data assigned. */
bool HasData() const { return Root->GetNumPoints() > 0; }
/** Returns the number of different LODs. */
int32 GetNumLODs() const;
/** Returns the Cloud bounds. */
FBox GetBounds() const { return FBox(-Extent, Extent); }
/** Returns the extent of the Cloud's bounds. */
FORCEINLINE FVector3f GetExtent() const { return Extent; }
/** Recalculates and updates points bounds. */
void RefreshBounds();
/** Returns the total number of points. */
int64 GetNumPoints() const;
/** Returns the total number of visible points. */
int64 GetNumVisiblePoints() const;
/** Returns the total number of nodes. */
int32 GetNumNodes() const;
/** Returns the total number of nodes. */
FORCEINLINE int32 GetNumNodesInUse() const { return NodesInUse.Num(); }
/** Returns a pointer to the Point Cloud asset, which owns this Octree. */
ULidarPointCloud* GetOwner() const { return Owner; }
/** Returns the amount of memory used by this Octree, including the BulkData */
int64 GetAllocatedSize() const;
/** Returns the amount of memory used by this Octree, excluding the BulkData */
int64 GetAllocatedStructureSize() const;
/** Returns the grid cell size at root level. */
float GetRootCellSize() const { return SharedData[0].GridSize; }
/** Returns an estimated spacing between points */
float GetEstimatedPointSpacing() const;
/** Returns true, if the Octree has collision built */
bool HasCollisionData() const { return CollisionMesh.Vertices.Num() > 0; }
/** Builds collision using the accuracy provided */
void BuildCollision(const float& Accuracy, const bool& bVisibleOnly);
/** Removes collision mesh data */
void RemoveCollision();
/** Returns pointer to the collision data */
const FTriMeshCollisionData* GetCollisionData() const { return &CollisionMesh; }
/** Constructs and returns the MeshBuffers struct from the data */
void BuildStaticMeshBuffers(float CellSize, LidarPointCloudMeshing::FMeshBuffers* OutMeshBuffers, const FTransform& Transform);
/** Populates the given array with points from the tree */
void GetPoints(TArray<FLidarPointCloudPoint*>& SelectedPoints, int64 StartIndex = 0, int64 Count = -1);
void GetPoints(TArray64<FLidarPointCloudPoint*>& SelectedPoints, int64 StartIndex = 0, int64 Count = -1);
/** Populates the array with the list of points within the given sphere. */
void GetPointsInSphere(TArray<FLidarPointCloudPoint*>& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly);
void GetPointsInSphere(TArray64<FLidarPointCloudPoint*>& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly);
/** Populates the array with the list of pointers to points within the given box. */
void GetPointsInBox(TArray<const FLidarPointCloudPoint*>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly) const;
void GetPointsInBox(TArray64<const FLidarPointCloudPoint*>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly) const;
void GetPointsInBox(TArray<FLidarPointCloudPoint*>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly);
void GetPointsInBox(TArray64<FLidarPointCloudPoint*>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly);
/** Populates the array with the list of points within the given convex volume. */
void GetPointsInConvexVolume(TArray<FLidarPointCloudPoint*>& SelectedPoints, const FConvexVolume& ConvexVolume, const bool& bVisibleOnly);
void GetPointsInConvexVolume(TArray64<FLidarPointCloudPoint*>& SelectedPoints, const FConvexVolume& ConvexVolume, const bool& bVisibleOnly);
/** Populates the given array with copies of points from the tree */
void GetPointsAsCopies(TArray<FLidarPointCloudPoint>& SelectedPoints, const FTransform* LocalToWorld, int64 StartIndex = 0, int64 Count = -1) const;
void GetPointsAsCopies(TArray64<FLidarPointCloudPoint>& SelectedPoints, const FTransform* LocalToWorld, int64 StartIndex = 0, int64 Count = -1) const;
/** Executes the provided action on batches of points. */
void GetPointsAsCopiesInBatches(TFunction<void(TSharedPtr<TArray64<FLidarPointCloudPoint>>)> Action, const int64& BatchSize, const bool& bVisibleOnly);
/** Populates the array with the list of points within the given sphere. */
void GetPointsInSphereAsCopies(TArray<FLidarPointCloudPoint>& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly, const FTransform* LocalToWorld) const;
void GetPointsInSphereAsCopies(TArray64<FLidarPointCloudPoint>& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly, const FTransform* LocalToWorld) const;
/** Populates the array with the list of pointers to points within the given box. */
void GetPointsInBoxAsCopies(TArray<FLidarPointCloudPoint>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly, const FTransform* LocalToWorld) const;
void GetPointsInBoxAsCopies(TArray64<FLidarPointCloudPoint>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly, const FTransform* LocalToWorld) const;
/** Performs a raycast test against the point cloud. Returns the pointer if hit or nullptr otherwise. */
FLidarPointCloudPoint* RaycastSingle(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly);
/**
* Performs a raycast test against the point cloud.
* Populates OutHits array with the results.
* Returns true it anything has been hit.
*/
bool RaycastMulti(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly, TArray<FLidarPointCloudPoint*>& OutHits);
bool RaycastMulti(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly, const FTransform* LocalToWorld, TArray<FLidarPointCloudPoint>& OutHits);
/** Returns true if there are any points within the given sphere. */
bool HasPointsInSphere(const FSphere& Sphere, const bool& bVisibleOnly) const;
/** Returns true if there are any points within the given box. */
bool HasPointsInBox(const FBox& Box, const bool& bVisibleOnly) const;
/** Returns true if there are any points hit by the given ray. */
bool HasPointsByRay(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly) const;
/** Sets visibility of points within the given sphere. */
void SetVisibilityOfPointsInSphere(const bool& bNewVisibility, const FSphere& Sphere);
/** Sets visibility of points within the given box. */
void SetVisibilityOfPointsInBox(const bool& bNewVisibility, const FBox& Box);
/** Sets visibility of the first point hit by the given ray. */
void SetVisibilityOfFirstPointByRay(const bool& bNewVisibility, const FLidarPointCloudRay& Ray, const float& Radius);
/** Sets visibility of points hit by the given ray. */
void SetVisibilityOfPointsByRay(const bool& bNewVisibility, const FLidarPointCloudRay& Ray, const float& Radius);
/** Marks all points hidden */
void HideAll();
/** Marks all points visible */
void UnhideAll();
/** Executes the provided action on each of the points. */
void ExecuteActionOnAllPoints(TFunction<void(FLidarPointCloudPoint*)> Action, const bool& bVisibleOnly);
/** Executes the provided action on each of the points within the given sphere. */
void ExecuteActionOnPointsInSphere(TFunction<void(FLidarPointCloudPoint*)> Action, const FSphere& Sphere, const bool& bVisibleOnly);
/** Executes the provided action on each of the points within the given box. */
void ExecuteActionOnPointsInBox(TFunction<void(FLidarPointCloudPoint*)> Action, const FBox& Box, const bool& bVisibleOnly);
/** Executes the provided action on the first point hit by the given ray. */
void ExecuteActionOnFirstPointByRay(TFunction<void(FLidarPointCloudPoint*)> Action, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly);
/** Executes the provided action on each of the points hit by the given ray. */
void ExecuteActionOnPointsByRay(TFunction<void(FLidarPointCloudPoint*)> Action, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly);
/** Applies the given color to all points */
void ApplyColorToAllPoints(const FColor& NewColor, const bool& bVisibleOnly);
/** Applies the given color to all points within the sphere */
void ApplyColorToPointsInSphere(const FColor& NewColor, const FSphere& Sphere, const bool& bVisibleOnly);
/** Applies the given color to all points within the box */
void ApplyColorToPointsInBox(const FColor& NewColor, const FBox& Box, const bool& bVisibleOnly);
/** Applies the given color to the first point hit by the given ray */
void ApplyColorToFirstPointByRay(const FColor& NewColor, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly);
/** Applies the given color to all points hit by the given ray */
void ApplyColorToPointsByRay(const FColor& NewColor, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly);
/**
* This should to be called if any manual modification to individual points' visibility has been made.
* If not marked dirty, the rendering may work suboptimally.
*/
void MarkPointVisibilityDirty();
/** Marks render data of all nodes as dirty. */
void MarkRenderDataDirty();
/** Marks render data of all nodes within the given sphere as dirty. */
void MarkRenderDataInSphereDirty(const FSphere& Sphere);
/** Marks render data of all nodes within the given convex volume as dirty. */
void MarkRenderDataInConvexVolumeDirty(const FConvexVolume& ConvexVolume);
#if WITH_EDITOR
void SelectByConvexVolume(const FConvexVolume& ConvexVolume, bool bAdditive, bool bVisibleOnly);
void SelectBySphere(const FSphere& Sphere, bool bAdditive, bool bVisibleOnly);
void HideSelected();
void DeleteSelected();
void InvertSelection();
int64 NumSelectedPoints() const;
bool HasSelectedPoints() const;
void GetSelectedPoints(TArray64<FLidarPointCloudPoint*>& SelectedPoints) const;
void GetSelectedPointsAsCopies(TArray64<FLidarPointCloudPoint>& SelectedPoints, const FTransform& Transform) const;
void GetSelectedPointsInBox(TArray64<const FLidarPointCloudPoint*>& SelectedPoints, const FBox& Box) const;
void ClearSelection();
void BuildStaticMeshBuffersForSelection(float CellSize, LidarPointCloudMeshing::FMeshBuffers* OutMeshBuffers, const FTransform& Transform);
#endif
/** Initializes the Octree properties. */
void Initialize(const FVector3f& InExtent);
/** Inserts the given point into the Octree structure, internally thread-safe. */
void InsertPoint(const FLidarPointCloudPoint* Point, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector3f& Translation);
/** Inserts group of points into the Octree structure, internally thread-safe. */
void InsertPoints(FLidarPointCloudPoint* Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector3f& Translation);
void InsertPoints(const FLidarPointCloudPoint* Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector3f& Translation);
void InsertPoints(FLidarPointCloudPoint** Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector3f& Translation);
/** Attempts to remove the given point. */
void RemovePoint(const FLidarPointCloudPoint* Point);
void RemovePoint(FLidarPointCloudPoint Point);
/** Removes points in bulk */
void RemovePoints(TArray<FLidarPointCloudPoint*>& Points);
void RemovePoints(TArray64<FLidarPointCloudPoint*>& Points);
/** Removes all points within the given sphere */
void RemovePointsInSphere(const FSphere& Sphere, const bool& bVisibleOnly);
/** Removes all points within the given box */
void RemovePointsInBox(const FBox& Box, const bool& bVisibleOnly);
/** Removes the first point hit by the given ray */
void RemoveFirstPointByRay(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly);
/** Removes all points hit by the given ray */
void RemovePointsByRay(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly);
/** Removes all hidden points */
void RemoveHiddenPoints();
/** Resets all normals information */
void ResetNormals();
/**
* Calculates Normals for the provided points
* If a nullptr is passed, the calculation will be executed on the whole cloud
*/
void CalculateNormals(FThreadSafeBool* bCancelled, int32 Quality, float Tolerance, TArray64<FLidarPointCloudPoint*>* InPointSelection);
/** Removes all points and, optionally, all nodes except for the root node. Retains the bounds. */
void Empty(bool bDestroyNodes);
/** Adds the given traversal octree to the list of linked octrees. */
void RegisterTraversalOctree(TWeakPtr<FLidarPointCloudTraversalOctree, ESPMode::ThreadSafe> TraversalOctree)
{
if (TraversalOctree.IsValid())
{
LinkedTraversalOctrees.Add(TraversalOctree);
}
}
/** Removes the given traversal octree from the list */
void UnregisterTraversalOctree(FLidarPointCloudTraversalOctree* TraversalOctree);
/**
* Streams requested nodes or extends their lifetime, if already loaded
* Unloads all unused nodes with expired lifetime
*/
void StreamNodes(TArray<FLidarPointCloudOctreeNode*>& Nodes, const float& CurrentTime);
/** Returns true, if the cloud is fully and persistently loaded. */
bool IsFullyLoaded() const { return bIsFullyLoaded; }
/** Loads all nodes. */
void LoadAllNodes(bool bLoadPersistently);
/**
* Releases all nodes.
* Optionally, releases persistent nodes too.
*/
void ReleaseAllNodes(bool bIncludePersistent);
bool IsOptimizedForDynamicData() const;
void OptimizeForDynamicData();
void OptimizeForStaticData();
IAsyncReadFileHandle* GetReadHandle();
void CloseReadHandle();
//~ Begin Deprecated
UE_DEPRECATED(4.27, "Use GetPointsInConvexVolume instead.")
void GetPointsInFrustum(TArray<FLidarPointCloudPoint*>& SelectedPoints, const FConvexVolume& Frustum, const bool& bVisibleOnly);
UE_DEPRECATED(4.27, "Use GetPointsInConvexVolume instead.")
void GetPointsInFrustum(TArray64<FLidarPointCloudPoint*>& SelectedPoints, const FConvexVolume& Frustum, const bool& bVisibleOnly);
UE_DEPRECATED(4.27, "Use MarkRenderDataInConvexVolumeDirty instead.")
void MarkRenderDataInFrustumDirty(const FConvexVolume& Frustum);
//~ End Deprecated
private:
void RefreshAllocatedSize();
template <typename T>
void InsertPoints_Internal(T Points, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector3f& Translation);
template <typename T>
void GetPoints_Internal(TArray<FLidarPointCloudPoint*, T>& Points, int64 StartIndex = 0, int64 Count = -1);
template <typename T>
void GetPointsInSphere_Internal(TArray<FLidarPointCloudPoint*, T>& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly);
template <typename T>
void GetPointsInBox_Internal(TArray<FLidarPointCloudPoint*, T>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly);
template <typename T>
void GetPointsInBox_Internal(TArray<const FLidarPointCloudPoint*, T>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly) const;
template <typename T>
void GetPointsInConvexVolume_Internal(TArray<FLidarPointCloudPoint*, T>& SelectedPoints, const FConvexVolume& ConvexVolume, const bool& bVisibleOnly);
template <typename T>
void GetPointsAsCopies_Internal(TArray<FLidarPointCloudPoint, T>& Points, const FTransform* LocalToWorld, int64 StartIndex = 0, int64 Count = -1) const;
template <typename T>
void GetPointsInSphereAsCopies_Internal(TArray<FLidarPointCloudPoint, T>& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly, const FTransform* LocalToWorld) const;
template <typename T>
void GetPointsInBoxAsCopies_Internal(TArray<FLidarPointCloudPoint, T>& SelectedPoints, const FBox& Box, const bool& bVisibleOnly, const FTransform* LocalToWorld) const;
template <typename T>
void RemovePoints_Internal(TArray<FLidarPointCloudPoint*, T>& Points);
void RemovePoint_Internal(FLidarPointCloudOctreeNode* Node, int32 Index);
/** Notifies all linked traversal octrees that they should invalidate and regenerate the data. */
void MarkTraversalOctreesForInvalidation();
void Serialize(FArchive& Ar);
void SerializeBulkData(FArchive& Ar);
void StreamNodeData(FLidarPointCloudOctreeNode* Node);
friend FArchive& operator<<(FArchive& Ar, FLidarPointCloudOctree& O)
{
O.Serialize(Ar);
return Ar;
}
friend FLidarPointCloudOctreeNode;
friend FLidarPointCloudTraversalOctree;
friend void LidarPointCloudMeshing::CalculateNormals(FLidarPointCloudOctree*, FThreadSafeBool*, int32, float, TArray64<FLidarPointCloudPoint*>&);
};
/**
* Represents a single octant in the traversal tree.
*/
struct FLidarPointCloudTraversalOctreeNode
{
/** Pointer to the target node. */
FLidarPointCloudOctreeNode* DataNode;
/** Stores the center of the target node in World space. */
FVector3f Center;
/** Depth of this node */
uint8 Depth;
/** Calculated for use with adaptive sprite scaling */
uint8 VirtualDepth;
FLidarPointCloudTraversalOctreeNode* Parent;
FLidarPointCloudTraversalOctree* Octree;
/** Stores the children array */
TArray<FLidarPointCloudTraversalOctreeNode> Children;
/** Holds true if the node has been selected for rendering. */
bool bSelected;
bool bFullyContained;
FLidarPointCloudTraversalOctreeNode();
/** Builds the traversal version of the given node. */
void Build(FLidarPointCloudTraversalOctree* TraversalOctree, FLidarPointCloudOctreeNode* Node, const FTransform& LocalToWorld, const FVector3f& LocationOffset);
/** Calculates virtual depth of this node, to be used to estimate the best sprite size */
void CalculateVirtualDepth(const TArray<float>& LevelWeights, const float& PointSizeBias);
FORCEINLINE bool IsAvailable() const { return bSelected && DataNode->HasRenderData(); }
};
/** Used for node size sorting and node selection. */
struct FLidarPointCloudTraversalOctreeNodeSizeData
{
FLidarPointCloudTraversalOctreeNode* Node;
float Size;
int32 ProxyIndex;
FLidarPointCloudTraversalOctreeNodeSizeData(FLidarPointCloudTraversalOctreeNode* Node, const float& Size, const int32& ProxyIndex);
};
/** Convenience struct to group all selection params into one */
struct FLidarPointCloudNodeSelectionParams
{
float MinScreenSize;
float ScreenCenterImportance;
int32 MinDepth;
int32 MaxDepth;
float BoundsScale;
bool bUseFrustumCulling;
const TArray<struct FLidarPointCloudClippingVolumeParams>* ClippingVolumes;
};
/**
* Used as a traversal tree for node selection during rendering
*/
struct FLidarPointCloudTraversalOctree
{
FLidarPointCloudTraversalOctreeNode Root;
/** Stores per-LOD bounds in World space. */
TArray<float> RadiiSq;
TArray<FVector3f> Extents;
/** Stores the number of LODs. */
uint8 NumLODs;
/** Normalized histogram of level weights, one for each LOD. Used for point scaling */
TArray<float> LevelWeights;
float VirtualDepthMultiplier;
float ReversedVirtualDepthMultiplier;
/** Pointer to the source Octree */
FLidarPointCloudOctree* Octree;
bool bValid;
/** Build the Traversal tree from the Octree provided */
FLidarPointCloudTraversalOctree(FLidarPointCloudOctree* Octree, const FTransform& LocalToWorld);
~FLidarPointCloudTraversalOctree();
FLidarPointCloudTraversalOctree(const FLidarPointCloudTraversalOctree&) = delete;
FLidarPointCloudTraversalOctree(FLidarPointCloudTraversalOctree&&) = delete;
FLidarPointCloudTraversalOctree& operator=(const FLidarPointCloudTraversalOctree&) = delete;
FLidarPointCloudTraversalOctree& operator=(FLidarPointCloudTraversalOctree&&) = delete;
/**
* Selects and appends the subset of visible nodes for rendering.
* Returns number of selected nodes
*/
int32 GetVisibleNodes(TArray<FLidarPointCloudTraversalOctreeNodeSizeData>& NodeSizeData, const struct FLidarPointCloudViewData* ViewData, const int32& ProxyIndex, const FLidarPointCloudNodeSelectionParams& SelectionParams);
void CalculateVisibilityStructure(TArray<uint32>& OutData);
void CalculateLevelWeightsForSelectedNodes(TArray<float>& OutLevelWeights);
FVector GetCenter() const { return (FVector)Root.Center; }
FVector GetExtent() const { return (FVector)Extents[0]; }
};