Files
UnrealEngine/Engine/Plugins/Experimental/MeshModelingToolsetExp/Source/MeshModelingToolsExp/Public/PatternTool.h
2025-05-18 13:04:45 +08:00

622 lines
23 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "BaseTools/MultiSelectionMeshEditingTool.h"
#include "InteractiveToolBuilder.h"
#include "BaseBehaviors/BehaviorTargetInterfaces.h"
#include "Changes/TransformChange.h"
#include "FrameTypes.h"
#include "BoxTypes.h"
#include "ToolDataVisualizer.h"
#include "TransformTypes.h"
#include "PatternTool.generated.h"
#define UE_API MESHMODELINGTOOLSEXP_API
class UBaseAxisTranslationGizmo;
class UAxisAngleGizmo;
class UDragAlignmentMechanic;
class UCombinedTransformGizmo;
class UTransformProxy;
class UPreviewGeometry;
class UDynamicMesh;
class UDynamicMeshComponent;
class UInteractiveGizmo;
class UStaticMesh;
class UStaticMeshComponent;
class UMaterialInterface;
class UConstructionPlaneMechanic;
class UComponentBoundTransformProxy;
/**
*
*/
UCLASS(MinimalAPI)
class UPatternToolBuilder : public UMultiSelectionMeshEditingToolBuilder
{
GENERATED_BODY()
public:
UE_API virtual bool CanBuildTool(const FToolBuilderState& SceneState) const override;
UE_API virtual UMultiSelectionMeshEditingTool* CreateNewTool(const FToolBuilderState& SceneState) const override;
UE_API virtual void InitializeNewTool(UMultiSelectionMeshEditingTool* NewTool, const FToolBuilderState& SceneState) const override;
bool bEnableCreateISMCs = true;
protected:
UE_API virtual const FToolTargetTypeRequirements& GetTargetRequirements() const override;
};
UENUM()
enum class EPatternToolShape : uint8
{
/** Arrange pattern elements along a Line */
Line = 0,
/** Arrange pattern elements in a 2D Grid */
Grid = 1,
/** Arrange pattern elements in a Circle */
Circle = 2
};
UENUM()
enum class EPatternToolSingleAxis : uint8
{
XAxis = 0,
YAxis = 1,
ZAxis = 2
};
UENUM()
enum class EPatternToolSinglePlane : uint8
{
XYPlane = 0,
XZPlane = 1,
YZPlane = 2
};
UENUM()
enum class EPatternToolAxisSpacingMode : uint8
{
/** Place a specific number of Pattern Elements along the pattern geometry */
ByCount = 0,
/** Place Pattern Elements at regular increments along the Pattern Geometry (on-center) */
StepSize = 1,
/** Pack in as many Pattern Elements as fits in the available space */
Packed = 2
};
/**
* Settings for the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternToolSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** The seed used to introduce random transform variations when enabled */
UPROPERTY(EditAnywhere, Category = General, meta = (NoResetToDefault, Delta = 1, LinearDeltaSensitivity = 50))
int32 Seed = FMath::Rand();
/** Whether or not the pattern items should be projected along the negative Z axis of the plane mechanic */
UPROPERTY(EditAnywhere, Category = General)
bool bProjectElementsDown = false;
/** How much each pattern item should be moved along the negative Z axis of the plane mechanic if Project Elements Down is enabled */
UPROPERTY(EditAnywhere, Category = General, meta = (EditCondition = "bProjectElementsDown == true", EditConditionHides, Delta = 0.1, LinearDeltaSensitivity = 1))
float ProjectionOffset = 0.0f;
/** Hide the source meshes when enabled */
UPROPERTY(EditAnywhere, Category = General)
bool bHideSources = true;
/** If false, all pattern elements will be positioned at the origin of the first pattern element */
UPROPERTY(EditAnywhere, Category = General)
bool bUseRelativeTransforms = true;
/** Whether to randomly pick which source mesh is scattered at each location, or to always use all source meshes */
UPROPERTY(EditAnywhere, Category = General)
bool bRandomlyPickElements = false;
/** Shape of the underlying Pattern */
UPROPERTY(EditAnywhere, Category = Shape)
EPatternToolShape Shape = EPatternToolShape::Line;
/** Axis direction used for the Pattern geometry */
UPROPERTY(EditAnywhere, Category = Shape, meta = (DisplayName = "Direction", EditCondition = "Shape == EPatternToolShape::Line", EditConditionHides))
EPatternToolSingleAxis SingleAxis = EPatternToolSingleAxis::XAxis;
/** Plane used for the Pattern geometry */
UPROPERTY(EditAnywhere, Category = Shape, meta = (DisplayName = "Plane", EditCondition = "Shape != EPatternToolShape::Line", EditConditionHides))
EPatternToolSinglePlane SinglePlane = EPatternToolSinglePlane::XYPlane;
};
/**
* Settings for Bounding Box adjustments in the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternTool_BoundingBoxSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** If true, pattern element bounding boxes are not changed to account for StartScale or StartRotation */
UPROPERTY(EditAnywhere, Category = BoundingBox)
bool bIgnoreTransforms = false;
/** Value added to the all pattern elements' bounding boxes for adjusting the behavior of packed spacing mode manually */
UPROPERTY(EditAnywhere, Category = BoundingBox, meta = (Delta = 0.1, LinearDeltaSensitivity = 1))
float Adjustment = 0.0f;
/** If true, the bounding boxes of each element are rendered in green and the combined bounding box of all source elements is rendered in red */
UPROPERTY(EditAnywhere, Category = BoundingBox)
bool bVisualize = false;
};
/**
* Settings for Linear Patterns in the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternTool_LinearSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Spacing Technique used to distribute Pattern Elements */
UPROPERTY(EditAnywhere, Category = LinearPattern)
EPatternToolAxisSpacingMode SpacingMode = EPatternToolAxisSpacingMode::ByCount;
/** Number of Pattern Elements to place */
UPROPERTY(EditAnywhere, Category = LinearPattern, meta = (ClampMin = 1, UIMax = 25, EditCondition = "SpacingMode == EPatternToolAxisSpacingMode::ByCount", EditConditionHides))
int32 Count = 10;
/** Fixed Increment used to place Pattern Elements */
UPROPERTY(EditAnywhere, Category = LinearPattern, meta = (ClampMin = 0, EditCondition = "SpacingMode == EPatternToolAxisSpacingMode::StepSize", EditConditionHides))
double StepSize = 100.0;
/** Length of Pattern along the Axis */
UPROPERTY(EditAnywhere, Category = LinearPattern, meta = (ClampMin = 0))
double Extent = 1000.0;
/** If true, Pattern is centered at the Origin, otherwise Pattern starts at the Origin */
UPROPERTY(EditAnywhere, Category = LinearPattern)
bool bCentered = true;
};
/**
* Settings for Grid Patterns in the Pattern Tool
* TODO: maybe we can just re-use UPatternTool_LinearSettings for this??
*/
UCLASS(MinimalAPI)
class UPatternTool_GridSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Spacing Technique used to distribute Pattern Elements along the Main axis */
UPROPERTY(EditAnywhere, Category = GridPatternX)
EPatternToolAxisSpacingMode SpacingX = EPatternToolAxisSpacingMode::ByCount;
/** Number of Pattern Elements to place along the Main axis */
UPROPERTY(EditAnywhere, Category = GridPatternX, meta = (ClampMin = 1, UIMax = 25, EditCondition = "SpacingX == EPatternToolAxisSpacingMode::ByCount", EditConditionHides))
int32 CountX = 10;
/** Fixed Increment used to place Pattern Elements along the Main axis */
UPROPERTY(EditAnywhere, Category = GridPatternX, meta = (ClampMin = 0, EditCondition = "SpacingX == EPatternToolAxisSpacingMode::StepSize", EditConditionHides))
double StepSizeX = 100.0;
/** Length/Extent of Pattern falong the Main Axis */
UPROPERTY(EditAnywhere, Category = GridPatternX, meta = (ClampMin = 0))
double ExtentX = 1000.0;
/** If true, Pattern is centered at the Origin along the Main axis, otherwise Pattern starts at the Origin */
UPROPERTY(EditAnywhere, Category = GridPatternX)
bool bCenteredX = true;
/** Spacing Technique used to distribute Pattern Elements along the Secondary axis*/
UPROPERTY(EditAnywhere, Category = GridPatternY)
EPatternToolAxisSpacingMode SpacingY = EPatternToolAxisSpacingMode::ByCount;
/** Number of Pattern Elements to place along the Secondary axis */
UPROPERTY(EditAnywhere, Category = GridPatternY, meta = (ClampMin = 1, UIMax = 25, EditCondition = "SpacingY == EPatternToolAxisSpacingMode::ByCount", EditConditionHides))
int32 CountY = 10;
/** Fixed Increment used to place Pattern Elements along the Secondary axis */
UPROPERTY(EditAnywhere, Category = GridPatternY, meta = (ClampMin = 0, EditCondition = "SpacingY == EPatternToolAxisSpacingMode::StepSize", EditConditionHides))
double StepSizeY = 100.0;
/** Length/Extent of Pattern falong the Secondary Axis */
UPROPERTY(EditAnywhere, Category = GridPatternY, meta = (ClampMin = 0))
double ExtentY = 1000.0;
/** If true, Pattern is centered at the Origin along the Secondary axis, otherwise Pattern starts at the Origin */
UPROPERTY(EditAnywhere, Category = GridPatternY)
bool bCenteredY = true;
};
/**
* Settings for Radial Patterns in the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternTool_RadialSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Spacing Technique used to distribute Pattern Elements around the Circle/Arc */
UPROPERTY(EditAnywhere, Category = RadialPattern)
EPatternToolAxisSpacingMode SpacingMode = EPatternToolAxisSpacingMode::ByCount;
/** Number of Pattern Elements to place */
UPROPERTY(EditAnywhere, Category = RadialPattern, meta = (ClampMin = 1, UIMax = 25, EditCondition = "SpacingMode == EPatternToolAxisSpacingMode::ByCount", EditConditionHides))
int32 Count = 10;
/** Fixed Increment (in Degrees) used to position Pattern Elements around the Circle/Arc */
UPROPERTY(EditAnywhere, Category = RadialPattern, meta = (Units = "Degrees", ClampMin = 0, EditCondition = "SpacingMode == EPatternToolAxisSpacingMode::StepSize", EditConditionHides))
double StepSize = 100.0;
/** Radius of the Circle/Arc */
UPROPERTY(EditAnywhere, Category = RadialPattern, meta = (ClampMin = 0))
double Radius = 250;
/** Start angle of the Circle/Arc */
UPROPERTY(EditAnywhere, Category = RadialPattern, meta = (Units = "Degrees", UIMin = -360, UIMax = 360))
double StartAngle = 0.0;
/** End angle of the Circle/Arc */
UPROPERTY(EditAnywhere, Category = RadialPattern, meta = (Units = "Degrees", UIMin = -360, UIMax = 360))
double EndAngle = 360.0;
/** Fixed offset added to Start/End Angles */
UPROPERTY(EditAnywhere, Category = RadialPattern, meta = (Units = "Degrees", ClampMin = -180, ClampMax = 180))
double AngleShift = 0.0;
/** If true, Pattern elements are rotated to align with the Circle tangent */
UPROPERTY(EditAnywhere, Category = RadialPattern)
bool bOriented = true;
};
/**
* Settings for Per Element Rotation in the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternTool_RotationSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** If true, Rotation is linearly interpolated between StartRotation and Rotation values */
UPROPERTY(EditAnywhere, Category = Rotation, meta = (InlineEditConditionToggle))
bool bInterpolate = false;
/** If true, Rotation at each Pattern Element is offset by a uniformly chosen random value in the range of [-RotationJitterRange, RotationJitterRange] */
UPROPERTY(EditAnywhere, Category = Rotation, meta = (InlineEditConditionToggle))
bool bJitter = false;
/** Rotation applied to all Pattern Elements, or to first Pattern Element for Interpolated rotation */
UPROPERTY(EditAnywhere, Category = Rotation, meta = (UIMin = -360, UIMax = 360))
FRotator StartRotation = FRotator::ZeroRotator;
/** Rotation applied to last Pattern Elements for Interpolated rotation */
UPROPERTY(EditAnywhere, Category = Rotation, meta = (EditCondition = "bInterpolate", UIMin = -360, UIMax = 360))
FRotator EndRotation = FRotator::ZeroRotator;
/** Upper bound of the range which is sampled to randomly rotate each Pattern Element if Jitter is true */
UPROPERTY(EditAnywhere, Category = Rotation, meta = (ClampMin = 0, EditCondition = "bJitter", UIMin = -360, UIMax = 360))
FRotator Jitter = FRotator::ZeroRotator;
};
/**
* Settings for Per Element Translation in the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternTool_TranslationSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** If true, Translation is linearly interpolated between StartTranslation and Translation values */
UPROPERTY(EditAnywhere, Category = Translation, meta = (InlineEditConditionToggle))
bool bInterpolate = false;
/** If true, Translation at each Pattern Element is offset by a uniformly chosen random value in the range of [-TranslationJitterRange, TranslationJitterRange] */
UPROPERTY(EditAnywhere, Category = Translation, meta = (InlineEditConditionToggle))
bool bJitter = false;
/** Translation applied to all Pattern Elements, or to first Pattern Element for Interpolated translation */
UPROPERTY(EditAnywhere, Category = Translation)
FVector StartTranslation = FVector::ZeroVector;
/** Translation applied to last Pattern Element for Interpolated translation */
UPROPERTY(EditAnywhere, Category = Translation, meta = (EditCondition = "bInterpolate"))
FVector EndTranslation = FVector::ZeroVector;
/** Upper bound of the range which is sampled to randomly translate each Pattern Element if Jitter is true */
UPROPERTY(EditAnywhere, Category = Translation, meta = (ClampMin = 0, EditCondition = "bJitter"))
FVector Jitter = FVector::ZeroVector;
};
/**
* Settings for Per Element Scale in the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternTool_ScaleSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Initial value for Jitter and referenced in FPatternGenerator when applying scale jitter. Can't be used for ClampMin. */
static constexpr double MinScale = 0.001;
/** If true, changes to Start Scale, End Scale, and Jitter are proportional along all the axes */
UPROPERTY(EditAnywhere, Category = Scale)
bool bProportional = true;
/** If true, Scale is linearly interpolated between StartScale and Scale values */
UPROPERTY(EditAnywhere, Category = Scale, meta = (InlineEditConditionToggle))
bool bInterpolate = false;
/** If true, Scale at each Pattern Element is offset by a uniformly chosen random value in the range of [-ScaleJitterRange, ScaleJitterRange] */
UPROPERTY(EditAnywhere, Category = Scale, meta = (InlineEditConditionToggle))
bool bJitter = false;
/** Scale applied to all Pattern Elements, or to first Pattern Element for Interpolated scale */
UPROPERTY(EditAnywhere, Category = Scale, meta = (ClampMin = 0.001, Delta = 0.01, LinearDeltaSensitivity = 1))
FVector StartScale = FVector::OneVector;
/** Scale applied to last Pattern Element for Interpolated scale */
UPROPERTY(EditAnywhere, Category = Scale, meta = (ClampMin = 0.001, EditCondition = "bInterpolate", Delta = 0.01, LinearDeltaSensitivity = 1))
FVector EndScale = FVector::OneVector;
/** Upper bound of the range which is sampled to randomly scale each Pattern Element if Jitter is true */
UPROPERTY(EditAnywhere, Category = Scale, meta = (ClampMin = 0.001, EditCondition = "bJitter", Delta = 0.01, LinearDeltaSensitivity = 1))
FVector Jitter = FVector(MinScale);
};
/**
* Output Settings for the Pattern Tool
*/
UCLASS(MinimalAPI)
class UPatternTool_OutputSettings : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Emit a separate Actor for each pattern element */
UPROPERTY(EditAnywhere, Category = Output)
bool bSeparateActors = false;
/** Emit StaticMesh pattern elements as DynamicMeshes */
UPROPERTY(EditAnywhere, Category = Output, meta = (EditCondition = "bHaveStaticMeshes == true", HideEditConditionToggle))
bool bConvertToDynamic = false;
/** Create InstancedStaticMeshComponents instead multiple StaticMeshComponents, for StaticMesh pattern elements */
UPROPERTY(EditAnywhere, Category = Output, meta = (EditCondition = "bHaveStaticMeshes == true && bSeparateActors == false && bConvertToDynamic == false && bEnableCreateISMCs == true", HideEditConditionToggle))
bool bCreateISMCs = false;
/** internal, used to control state of Instance settings */
UPROPERTY(meta = (TransientToolProperty))
bool bHaveStaticMeshes = false;
// internal, used to disable the creation of ISMCs
UPROPERTY(meta = (TransientToolProperty))
bool bEnableCreateISMCs = true;
};
/**
* UPatternTool takes input meshes and generates 3D Patterns of those meshes, by
* placing repeated copies along geometric paths like lines, grids, circles, etc.
* The output can be a single Actor per pattern Element, or combined into single
* Actors in various ways depending on the input mesh type.
*/
UCLASS(MinimalAPI)
class UPatternTool : public UMultiSelectionMeshEditingTool
{
GENERATED_BODY()
public:
UE_API UPatternTool();
UE_API virtual void Setup() override;
UE_API virtual void OnShutdown(EToolShutdownType ShutdownType) override;
UE_API virtual void Render(IToolsContextRenderAPI* RenderAPI) override;
UE_API virtual void OnPropertyModified(UObject* PropertySet, FProperty* Property) override;
virtual bool HasCancel() const override { return true; }
virtual bool HasAccept() const override { return true; }
virtual bool CanAccept() const override { return true; }
UE_API virtual void SetEnableCreateISMCs(bool bEnable);
public:
UPROPERTY()
TObjectPtr<UPatternToolSettings> Settings;
UPROPERTY()
TObjectPtr<UPatternTool_BoundingBoxSettings> BoundingBoxSettings;
UPROPERTY()
TObjectPtr<UPatternTool_LinearSettings> LinearSettings;
UPROPERTY()
TObjectPtr<UPatternTool_GridSettings> GridSettings;
UPROPERTY()
TObjectPtr<UPatternTool_RadialSettings> RadialSettings;
UPROPERTY()
TObjectPtr<UPatternTool_RotationSettings> RotationSettings;
UPROPERTY()
TObjectPtr<UPatternTool_TranslationSettings> TranslationSettings;
UPROPERTY()
TObjectPtr<UPatternTool_ScaleSettings> ScaleSettings;
FVector CachedStartScale;
FVector CachedEndScale;
FVector CachedJitterScale;
int32 StartScaleWatcherIdx;
int32 EndScaleWatcherIdx;
int32 JitterScaleWatcherIdx;
UPROPERTY()
TObjectPtr<UPatternTool_OutputSettings> OutputSettings;
protected:
/**
* Pattern Gizmo:
*/
UPROPERTY()
TObjectPtr<UComponentBoundTransformProxy> PatternGizmoProxy = nullptr;
UPROPERTY()
TObjectPtr<UInteractiveGizmo> PatternGizmo = nullptr;
UPROPERTY()
TObjectPtr<UPrimitiveComponent> PatternGizmoComponent = nullptr;
// If true, Settings->SingleAxis is being used. If false, Settings->SinglePlane is being used
bool bUsingSingleAxis;
int32 LinearExtentWatcherIdx;
int32 GridExtentXWatcherIdx;
int32 GridExtentYWatcherIdx;
int32 RadiusWatcherIdx;
UE_API void OnTransformGizmoUpdated(UTransformProxy* Proxy, FTransform Transform);
UE_API void ResetTransformGizmoPosition();
UE_API void ReconstructTransformGizmos();
UPROPERTY()
TObjectPtr<UDragAlignmentMechanic> DragAlignmentMechanic = nullptr;
UPROPERTY()
TObjectPtr<UConstructionPlaneMechanic> PlaneMechanic = nullptr;
UE::Geometry::FFrame3d CurrentStartFrameWorld;
TArray<UE::Geometry::FTransformSRT3d> CurrentPattern;
bool bPatternNeedsUpdating = false;
FDateTime LastPatternUpdateTime;
UE_API void MarkPatternDirty();
UE_API void OnSourceVisibilityToggled(bool bVisible);
UE_API void OnMainFrameUpdated();
UE_API void OnShapeUpdated();
UE_API void OnSingleAxisUpdated();
UE_API void OnSinglePlaneUpdated();
UE_API void OnSpacingModeUpdated();
UE_API void OnParametersUpdated();
UE_API void UpdatePattern();
UE_API void ComputeWorldTransform(FTransform& OutWorldTransform, const FTransform& InElementTransform, const FTransform& InPatternTransform) const;
UE_API void GetPatternTransforms_Linear(TArray<UE::Geometry::FTransformSRT3d>& TransformsOut);
UE_API void GetPatternTransforms_Grid(TArray<UE::Geometry::FTransformSRT3d>& TransformsOut);
UE_API void GetPatternTransforms_Radial(TArray<UE::Geometry::FTransformSRT3d>& TransformsOut);
UE_API void RenderBoundingBoxes(IToolsContextRenderAPI* RenderAPI);
FToolDataVisualizer BoundingBoxVisualizer;
struct FPatternElement
{
int32 TargetIndex = 0;
// todo: This is no longer necessary now that InitializeNewTool filters out invalid targets.
bool bValid = true;
UPrimitiveComponent* SourceComponent = nullptr;
TArray<UMaterialInterface*> SourceMaterials;
UE::Geometry::FTransformSRT3d SourceTransform = UE::Geometry::FTransformSRT3d::Identity();
UE::Geometry::FTransformSRT3d BaseRotateScale = UE::Geometry::FTransformSRT3d::Identity();
// We don't need to store rotation or scale relative to first
// element because that is handled by BaseRotateScale
FVector3d RelativePosition = FVector3d::ZeroVector;
UDynamicMesh* SourceDynamicMesh = nullptr;
UStaticMesh* SourceStaticMesh = nullptr;
UE::Geometry::FAxisAlignedBox3d LocalBounds = UE::Geometry::FAxisAlignedBox3d::Empty(); // The unchanged bounding box of the source mesh. Only used indirectly through PatternBounds
UE::Geometry::FAxisAlignedBox3d PatternBounds = UE::Geometry::FAxisAlignedBox3d::Empty(); // The bounding box used for computing CombinedPatternBounds for packed spacing. By default this box adapts to StartScale/StartRotation
};
TArray<FPatternElement> Elements;
UE::Geometry::FAxisAlignedBox3d CombinedPatternBounds = UE::Geometry::FAxisAlignedBox3d::Empty(); // The bounding box that contains all of the elements' PatternBounds bounding boxes. Used for packed mode spacing
UE_API void ComputePatternBounds(int32 ElemIdx);
UE_API void ComputeCombinedPatternBounds();
// Given an Element index and an FTransformSRT3d, determine the bounding box that contains the transformed underlying mesh
// BoundingBox is made empty before growing to contain the transformed mesh.
UE_API void ComputeBoundingBoxWithTransform(int32 ElemIdx, UE::Geometry::FAxisAlignedBox3d& BoundingBox, const UE::Geometry::FTransformSRT3d& Transform);
bool bHaveNonUniformScaleElements = false;
bool bEnableCreateISMCs = true;
struct FComponentSet
{
TArray<UPrimitiveComponent*> Components;
};
TArray<FComponentSet> PreviewComponents;
// This duplicates the data stored by PreviewComponents but it is necessary to have a simple
// TArray<UPrimitiveComponent*> of all preview components when raycasting, otherwise the raycasts
// will hit the preview components from the previous frame.
TArray<const UPrimitiveComponent*> AllPreviewComponents; // This is passed to FindNearestVisibleObjectHit as ComponentsToIgnore
protected:
UPROPERTY()
TSet<TObjectPtr<UPrimitiveComponent>> AllComponents; // to keep components in FComponentSet alive
TMap<int32, FComponentSet> StaticMeshPools;
UE_API UStaticMeshComponent* GetPreviewStaticMesh(const FPatternElement& Element);
UE_API void ReturnStaticMeshes(FPatternElement& Element, FComponentSet& ComponentSet);
TMap<int32, FComponentSet> DynamicMeshPools;
UE_API UDynamicMeshComponent* GetPreviewDynamicMesh(const FPatternElement& Element);
UE_API void ReturnDynamicMeshes(FPatternElement& Element, FComponentSet& ComponentSet);
UE_API void HideReturnedPreviewMeshes();
UPROPERTY()
TObjectPtr<UPreviewGeometry> PreviewGeometry = nullptr; // parent actor for all preview components
UE_API void InitializeElements();
UE_API void ResetPreviews();
UE_API void DestroyPreviews();
UE_API void EmitResults();
};
#undef UE_API