2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
# include "MeshSelectionTool.h"
# include "InteractiveToolManager.h"
# include "ToolBuilderUtil.h"
# include "Drawing/MeshDebugDrawing.h"
# include "DynamicMeshEditor.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMeshChangeTracker.h"
2019-10-01 20:41:42 -04:00
# include "Changes/ToolCommandChangeSequence.h"
# include "Changes/MeshChange.h"
2019-12-19 18:07:47 -05:00
# include "Util/ColorConstants.h"
# include "Selections/MeshConnectedComponents.h"
# include "MeshRegionBoundaryLoops.h"
2021-05-22 01:32:46 -04:00
# include "DynamicMesh/MeshIndexUtil.h"
2021-06-02 15:58:00 -04:00
# include "ModelingObjectsCreationAPI.h"
2019-10-01 20:41:42 -04:00
# include "ToolSetupUtil.h"
2019-12-19 18:07:47 -05:00
# include "Selections/MeshConnectedComponents.h"
2020-01-27 20:11:15 -05:00
# include "Selections/MeshFaceSelection.h"
2021-06-11 22:42:32 -04:00
# include "ModelingToolTargetUtil.h"
2021-06-25 01:41:35 -04:00
# include "Properties/MeshStatisticsProperties.h"
# include "Drawing/MeshElementsVisualizer.h"
# include "Properties/MeshUVChannelProperties.h"
# include "PropertySets/PolygroupLayersProperties.h"
# include "Polygroups/PolygroupUtil.h"
2020-01-27 20:11:15 -05:00
# include "Algo/MaxElement.h"
2019-10-01 20:41:42 -04:00
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2019-10-01 20:41:42 -04:00
# define LOCTEXT_NAMESPACE "UMeshSelectionTool"
/*
* ToolBuilder
*/
UMeshSurfacePointTool * UMeshSelectionToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
{
UMeshSelectionTool * SelectionTool = NewObject < UMeshSelectionTool > ( SceneState . ToolManager ) ;
SelectionTool - > SetWorld ( SceneState . World ) ;
return SelectionTool ;
}
2020-04-18 18:42:59 -04:00
/*
* Properties
*/
2019-10-01 20:41:42 -04:00
void UMeshSelectionToolActionPropertySet : : PostAction ( EMeshSelectionToolActions Action )
{
if ( ParentTool . IsValid ( ) )
{
ParentTool - > RequestAction ( Action ) ;
}
}
/*
* Tool
*/
UMeshSelectionTool : : UMeshSelectionTool ( )
{
}
void UMeshSelectionTool : : SetWorld ( UWorld * World )
{
this - > TargetWorld = World ;
}
void UMeshSelectionTool : : Setup ( )
{
UDynamicMeshBrushTool : : Setup ( ) ;
2019-12-19 18:07:47 -05:00
// hide strength and falloff
2020-03-13 13:40:51 -04:00
BrushProperties - > bShowStrength = BrushProperties - > bShowFalloff = false ;
2020-01-27 20:11:15 -05:00
BrushProperties - > RestoreProperties ( this ) ;
2019-12-19 18:07:47 -05:00
2019-10-01 20:41:42 -04:00
SelectionProps = NewObject < UMeshSelectionToolProperties > ( this ) ;
SelectionProps - > RestoreProperties ( this ) ;
AddToolPropertySource ( SelectionProps ) ;
2021-06-25 01:41:35 -04:00
PolygroupLayerProperties = NewObject < UPolygroupLayersProperties > ( this ) ;
PolygroupLayerProperties - > RestoreProperties ( this ) ;
PreviewMesh - > ProcessMesh ( [ & ] ( const FDynamicMesh3 & ReadMesh ) { PolygroupLayerProperties - > InitializeGroupLayers ( & ReadMesh ) ; } ) ;
PolygroupLayerProperties - > WatchProperty ( PolygroupLayerProperties - > ActiveGroupLayer , [ & ] ( FName ) { UpdateActiveGroupLayer ( ) ; bColorsUpdatePending = true ; bFullMeshInvalidationPending = true ; } ) ;
AddToolPropertySource ( PolygroupLayerProperties ) ;
UpdateActiveGroupLayer ( ) ;
UVChannelProperties = NewObject < UMeshUVChannelProperties > ( this ) ;
UVChannelProperties - > RestoreProperties ( this ) ;
PreviewMesh - > ProcessMesh ( [ & ] ( const FDynamicMesh3 & ReadMesh ) { UVChannelProperties - > Initialize ( & ReadMesh , false ) ; } ) ;
UVChannelProperties - > ValidateSelection ( true ) ;
UVChannelProperties - > WatchProperty ( UVChannelProperties - > UVChannel , [ this ] ( const FString & NewValue ) { CacheUVIslandIDs ( ) ; bColorsUpdatePending = true ; bFullMeshInvalidationPending = true ; } ) ;
AddToolPropertySource ( UVChannelProperties ) ;
// we could probably calculate this on-demand but we need to do it before making any mesh changes? or update?
CacheUVIslandIDs ( ) ;
2019-12-19 18:07:47 -05:00
AddSubclassPropertySets ( ) ;
2019-10-01 20:41:42 -04:00
SelectionActions = NewObject < UMeshSelectionEditActions > ( this ) ;
SelectionActions - > Initialize ( this ) ;
AddToolPropertySource ( SelectionActions ) ;
2019-12-19 18:07:47 -05:00
EditActions = CreateEditActions ( ) ;
2019-10-01 20:41:42 -04:00
AddToolPropertySource ( EditActions ) ;
2020-03-07 10:52:46 -05:00
// set autocalculated tangents
2021-06-11 22:42:32 -04:00
PreviewMesh - > SetTangentsMode ( EDynamicMeshComponentTangentsMode : : AutoCalculated ) ;
2020-03-07 10:52:46 -05:00
2019-12-19 18:07:47 -05:00
// disable shadows
2021-06-17 19:18:41 -04:00
PreviewMesh - > SetShadowsEnabled ( false ) ;
2019-10-01 20:41:42 -04:00
2019-12-19 18:07:47 -05:00
// configure secondary render material
UMaterialInterface * SelectionMaterial = ToolSetupUtil : : GetSelectionMaterial ( FLinearColor ( 0.9f , 0.1f , 0.1f ) , GetToolManager ( ) ) ;
if ( SelectionMaterial ! = nullptr )
{
PreviewMesh - > SetSecondaryRenderMaterial ( SelectionMaterial ) ;
}
// enable secondary triangle buffers
PreviewMesh - > EnableSecondaryTriangleBuffers (
[ this ] ( const FDynamicMesh3 * Mesh , int32 TriangleID )
{
return SelectedTriangles [ TriangleID ] ? true : false ;
} ) ;
2021-01-24 16:05:21 -04:00
// enable auto-chunking of mesh into separate render buffers, so that partial updates can be done during selection paint
PreviewMesh - > SetEnableRenderMeshDecomposition ( true ) ;
2019-10-01 20:41:42 -04:00
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
SelectedVertices = TBitArray < > ( false , Mesh - > MaxVertexID ( ) ) ;
SelectedTriangles = TBitArray < > ( false , Mesh - > MaxTriangleID ( ) ) ;
this - > Selection = NewObject < UMeshSelectionSet > ( this ) ;
Selection - > GetOnModified ( ) . AddLambda ( [ this ] ( USelectionSet * SelectionObj )
{
OnExternalSelectionChange ( ) ;
} ) ;
// rebuild octree if mesh changes
2021-06-25 01:41:35 -04:00
PreviewMesh - > GetOnMeshChanged ( ) . AddLambda ( [ this ] ( ) {
bOctreeValid = false ;
bFullMeshInvalidationPending = true ;
bColorsUpdatePending = true ;
CacheUVIslandIDs ( ) ;
UpdateActiveGroupLayer ( ) ;
} ) ;
2019-10-01 20:41:42 -04:00
2020-04-18 18:42:59 -04:00
SelectionProps - > WatchProperty ( SelectionProps - > FaceColorMode ,
[ this ] ( EMeshFacesColorMode NewValue )
{
bColorsUpdatePending = true ; UpdateVisualization ( false ) ;
} ) ;
2019-12-19 18:07:47 -05:00
bColorsUpdatePending = ( SelectionProps - > FaceColorMode ! = EMeshFacesColorMode : : None ) ;
2020-01-27 20:11:15 -05:00
2021-06-25 01:41:35 -04:00
MeshElementsDisplay = NewObject < UMeshElementsVisualizer > ( this ) ;
MeshElementsDisplay - > CreateInWorld ( PreviewMesh - > GetWorld ( ) , PreviewMesh - > GetTransform ( ) ) ;
if ( ensure ( MeshElementsDisplay - > Settings ) )
{
MeshElementsDisplay - > Settings - > bShowWireframe = true ;
MeshElementsDisplay - > Settings - > bShowUVSeams = false ;
MeshElementsDisplay - > Settings - > bShowNormalSeams = false ;
MeshElementsDisplay - > Settings - > bShowColorSeams = false ;
MeshElementsDisplay - > Settings - > RestoreProperties ( this , TEXT ( " MeshSelection " ) ) ;
AddToolPropertySource ( MeshElementsDisplay - > Settings ) ;
}
MeshElementsDisplay - > SetMeshAccessFunction ( [ this ] ( UMeshElementsVisualizer : : ProcessDynamicMeshFunc ProcessFunc ) {
PreviewMesh - > ProcessMesh ( ProcessFunc ) ;
} ) ;
MeshStatisticsProperties = NewObject < UMeshStatisticsProperties > ( this ) ;
AddToolPropertySource ( MeshStatisticsProperties ) ;
2020-01-27 20:11:15 -05:00
RecalculateBrushRadius ( ) ;
UpdateVisualization ( true ) ;
2020-03-10 14:00:36 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " Select Triangles " ) ) ;
2020-03-10 14:00:36 -04:00
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnStartMeshSelectionTool " , " This Tool allows you to modify the mesh based on a triangle selection. [Q] cyles through Selection Mode. [A] cycles through Face Color modes. [ and ] change brush size, < and > grow/shrink selection. " ) ,
EToolMessageLevel : : UserNotification ) ;
2019-10-01 20:41:42 -04:00
}
2019-12-19 18:07:47 -05:00
UMeshSelectionToolActionPropertySet * UMeshSelectionTool : : CreateEditActions ( )
{
UMeshSelectionMeshEditActions * Actions = NewObject < UMeshSelectionMeshEditActions > ( this ) ;
Actions - > Initialize ( this ) ;
return Actions ;
}
2019-10-01 20:41:42 -04:00
2021-06-25 01:41:35 -04:00
void UMeshSelectionTool : : ApplyShutdownAction ( EToolShutdownType ShutdownType )
2019-10-01 20:41:42 -04:00
{
if ( bHaveModifiedMesh & & ShutdownType = = EToolShutdownType : : Accept )
{
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " MeshSelectionToolTransactionName " , " Edit Mesh " ) ) ;
2021-06-11 22:42:32 -04:00
UE : : ToolTarget : : CommitDynamicMeshUpdate ( Target , * PreviewMesh - > GetMesh ( ) , true ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
2020-02-14 19:26:35 -05:00
else if ( ShutdownType = = EToolShutdownType : : Cancel )
{
for ( AActor * Spawned : SpawnedActors )
{
Spawned - > Destroy ( ) ;
}
}
2019-10-01 20:41:42 -04:00
}
2021-06-25 01:41:35 -04:00
void UMeshSelectionTool : : OnShutdown ( EToolShutdownType ShutdownType )
{
SelectionProps - > SaveProperties ( this ) ;
BrushProperties - > SaveProperties ( this ) ;
UVChannelProperties - > SaveProperties ( this ) ;
PolygroupLayerProperties - > SaveProperties ( this ) ;
if ( ensure ( MeshElementsDisplay - > Settings ) )
{
MeshElementsDisplay - > Settings - > SaveProperties ( this , TEXT ( " MeshSelection " ) ) ;
}
MeshElementsDisplay - > Disconnect ( ) ;
ApplyShutdownAction ( ShutdownType ) ;
}
2019-10-01 20:41:42 -04:00
void UMeshSelectionTool : : RegisterActions ( FInteractiveToolActionSet & ActionSet )
{
UDynamicMeshBrushTool : : RegisterActions ( ActionSet ) ;
2021-01-25 21:09:02 -04:00
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 50 ,
TEXT ( " TriSelectIncreaseSize " ) ,
LOCTEXT ( " TriSelectIncreaseSize " , " Increase Size " ) ,
LOCTEXT ( " TriSelectIncreaseSizeTooltip " , " Increase Brush Size " ) ,
EModifierKey : : None , EKeys : : D ,
[ this ] ( ) { IncreaseBrushSizeAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 51 ,
TEXT ( " TriSelectDecreaseSize " ) ,
LOCTEXT ( " TriSelectDecreaseSize " , " Decrease Size " ) ,
LOCTEXT ( " TriSelectDecreaseSizeTooltip " , " Decrease Brush Size " ) ,
EModifierKey : : None , EKeys : : S ,
[ this ] ( ) { DecreaseBrushSizeAction ( ) ; } ) ;
2019-10-01 20:41:42 -04:00
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 1 ,
TEXT ( " MeshSelectionToolDelete " ) ,
LOCTEXT ( " MeshSelectionToolDelete " , " Delete " ) ,
LOCTEXT ( " MeshSelectionToolDeleteTooltip " , " Delete Selected Elements " ) ,
EModifierKey : : None , EKeys : : Delete ,
[ this ] ( ) { DeleteSelectedTriangles ( ) ; } ) ;
2020-01-27 20:11:15 -05:00
# if WITH_EDITOR // enum HasMetaData() is not available at runtime
ActionSet . RegisterAction ( this , ( int32 ) EMeshSelectionToolActions : : CycleSelectionMode ,
TEXT ( " CycleSelectionMode " ) ,
LOCTEXT ( " CycleSelectionMode " , " Cycle Selection Mode " ) ,
LOCTEXT ( " CycleSelectionModeTooltip " , " Cycle through selection modes " ) ,
EModifierKey : : None , EKeys : : Q ,
[ this ] ( ) {
const UEnum * SelectionModeEnum = StaticEnum < EMeshSelectionToolPrimaryMode > ( ) ;
check ( SelectionModeEnum ) ;
int32 NumEnum = SelectionModeEnum - > NumEnums ( ) - 1 ;
do {
SelectionProps - > SelectionMode = ( EMeshSelectionToolPrimaryMode ) ( ( ( int32 ) SelectionProps - > SelectionMode + 1 ) % NumEnum ) ;
} while ( SelectionModeEnum - > HasMetaData ( TEXT ( " Hidden " ) , ( int32 ) SelectionProps - > SelectionMode ) ) ;
}
) ;
ActionSet . RegisterAction ( this , ( int32 ) EMeshSelectionToolActions : : CycleViewMode ,
TEXT ( " CycleViewMode " ) ,
LOCTEXT ( " CycleViewMode " , " Cycle View Mode " ) ,
LOCTEXT ( " CycleViewModeTooltip " , " Cycle through face coloring modes " ) ,
EModifierKey : : None , EKeys : : A ,
[ this ] ( ) {
const UEnum * ViewModeEnum = StaticEnum < EMeshFacesColorMode > ( ) ;
check ( ViewModeEnum ) ;
int32 NumEnum = ViewModeEnum - > NumEnums ( ) - 1 ;
do {
SelectionProps - > FaceColorMode = ( EMeshFacesColorMode ) ( ( ( int32 ) SelectionProps - > FaceColorMode + 1 ) % NumEnum ) ;
} while ( ViewModeEnum - > HasMetaData ( TEXT ( " Hidden " ) , ( int32 ) SelectionProps - > FaceColorMode ) ) ;
}
) ;
# endif
ActionSet . RegisterAction ( this , ( int32 ) EMeshSelectionToolActions : : ShrinkSelection ,
TEXT ( " ShrinkSelection " ) ,
LOCTEXT ( " ShrinkSelection " , " Shrink Selection " ) ,
LOCTEXT ( " ShrinkSelectionTooltip " , " Shrink selection " ) ,
2020-03-10 14:00:36 -04:00
EModifierKey : : Shift , EKeys : : Comma ,
2020-01-27 20:11:15 -05:00
[ this ] ( ) { GrowShrinkSelection ( false ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EMeshSelectionToolActions : : GrowSelection ,
TEXT ( " GrowSelection " ) ,
LOCTEXT ( " GrowSelection " , " Grow Selection " ) ,
LOCTEXT ( " GrowSelectionTooltip " , " Grow selection " ) ,
2020-03-10 14:00:36 -04:00
EModifierKey : : Shift , EKeys : : Period ,
2020-01-27 20:11:15 -05:00
[ this ] ( ) { GrowShrinkSelection ( true ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EMeshSelectionToolActions : : OptimizeSelection ,
TEXT ( " OptimizeSelection " ) ,
LOCTEXT ( " OptimizeSelection " , " Optimize Selection " ) ,
LOCTEXT ( " OptimizeSelectionTooltip " , " Optimize selection " ) ,
EModifierKey : : None , EKeys : : O ,
[ this ] ( ) { OptimizeSelection ( ) ; } ) ;
2022-02-08 15:08:17 -05:00
ActionSet . RegisterAction ( this , ( int32 ) EMeshSelectionToolActions : : SmoothBoundary ,
TEXT ( " SmoothBoundary " ) ,
LOCTEXT ( " SmoothBoundary " , " Smooth Boundary " ) ,
LOCTEXT ( " SmoothBoundaryTooltip " , " Smooth Boundary " ) ,
EModifierKey : : None , EKeys : : B ,
[ this ] ( ) { SmoothSelectionBoundary ( ) ; } ) ;
2019-10-01 20:41:42 -04:00
}
void UMeshSelectionTool : : OnExternalSelectionChange ( )
{
2021-01-24 16:05:21 -04:00
int32 NumTriangles = SelectedTriangles . Num ( ) ;
TSet < int32 > AllModifiedTriangles ;
for ( int32 k = 0 ; k < NumTriangles ; + + k )
{
if ( SelectedTriangles [ k ] )
{
AllModifiedTriangles . Add ( k ) ;
}
}
2019-10-01 20:41:42 -04:00
SelectedVertices . SetRange ( 0 , SelectedVertices . Num ( ) , false ) ;
SelectedTriangles . SetRange ( 0 , SelectedTriangles . Num ( ) , false ) ;
if ( SelectionType = = EMeshSelectionElementType : : Vertex )
{
2021-01-24 16:05:21 -04:00
ensure ( false ) ; // not supported
2019-10-01 20:41:42 -04:00
for ( int VertIdx : Selection - > Vertices )
{
SelectedVertices [ VertIdx ] = true ;
}
}
else if ( SelectionType = = EMeshSelectionElementType : : Face )
{
for ( int FaceIdx : Selection - > Faces )
{
SelectedTriangles [ FaceIdx ] = true ;
2021-01-24 16:05:21 -04:00
AllModifiedTriangles . Add ( FaceIdx ) ;
2019-10-01 20:41:42 -04:00
}
2021-01-24 16:05:21 -04:00
// todo: more efficient for rendering update to compute the delta set here...
OnRegionHighlightUpdated ( AllModifiedTriangles ) ;
2019-10-01 20:41:42 -04:00
}
}
bool UMeshSelectionTool : : HitTest ( const FRay & Ray , FHitResult & OutHit )
{
bool bHit = UDynamicMeshBrushTool : : HitTest ( Ray , OutHit ) ;
if ( bHit & & SelectionProps - > bHitBackFaces = = false )
{
const FDynamicMesh3 * SourceMesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
FVector3d Normal , Centroid ;
double Area ;
SourceMesh - > GetTriInfo ( OutHit . FaceIndex , Normal , Area , Centroid ) ;
FViewCameraState StateOut ;
GetToolManager ( ) - > GetContextQueriesAPI ( ) - > GetCurrentViewState ( StateOut ) ;
2022-01-29 14:37:53 -05:00
FTransform3d LocalToWorld = UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
2021-06-11 22:42:32 -04:00
FVector3d LocalEyePosition ( LocalToWorld . InverseTransformPosition ( StateOut . Position ) ) ;
2019-10-01 20:41:42 -04:00
if ( Normal . Dot ( ( Centroid - LocalEyePosition ) ) > 0 )
{
bHit = false ;
}
}
return bHit ;
}
void UMeshSelectionTool : : OnBeginDrag ( const FRay & WorldRay )
{
UDynamicMeshBrushTool : : OnBeginDrag ( WorldRay ) ;
PreviewBrushROI . Reset ( ) ;
if ( IsInBrushStroke ( ) )
{
bInRemoveStroke = GetShiftToggle ( ) ;
BeginChange ( bInRemoveStroke = = false ) ;
StartStamp = UBaseBrushTool : : LastBrushStamp ;
LastStamp = StartStamp ;
bStampPending = true ;
}
}
void UMeshSelectionTool : : OnUpdateDrag ( const FRay & WorldRay )
{
UDynamicMeshBrushTool : : OnUpdateDrag ( WorldRay ) ;
if ( IsInBrushStroke ( ) )
{
LastStamp = UBaseBrushTool : : LastBrushStamp ;
bStampPending = true ;
}
}
TUniquePtr < FDynamicMeshOctree3 > & UMeshSelectionTool : : GetOctree ( )
{
if ( bOctreeValid = = false )
{
Octree = MakeUnique < FDynamicMeshOctree3 > ( ) ;
Octree - > Initialize ( PreviewMesh - > GetPreviewDynamicMesh ( ) ) ;
bOctreeValid = true ;
}
return Octree ;
}
void UMeshSelectionTool : : CalculateVertexROI ( const FBrushStampData & Stamp , TArray < int > & VertexROI )
{
2022-01-29 14:37:53 -05:00
FTransform3d Transform = UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
2021-03-30 21:25:22 -04:00
FVector3d StampPosLocal = Transform . InverseTransformPosition ( ( FVector3d ) Stamp . WorldPosition ) ;
2019-10-01 20:41:42 -04:00
// TODO: need dynamic vertex hash table!
2020-10-22 19:19:16 -04:00
float Radius = GetCurrentBrushRadiusLocal ( ) ;
float RadiusSqr = Radius * Radius ;
2019-10-01 20:41:42 -04:00
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
for ( int VertIdx : Mesh - > VertexIndicesItr ( ) )
{
FVector3d Position = Mesh - > GetVertex ( VertIdx ) ;
if ( ( Position - StampPosLocal ) . SquaredLength ( ) < RadiusSqr )
{
VertexROI . Add ( VertIdx ) ;
}
}
}
void UMeshSelectionTool : : CalculateTriangleROI ( const FBrushStampData & Stamp , TArray < int > & TriangleROI )
{
2022-01-29 14:37:53 -05:00
FTransform3d Transform = UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
2021-03-30 21:25:22 -04:00
FVector3d StampPosLocal = Transform . InverseTransformPosition ( ( FVector3d ) Stamp . WorldPosition ) ;
2019-10-01 20:41:42 -04:00
// always select first triangle
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
2020-10-22 19:19:16 -04:00
float Radius = GetCurrentBrushRadiusLocal ( ) ;
float RadiusSqr = Radius * Radius ;
2020-01-27 20:11:15 -05:00
if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : VolumetricBrush )
2019-10-01 20:41:42 -04:00
{
if ( Mesh - > IsTriangle ( Stamp . HitResult . FaceIndex ) )
{
TriangleROI . Add ( Stamp . HitResult . FaceIndex ) ;
}
2020-10-22 19:19:16 -04:00
FAxisAlignedBox3d Bounds ( StampPosLocal - Radius * FVector3d : : One ( ) , StampPosLocal + Radius * FVector3d : : One ( ) ) ;
2019-10-01 20:41:42 -04:00
TemporaryBuffer . Reset ( ) ;
GetOctree ( ) - > RangeQuery ( Bounds , TemporaryBuffer ) ;
for ( int32 TriIdx : TemporaryBuffer )
{
FVector3d Position = Mesh - > GetTriCentroid ( TriIdx ) ;
if ( ( Position - StampPosLocal ) . SquaredLength ( ) < RadiusSqr )
{
TriangleROI . Add ( TriIdx ) ;
}
}
}
else
{
TArray < int32 > StartROI ;
StartROI . Add ( Stamp . HitResult . FaceIndex ) ;
2019-12-19 18:07:47 -05:00
FMeshConnectedComponents : : GrowToConnectedTriangles ( Mesh , StartROI , TriangleROI , & TemporaryBuffer , & TemporarySet ,
2019-10-01 20:41:42 -04:00
[ Mesh , RadiusSqr , StampPosLocal ] ( int t1 , int t2 ) { return ( Mesh - > GetTriCentroid ( t2 ) - StampPosLocal ) . SquaredLength ( ) < RadiusSqr ; } ) ;
}
}
static void UpdateList ( TArray < int > & List , int Value , bool bAdd )
{
if ( bAdd )
{
List . Add ( Value ) ;
}
else
{
List . RemoveSwap ( Value ) ;
}
}
void UMeshSelectionTool : : ApplyStamp ( const FBrushStampData & Stamp )
{
IndexBuf . Reset ( ) ;
bool bDesiredValue = bInRemoveStroke ? false : true ;
if ( SelectionType = = EMeshSelectionElementType : : Face )
{
CalculateTriangleROI ( Stamp , IndexBuf ) ;
UpdateFaceSelection ( Stamp , IndexBuf ) ;
}
else
{
CalculateVertexROI ( Stamp , IndexBuf ) ;
for ( int VertIdx : IndexBuf )
{
if ( SelectedVertices [ VertIdx ] ! = bDesiredValue )
{
SelectedVertices [ VertIdx ] = bDesiredValue ;
UpdateList ( Selection - > Vertices , VertIdx , bDesiredValue ) ;
if ( ActiveSelectionChange ! = nullptr )
{
ActiveSelectionChange - > Add ( VertIdx ) ;
}
}
}
2021-01-24 16:05:21 -04:00
ensure ( false ) ; // not supported yet
}
2019-10-01 20:41:42 -04:00
}
void UMeshSelectionTool : : UpdateFaceSelection ( const FBrushStampData & Stamp , const TArray < int > & TriangleROI )
{
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
const TArray < int > * UseROI = & TriangleROI ;
TArray < int > LocalROI ;
if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : AllConnected )
{
2019-12-19 18:07:47 -05:00
FMeshConnectedComponents : : GrowToConnectedTriangles ( Mesh , TriangleROI , LocalROI , & TemporaryBuffer , & TemporarySet ) ;
2019-10-01 20:41:42 -04:00
UseROI = & LocalROI ;
}
else if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : AllInGroup )
{
2019-12-19 18:07:47 -05:00
FMeshConnectedComponents : : GrowToConnectedTriangles ( Mesh , TriangleROI , LocalROI , & TemporaryBuffer , & TemporarySet ,
2021-06-25 01:41:35 -04:00
[ & ] ( int t1 , int t2 ) { return ActiveGroupSet - > GetTriangleGroup ( t1 ) = = ActiveGroupSet - > GetTriangleGroup ( t2 ) ; } ) ;
2019-10-01 20:41:42 -04:00
UseROI = & LocalROI ;
}
2019-12-19 18:07:47 -05:00
else if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : ByMaterial )
{
const FDynamicMeshMaterialAttribute * MaterialIDs = Mesh - > Attributes ( ) - > GetMaterialID ( ) ;
TArray < int32 > StartROI ;
StartROI . Add ( Stamp . HitResult . FaceIndex ) ;
FMeshConnectedComponents : : GrowToConnectedTriangles ( Mesh , StartROI , LocalROI , & TemporaryBuffer , & TemporarySet ,
[ Mesh , MaterialIDs ] ( int t1 , int t2 ) { return MaterialIDs - > GetValue ( t1 ) = = MaterialIDs - > GetValue ( t2 ) ; } ) ;
UseROI = & LocalROI ;
}
else if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : ByUVIsland )
{
const FDynamicMeshMaterialAttribute * MaterialIDs = Mesh - > Attributes ( ) - > GetMaterialID ( ) ;
TArray < int32 > StartROI ;
StartROI . Add ( Stamp . HitResult . FaceIndex ) ;
FMeshConnectedComponents : : GrowToConnectedTriangles ( Mesh , StartROI , LocalROI , & TemporaryBuffer , & TemporarySet ,
[ & ] ( int t1 , int t2 ) { return TriangleToUVIsland [ t1 ] = = TriangleToUVIsland [ t2 ] ; } ) ;
UseROI = & LocalROI ;
}
2019-10-01 20:41:42 -04:00
else if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : AllWithinAngle )
{
TArray < int32 > StartROI ;
StartROI . Add ( Stamp . HitResult . FaceIndex ) ;
FVector3d StartNormal = Mesh - > GetTriNormal ( StartROI [ 0 ] ) ;
int AngleTol = SelectionProps - > AngleTolerance ;
2019-12-19 18:07:47 -05:00
FMeshConnectedComponents : : GrowToConnectedTriangles ( Mesh , StartROI , LocalROI , & TemporaryBuffer , & TemporarySet ,
2021-03-17 19:32:44 -04:00
[ Mesh , AngleTol , StartNormal ] ( int t1 , int t2 ) { return UE : : Geometry : : AngleD ( Mesh - > GetTriNormal ( t2 ) , StartNormal ) < AngleTol ; } ) ;
2020-01-27 20:11:15 -05:00
2019-10-01 20:41:42 -04:00
UseROI = & LocalROI ;
}
else if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : AngleFiltered )
{
TSet < int32 > BrushROI ( TriangleROI ) ;
TArray < int32 > StartROI ;
StartROI . Add ( Stamp . HitResult . FaceIndex ) ;
FVector3d StartNormal = Mesh - > GetTriNormal ( StartROI [ 0 ] ) ;
int AngleTol = SelectionProps - > AngleTolerance ;
2019-12-19 18:07:47 -05:00
FMeshConnectedComponents : : GrowToConnectedTriangles ( Mesh , StartROI , LocalROI , & TemporaryBuffer , & TemporarySet ,
2021-03-17 19:32:44 -04:00
[ Mesh , AngleTol , StartNormal , & BrushROI ] ( int t1 , int t2 ) { return BrushROI . Contains ( t2 ) & & UE : : Geometry : : AngleD ( Mesh - > GetTriNormal ( t2 ) , StartNormal ) < AngleTol ; } ) ;
2019-10-01 20:41:42 -04:00
UseROI = & LocalROI ;
}
else if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : Visible )
{
FViewCameraState StateOut ;
GetToolManager ( ) - > GetContextQueriesAPI ( ) - > GetCurrentViewState ( StateOut ) ;
2022-01-29 14:37:53 -05:00
FTransform3d LocalToWorld = UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
2021-06-11 22:42:32 -04:00
FVector3d LocalEyePosition ( LocalToWorld . InverseTransformPosition ( StateOut . Position ) ) ;
2019-10-01 20:41:42 -04:00
for ( int tid : TriangleROI )
{
FVector3d Centroid = Mesh - > GetTriCentroid ( tid ) ;
2021-11-17 21:06:46 -05:00
int HitTID = GetOctree ( ) - > FindNearestHitObject ( FRay3d ( LocalEyePosition , UE : : Geometry : : Normalized ( Centroid - LocalEyePosition ) ) ) ;
2019-10-01 20:41:42 -04:00
if ( HitTID = = tid )
{
LocalROI . Add ( HitTID ) ;
}
}
UseROI = & LocalROI ;
}
2021-01-24 16:05:21 -04:00
// separate paths for add and remove because we can't efficiently remove from Selection->Faces TArray
if ( bInRemoveStroke = = false )
2019-10-01 20:41:42 -04:00
{
2021-01-24 16:05:21 -04:00
for ( int TriIdx : * UseROI )
2019-10-01 20:41:42 -04:00
{
2021-01-24 16:05:21 -04:00
if ( SelectedTriangles [ TriIdx ] = = false )
2019-10-01 20:41:42 -04:00
{
2021-01-24 16:05:21 -04:00
SelectedTriangles [ TriIdx ] = true ;
Selection - > Faces . Add ( TriIdx ) ;
if ( ActiveSelectionChange ! = nullptr )
{
ActiveSelectionChange - > Add ( TriIdx ) ;
}
}
}
}
else
{
bool bModified = false ;
TArray < int32 > CurSelection = Selection - > Faces ;
for ( int TriIdx : * UseROI )
{
if ( SelectedTriangles [ TriIdx ] = = true )
{
SelectedTriangles [ TriIdx ] = false ;
bModified = true ;
if ( ActiveSelectionChange ! = nullptr )
{
ActiveSelectionChange - > Add ( TriIdx ) ;
}
}
}
// rebuild selection
if ( bModified )
{
Selection - > Faces . Reset ( ) ;
for ( int32 tid : CurSelection )
{
if ( SelectedTriangles [ tid ] )
{
Selection - > Faces . Add ( tid ) ;
}
2019-10-01 20:41:42 -04:00
}
}
}
2021-01-24 16:05:21 -04:00
OnRegionHighlightUpdated ( * UseROI ) ;
2019-10-01 20:41:42 -04:00
}
void UMeshSelectionTool : : OnEndDrag ( const FRay & Ray )
{
UDynamicMeshBrushTool : : OnEndDrag ( Ray ) ;
bInRemoveStroke = false ;
bStampPending = false ;
// close change record
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > Change = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( Change ) , LOCTEXT ( " MeshSelectionChange " , " Mesh Selection " ) ) ;
}
bool UMeshSelectionTool : : OnUpdateHover ( const FInputDeviceRay & DevicePos )
{
UDynamicMeshBrushTool : : OnUpdateHover ( DevicePos ) ;
// todo get rid of this redundant hit test!
FHitResult OutHit ;
if ( UDynamicMeshBrushTool : : HitTest ( DevicePos . WorldRay , OutHit ) )
{
PreviewBrushROI . Reset ( ) ;
if ( SelectionType = = EMeshSelectionElementType : : Face )
{
CalculateTriangleROI ( LastBrushStamp , PreviewBrushROI ) ;
}
else
{
CalculateVertexROI ( LastBrushStamp , PreviewBrushROI ) ;
}
}
return true ;
}
2021-05-10 01:17:30 -04:00
FBox UMeshSelectionTool : : GetWorldSpaceFocusBox ( )
{
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) > 0 )
{
FAxisAlignedBox3d Bounds = FAxisAlignedBox3d : : Empty ( ) ;
const FDynamicMesh3 * Mesh = PreviewMesh - > GetMesh ( ) ;
2022-01-29 14:37:53 -05:00
FTransform3d Transform ( PreviewMesh - > GetTransform ( ) ) ;
2021-05-10 01:17:30 -04:00
for ( int32 tid : SelectedFaces )
{
FIndex3i Tri = Mesh - > GetTriangle ( tid ) ;
for ( int32 j = 0 ; j < 3 ; + + j )
{
Bounds . Contain ( Transform . TransformPosition ( Mesh - > GetVertex ( Tri [ j ] ) ) ) ;
}
}
if ( Bounds . MaxDim ( ) > FMathf : : ZeroTolerance )
{
return ( FBox ) Bounds ;
}
}
return PreviewMesh - > GetActor ( ) - > GetComponentsBoundingBox ( ) ;
}
2019-10-01 20:41:42 -04:00
2021-07-27 02:47:03 -04:00
bool UMeshSelectionTool : : SupportsNestedCancelCommand ( )
{
return true ;
}
bool UMeshSelectionTool : : CanCurrentlyNestedCancel ( )
{
return Selection & & ( Selection - > Faces . Num ( ) > 0 ) ;
}
bool UMeshSelectionTool : : ExecuteNestedCancelCommand ( )
{
if ( CanCurrentlyNestedCancel ( ) )
{
ClearSelection ( ) ;
return true ;
}
return false ;
}
2019-10-01 20:41:42 -04:00
2021-01-24 16:05:21 -04:00
void UMeshSelectionTool : : OnRegionHighlightUpdated ( )
2019-10-01 20:41:42 -04:00
{
2021-01-24 16:05:21 -04:00
PreviewMesh - > NotifyDeferredEditCompleted ( UPreviewMesh : : ERenderUpdateMode : : FastUpdate , EMeshRenderAttributeFlags : : SecondaryIndexBuffers , false ) ;
2019-10-01 20:41:42 -04:00
}
2021-01-24 16:05:21 -04:00
void UMeshSelectionTool : : OnRegionHighlightUpdated ( const TArray < int32 > & Triangles )
{
PreviewMesh - > NotifyRegionDeferredEditCompleted ( Triangles , EMeshRenderAttributeFlags : : SecondaryIndexBuffers ) ;
}
void UMeshSelectionTool : : OnRegionHighlightUpdated ( const TSet < int32 > & Triangles )
{
PreviewMesh - > NotifyRegionDeferredEditCompleted ( Triangles , EMeshRenderAttributeFlags : : SecondaryIndexBuffers ) ;
}
2019-10-01 20:41:42 -04:00
2019-12-19 18:07:47 -05:00
void UMeshSelectionTool : : UpdateVisualization ( bool bSelectionModified )
2019-10-01 20:41:42 -04:00
{
2019-12-19 18:07:47 -05:00
check ( SelectionType = = EMeshSelectionElementType : : Face ) ; // only face selection supported so far
2019-10-01 20:41:42 -04:00
2021-06-25 01:41:35 -04:00
SetToolPropertySourceEnabled ( UVChannelProperties ,
SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : ByUVIsland | |
SelectionProps - > FaceColorMode = = EMeshFacesColorMode : : ByUVIsland ) ;
if ( bFullMeshInvalidationPending )
{
PreviewMesh - > ProcessMesh ( [ & ] ( const FDynamicMesh3 & ReadMesh )
{
MeshStatisticsProperties - > Update ( ReadMesh ) ;
} ) ;
MeshElementsDisplay - > NotifyMeshChanged ( ) ;
bFullMeshInvalidationPending = false ;
}
2019-12-19 18:07:47 -05:00
// force an update of renderbuffers
if ( bSelectionModified )
2019-10-01 20:41:42 -04:00
{
2021-01-24 16:05:21 -04:00
PreviewMesh - > NotifyDeferredEditCompleted ( UPreviewMesh : : ERenderUpdateMode : : FullUpdate , EMeshRenderAttributeFlags : : AllVertexAttribs , true ) ;
2019-12-19 18:07:47 -05:00
}
if ( bColorsUpdatePending )
{
if ( SelectionProps - > FaceColorMode ! = EMeshFacesColorMode : : None )
{
PreviewMesh - > SetOverrideRenderMaterial ( ToolSetupUtil : : GetSelectionMaterial ( GetToolManager ( ) ) ) ;
PreviewMesh - > SetTriangleColorFunction ( [ this ] ( const FDynamicMesh3 * Mesh , int TriangleID )
{
return GetCurrentFaceColor ( Mesh , TriangleID ) ;
} ,
UPreviewMesh : : ERenderUpdateMode : : FastUpdate ) ;
}
else
{
PreviewMesh - > ClearOverrideRenderMaterial ( ) ;
PreviewMesh - > ClearTriangleColorFunction ( UPreviewMesh : : ERenderUpdateMode : : FastUpdate ) ;
}
bColorsUpdatePending = false ;
2019-10-01 20:41:42 -04:00
}
}
2019-12-19 18:07:47 -05:00
FColor UMeshSelectionTool : : GetCurrentFaceColor ( const FDynamicMesh3 * Mesh , int TriangleID )
{
if ( SelectionProps - > FaceColorMode = = EMeshFacesColorMode : : ByGroup )
{
2021-06-25 01:41:35 -04:00
return LinearColors : : SelectFColor ( ActiveGroupSet - > GetTriangleGroup ( TriangleID ) ) ;
2019-12-19 18:07:47 -05:00
}
else if ( SelectionProps - > FaceColorMode = = EMeshFacesColorMode : : ByMaterialID )
{
return LinearColors : : SelectFColor ( Mesh - > Attributes ( ) - > GetMaterialID ( ) - > GetValue ( TriangleID ) ) ;
}
else if ( SelectionProps - > FaceColorMode = = EMeshFacesColorMode : : ByUVIsland )
{
return LinearColors : : SelectFColor ( TriangleToUVIsland [ TriangleID ] ) ;
}
return FColor : : Red ;
}
void UMeshSelectionTool : : CacheUVIslandIDs ( )
{
const FDynamicMesh3 * Mesh = PreviewMesh - > GetMesh ( ) ;
FMeshConnectedComponents Components ( Mesh ) ;
TriangleToUVIsland . SetNum ( Mesh - > MaxTriangleID ( ) ) ;
2021-06-25 01:41:35 -04:00
int32 ActiveUVLayer = UVChannelProperties - > GetSelectedChannelIndex ( true ) ;
const FDynamicMeshUVOverlay * UV = Mesh - > Attributes ( ) - > GetUVLayer ( ActiveUVLayer ) ;
2019-12-19 18:07:47 -05:00
Components . FindConnectedTriangles ( [ & ] ( int32 TriIdx0 , int32 TriIdx1 )
{
return UV - > AreTrianglesConnected ( TriIdx0 , TriIdx1 ) ;
} ) ;
int32 NumComponents = Components . Num ( ) ;
for ( int32 ci = 0 ; ci < NumComponents ; + + ci )
{
for ( int32 TriIdx : Components . GetComponent ( ci ) . Indices )
{
TriangleToUVIsland [ TriIdx ] = ci ;
}
}
}
2019-10-01 20:41:42 -04:00
2021-06-25 01:41:35 -04:00
void UMeshSelectionTool : : UpdateActiveGroupLayer ( )
{
// todo: need this to be const
const FDynamicMesh3 * SourceMesh = PreviewMesh - > GetMesh ( ) ;
if ( PolygroupLayerProperties - > HasSelectedPolygroup ( ) = = false )
{
ActiveGroupSet = MakeShared < UE : : Geometry : : FPolygroupSet , ESPMode : : ThreadSafe > ( SourceMesh ) ;
}
else
{
FName SelectedName = PolygroupLayerProperties - > ActiveGroupLayer ;
const FDynamicMeshPolygroupAttribute * FoundAttrib = UE : : Geometry : : FindPolygroupLayerByName ( * SourceMesh , SelectedName ) ;
ensureMsgf ( FoundAttrib , TEXT ( " Selected Attribute Not Found! Falling back to Default group layer. " ) ) ;
ActiveGroupSet = MakeShared < UE : : Geometry : : FPolygroupSet , ESPMode : : ThreadSafe > ( SourceMesh , FoundAttrib ) ;
}
}
2019-10-01 20:41:42 -04:00
void UMeshSelectionTool : : Render ( IToolsContextRenderAPI * RenderAPI )
{
UDynamicMeshBrushTool : : Render ( RenderAPI ) ;
2021-06-11 22:42:32 -04:00
FTransform WorldTransform = ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
2019-12-19 18:07:47 -05:00
const FDynamicMesh3 * Mesh = PreviewMesh - > GetMesh ( ) ;
2019-10-01 20:41:42 -04:00
2021-01-24 16:05:21 -04:00
if ( SelectionProps - > bShowPoints )
2019-10-01 20:41:42 -04:00
{
2021-01-24 16:05:21 -04:00
float PDIScale = RenderAPI - > GetCameraState ( ) . GetPDIScalingFactor ( ) ;
if ( SelectionType = = EMeshSelectionElementType : : Vertex )
{
MeshDebugDraw : : DrawVertices ( Mesh , Selection - > Vertices ,
12.0f * PDIScale , FColor : : Orange , RenderAPI - > GetPrimitiveDrawInterface ( ) , WorldTransform ) ;
MeshDebugDraw : : DrawVertices ( Mesh , PreviewBrushROI ,
8.0f * PDIScale , FColor ( 40 , 200 , 40 ) , RenderAPI - > GetPrimitiveDrawInterface ( ) , WorldTransform ) ;
}
else
{
MeshDebugDraw : : DrawTriCentroids ( Mesh , PreviewBrushROI ,
4.0f * PDIScale , FColor ( 40 , 200 , 40 ) , RenderAPI - > GetPrimitiveDrawInterface ( ) , WorldTransform ) ;
}
2019-10-01 20:41:42 -04:00
}
}
2020-04-18 18:42:59 -04:00
void UMeshSelectionTool : : OnTick ( float DeltaTime )
2019-10-01 20:41:42 -04:00
{
if ( bStampPending )
{
ApplyStamp ( LastStamp ) ;
bStampPending = false ;
}
if ( bHavePendingAction )
{
ApplyAction ( PendingAction ) ;
bHavePendingAction = false ;
PendingAction = EMeshSelectionToolActions : : NoAction ;
}
2021-06-25 01:41:35 -04:00
if ( bFullMeshInvalidationPending )
{
UpdateVisualization ( false ) ;
}
MeshElementsDisplay - > OnTick ( DeltaTime ) ;
2019-10-01 20:41:42 -04:00
}
void UMeshSelectionTool : : BeginChange ( bool bAdding )
{
check ( ActiveSelectionChange = = nullptr ) ;
ActiveSelectionChange = new FMeshSelectionChangeBuilder ( SelectionType , bAdding ) ;
}
void UMeshSelectionTool : : CancelChange ( )
{
if ( ActiveSelectionChange ! = nullptr )
{
delete ActiveSelectionChange ;
ActiveSelectionChange = nullptr ;
}
}
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > UMeshSelectionTool : : EndChange ( )
2019-10-01 20:41:42 -04:00
{
check ( ActiveSelectionChange ) ;
if ( ActiveSelectionChange ! = nullptr )
{
TUniquePtr < FMeshSelectionChange > Result = MoveTemp ( ActiveSelectionChange - > Change ) ;
delete ActiveSelectionChange ;
ActiveSelectionChange = nullptr ;
return Result ;
}
return TUniquePtr < FMeshSelectionChange > ( ) ;
}
void UMeshSelectionTool : : RequestAction ( EMeshSelectionToolActions ActionType )
{
if ( bHavePendingAction )
{
return ;
}
PendingAction = ActionType ;
bHavePendingAction = true ;
}
void UMeshSelectionTool : : ApplyAction ( EMeshSelectionToolActions ActionType )
{
switch ( ActionType )
{
2020-01-27 20:11:15 -05:00
case EMeshSelectionToolActions : : SelectAll :
SelectAll ( ) ;
break ;
2019-10-01 20:41:42 -04:00
case EMeshSelectionToolActions : : ClearSelection :
ClearSelection ( ) ;
break ;
case EMeshSelectionToolActions : : InvertSelection :
InvertSelection ( ) ;
break ;
case EMeshSelectionToolActions : : GrowSelection :
GrowShrinkSelection ( true ) ;
break ;
case EMeshSelectionToolActions : : ShrinkSelection :
GrowShrinkSelection ( false ) ;
break ;
2020-01-27 20:11:15 -05:00
case EMeshSelectionToolActions : : SelectLargestComponentByArea :
SelectLargestComponent ( true ) ;
break ;
case EMeshSelectionToolActions : : SelectLargestComponentByTriCount :
SelectLargestComponent ( false ) ;
break ;
case EMeshSelectionToolActions : : OptimizeSelection :
OptimizeSelection ( ) ;
break ;
2019-10-01 20:41:42 -04:00
case EMeshSelectionToolActions : : ExpandToConnected :
ExpandToConnected ( ) ;
break ;
case EMeshSelectionToolActions : : DeleteSelected :
DeleteSelectedTriangles ( ) ;
break ;
2019-12-19 18:07:47 -05:00
case EMeshSelectionToolActions : : DisconnectSelected :
DisconnectSelectedTriangles ( ) ;
break ;
2022-02-08 15:08:17 -05:00
case EMeshSelectionToolActions : : SmoothBoundary :
SmoothSelectionBoundary ( ) ;
break ;
2019-10-01 20:41:42 -04:00
case EMeshSelectionToolActions : : SeparateSelected :
2021-11-26 14:55:22 -05:00
SeparateSelectedTriangles ( true ) ;
break ;
case EMeshSelectionToolActions : : DuplicateSelected :
SeparateSelectedTriangles ( false ) ;
2019-10-01 20:41:42 -04:00
break ;
2019-12-19 18:07:47 -05:00
case EMeshSelectionToolActions : : FlipSelected :
FlipSelectedTriangles ( ) ;
break ;
case EMeshSelectionToolActions : : CreateGroup :
AssignNewGroupToSelectedTriangles ( ) ;
break ;
2019-10-01 20:41:42 -04:00
}
}
2020-01-27 20:11:15 -05:00
void UMeshSelectionTool : : SelectAll ( )
{
BeginChange ( true ) ;
TArray < int32 > AddFaces ;
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
for ( int tid : Mesh - > TriangleIndicesItr ( ) )
{
if ( SelectedTriangles [ tid ] = = false )
{
AddFaces . Add ( tid ) ;
}
}
ActiveSelectionChange - > Add ( AddFaces ) ;
Selection - > AddIndices ( EMeshSelectionElementType : : Face , AddFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2020-01-27 20:11:15 -05:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( SelectionChange ) , LOCTEXT ( " SelectAll " , " Select All " ) ) ;
OnExternalSelectionChange ( ) ;
}
2019-10-01 20:41:42 -04:00
void UMeshSelectionTool : : ClearSelection ( )
{
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
BeginChange ( false ) ;
ActiveSelectionChange - > Add ( SelectedFaces ) ;
Selection - > RemoveIndices ( EMeshSelectionElementType : : Face , SelectedFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( SelectionChange ) , LOCTEXT ( " ClearSelection " , " Clear Selection " ) ) ;
OnExternalSelectionChange ( ) ;
}
void UMeshSelectionTool : : InvertSelection ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
TArray < int32 > InvertedFaces ;
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
for ( int tid : Mesh - > TriangleIndicesItr ( ) )
{
if ( SelectedTriangles [ tid ] = = false )
{
InvertedFaces . Add ( tid ) ;
}
}
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " InvertSelection " , " Invert Selection " ) ) ;
// clear current selection
BeginChange ( false ) ;
ActiveSelectionChange - > Add ( SelectedFaces ) ;
Selection - > RemoveIndices ( EMeshSelectionElementType : : Face , SelectedFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > ClearChange = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( ClearChange ) , LOCTEXT ( " InvertSelection " , " Invert Selection " ) ) ;
// add inverted selection
BeginChange ( true ) ;
ActiveSelectionChange - > Add ( InvertedFaces ) ;
Selection - > AddIndices ( EMeshSelectionElementType : : Face , InvertedFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > AddChange = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( AddChange ) , LOCTEXT ( " InvertSelection " , " Invert Selection " ) ) ;
GetToolManager ( ) - > EndUndoTransaction ( ) ;
OnExternalSelectionChange ( ) ;
}
void UMeshSelectionTool : : GrowShrinkSelection ( bool bGrow )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
TArray < int32 > Vertices ;
2021-05-22 01:32:46 -04:00
UE : : Geometry : : TriangleToVertexIDs ( Mesh , SelectedFaces , Vertices ) ;
2019-10-01 20:41:42 -04:00
TSet < int32 > ChangeFaces ;
for ( int vid : Vertices )
{
int OutCount = 0 ;
for ( int tid : Mesh - > VtxTrianglesItr ( vid ) )
{
if ( SelectedTriangles [ tid ] = = false )
{
OutCount + + ;
}
}
if ( OutCount = = 0 )
{
continue ;
}
for ( int tid : Mesh - > VtxTrianglesItr ( vid ) )
{
if ( ( bGrow & & SelectedTriangles [ tid ] = = false ) | | ( bGrow = = false & & SelectedTriangles [ tid ] ) )
{
ChangeFaces . Add ( tid ) ;
}
}
}
2021-06-25 01:41:35 -04:00
if ( SelectionProps - > SelectionMode = = EMeshSelectionToolPrimaryMode : : AllInGroup )
2020-01-27 20:11:15 -05:00
{
TSet < int32 > AdjacentFaces { ChangeFaces } ;
TSet < int32 > AdjacentGroups { } ;
ChangeFaces . Empty ( ) ;
for ( int32 TID : AdjacentFaces )
{
2021-06-25 01:41:35 -04:00
AdjacentGroups . Add ( ActiveGroupSet - > GetTriangleGroup ( TID ) ) ;
2020-01-27 20:11:15 -05:00
}
for ( int32 TID : Mesh - > TriangleIndicesItr ( ) )
{
2021-06-25 01:41:35 -04:00
if ( AdjacentGroups . Contains ( ActiveGroupSet - > GetTriangleGroup ( TID ) ) )
2020-01-27 20:11:15 -05:00
{
ChangeFaces . Add ( TID ) ;
}
}
}
2019-10-01 20:41:42 -04:00
if ( ChangeFaces . Num ( ) = = 0 )
{
return ;
}
BeginChange ( bGrow ) ;
ActiveSelectionChange - > Add ( ChangeFaces ) ;
if ( bGrow )
{
Selection - > AddIndices ( EMeshSelectionElementType : : Face , ChangeFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( SelectionChange ) , LOCTEXT ( " GrowSelection " , " Grow Selection " ) ) ;
}
else
{
Selection - > RemoveIndices ( EMeshSelectionElementType : : Face , ChangeFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( SelectionChange ) , LOCTEXT ( " ShrinkSelection " , " Shrink Selection " ) ) ;
}
OnExternalSelectionChange ( ) ;
}
void UMeshSelectionTool : : ExpandToConnected ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
TArray < int32 > Queue ( SelectedFaces ) ;
TSet < int32 > AddFaces ;
while ( Queue . Num ( ) > 0 )
{
int32 CurTri = Queue . Pop ( false ) ;
FIndex3i NbrTris = Mesh - > GetTriNeighbourTris ( CurTri ) ;
for ( int j = 0 ; j < 3 ; + + j )
{
int32 tid = NbrTris [ j ] ;
2019-10-16 16:29:50 -04:00
if ( tid ! = FDynamicMesh3 : : InvalidID & & SelectedTriangles [ tid ] = = false & & AddFaces . Contains ( tid ) = = false )
2019-10-01 20:41:42 -04:00
{
AddFaces . Add ( tid ) ;
Queue . Add ( tid ) ;
}
}
}
if ( AddFaces . Num ( ) = = 0 )
{
return ;
}
BeginChange ( true ) ;
ActiveSelectionChange - > Add ( AddFaces ) ;
Selection - > AddIndices ( EMeshSelectionElementType : : Face , AddFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( SelectionChange ) , LOCTEXT ( " ExpandToConnected " , " Expand Selection " ) ) ;
OnExternalSelectionChange ( ) ;
}
2020-01-27 20:11:15 -05:00
void UMeshSelectionTool : : SelectLargestComponent ( bool bWeightByArea )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
// each component gets its own group id
FMeshConnectedComponents Components ( Mesh ) ;
Components . FindConnectedTriangles ( SelectedFaces ) ;
if ( Components . Num ( ) = = 0 ) // no triangles?
{
ClearSelection ( ) ;
return ;
}
int BestComponent = 0 ;
FMeshConnectedComponents : : FComponent * MaxComponent = Algo : : MaxElementBy ( Components , [ bWeightByArea , & Mesh ] ( const FMeshConnectedComponents : : FComponent & Component )
{
if ( bWeightByArea )
{
double AreaSum = 0 ;
for ( int TID : Component . Indices )
{
AreaSum + = Mesh - > GetTriArea ( TID ) ;
}
return AreaSum ;
}
else
{
return ( double ) Component . Indices . Num ( ) ;
}
} ) ;
BeginChange ( false ) ;
for ( FMeshConnectedComponents : : FComponent & Component : Components )
{
if ( & Component ! = MaxComponent )
{
ActiveSelectionChange - > Add ( Component . Indices ) ;
Selection - > RemoveIndices ( EMeshSelectionElementType : : Face , Component . Indices ) ;
}
}
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2020-01-27 20:11:15 -05:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( SelectionChange ) , LOCTEXT ( " SelectLargestComponentByArea " , " Select Largest Component By Area " ) ) ;
OnExternalSelectionChange ( ) ;
}
void UMeshSelectionTool : : OptimizeSelection ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
if ( Selection - > Faces . Num ( ) = = 0 )
{
return ;
}
const FDynamicMesh3 * Mesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
FMeshFaceSelection FaceSelection ( Mesh ) ;
TSet < int > OriginalSelection ( Selection - > Faces ) ;
FaceSelection . Select ( Selection - > Faces ) ;
FaceSelection . LocalOptimize ( true ) ;
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " OptimizeSelection " , " Optimize Selection " ) ) ;
// remove faces from the current selection that are not in the optimized one
BeginChange ( false ) ;
for ( int32 FaceSelIdx = Selection - > Faces . Num ( ) - 1 ; FaceSelIdx > = 0 ; FaceSelIdx - - )
{
int32 TID = Selection - > Faces [ FaceSelIdx ] ;
if ( ! FaceSelection . IsSelected ( TID ) )
{
Selection - > Faces . RemoveAtSwap ( FaceSelIdx , 1 , false ) ;
ActiveSelectionChange - > Add ( TID ) ;
}
}
Selection - > NotifySelectionSetModified ( ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > DeselectChange = EndChange ( ) ;
2020-01-27 20:11:15 -05:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( DeselectChange ) , LOCTEXT ( " OptimizeSelection " , " Optimize Selection " ) ) ;
// add faces from the optimized selection to the current selection, if they were not in the original
BeginChange ( true ) ;
Selection - > Faces . Reserve ( FaceSelection . Num ( ) ) ;
for ( int32 TID : FaceSelection . AsSet ( ) )
{
if ( ! OriginalSelection . Contains ( TID ) )
{
ActiveSelectionChange - > Add ( TID ) ;
Selection - > Faces . Add ( TID ) ;
}
}
Selection - > NotifySelectionSetModified ( ) ;
check ( Selection - > Faces . Num ( ) = = FaceSelection . Num ( ) ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > AddChange = EndChange ( ) ;
2020-01-27 20:11:15 -05:00
GetToolManager ( ) - > EmitObjectChange ( Selection , MoveTemp ( AddChange ) , LOCTEXT ( " OptimizeSelection " , " Optimize Selection " ) ) ;
GetToolManager ( ) - > EndUndoTransaction ( ) ;
OnExternalSelectionChange ( ) ;
}
2019-10-01 20:41:42 -04:00
void UMeshSelectionTool : : DeleteSelectedTriangles ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
2021-04-05 15:05:51 -04:00
if ( SelectedFaces . Num ( ) > = PreviewMesh - > GetMesh ( ) - > TriangleCount ( ) )
{
return ;
}
2019-10-01 20:41:42 -04:00
TUniquePtr < FToolCommandChangeSequence > ChangeSeq = MakeUnique < FToolCommandChangeSequence > ( ) ;
// clear current selection
BeginChange ( false ) ;
for ( int tid : SelectedFaces )
{
ActiveSelectionChange - > Add ( tid ) ;
}
Selection - > RemoveIndices ( EMeshSelectionElementType : : Face , SelectedFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2019-10-01 20:41:42 -04:00
ChangeSeq - > AppendChange ( Selection , MoveTemp ( SelectionChange ) ) ;
// delete triangles and emit delete triangles change
TUniquePtr < FMeshChange > MeshChange = PreviewMesh - > TrackedEditMesh (
[ & SelectedFaces ] ( FDynamicMesh3 & Mesh , FDynamicMeshChangeTracker & ChangeTracker )
{
FDynamicMeshEditor Editor ( & Mesh ) ;
Editor . RemoveTriangles ( SelectedFaces , true , [ & ChangeTracker ] ( int TriangleID ) { ChangeTracker . SaveTriangle ( TriangleID , true ) ; } ) ;
} ) ;
ChangeSeq - > AppendChange ( PreviewMesh , MoveTemp ( MeshChange ) ) ;
// emit combined change sequence
2019-10-08 14:28:14 -04:00
GetToolManager ( ) - > EmitObjectChange ( this , MoveTemp ( ChangeSeq ) , LOCTEXT ( " MeshSelectionToolDeleteFaces " , " Delete Faces " ) ) ;
2019-10-01 20:41:42 -04:00
2019-12-19 18:07:47 -05:00
bFullMeshInvalidationPending = true ;
2019-10-01 20:41:42 -04:00
OnExternalSelectionChange ( ) ;
bHaveModifiedMesh = true ;
bOctreeValid = false ;
}
2019-12-19 18:07:47 -05:00
void UMeshSelectionTool : : DisconnectSelectedTriangles ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
TUniquePtr < FToolCommandChangeSequence > ChangeSeq = MakeUnique < FToolCommandChangeSequence > ( ) ;
// split out selected triangles and emit triangle change
TUniquePtr < FMeshChange > MeshChange = PreviewMesh - > TrackedEditMesh (
[ & SelectedFaces ] ( FDynamicMesh3 & Mesh , FDynamicMeshChangeTracker & ChangeTracker )
{
// save vertices and triangles that are on the boundary of the selection
FMeshRegionBoundaryLoops BoundaryLoops ( & Mesh , SelectedFaces ) ;
for ( const FEdgeLoop & Loop : BoundaryLoops . Loops )
{
2020-03-26 17:20:25 -04:00
// include the whole one-ring in case the disconnect creates bowties that need to be split
ChangeTracker . SaveVertexOneRingTriangles ( Loop . Vertices , true ) ;
2019-12-19 18:07:47 -05:00
}
FDynamicMeshEditor Editor ( & Mesh ) ;
Editor . DisconnectTriangles ( SelectedFaces ) ;
} ) ;
ChangeSeq - > AppendChange ( PreviewMesh , MoveTemp ( MeshChange ) ) ;
// emit combined change sequence
GetToolManager ( ) - > EmitObjectChange ( this , MoveTemp ( ChangeSeq ) , LOCTEXT ( " MeshSelectionToolDisconnectFaces " , " Disconnect Faces " ) ) ;
bFullMeshInvalidationPending = true ;
bHaveModifiedMesh = true ;
}
2021-11-26 14:55:22 -05:00
void UMeshSelectionTool : : SeparateSelectedTriangles ( bool bDeleteSelected )
2019-10-01 20:41:42 -04:00
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
const FDynamicMesh3 * SourceMesh = PreviewMesh - > GetPreviewDynamicMesh ( ) ;
if ( SelectedFaces . Num ( ) = = SourceMesh - > TriangleCount ( ) )
{
return ; // don't separate entire mesh
}
// extract copy of triangles
FDynamicMesh3 SeparatedMesh ;
2022-01-12 14:28:31 -05:00
SeparatedMesh . EnableTriangleGroups ( ) ;
2019-10-01 20:41:42 -04:00
SeparatedMesh . EnableAttributes ( ) ;
2019-12-19 18:07:47 -05:00
SeparatedMesh . Attributes ( ) - > EnableMatchingAttributes ( * SourceMesh - > Attributes ( ) ) ;
2019-10-01 20:41:42 -04:00
FDynamicMeshEditor Editor ( & SeparatedMesh ) ;
FMeshIndexMappings Mappings ; FDynamicMeshEditResult EditResult ;
Editor . AppendTriangles ( SourceMesh , SelectedFaces , Mappings , EditResult ) ;
// emit new asset
2022-01-29 14:37:53 -05:00
FTransform3d Transform ( PreviewMesh - > GetTransform ( ) ) ;
2021-11-26 14:55:22 -05:00
GetToolManager ( ) - > BeginUndoTransaction (
( bDeleteSelected ) ? LOCTEXT ( " MeshSelectionToolSeparate " , " Separate " ) : LOCTEXT ( " MeshSelectionToolDuplicate " , " Duplicate " ) ) ;
2020-03-20 22:00:43 -04:00
// build array of materials from the original
2021-06-11 22:42:32 -04:00
FComponentMaterialSet MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Target ) ;
TArray < UMaterialInterface * > Materials = MaterialSet . Materials ;
2019-10-01 20:41:42 -04:00
2021-11-26 14:55:22 -05:00
AActor * TargetActor = UE : : ToolTarget : : GetTargetActor ( Target ) ;
FString AssetName = TargetActor - > GetActorNameOrLabel ( ) ;
2021-06-02 15:58:00 -04:00
FCreateMeshObjectParams NewMeshObjectParams ;
NewMeshObjectParams . TargetWorld = TargetWorld ;
NewMeshObjectParams . Transform = ( FTransform ) Transform ;
2021-11-26 14:55:22 -05:00
NewMeshObjectParams . BaseName = ( AssetName . IsEmpty ( ) ) ? TEXT ( " Submesh " ) : ( AssetName + TEXT ( " _Submesh " ) ) ;
2021-06-02 15:58:00 -04:00
NewMeshObjectParams . Materials = Materials ;
NewMeshObjectParams . SetMesh ( & SeparatedMesh ) ;
FCreateMeshObjectResult Result = UE : : Modeling : : CreateMeshObject ( GetToolManager ( ) , MoveTemp ( NewMeshObjectParams ) ) ;
if ( Result . IsOK ( ) & & Result . NewActor ! = nullptr )
{
SpawnedActors . Add ( Result . NewActor ) ;
}
GetToolManager ( ) - > EndUndoTransaction ( ) ;
2019-10-01 20:41:42 -04:00
// delete selected triangles from this mesh
2021-11-26 14:55:22 -05:00
if ( bDeleteSelected )
{
DeleteSelectedTriangles ( ) ;
}
// Currently have to mark the mesh as 'modified' so we can Accept, because if we Cancel,
// Actor created by duplicate operation will be rolled back
bHaveModifiedMesh = true ;
2019-10-01 20:41:42 -04:00
}
2019-12-19 18:07:47 -05:00
void UMeshSelectionTool : : FlipSelectedTriangles ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
2019-10-01 20:41:42 -04:00
2019-12-19 18:07:47 -05:00
TUniquePtr < FToolCommandChangeSequence > ChangeSeq = MakeUnique < FToolCommandChangeSequence > ( ) ;
// clear current selection
BeginChange ( false ) ;
for ( int tid : SelectedFaces )
{
ActiveSelectionChange - > Add ( tid ) ;
}
Selection - > RemoveIndices ( EMeshSelectionElementType : : Face , SelectedFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2019-12-19 18:07:47 -05:00
ChangeSeq - > AppendChange ( Selection , MoveTemp ( SelectionChange ) ) ;
// flip normals
TUniquePtr < FMeshChange > MeshChange = PreviewMesh - > TrackedEditMesh (
[ & SelectedFaces ] ( FDynamicMesh3 & Mesh , FDynamicMeshChangeTracker & ChangeTracker )
{
for ( int TID : SelectedFaces )
{
ChangeTracker . SaveTriangle ( TID , true ) ;
}
FDynamicMeshEditor Editor ( & Mesh ) ;
Editor . ReverseTriangleOrientations ( SelectedFaces , true ) ;
} ) ;
ChangeSeq - > AppendChange ( PreviewMesh , MoveTemp ( MeshChange ) ) ;
// emit combined change sequence
GetToolManager ( ) - > EmitObjectChange ( this , MoveTemp ( ChangeSeq ) , LOCTEXT ( " MeshSelectionToolFlipFaces " , " Flip Face Orientations " ) ) ;
bHaveModifiedMesh = true ;
}
void UMeshSelectionTool : : AssignNewGroupToSelectedTriangles ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
TUniquePtr < FToolCommandChangeSequence > ChangeSeq = MakeUnique < FToolCommandChangeSequence > ( ) ;
// clear current selection
BeginChange ( false ) ;
for ( int tid : SelectedFaces )
{
ActiveSelectionChange - > Add ( tid ) ;
}
Selection - > RemoveIndices ( EMeshSelectionElementType : : Face , SelectedFaces ) ;
2020-04-18 18:42:59 -04:00
TUniquePtr < FToolCommandChange > SelectionChange = EndChange ( ) ;
2019-12-19 18:07:47 -05:00
ChangeSeq - > AppendChange ( Selection , MoveTemp ( SelectionChange ) ) ;
// assign new groups to triangles
// note: using an FMeshChange is kind of overkill here
TUniquePtr < FMeshChange > MeshChange = PreviewMesh - > TrackedEditMesh (
2021-06-25 01:41:35 -04:00
[ & SelectedFaces , this ] ( FDynamicMesh3 & Mesh , FDynamicMeshChangeTracker & ChangeTracker )
2019-12-19 18:07:47 -05:00
{
// each component gets its own group id
FMeshConnectedComponents Components ( & Mesh ) ;
Components . FindConnectedTriangles ( SelectedFaces ) ;
for ( FMeshConnectedComponents : : FComponent & Component : Components )
{
int NewGroupID = Mesh . AllocateTriangleGroup ( ) ;
for ( int tid : Component . Indices )
{
ChangeTracker . SaveTriangle ( tid , true ) ;
2021-06-25 01:41:35 -04:00
ActiveGroupSet - > SetGroup ( tid , NewGroupID , Mesh ) ;
2019-12-19 18:07:47 -05:00
}
}
} ) ;
ChangeSeq - > AppendChange ( PreviewMesh , MoveTemp ( MeshChange ) ) ;
// emit combined change sequence
GetToolManager ( ) - > EmitObjectChange ( this , MoveTemp ( ChangeSeq ) , LOCTEXT ( " MeshSelectionToolCreateGroup " , " Create Polygroup " ) ) ;
OnExternalSelectionChange ( ) ;
bHaveModifiedMesh = true ;
}
2022-02-08 15:08:17 -05:00
void UMeshSelectionTool : : SmoothSelectionBoundary ( )
{
check ( SelectionType = = EMeshSelectionElementType : : Face ) ;
TArray < int32 > SelectedFaces = Selection - > GetElements ( EMeshSelectionElementType : : Face ) ;
if ( SelectedFaces . Num ( ) = = 0 )
{
return ;
}
2019-12-19 18:07:47 -05:00
2022-02-08 15:08:17 -05:00
FMeshRegionBoundaryLoops BoundaryLoops ( PreviewMesh - > GetMesh ( ) , SelectedFaces , true ) ;
if ( BoundaryLoops . Loops . Num ( ) = = 0 )
{
return ;
}
TUniquePtr < FToolCommandChangeSequence > ChangeSeq = MakeUnique < FToolCommandChangeSequence > ( ) ;
TUniquePtr < FMeshChange > MeshChange = PreviewMesh - > TrackedEditMesh (
[ & BoundaryLoops , this ] ( FDynamicMesh3 & Mesh , FDynamicMeshChangeTracker & ChangeTracker )
{
constexpr double Alpha = 0.75 ;
TMap < int , FVector3d > NewLoopPositions ;
for ( const FEdgeLoop & Loop : BoundaryLoops . Loops )
{
int NumLoopVertices = Loop . GetVertexCount ( ) ;
for ( int LoopVertexIndex = 0 ; LoopVertexIndex < NumLoopVertices ; + + LoopVertexIndex )
{
const FVector3d PrevPoint = Loop . GetPrevVertex ( LoopVertexIndex ) ;
const FVector3d NextPoint = Loop . GetNextVertex ( LoopVertexIndex ) ;
const FVector3d Avg = 0.5 * ( PrevPoint + NextPoint ) ;
const FVector3d CurrPoint = Loop . GetVertex ( LoopVertexIndex ) ;
const FVector3d NewCurrPoint = ( 1.0 - Alpha ) * CurrPoint + Alpha * Avg ;
const int VertexIndex = Loop . Vertices [ LoopVertexIndex ] ;
// TODO: Reproject to original surface?
// TODO: Fix the UVs
NewLoopPositions . Add ( VertexIndex , NewCurrPoint ) ;
}
}
PreviewMesh - > EditMesh ( [ NewLoopPositions ] ( FDynamicMesh3 & Mesh )
{
for ( const TPair < int , FVector3d > & NewVert : NewLoopPositions )
{
Mesh . SetVertex ( NewVert . Key , NewVert . Value ) ;
}
} ) ;
} ) ;
ChangeSeq - > AppendChange ( PreviewMesh , MoveTemp ( MeshChange ) ) ;
GetToolManager ( ) - > EmitObjectChange ( this , MoveTemp ( ChangeSeq ) , LOCTEXT ( " MeshSelectionToolSmoothBoundary " , " Smooth Selection Boundary " ) ) ;
OnExternalSelectionChange ( ) ;
bHaveModifiedMesh = true ;
}
2019-12-19 18:07:47 -05:00
# undef LOCTEXT_NAMESPACE