2020-04-18 18:42:59 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "SelfUnionMeshesTool.h"
# include "CompositionOps/SelfUnionMeshesOp.h"
# include "InteractiveToolManager.h"
# include "ToolSetupUtil.h"
2021-05-20 16:39:39 -04:00
# include "BaseGizmos/TransformProxy.h"
2021-11-23 09:42:40 -05:00
# include "ModelingToolTargetUtil.h"
2020-04-18 18:42:59 -04:00
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMesh3.h"
2020-04-18 18:42:59 -04:00
# include "DynamicMeshEditor.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/MeshTransforms.h"
2020-04-18 18:42:59 -04:00
# include "MeshDescriptionToDynamicMesh.h"
# include "DynamicMeshToMeshDescription.h"
2021-11-23 09:42:40 -05:00
# include "TargetInterfaces/MeshDescriptionProvider.h"
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2020-04-18 18:42:59 -04:00
# define LOCTEXT_NAMESPACE "USelfUnionMeshesTool"
2020-08-11 01:36:57 -04:00
void USelfUnionMeshesTool : : SetupProperties ( )
2020-04-18 18:42:59 -04:00
{
2020-08-11 01:36:57 -04:00
Super : : SetupProperties ( ) ;
2020-04-18 18:42:59 -04:00
Properties = NewObject < USelfUnionMeshesToolProperties > ( this ) ;
Properties - > RestoreProperties ( this ) ;
AddToolPropertySource ( Properties ) ;
2020-09-24 00:43:27 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " Merge " ) ) ;
2020-09-24 00:43:27 -04:00
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnStartTool " , " Compute a Self-Union of the input meshes, to resolve self-intersections. Use the transform gizmos to tweak the positions of the input objects (can help to resolve errors/failures) " ) ,
EToolMessageLevel : : UserNotification ) ;
2020-08-11 01:36:57 -04:00
}
2020-04-18 18:42:59 -04:00
2020-08-11 01:36:57 -04:00
void USelfUnionMeshesTool : : SaveProperties ( )
{
Super : : SaveProperties ( ) ;
Properties - > SaveProperties ( this ) ;
}
2020-04-18 18:42:59 -04:00
2020-08-11 01:36:57 -04:00
void USelfUnionMeshesTool : : TransformChanged ( UTransformProxy * Proxy , FTransform Transform )
{
ConvertInputsAndSetPreviewMaterials ( false ) ; // have to redo the conversion because the transforms are all baked there
2020-04-18 18:42:59 -04:00
Preview - > InvalidateResult ( ) ;
}
2020-08-11 01:36:57 -04:00
void USelfUnionMeshesTool : : ConvertInputsAndSetPreviewMaterials ( bool bSetPreviewMesh )
2020-04-18 18:42:59 -04:00
{
FComponentMaterialSet AllMaterialSet ;
TMap < UMaterialInterface * , int > KnownMaterials ;
2021-03-11 11:40:03 -04:00
TArray < TArray < int > > MaterialRemap ; MaterialRemap . SetNum ( Targets . Num ( ) ) ;
2020-04-22 21:12:20 -04:00
if ( ! Properties - > bOnlyUseFirstMeshMaterials )
2020-04-18 18:42:59 -04:00
{
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-04-18 18:42:59 -04:00
{
2021-11-23 09:42:40 -05:00
const FComponentMaterialSet ComponentMaterialSet = UE : : ToolTarget : : GetMaterialSet ( Targets [ ComponentIdx ] ) ;
2020-04-22 21:12:20 -04:00
for ( UMaterialInterface * Mat : ComponentMaterialSet . Materials )
2020-04-18 18:42:59 -04:00
{
2020-04-22 21:12:20 -04:00
int * FoundMatIdx = KnownMaterials . Find ( Mat ) ;
int MatIdx ;
if ( FoundMatIdx )
{
MatIdx = * FoundMatIdx ;
}
else
{
MatIdx = AllMaterialSet . Materials . Add ( Mat ) ;
KnownMaterials . Add ( Mat , MatIdx ) ;
}
MaterialRemap [ ComponentIdx ] . Add ( MatIdx ) ;
2020-04-18 18:42:59 -04:00
}
2020-04-22 21:12:20 -04:00
}
}
else
{
2021-11-23 09:42:40 -05:00
AllMaterialSet = UE : : ToolTarget : : GetMaterialSet ( Targets [ 0 ] ) ;
2020-04-22 21:12:20 -04:00
for ( int MatIdx = 0 ; MatIdx < AllMaterialSet . Materials . Num ( ) ; MatIdx + + )
{
MaterialRemap [ 0 ] . Add ( MatIdx ) ;
}
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 1 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-04-22 21:12:20 -04:00
{
2021-11-23 09:42:40 -05:00
MaterialRemap [ ComponentIdx ] . Init ( 0 , Cast < IMaterialProvider > ( Targets [ ComponentIdx ] ) - > GetNumMaterials ( ) ) ;
2020-04-18 18:42:59 -04:00
}
}
2021-02-17 11:50:23 -04:00
CombinedSourceMeshes = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( ) ;
2020-04-18 18:42:59 -04:00
CombinedSourceMeshes - > EnableAttributes ( ) ;
2020-06-23 18:40:00 -04:00
CombinedSourceMeshes - > EnableTriangleGroups ( 0 ) ;
2020-04-18 18:42:59 -04:00
CombinedSourceMeshes - > Attributes ( ) - > EnableMaterialID ( ) ;
2021-04-19 10:47:52 -04:00
CombinedSourceMeshes - > Attributes ( ) - > EnablePrimaryColors ( ) ;
2020-04-18 18:42:59 -04:00
FDynamicMeshEditor AppendEditor ( CombinedSourceMeshes . Get ( ) ) ;
2021-04-19 10:47:52 -04:00
bool bNeedColorAttr = false ;
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-04-18 18:42:59 -04:00
{
FDynamicMesh3 ComponentMesh ;
FMeshDescriptionToDynamicMesh Converter ;
2021-11-23 09:42:40 -05:00
Converter . Convert ( UE : : ToolTarget : : GetMeshDescription ( Targets [ ComponentIdx ] ) , ComponentMesh ) ;
2021-04-19 10:47:52 -04:00
bNeedColorAttr = bNeedColorAttr | | ( ComponentMesh . Attributes ( ) - > HasPrimaryColors ( ) ) ;
2020-04-18 18:42:59 -04:00
// ensure materials and attributes are always enabled
ComponentMesh . EnableAttributes ( ) ;
ComponentMesh . Attributes ( ) - > EnableMaterialID ( ) ;
FDynamicMeshMaterialAttribute * MaterialIDs = ComponentMesh . Attributes ( ) - > GetMaterialID ( ) ;
for ( int TID : ComponentMesh . TriangleIndicesItr ( ) )
{
MaterialIDs - > SetValue ( TID , MaterialRemap [ ComponentIdx ] [ MaterialIDs - > GetValue ( TID ) ] ) ;
}
// TODO: center the meshes
2022-01-29 14:37:53 -05:00
FTransformSRT3d WorldTransform = TransformProxies [ ComponentIdx ] - > GetTransform ( ) ;
2020-06-23 18:40:00 -04:00
if ( WorldTransform . GetDeterminant ( ) < 0 )
{
ComponentMesh . ReverseOrientation ( false ) ;
}
2020-04-18 18:42:59 -04:00
FMeshIndexMappings IndexMaps ;
AppendEditor . AppendMesh ( & ComponentMesh , IndexMaps ,
[ WorldTransform ] ( int VID , const FVector3d & Pos )
{
return WorldTransform . TransformPosition ( Pos ) ;
} ,
[ WorldTransform ] ( int VID , const FVector3d & Normal )
{
return WorldTransform . TransformNormal ( Normal ) ;
}
2020-04-22 21:12:20 -04:00
) ;
2020-04-18 18:42:59 -04:00
}
2021-04-19 10:47:52 -04:00
if ( ! bNeedColorAttr )
{
CombinedSourceMeshes - > Attributes ( ) - > DisablePrimaryColors ( ) ;
}
2020-04-18 18:42:59 -04:00
2020-04-22 21:12:20 -04:00
Preview - > ConfigureMaterials ( AllMaterialSet . Materials , ToolSetupUtil : : GetDefaultWorkingMaterial ( GetToolManager ( ) ) ) ;
2020-08-11 01:36:57 -04:00
if ( bSetPreviewMesh )
{
Preview - > PreviewMesh - > UpdatePreview ( CombinedSourceMeshes . Get ( ) ) ;
}
2020-04-22 21:12:20 -04:00
}
2020-08-11 01:36:57 -04:00
void USelfUnionMeshesTool : : SetPreviewCallbacks ( )
2020-04-22 21:12:20 -04:00
{
2020-04-18 18:42:59 -04:00
DrawnLineSet = NewObject < ULineSetComponent > ( Preview - > PreviewMesh - > GetRootComponent ( ) ) ;
DrawnLineSet - > SetupAttachment ( Preview - > PreviewMesh - > GetRootComponent ( ) ) ;
DrawnLineSet - > SetLineMaterial ( ToolSetupUtil : : GetDefaultLineComponentMaterial ( GetToolManager ( ) ) ) ;
DrawnLineSet - > RegisterComponent ( ) ;
Preview - > OnOpCompleted . AddLambda (
[ this ] ( const FDynamicMeshOperator * Op )
{
const FSelfUnionMeshesOp * UnionOp = ( const FSelfUnionMeshesOp * ) ( Op ) ;
CreatedBoundaryEdges = UnionOp - > GetCreatedBoundaryEdges ( ) ;
}
) ;
Preview - > OnMeshUpdated . AddLambda (
[ this ] ( const UMeshOpPreviewWithBackgroundCompute * )
{
GetToolManager ( ) - > PostInvalidation ( ) ;
UpdateVisualization ( ) ;
}
) ;
}
void USelfUnionMeshesTool : : UpdateVisualization ( )
{
FColor BoundaryEdgeColor ( 240 , 15 , 15 ) ;
float BoundaryEdgeThickness = 2.0 ;
float BoundaryEdgeDepthBias = 2.0f ;
const FDynamicMesh3 * TargetMesh = Preview - > PreviewMesh - > GetPreviewDynamicMesh ( ) ;
FVector3d A , B ;
DrawnLineSet - > Clear ( ) ;
if ( Properties - > bShowNewBoundaryEdges )
{
for ( int EID : CreatedBoundaryEdges )
{
TargetMesh - > GetEdgeV ( EID , A , B ) ;
DrawnLineSet - > AddLine ( ( FVector ) A , ( FVector ) B , BoundaryEdgeColor , BoundaryEdgeThickness , BoundaryEdgeDepthBias ) ;
}
}
}
TUniquePtr < FDynamicMeshOperator > USelfUnionMeshesTool : : MakeNewOperator ( )
{
TUniquePtr < FSelfUnionMeshesOp > Op = MakeUnique < FSelfUnionMeshesOp > ( ) ;
2021-11-18 14:37:34 -05:00
Op - > bAttemptFixHoles = Properties - > bTryFixHoles ;
Op - > bTryCollapseExtraEdges = Properties - > bTryCollapseEdges ;
Op - > WindingNumberThreshold = Properties - > WindingThreshold ;
2020-06-23 18:40:00 -04:00
Op - > bTrimFlaps = Properties - > bTrimFlaps ;
2020-04-18 18:42:59 -04:00
2022-01-29 14:37:53 -05:00
Op - > SetResultTransform ( FTransformSRT3d : : Identity ( ) ) ; // TODO Center the combined meshes (when building them) and change this transform accordingly
2020-04-18 18:42:59 -04:00
Op - > CombinedMesh = CombinedSourceMeshes ;
return Op ;
}
void USelfUnionMeshesTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
{
2020-04-22 21:12:20 -04:00
if ( Property & & ( Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( USelfUnionMeshesToolProperties , bOnlyUseFirstMeshMaterials ) ) )
{
2020-11-24 18:42:39 -04:00
if ( ! AreAllTargetsValid ( ) )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " InvalidTargets " , " Target meshes are no longer valid " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2020-08-11 01:36:57 -04:00
ConvertInputsAndSetPreviewMaterials ( false ) ;
2020-04-22 21:12:20 -04:00
Preview - > InvalidateResult ( ) ;
}
else if ( PropertySet = = HandleSourcesProperties )
2020-04-18 18:42:59 -04:00
{
// nothing
}
else if ( Property & & ( Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( USelfUnionMeshesToolProperties , bShowNewBoundaryEdges ) ) )
{
GetToolManager ( ) - > PostInvalidation ( ) ;
UpdateVisualization ( ) ;
}
else
{
2020-08-11 01:36:57 -04:00
Super : : OnPropertyModified ( PropertySet , Property ) ;
2020-04-18 18:42:59 -04:00
}
}
2020-08-11 01:36:57 -04:00
FString USelfUnionMeshesTool : : GetCreatedAssetName ( ) const
2020-04-18 18:42:59 -04:00
{
2020-08-11 01:36:57 -04:00
return TEXT ( " Merge " ) ;
2020-04-18 18:42:59 -04:00
}
2020-08-11 01:36:57 -04:00
FText USelfUnionMeshesTool : : GetActionName ( ) const
2020-04-18 18:42:59 -04:00
{
2020-08-11 01:36:57 -04:00
return LOCTEXT ( " SelfUnionMeshes " , " Merge Meshes " ) ;
2020-04-18 18:42:59 -04:00
}
2020-08-11 01:36:57 -04:00
2020-04-18 18:42:59 -04:00
# undef LOCTEXT_NAMESPACE