Files
UnrealEngine/Engine/Plugins/Runtime/MeshModelingToolset/Source/ModelingComponents/Public/Snapping/ModelingSceneSnappingManager.h
2025-05-18 13:04:45 +08:00

186 lines
7.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GeometryBase.h"
#include "SceneQueries/SceneSnappingManager.h"
#include "ModelingSceneSnappingManager.generated.h"
#define UE_API MODELINGCOMPONENTS_API
class IToolsContextQueriesAPI;
class UInteractiveToolsContext;
class UInteractiveToolManager;
class UDynamicMeshComponent;
PREDECLARE_GEOMETRY(class FSceneGeometrySpatialCache);
/**
* UModelingSceneSnappingManager is an implementation of snapping suitable for use in
* Modeling Tools/Gizmos (and potentially other places).
*
* Currently Supports:
* - snap to position/rotation grid
* - snap to mesh vertex position
* - snap to mesh edge position
*
* Snapping to mesh vertex/edge positions currently works for Volume (BrushComponent), StaticMeshComponent,
* and DynamicMeshComponent.
*
* Currently the StaticMesh vertex/edge snapping is dependent on the Physics
* system, and may fail or return nonsense results in some cases, due to the physics
* complex-collision mesh deviating from the source-model mesh.
*/
UCLASS(MinimalAPI)
class UModelingSceneSnappingManager : public USceneSnappingManager
{
GENERATED_BODY()
public:
UE_API virtual void Initialize(TObjectPtr<UInteractiveToolsContext> ToolsContext);
UE_API virtual void Shutdown();
//
// USceneSnappingManager API
//
/**
* Try to find a Hit Point in the scene that satisfies the HitQuery Request.
* @param Request hit query configuration
* @param ResultOut hit query result, if return is true
* @return true if a valid hit was found
* @warning implementations are not required (and may not be able) to support hit-testing
*/
UE_API virtual bool ExecuteSceneHitQuery(const FSceneHitQueryRequest& Request, FSceneHitQueryResult& ResultOut) const override;
/**
* Try to find Snap Targets in the scene that satisfy the Snap Query.
* @param Request snap query configuration
* @param Results list of potential snap results
* @return true if any valid snap target was found
* @warning implementations are not required (and may not be able) to support snapping
*/
UE_API virtual bool ExecuteSceneSnapQuery(const FSceneSnapQueryRequest& Request, TArray<FSceneSnapQueryResult>& Results) const override;
//
// API for managing the set of Actors/Components that the snapping system knows about.
// Currently this is for Volumes and DynamicMeshActors/Components, the SnappingManager builds
// it's own spatial data structure cache for these types of meshes. StaticMeshComponents are
// automatically included and handled via world-traces and the physics system.
//
public:
/** @return true if this Component type is supported by the spatial-cache tracking for hit and snap testing */
UE_API virtual bool IsComponentTypeSupported(const UPrimitiveComponent* Component) const;
/** Enable spatial-cache tracking for the Components of the Actor that pass the PrimitiveFilter */
UE_API virtual void OnActorAdded(AActor* Actor, TFunctionRef<bool(UPrimitiveComponent*)> PrimitiveFilter);
/** Disable spatial-cache tracking for any Components of the Actor */
UE_API virtual void OnActorRemoved(AActor* Actor);
/** Enable spatial-cache tracking for the Component */
UE_API virtual void OnComponentAdded(UPrimitiveComponent* Component);
/** Disable spatial-cache tracking for the Component */
UE_API virtual void OnComponentRemoved(UPrimitiveComponent* Component);
/** Notify the internal spatial-cache tracking system that the Component has been modified (ie cache needs to be rebiult) */
UE_API virtual void OnComponentModified(UActorComponent* Component);
/** Explicitly populate the spatial-cache tracking set with specific Actors/Components (alternative to OnActorAdded route) */
UE_API virtual void BuildSpatialCacheForWorld(
UWorld* World,
TFunctionRef<bool(AActor*)> ActorFilter,
TFunctionRef<bool(UPrimitiveComponent*)> PrimitiveFilter );
//
// APIs for configuring the SceneSnappingManager behavior
//
public:
/***
* Temporarily disable live updates of any modified Actors/Components. Any changes that are
* detected while updates are paused will be executed on Unpause.
* This is mainly intended for use in interactive operations, eg while live-editing a mesh,
* changes may be posted every frame but the cache BVHs/etc only need to be updated on mouse-up, etc
*/
UE_API virtual void PauseSceneGeometryUpdates();
/**
* Re-enable live updates that were prevented by PauseSceneGeometryUpdates(), and execute
* any pending updates that were requested while in the pause state.
* @param bImmediateRebuilds If true (default), things like BVH updates will happen immediately, instead of simply being marked as pending
*/
UE_API virtual void UnPauseSceneGeometryUpdates(bool bImmediateRebuilds = true);
protected:
UPROPERTY()
TObjectPtr<UInteractiveToolsContext> ParentContext;
const IToolsContextQueriesAPI* QueriesAPI = nullptr;
UE_API virtual bool ExecuteSceneSnapQueryRotation(const FSceneSnapQueryRequest& Request, TArray<FSceneSnapQueryResult>& Results) const;
UE_API virtual bool ExecuteSceneSnapQueryPosition(const FSceneSnapQueryRequest& Request, TArray<FSceneSnapQueryResult>& Results) const;
// This map allows us to identify the Components belonging to Actors. Need to store this
// because if the Actor is deleted we will not be able to identify it's (previous) Components
TMap<UPrimitiveComponent*, AActor*> ComponentToActorMap;
// cache for objects in the level
TSharedPtr<UE::Geometry::FSceneGeometrySpatialCache> SpatialCache;
FDelegateHandle OnObjectModifiedHandler;
UE_API void HandleGlobalObjectModifiedDelegate(UObject* Object);
FDelegateHandle OnComponentTransformChangedHandle;
UE_API void HandleGlobalComponentTransformChangedDelegate(USceneComponent* Component);
TMap<UPrimitiveComponent*, TWeakObjectPtr<UDynamicMeshComponent>> DynamicMeshComponents;
UE_API void HandleDynamicMeshModifiedDelegate(UDynamicMeshComponent* Component);
// PauseSceneGeometryUpdates / UnPauseSceneGeometryUpdates support
bool bQueueModifiedDynamicMeshUpdates = false;
TSet<UDynamicMeshComponent*> PendingModifiedDynamicMeshes;
};
namespace UE
{
namespace Geometry
{
//
// The functions below are helper functions that simplify usage of a UModelingSceneSnappingManager
// that is registered as a ContextStoreObject in an InteractiveToolsContext
//
/**
* If one does not already exist, create a new instance of UModelingSceneSnappingManager and add it to the
* ToolsContext's ContextObjectStore
* @return true if the ContextObjectStore now has a UModelingSceneSnappingManager (whether it already existed, or was created)
*/
MODELINGCOMPONENTS_API bool RegisterSceneSnappingManager(UInteractiveToolsContext* ToolsContext);
/**
* Remove any existing UModelingSceneSnappingManager from the ToolsContext's ContextObjectStore
* @return true if the ContextObjectStore no longer has a UModelingSceneSnappingManager (whether it was removed, or did not exist)
*/
MODELINGCOMPONENTS_API bool DeregisterSceneSnappingManager(UInteractiveToolsContext* ToolsContext);
/**
* Find an existing UModelingSceneSnappingManager in the ToolsContext's ContextObjectStore
* @return SelectionManager pointer or nullptr if not found
*/
MODELINGCOMPONENTS_API UModelingSceneSnappingManager* FindModelingSceneSnappingManager(UInteractiveToolManager* ToolManager);
}
}
#undef UE_API