2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
# include "RemeshMeshTool.h"
2020-01-27 20:11:15 -05:00
# include "ComponentSourceInterfaces.h"
2019-10-01 20:41:42 -04:00
# include "InteractiveToolManager.h"
# include "ToolBuilderUtil.h"
2021-06-15 17:05:40 -04:00
# include "Properties/RemeshProperties.h"
# include "Properties/MeshStatisticsProperties.h"
# include "Drawing/MeshElementsVisualizer.h"
2020-01-27 20:11:15 -05:00
# include "Util/ColorConstants.h"
2019-10-17 20:47:09 -04:00
# include "ToolSetupUtil.h"
2021-06-15 17:05:40 -04:00
# include "ModelingToolTargetUtil.h"
# include "ToolSetupUtil.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMesh3.h"
2021-06-15 17:05:40 -04:00
# include "DynamicMesh/DynamicMeshAABBTree3.h"
2019-10-17 20:47:09 -04:00
# include "MeshDescriptionToDynamicMesh.h"
# include "DynamicMeshToMeshDescription.h"
2021-03-11 11:40:03 -04:00
# include "TargetInterfaces/MaterialProvider.h"
# include "TargetInterfaces/MeshDescriptionCommitter.h"
# include "TargetInterfaces/MeshDescriptionProvider.h"
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
# include "ToolTargetManager.h"
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2019-10-01 20:41:42 -04:00
2021-03-09 19:33:56 -04:00
# define LOCTEXT_NAMESPACE "URemeshMeshTool"
2019-10-01 20:41:42 -04:00
/*
* ToolBuilder
*/
2021-03-11 11:40:03 -04:00
2019-10-01 20:41:42 -04:00
bool URemeshMeshToolBuilder : : CanBuildTool ( const FToolBuilderState & SceneState ) const
{
2021-03-11 11:40:03 -04:00
return SceneState . TargetManager - > CountSelectedAndTargetable ( SceneState , GetTargetRequirements ( ) ) = = 1 ;
2019-10-01 20:41:42 -04:00
}
2021-11-23 09:42:40 -05:00
UMultiSelectionMeshEditingTool * URemeshMeshToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
2019-10-01 20:41:42 -04:00
{
2021-11-23 09:42:40 -05:00
return NewObject < URemeshMeshTool > ( SceneState . ToolManager ) ;
2019-10-01 20:41:42 -04:00
}
/*
* Tool
*/
URemeshMeshToolProperties : : URemeshMeshToolProperties ( )
{
TargetTriangleCount = 5000 ;
2020-01-27 20:11:15 -05:00
SmoothingStrength = 0.25 ;
2019-10-01 20:41:42 -04:00
RemeshIterations = 20 ;
2020-12-09 19:29:10 -04:00
MaxRemeshIterations = 20 ;
ExtraProjectionIterations = 5 ;
2019-10-01 20:41:42 -04:00
bDiscardAttributes = false ;
2020-04-18 18:42:59 -04:00
RemeshType = ERemeshType : : Standard ;
2019-10-01 20:41:42 -04:00
SmoothingType = ERemeshSmoothingType : : MeanValue ;
bPreserveSharpEdges = true ;
2020-01-27 20:11:15 -05:00
bShowGroupColors = false ;
2019-10-01 20:41:42 -04:00
TargetEdgeLength = 5.0 ;
bFlips = true ;
bSplits = true ;
bCollapses = true ;
bReproject = true ;
2022-04-22 12:56:47 -04:00
bReprojectConstraints = false ;
BoundaryCornerAngleThreshold = 45.0 ;
2019-10-01 20:41:42 -04:00
bPreventNormalFlips = true ;
2022-03-16 12:41:13 -04:00
bPreventTinyTriangles = true ;
2019-10-01 20:41:42 -04:00
bUseTargetEdgeLength = false ;
}
2020-08-11 01:36:57 -04:00
URemeshMeshTool : : URemeshMeshTool ( const FObjectInitializer & )
2019-10-01 20:41:42 -04:00
{
2020-08-11 01:36:57 -04:00
BasicProperties = CreateDefaultSubobject < URemeshMeshToolProperties > ( TEXT ( " RemeshProperties " ) ) ;
2021-03-24 18:11:10 -04:00
// CreateDefaultSubobject automatically sets RF_Transactional flag, we need to clear it so that undo/redo doesn't affect tool properties
BasicProperties - > ClearFlags ( RF_Transactional ) ;
2019-10-01 20:41:42 -04:00
}
2019-10-17 20:47:09 -04:00
2019-10-01 20:41:42 -04:00
void URemeshMeshTool : : Setup ( )
{
UInteractiveTool : : Setup ( ) ;
2020-08-11 01:36:57 -04:00
check ( BasicProperties ) ;
2020-03-10 16:59:50 -04:00
BasicProperties - > RestoreProperties ( this ) ;
2019-10-17 20:47:09 -04:00
MeshStatisticsProperties = NewObject < UMeshStatisticsProperties > ( this ) ;
2019-10-01 20:41:42 -04:00
2021-03-11 11:40:03 -04:00
check ( Targets . Num ( ) > 0 ) ;
check ( Targets [ 0 ] ) ;
2020-08-11 01:36:57 -04:00
2019-10-17 20:47:09 -04:00
// hide component and create + show preview
2021-11-23 09:42:40 -05:00
UE : : ToolTarget : : HideSourceObject ( Targets [ 0 ] ) ;
2021-06-15 17:05:40 -04:00
Preview = NewObject < UMeshOpPreviewWithBackgroundCompute > ( this ) ;
2022-01-28 10:18:10 -05:00
Preview - > Setup ( GetTargetWorld ( ) , this ) ;
2021-10-07 22:25:54 -04:00
ToolSetupUtil : : ApplyRenderingConfigurationToPreview ( Preview - > PreviewMesh , Targets [ 0 ] ) ;
2021-06-15 17:05:40 -04:00
2021-11-23 09:42:40 -05:00
const FComponentMaterialSet MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Targets [ 0 ] ) ;
2019-12-19 18:07:47 -05:00
Preview - > ConfigureMaterials ( MaterialSet . Materials ,
2020-01-27 20:11:15 -05:00
ToolSetupUtil : : GetDefaultWorkingMaterial ( GetToolManager ( ) )
2019-10-17 20:47:09 -04:00
) ;
2020-04-18 18:42:59 -04:00
BasicProperties - > WatchProperty ( BasicProperties - > bShowGroupColors ,
[ this ] ( bool bNewValue ) { UpdateVisualization ( ) ; } ) ;
2019-10-17 20:47:09 -04:00
2021-02-17 11:50:23 -04:00
OriginalMesh = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( ) ;
2019-10-17 20:47:09 -04:00
FMeshDescriptionToDynamicMesh Converter ;
2021-11-23 09:42:40 -05:00
Converter . Convert ( UE : : ToolTarget : : GetMeshDescription ( Targets [ 0 ] ) , * OriginalMesh ) ;
2019-10-17 20:47:09 -04:00
2021-11-23 09:42:40 -05:00
Preview - > PreviewMesh - > SetTransform ( ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ 0 ] ) ) ;
2021-06-11 22:42:32 -04:00
Preview - > PreviewMesh - > SetTangentsMode ( EDynamicMeshComponentTangentsMode : : AutoCalculated ) ;
2019-10-17 20:47:09 -04:00
Preview - > PreviewMesh - > UpdatePreview ( OriginalMesh . Get ( ) ) ;
2021-02-17 11:50:23 -04:00
OriginalMeshSpatial = MakeShared < FDynamicMeshAABBTree3 , ESPMode : : ThreadSafe > ( OriginalMesh . Get ( ) , true ) ;
2019-10-01 20:41:42 -04:00
2022-06-08 15:29:16 -04:00
// calculate initial mesh area
InitialMeshArea = TMeshQueries < FDynamicMesh3 > : : GetVolumeArea ( * OriginalMesh ) . Y ;
2020-01-27 20:11:15 -05:00
2019-10-17 20:47:09 -04:00
// set properties defaults
2020-01-27 20:11:15 -05:00
// arbitrary threshold of 5000 tris seems reasonable?
2019-10-17 20:47:09 -04:00
BasicProperties - > TargetTriangleCount = ( OriginalMesh - > TriangleCount ( ) < 5000 ) ? 5000 : OriginalMesh - > TriangleCount ( ) ;
2022-06-08 15:29:16 -04:00
BasicProperties - > TargetEdgeLength = FRemeshMeshOp : : CalculateTargetEdgeLength ( OriginalMesh . Get ( ) , BasicProperties - > TargetTriangleCount , InitialMeshArea ) ;
2019-10-01 20:41:42 -04:00
2019-10-17 20:47:09 -04:00
// add properties to GUI
2019-10-01 20:41:42 -04:00
AddToolPropertySource ( BasicProperties ) ;
AddToolPropertySource ( MeshStatisticsProperties ) ;
2021-06-15 17:05:40 -04:00
MeshElementsDisplay = NewObject < UMeshElementsVisualizer > ( this ) ;
MeshElementsDisplay - > CreateInWorld ( Preview - > PreviewMesh - > GetWorld ( ) , Preview - > PreviewMesh - > GetTransform ( ) ) ;
if ( ensure ( MeshElementsDisplay - > Settings ) )
{
MeshElementsDisplay - > Settings - > bShowWireframe = true ;
MeshElementsDisplay - > Settings - > RestoreProperties ( this , TEXT ( " Remesh " ) ) ;
AddToolPropertySource ( MeshElementsDisplay - > Settings ) ;
}
MeshElementsDisplay - > SetMeshAccessFunction ( [ this ] ( UMeshElementsVisualizer : : ProcessDynamicMeshFunc ProcessFunc ) {
Preview - > ProcessCurrentMesh ( ProcessFunc ) ;
} ) ;
Preview - > OnMeshUpdated . AddLambda ( [ this ] ( UMeshOpPreviewWithBackgroundCompute * Compute )
{
Compute - > ProcessCurrentMesh ( [ & ] ( const FDynamicMesh3 & ReadMesh )
{
MeshStatisticsProperties - > Update ( ReadMesh ) ;
MeshElementsDisplay - > NotifyMeshChanged ( ) ;
} ) ;
} ) ;
2019-10-17 20:47:09 -04:00
Preview - > InvalidateResult ( ) ;
2020-09-24 00:43:27 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " Remesh " ) ) ;
2020-09-24 00:43:27 -04:00
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnStartTool " , " Retriangulate the selected Mesh. Use the Boundary Constraints to preserve mesh borders. Enable Discard Attributes to ignore UV/Normal Seams. " ) ,
EToolMessageLevel : : UserNotification ) ;
2019-10-01 20:41:42 -04:00
}
2022-01-28 18:40:54 -05:00
void URemeshMeshTool : : OnShutdown ( EToolShutdownType ShutdownType )
2019-10-01 20:41:42 -04:00
{
2020-03-10 16:59:50 -04:00
BasicProperties - > SaveProperties ( this ) ;
2021-06-15 17:05:40 -04:00
if ( ensure ( MeshElementsDisplay - > Settings ) )
{
MeshElementsDisplay - > Settings - > SaveProperties ( this , TEXT ( " Remesh " ) ) ;
}
MeshElementsDisplay - > Disconnect ( ) ;
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-08-11 01:36:57 -04:00
{
2021-06-15 17:05:40 -04:00
UE : : ToolTarget : : ShowSourceObject ( Targets [ ComponentIdx ] ) ;
2020-08-11 01:36:57 -04:00
}
2021-06-15 17:05:40 -04:00
2019-11-01 17:39:56 -04:00
FDynamicMeshOpResult Result = Preview - > Shutdown ( ) ;
2019-10-17 20:47:09 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
2019-10-01 20:41:42 -04:00
{
2021-06-16 13:27:00 -04:00
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " RemeshMeshToolTransactionName " , " Remesh Mesh " ) ) ;
UE : : ToolTarget : : CommitDynamicMeshUpdate ( Targets [ 0 ] , * Result . Mesh , true ) ;
GetToolManager ( ) - > EndUndoTransaction ( ) ;
2019-10-01 20:41:42 -04:00
}
}
2020-04-18 18:42:59 -04:00
void URemeshMeshTool : : OnTick ( float DeltaTime )
2019-10-17 20:47:09 -04:00
{
Preview - > Tick ( DeltaTime ) ;
2021-06-15 17:05:40 -04:00
MeshElementsDisplay - > OnTick ( DeltaTime ) ;
2019-10-17 20:47:09 -04:00
}
2019-11-01 17:39:56 -04:00
TUniquePtr < FDynamicMeshOperator > URemeshMeshTool : : MakeNewOperator ( )
2019-10-17 20:47:09 -04:00
{
2019-11-01 17:39:56 -04:00
TUniquePtr < FRemeshMeshOp > Op = MakeUnique < FRemeshMeshOp > ( ) ;
2019-10-17 20:47:09 -04:00
2020-04-18 18:42:59 -04:00
Op - > RemeshType = BasicProperties - > RemeshType ;
2019-10-17 20:47:09 -04:00
if ( ! BasicProperties - > bUseTargetEdgeLength )
{
2022-06-08 15:29:16 -04:00
Op - > TargetEdgeLength = FRemeshMeshOp : : CalculateTargetEdgeLength ( OriginalMesh . Get ( ) , BasicProperties - > TargetTriangleCount , InitialMeshArea ) ;
2021-05-17 17:27:58 -04:00
Op - > TriangleCountHint = 2.0 * BasicProperties - > TargetTriangleCount ;
2019-10-17 20:47:09 -04:00
}
else
{
Op - > TargetEdgeLength = BasicProperties - > TargetEdgeLength ;
}
Op - > bCollapses = BasicProperties - > bCollapses ;
Op - > bDiscardAttributes = BasicProperties - > bDiscardAttributes ;
2022-01-16 10:42:36 -05:00
// We always want attributes enabled on result even if we discard them initially
Op - > bResultMustHaveAttributesEnabled = true ;
2019-10-17 20:47:09 -04:00
Op - > bFlips = BasicProperties - > bFlips ;
Op - > bPreserveSharpEdges = BasicProperties - > bPreserveSharpEdges ;
2020-01-27 20:11:15 -05:00
Op - > MeshBoundaryConstraint = ( EEdgeRefineFlags ) BasicProperties - > MeshBoundaryConstraint ;
Op - > GroupBoundaryConstraint = ( EEdgeRefineFlags ) BasicProperties - > GroupBoundaryConstraint ;
Op - > MaterialBoundaryConstraint = ( EEdgeRefineFlags ) BasicProperties - > MaterialBoundaryConstraint ;
2019-10-17 20:47:09 -04:00
Op - > bPreventNormalFlips = BasicProperties - > bPreventNormalFlips ;
2022-03-16 12:41:13 -04:00
Op - > bPreventTinyTriangles = BasicProperties - > bPreventTinyTriangles ;
2019-10-17 20:47:09 -04:00
Op - > bReproject = BasicProperties - > bReproject ;
2022-04-22 12:56:47 -04:00
Op - > bReprojectConstraints = BasicProperties - > bReprojectConstraints ;
Op - > BoundaryCornerAngleThreshold = BasicProperties - > BoundaryCornerAngleThreshold ;
2019-10-17 20:47:09 -04:00
Op - > bSplits = BasicProperties - > bSplits ;
Op - > RemeshIterations = BasicProperties - > RemeshIterations ;
2020-12-09 19:29:10 -04:00
Op - > MaxRemeshIterations = BasicProperties - > MaxRemeshIterations ;
Op - > ExtraProjectionIterations = BasicProperties - > ExtraProjectionIterations ;
2020-01-27 20:11:15 -05:00
Op - > SmoothingStrength = BasicProperties - > SmoothingStrength ;
2019-10-17 20:47:09 -04:00
Op - > SmoothingType = BasicProperties - > SmoothingType ;
2021-06-15 17:05:40 -04:00
FTransform LocalToWorld = ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ 0 ] ) ;
2019-10-17 20:47:09 -04:00
Op - > SetTransform ( LocalToWorld ) ;
Op - > OriginalMesh = OriginalMesh ;
Op - > OriginalMeshSpatial = OriginalMeshSpatial ;
2020-08-11 01:36:57 -04:00
Op - > ProjectionTarget = nullptr ;
Op - > ProjectionTargetSpatial = nullptr ;
2019-10-17 20:47:09 -04:00
return Op ;
}
2019-10-01 20:41:42 -04:00
2020-01-07 15:54:23 -05:00
void URemeshMeshTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
2019-10-01 20:41:42 -04:00
{
2020-03-06 16:56:32 -05:00
if ( Property )
{
2021-06-15 17:05:40 -04:00
if ( Property - > GetFName ( ) ! = GET_MEMBER_NAME_CHECKED ( URemeshMeshToolProperties , bShowGroupColors ) )
2020-03-06 16:56:32 -05:00
{
Preview - > InvalidateResult ( ) ;
}
}
2019-10-01 20:41:42 -04:00
}
2020-01-27 20:11:15 -05:00
void URemeshMeshTool : : UpdateVisualization ( )
{
FComponentMaterialSet MaterialSet ;
if ( BasicProperties - > bShowGroupColors )
{
MaterialSet . Materials = { ToolSetupUtil : : GetSelectionMaterial ( GetToolManager ( ) ) } ;
Preview - > PreviewMesh - > SetTriangleColorFunction ( [ this ] ( const FDynamicMesh3 * Mesh , int TriangleID )
{
return LinearColors : : SelectFColor ( Mesh - > GetTriangleGroup ( TriangleID ) ) ;
} ,
UPreviewMesh : : ERenderUpdateMode : : FastUpdate ) ;
}
else
{
2021-06-15 17:05:40 -04:00
MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Targets [ 0 ] ) ;
2020-01-27 20:11:15 -05:00
Preview - > PreviewMesh - > ClearTriangleColorFunction ( UPreviewMesh : : ERenderUpdateMode : : FastUpdate ) ;
}
Preview - > ConfigureMaterials ( MaterialSet . Materials ,
ToolSetupUtil : : GetDefaultWorkingMaterial ( GetToolManager ( ) ) ) ;
}
2019-10-01 20:41:42 -04:00
bool URemeshMeshTool : : CanAccept ( ) const
{
2020-11-24 18:42:39 -04:00
return Super : : CanAccept ( ) & & Preview - > HaveValidResult ( ) ;
2019-10-17 20:47:09 -04:00
}
2019-10-01 20:41:42 -04:00
# undef LOCTEXT_NAMESPACE