2020-09-01 14:07:48 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Physics/SetCollisionGeometryTool.h"
# include "InteractiveToolManager.h"
# include "ToolBuilderUtil.h"
# include "ToolSetupUtil.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/MeshTransforms.h"
2020-09-01 14:07:48 -04:00
# include "DynamicMeshEditor.h"
# include "Selections/MeshConnectedComponents.h"
# include "DynamicSubmesh3.h"
2021-06-20 17:01:49 -04:00
# include "Polygroups/PolygroupUtil.h"
2022-04-22 15:40:09 -04:00
# include "Util/ColorConstants.h"
2020-09-01 14:07:48 -04:00
# include "ShapeApproximation/ShapeDetection3.h"
# include "ShapeApproximation/MeshSimpleShapeApproximation.h"
# include "Physics/CollisionGeometryVisualization.h"
// physics data
# include "Engine/Classes/Engine/StaticMesh.h"
# include "Engine/Classes/Components/StaticMeshComponent.h"
# include "Engine/Classes/PhysicsEngine/BodySetup.h"
# include "Async/ParallelFor.h"
2021-03-11 11:40:03 -04:00
# include "TargetInterfaces/MeshDescriptionProvider.h"
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
# include "ToolTargetManager.h"
2021-06-20 17:01:49 -04:00
# include "ModelingToolTargetUtil.h"
2021-03-11 11:40:03 -04:00
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2020-09-01 14:07:48 -04:00
# define LOCTEXT_NAMESPACE "USetCollisionGeometryTool"
2021-03-11 11:40:03 -04:00
2022-04-19 15:48:15 -04:00
/*
* Operators
*/
class FPhysicsCollectionOp : public TGenericDataOperator < FPhysicsDataCollection >
{
public :
TSharedPtr < FPhysicsDataCollection , ESPMode : : ThreadSafe > InitialCollision ;
TUniquePtr < FMeshSimpleShapeApproximation > UseShapeGenerator ;
// Note: UseShapeGenerator holds raw pointers to these meshes, so we keep the array of shared pointers to prevent them from getting deleted while the op runs
TArray < TSharedPtr < FDynamicMesh3 , ESPMode : : ThreadSafe > > ActiveInputMeshes ;
ECollisionGeometryType ComputeType ;
bool bUseMaxCount ;
bool bRemoveContained ;
bool bAppendToExisting ;
EProjectedHullAxis SweepAxis ;
int32 MaxCount ;
// Begin TGenericDataOperator interface
virtual void CalculateResult ( FProgressCancel * Progress ) override
{
check ( UseShapeGenerator . IsValid ( ) ) ;
check ( InitialCollision . IsValid ( ) ) ;
// calculate new collision
TUniquePtr < FPhysicsDataCollection > NewCollision = MakeUnique < FPhysicsDataCollection > ( ) ;
NewCollision - > InitializeFromExisting ( * InitialCollision ) ;
if ( bAppendToExisting | | ComputeType = = ECollisionGeometryType : : KeepExisting )
{
NewCollision - > CopyGeometryFromExisting ( * InitialCollision ) ;
}
switch ( ComputeType )
{
case ECollisionGeometryType : : KeepExisting :
case ECollisionGeometryType : : None :
break ;
case ECollisionGeometryType : : AlignedBoxes :
UseShapeGenerator - > Generate_AlignedBoxes ( NewCollision - > Geometry ) ;
break ;
case ECollisionGeometryType : : OrientedBoxes :
UseShapeGenerator - > Generate_OrientedBoxes ( NewCollision - > Geometry ) ;
break ;
case ECollisionGeometryType : : MinimalSpheres :
UseShapeGenerator - > Generate_MinimalSpheres ( NewCollision - > Geometry ) ;
break ;
case ECollisionGeometryType : : Capsules :
UseShapeGenerator - > Generate_Capsules ( NewCollision - > Geometry ) ;
break ;
case ECollisionGeometryType : : ConvexHulls :
if ( UseShapeGenerator - > ConvexDecompositionMaxPieces > 1 )
{
UseShapeGenerator - > Generate_ConvexHullDecompositions ( NewCollision - > Geometry ) ;
}
else
{
UseShapeGenerator - > Generate_ConvexHulls ( NewCollision - > Geometry ) ;
}
break ;
case ECollisionGeometryType : : SweptHulls :
UseShapeGenerator - > Generate_ProjectedHulls ( NewCollision - > Geometry ,
( FMeshSimpleShapeApproximation : : EProjectedHullAxisMode ) ( int32 ) SweepAxis ) ;
break ;
2022-05-30 16:48:48 -04:00
case ECollisionGeometryType : : LevelSets :
UseShapeGenerator - > Generate_LevelSets ( NewCollision - > Geometry ) ;
break ;
2022-04-19 15:48:15 -04:00
case ECollisionGeometryType : : MinVolume :
UseShapeGenerator - > Generate_MinVolume ( NewCollision - > Geometry ) ;
break ;
}
if ( ! NewCollision )
{
ensure ( false ) ;
return ;
}
if ( bRemoveContained )
{
NewCollision - > Geometry . RemoveContainedGeometry ( ) ;
}
if ( bUseMaxCount )
{
NewCollision - > Geometry . FilterByVolume ( MaxCount ) ;
}
NewCollision - > CopyGeometryToAggregate ( ) ;
SetResult ( MoveTemp ( NewCollision ) ) ;
}
// End TGenericDataOperator interface
} ;
2021-03-11 11:40:03 -04:00
const FToolTargetTypeRequirements & USetCollisionGeometryToolBuilder : : GetTargetRequirements ( ) const
{
static FToolTargetTypeRequirements TypeRequirements ( {
UMeshDescriptionProvider : : StaticClass ( ) ,
UPrimitiveComponentBackedTarget : : StaticClass ( )
} ) ;
return TypeRequirements ;
}
2020-09-01 14:07:48 -04:00
bool USetCollisionGeometryToolBuilder : : CanBuildTool ( const FToolBuilderState & SceneState ) const
{
2021-05-05 16:43:24 -04:00
UActorComponent * LastValidTarget = nullptr ;
SceneState . TargetManager - > EnumerateSelectedAndTargetableComponents ( SceneState , GetTargetRequirements ( ) ,
[ & ] ( UActorComponent * Component ) { LastValidTarget = Component ; } ) ;
return ( LastValidTarget ! = nullptr & & Cast < UStaticMeshComponent > ( LastValidTarget ) ! = nullptr ) ;
2020-09-01 14:07:48 -04:00
}
2021-11-23 09:42:40 -05:00
UMultiSelectionMeshEditingTool * USetCollisionGeometryToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
2020-09-01 14:07:48 -04:00
{
2021-11-23 09:42:40 -05:00
return NewObject < USetCollisionGeometryTool > ( SceneState . ToolManager ) ;
2020-09-01 14:07:48 -04:00
}
void USetCollisionGeometryTool : : Setup ( )
{
UInteractiveTool : : Setup ( ) ;
2021-03-11 11:40:03 -04:00
// if we have one selection, use it as the source, otherwise use all but the last selected mesh
bSourcesHidden = ( Targets . Num ( ) > 1 ) ;
if ( Targets . Num ( ) = = 1 )
2020-09-01 14:07:48 -04:00
{
SourceObjectIndices . Add ( 0 ) ;
}
else
{
2021-03-11 11:40:03 -04:00
for ( int32 k = 0 ; k < Targets . Num ( ) - 1 ; + + k )
2020-09-01 14:07:48 -04:00
{
SourceObjectIndices . Add ( k ) ;
2021-06-20 17:01:49 -04:00
UE : : ToolTarget : : HideSourceObject ( Targets [ k ] ) ;
2020-09-01 14:07:48 -04:00
}
}
2021-06-20 17:01:49 -04:00
// collect input meshes
InitialSourceMeshes . SetNum ( SourceObjectIndices . Num ( ) ) ;
ParallelFor ( SourceObjectIndices . Num ( ) , [ & ] ( int32 k )
{
InitialSourceMeshes [ k ] = UE : : ToolTarget : : GetDynamicMeshCopy ( Targets [ k ] ) ;
} ) ;
UToolTarget * CollisionTarget = Targets [ Targets . Num ( ) - 1 ] ;
2020-09-01 14:07:48 -04:00
PreviewGeom = NewObject < UPreviewGeometry > ( this ) ;
2021-06-20 17:01:49 -04:00
FTransform PreviewTransform = ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( CollisionTarget ) ;
2020-09-01 14:07:48 -04:00
OrigTargetTransform = PreviewTransform ;
TargetScale3D = PreviewTransform . GetScale3D ( ) ;
PreviewTransform . SetScale3D ( FVector : : OneVector ) ;
2021-06-20 17:01:49 -04:00
PreviewGeom - > CreateInWorld ( UE : : ToolTarget : : GetTargetActor ( CollisionTarget ) - > GetWorld ( ) , PreviewTransform ) ;
2020-09-01 14:07:48 -04:00
// initialize initial collision object
2021-02-17 11:50:23 -04:00
InitialCollision = MakeShared < FPhysicsDataCollection , ESPMode : : ThreadSafe > ( ) ;
2021-06-20 17:01:49 -04:00
InitialCollision - > InitializeFromComponent ( UE : : ToolTarget : : GetTargetComponent ( CollisionTarget ) , true ) ;
2020-09-01 14:07:48 -04:00
InitialCollision - > ExternalScale3D = TargetScale3D ;
// create tool options
Settings = NewObject < USetCollisionGeometryToolProperties > ( this ) ;
Settings - > RestoreProperties ( this ) ;
AddToolPropertySource ( Settings ) ;
Settings - > bUseWorldSpace = ( SourceObjectIndices . Num ( ) > 1 ) ;
2021-06-20 17:01:49 -04:00
Settings - > WatchProperty ( Settings - > InputMode , [ this ] ( ESetCollisionGeometryInputMode ) { OnInputModeChanged ( ) ; } ) ;
2022-04-19 15:48:15 -04:00
Settings - > WatchProperty ( Settings - > GeometryType , [ this ] ( ECollisionGeometryType ) { InvalidateCompute ( ) ; } ) ;
2020-09-01 14:07:48 -04:00
Settings - > WatchProperty ( Settings - > bUseWorldSpace , [ this ] ( bool ) { bInputMeshesValid = false ; } ) ;
2022-04-19 15:48:15 -04:00
Settings - > WatchProperty ( Settings - > bAppendToExisting , [ this ] ( bool ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > bRemoveContained , [ this ] ( bool ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > bEnableMaxCount , [ this ] ( bool ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > MaxCount , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > MinThickness , [ this ] ( float ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > bDetectBoxes , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > bDetectSpheres , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > bDetectCapsules , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > bSimplifyHulls , [ this ] ( bool ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > HullTargetFaceCount , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > MaxHullsPerMesh , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > ConvexDecompositionSearchFactor , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > AddHullsErrorTolerance , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
2022-05-09 16:41:33 -04:00
Settings - > WatchProperty ( Settings - > MinPartThickness , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
2022-04-19 15:48:15 -04:00
Settings - > WatchProperty ( Settings - > bSimplifyPolygons , [ this ] ( bool ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > HullTolerance , [ this ] ( float ) { InvalidateCompute ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > SweepAxis , [ this ] ( EProjectedHullAxis ) { InvalidateCompute ( ) ; } ) ;
2022-05-30 16:48:48 -04:00
Settings - > WatchProperty ( Settings - > LevelSetResolution , [ this ] ( int32 ) { InvalidateCompute ( ) ; } ) ;
2021-06-20 17:01:49 -04:00
if ( InitialSourceMeshes . Num ( ) = = 1 )
{
PolygroupLayerProperties = NewObject < UPolygroupLayersProperties > ( this ) ;
PolygroupLayerProperties - > RestoreProperties ( this , TEXT ( " SetCollisionGeometryTool " ) ) ;
PolygroupLayerProperties - > InitializeGroupLayers ( & InitialSourceMeshes [ 0 ] ) ;
PolygroupLayerProperties - > WatchProperty ( PolygroupLayerProperties - > ActiveGroupLayer , [ & ] ( FName ) { OnSelectedGroupLayerChanged ( ) ; } ) ;
AddToolPropertySource ( PolygroupLayerProperties ) ;
}
2020-09-01 14:07:48 -04:00
VizSettings = NewObject < UCollisionGeometryVisualizationProperties > ( this ) ;
VizSettings - > RestoreProperties ( this ) ;
AddToolPropertySource ( VizSettings ) ;
2020-10-29 13:38:15 -04:00
VizSettings - > WatchProperty ( VizSettings - > LineThickness , [ this ] ( float NewValue ) { bVisualizationDirty = true ; } ) ;
VizSettings - > WatchProperty ( VizSettings - > Color , [ this ] ( FColor NewValue ) { bVisualizationDirty = true ; } ) ;
2022-04-22 15:40:09 -04:00
VizSettings - > WatchProperty ( VizSettings - > bRandomColors , [ this ] ( bool bNewValue ) { bVisualizationDirty = true ; } ) ;
2020-10-29 13:38:15 -04:00
VizSettings - > WatchProperty ( VizSettings - > bShowHidden , [ this ] ( bool bNewValue ) { bVisualizationDirty = true ; } ) ;
2020-09-01 14:07:48 -04:00
// add option for collision properties
CollisionProps = NewObject < UPhysicsObjectToolPropertySet > ( this ) ;
AddToolPropertySource ( CollisionProps ) ;
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " Mesh To Collision " ) ) ;
2020-09-01 14:07:48 -04:00
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnStartTool " , " Initialize Simple Collision geometry for a Mesh from one or more input Meshes (including itself). " ) ,
EToolMessageLevel : : UserNotification ) ;
2022-04-19 15:48:15 -04:00
// Make sure we are set to precompute input meshes on first tick
bInputMeshesValid = false ;
}
TUniquePtr < UE : : Geometry : : TGenericDataOperator < FPhysicsDataCollection > > USetCollisionGeometryTool : : MakeNewOperator ( )
{
TUniquePtr < FPhysicsCollectionOp > Op = MakeUnique < FPhysicsCollectionOp > ( ) ;
Op - > InitialCollision = InitialCollision ;
// Pick the approximator and input meshes that will be used by the op
TSharedPtr < UE : : Geometry : : FMeshSimpleShapeApproximation , ESPMode : : ThreadSafe > * Approximator = nullptr ;
TArray < TSharedPtr < FDynamicMesh3 , ESPMode : : ThreadSafe > > * Inputs = nullptr ;
if ( Settings - > InputMode = = ESetCollisionGeometryInputMode : : CombineAll )
{
Approximator = & CombinedInputMeshesApproximator ;
Inputs = & CombinedInputMeshes ;
}
else if ( Settings - > InputMode = = ESetCollisionGeometryInputMode : : PerMeshComponent )
{
Approximator = & SeparatedMeshesApproximator ;
Inputs = & SeparatedInputMeshes ;
}
else if ( Settings - > InputMode = = ESetCollisionGeometryInputMode : : PerMeshGroup )
{
Approximator = & PerGroupMeshesApproximator ;
Inputs = & PerGroupInputMeshes ;
}
else
{
Approximator = & InputMeshesApproximator ;
Inputs = & InputMeshes ;
}
Op - > UseShapeGenerator = MakeUnique < FMeshSimpleShapeApproximation > ( * * Approximator ) ;
Op - > ActiveInputMeshes = * Inputs ;
Op - > UseShapeGenerator - > bDetectSpheres = Settings - > bDetectSpheres ;
Op - > UseShapeGenerator - > bDetectBoxes = Settings - > bDetectBoxes ;
Op - > UseShapeGenerator - > bDetectCapsules = Settings - > bDetectCapsules ;
Op - > UseShapeGenerator - > MinDimension = Settings - > MinThickness ;
Op - > UseShapeGenerator - > bSimplifyHulls = Settings - > bSimplifyHulls ;
Op - > UseShapeGenerator - > HullTargetFaceCount = Settings - > HullTargetFaceCount ;
Op - > UseShapeGenerator - > ConvexDecompositionMaxPieces = Settings - > MaxHullsPerMesh ;
Op - > UseShapeGenerator - > ConvexDecompositionSearchFactor = Settings - > ConvexDecompositionSearchFactor ;
Op - > UseShapeGenerator - > ConvexDecompositionErrorTolerance = Settings - > AddHullsErrorTolerance ;
2022-05-09 16:41:33 -04:00
Op - > UseShapeGenerator - > ConvexDecompositionMinPartThickness = Settings - > MinPartThickness ;
2022-04-19 15:48:15 -04:00
Op - > UseShapeGenerator - > HullSimplifyTolerance = Settings - > HullTolerance ;
2022-05-30 16:48:48 -04:00
Op - > UseShapeGenerator - > LevelSetGridResolution = Settings - > LevelSetResolution ;
2022-04-19 15:48:15 -04:00
Op - > ComputeType = Settings - > GeometryType ;
Op - > bAppendToExisting = Settings - > bAppendToExisting ;
Op - > bUseMaxCount = Settings - > bEnableMaxCount ;
Op - > MaxCount = Settings - > MaxCount ;
Op - > bRemoveContained = Settings - > bRemoveContained ;
Op - > SweepAxis = Settings - > SweepAxis ;
return Op ;
2020-09-01 14:07:48 -04:00
}
2022-01-28 18:40:54 -05:00
void USetCollisionGeometryTool : : OnShutdown ( EToolShutdownType ShutdownType )
2020-09-01 14:07:48 -04:00
{
VizSettings - > SaveProperties ( this ) ;
Settings - > SaveProperties ( this ) ;
2021-06-20 17:01:49 -04:00
if ( PolygroupLayerProperties )
{
PolygroupLayerProperties - > SaveProperties ( this , TEXT ( " SetCollisionGeometryTool " ) ) ;
}
2020-09-01 14:07:48 -04:00
PreviewGeom - > Disconnect ( ) ;
// show hidden sources
if ( bSourcesHidden )
{
for ( int32 k : SourceObjectIndices )
{
2021-06-20 17:01:49 -04:00
UE : : ToolTarget : : ShowSourceObject ( Targets [ k ] ) ;
2020-09-01 14:07:48 -04:00
}
}
2022-04-19 15:48:15 -04:00
if ( Compute )
{
Compute - > Shutdown ( ) ;
}
2020-09-01 14:07:48 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
2020-10-29 13:38:15 -04:00
// Make sure rendering is done so that we are not changing data being used by collision drawing.
FlushRenderingCommands ( ) ;
2020-09-01 14:07:48 -04:00
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " UpdateCollision " , " Update Collision " ) ) ;
2020-10-29 13:38:15 -04:00
// code below derived from FStaticMeshEditor::DuplicateSelectedPrims(), FStaticMeshEditor::OnCollisionSphere(), and GeomFitUtils.cpp::GenerateSphylAsSimpleCollision()
2020-09-01 14:07:48 -04:00
2021-06-20 17:01:49 -04:00
UPrimitiveComponent * Component = UE : : ToolTarget : : GetTargetComponent ( Targets [ Targets . Num ( ) - 1 ] ) ;
UStaticMeshComponent * StaticMeshComponent = Cast < UStaticMeshComponent > ( Component ) ;
2021-06-22 02:09:15 -04:00
TObjectPtr < UStaticMesh > StaticMesh = ( StaticMeshComponent ) ? StaticMeshComponent - > GetStaticMesh ( ) : nullptr ;
2021-06-20 17:01:49 -04:00
UBodySetup * BodySetup = ( StaticMesh ) ? StaticMesh - > GetBodySetup ( ) : nullptr ;
if ( BodySetup ! = nullptr )
2020-10-29 13:38:15 -04:00
{
2021-06-20 17:01:49 -04:00
// mark the BodySetup for modification. Do we need to modify the UStaticMesh??
BodySetup - > Modify ( ) ;
// clear existing simple collision. This will call BodySetup->InvalidatePhysicsData()
BodySetup - > RemoveSimpleCollision ( ) ;
// set new collision geometry
BodySetup - > AggGeom = GeneratedCollision - > AggGeom ;
// update collision type
BodySetup - > CollisionTraceFlag = ( ECollisionTraceFlag ) ( int32 ) Settings - > SetCollisionType ;
// rebuild physics meshes
BodySetup - > CreatePhysicsMeshes ( ) ;
// rebuild nav collision (? StaticMeshEditor does this)
StaticMesh - > CreateNavCollision ( /*bIsUpdate=*/ true ) ;
// update physics state on all components using this StaticMesh
for ( FThreadSafeObjectIterator Iter ( UStaticMeshComponent : : StaticClass ( ) ) ; Iter ; + + Iter )
2020-10-29 13:38:15 -04:00
{
2021-06-20 17:01:49 -04:00
UStaticMeshComponent * SMComponent = Cast < UStaticMeshComponent > ( * Iter ) ;
if ( SMComponent - > GetStaticMesh ( ) = = StaticMesh )
2020-10-29 13:38:15 -04:00
{
2021-06-20 17:01:49 -04:00
if ( SMComponent - > IsPhysicsStateCreated ( ) )
{
SMComponent - > RecreatePhysicsState ( ) ;
}
2020-10-29 13:38:15 -04:00
}
}
2021-06-20 17:01:49 -04:00
// do we need to do a post edit change here??
2020-09-01 14:07:48 -04:00
2021-06-20 17:01:49 -04:00
// mark static mesh as dirty so it gets resaved?
StaticMesh - > MarkPackageDirty ( ) ;
2020-10-29 13:38:15 -04:00
# if WITH_EDITORONLY_DATA
2021-06-20 17:01:49 -04:00
// mark the static mesh as having customized collision so it is not regenerated on reimport
StaticMesh - > bCustomizedCollision = true ;
2020-10-29 13:38:15 -04:00
# endif // WITH_EDITORONLY_DATA
2021-06-20 17:01:49 -04:00
}
2020-09-01 14:07:48 -04:00
// post the undo transaction
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
}
void USetCollisionGeometryTool : : OnTick ( float DeltaTime )
{
if ( bInputMeshesValid = = false )
{
PrecomputeInputMeshes ( ) ;
bInputMeshesValid = true ;
2022-04-19 15:48:15 -04:00
InvalidateCompute ( ) ;
2020-09-01 14:07:48 -04:00
}
2022-04-19 15:48:15 -04:00
if ( Compute )
2020-09-01 14:07:48 -04:00
{
2022-04-19 15:48:15 -04:00
Compute - > Tick ( DeltaTime ) ;
if ( Compute - > HaveValidResult ( ) )
{
TUniquePtr < FPhysicsDataCollection > Result = Compute - > Shutdown ( ) ;
if ( Result . IsValid ( ) )
{
GeneratedCollision = MakeShareable < FPhysicsDataCollection > ( Result . Release ( ) ) ;
bVisualizationDirty = true ;
// update visualization
PreviewGeom - > RemoveAllLineSets ( ) ;
UE : : PhysicsTools : : InitializePreviewGeometryLines ( * GeneratedCollision , PreviewGeom ,
2022-04-22 15:40:09 -04:00
VizSettings - > Color , VizSettings - > LineThickness , 0.0f , 16 , VizSettings - > bRandomColors ) ;
2022-04-19 15:48:15 -04:00
// update property set
CollisionProps - > Reset ( ) ;
UE : : PhysicsTools : : InitializePhysicsToolObjectPropertySet ( GeneratedCollision . Get ( ) , CollisionProps ) ;
}
}
2020-09-01 14:07:48 -04:00
}
if ( bVisualizationDirty )
{
UpdateVisualization ( ) ;
bVisualizationDirty = false ;
}
}
2022-04-19 15:48:15 -04:00
void USetCollisionGeometryTool : : InvalidateCompute ( )
{
if ( PreviewGeom )
{
PreviewGeom - > RemoveAllLineSets ( ) ;
}
if ( ! bInputMeshesValid )
{
// InvalidateCompute() will be called again when the input meshes are valid
return ;
}
if ( ! Compute )
{
// Initialize background compute
Compute = MakeUnique < TGenericDataBackgroundCompute < FPhysicsDataCollection > > ( ) ;
Compute - > Setup ( this ) ;
}
Compute - > InvalidateResult ( ) ;
}
2021-06-20 17:01:49 -04:00
void USetCollisionGeometryTool : : OnInputModeChanged ( )
{
if ( PolygroupLayerProperties ! = nullptr )
{
SetToolPropertySourceEnabled ( PolygroupLayerProperties , Settings - > InputMode = = ESetCollisionGeometryInputMode : : PerMeshGroup ) ;
}
2022-04-19 15:48:15 -04:00
InvalidateCompute ( ) ;
2021-06-20 17:01:49 -04:00
}
void USetCollisionGeometryTool : : OnSelectedGroupLayerChanged ( )
{
bInputMeshesValid = false ;
2022-04-19 15:48:15 -04:00
InvalidateCompute ( ) ;
2021-06-20 17:01:49 -04:00
}
void USetCollisionGeometryTool : : UpdateActiveGroupLayer ( )
{
if ( InitialSourceMeshes . Num ( ) ! = 1 )
{
ensure ( false ) ; // should not get here
return ;
}
FDynamicMesh3 * GroupLayersMesh = & InitialSourceMeshes [ 0 ] ;
if ( PolygroupLayerProperties - > HasSelectedPolygroup ( ) = = false )
{
ActiveGroupSet = MakeUnique < UE : : Geometry : : FPolygroupSet > ( GroupLayersMesh ) ;
}
else
{
FName SelectedName = PolygroupLayerProperties - > ActiveGroupLayer ;
FDynamicMeshPolygroupAttribute * FoundAttrib = UE : : Geometry : : FindPolygroupLayerByName ( * GroupLayersMesh , SelectedName ) ;
ensureMsgf ( FoundAttrib , TEXT ( " Selected Attribute Not Found! Falling back to Default group layer. " ) ) ;
ActiveGroupSet = MakeUnique < UE : : Geometry : : FPolygroupSet > ( GroupLayersMesh , FoundAttrib ) ;
}
}
2020-09-01 14:07:48 -04:00
void USetCollisionGeometryTool : : UpdateVisualization ( )
{
float UseThickness = VizSettings - > LineThickness ;
FColor UseColor = VizSettings - > Color ;
2022-04-22 15:40:09 -04:00
int32 ColorIdx = 0 ;
2020-09-01 14:07:48 -04:00
PreviewGeom - > UpdateAllLineSets ( [ & ] ( ULineSetComponent * LineSet )
{
LineSet - > SetAllLinesThickness ( UseThickness ) ;
2022-04-22 15:40:09 -04:00
LineSet - > SetAllLinesColor ( VizSettings - > bRandomColors ? LinearColors : : SelectFColor ( ColorIdx + + ) : UseColor ) ;
2020-09-01 14:07:48 -04:00
} ) ;
2020-10-29 13:38:15 -04:00
LineMaterial = ToolSetupUtil : : GetDefaultLineComponentMaterial ( GetToolManager ( ) , ! VizSettings - > bShowHidden ) ;
PreviewGeom - > SetAllLineSetsMaterial ( LineMaterial ) ;
2020-09-01 14:07:48 -04:00
}
void USetCollisionGeometryTool : : InitializeDerivedMeshSet (
2021-02-17 11:50:23 -04:00
const TArray < TSharedPtr < FDynamicMesh3 , ESPMode : : ThreadSafe > > & FromInputMeshes ,
TArray < TSharedPtr < FDynamicMesh3 , ESPMode : : ThreadSafe > > & ToMeshes ,
2020-09-01 14:07:48 -04:00
TFunctionRef < bool ( const FDynamicMesh3 * Mesh , int32 Tri0 , int32 Tri1 ) > TrisConnectedPredicate )
{
// find connected-components on input meshes, under given connectivity predicate
TArray < TUniquePtr < FMeshConnectedComponents > > ComponentSets ;
ComponentSets . SetNum ( FromInputMeshes . Num ( ) ) ;
ParallelFor ( FromInputMeshes . Num ( ) , [ & ] ( int32 k )
{
const FDynamicMesh3 * Mesh = FromInputMeshes [ k ] . Get ( ) ;
ComponentSets [ k ] = MakeUnique < FMeshConnectedComponents > ( Mesh ) ;
ComponentSets [ k ] - > FindConnectedTriangles (
[ Mesh , & TrisConnectedPredicate ] ( int32 Tri0 , int32 Tri1 )
{
return TrisConnectedPredicate ( Mesh , Tri0 , Tri1 ) ;
}
) ;
} ) ;
// Assemble a list of all the submeshes we want to compute, so we can do them all in parallel
struct FSubmeshSource
{
const FDynamicMesh3 * SourceMesh ;
FIndex2i ComponentIdx ;
} ;
TArray < FSubmeshSource > AllSubmeshes ;
for ( int32 k = 0 ; k < FromInputMeshes . Num ( ) ; + + k )
{
const FDynamicMesh3 * Mesh = FromInputMeshes [ k ] . Get ( ) ;
int32 NumComponents = ComponentSets [ k ] - > Num ( ) ;
for ( int32 j = 0 ; j < NumComponents ; + + j )
{
const FMeshConnectedComponents : : FComponent & Component = ComponentSets [ k ] - > GetComponent ( j ) ;
if ( Component . Indices . Num ( ) > 1 ) // ignore single triangles
{
AllSubmeshes . Add ( FSubmeshSource { Mesh , FIndex2i ( k , j ) } ) ;
}
}
}
// compute all the submeshes
ToMeshes . Reset ( ) ;
ToMeshes . SetNum ( AllSubmeshes . Num ( ) ) ;
ParallelFor ( AllSubmeshes . Num ( ) , [ & ] ( int32 k )
{
const FSubmeshSource & Source = AllSubmeshes [ k ] ;
const FMeshConnectedComponents : : FComponent & Component = ComponentSets [ Source . ComponentIdx . A ] - > GetComponent ( Source . ComponentIdx . B ) ;
FDynamicSubmesh3 Submesh ( Source . SourceMesh , Component . Indices , ( int32 ) EMeshComponents : : None , false ) ;
2021-02-17 11:50:23 -04:00
ToMeshes [ k ] = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( MoveTemp ( Submesh . GetSubmesh ( ) ) ) ;
2020-09-01 14:07:48 -04:00
} ) ;
}
template < typename T >
2021-02-17 11:50:23 -04:00
TArray < const T * > MakeRawPointerList ( const TArray < TSharedPtr < T , ESPMode : : ThreadSafe > > & InputList )
2020-09-01 14:07:48 -04:00
{
TArray < const T * > Result ;
Result . Reserve ( InputList . Num ( ) ) ;
2021-02-17 11:50:23 -04:00
for ( const TSharedPtr < T , ESPMode : : ThreadSafe > & Ptr : InputList )
2020-09-01 14:07:48 -04:00
{
Result . Add ( Ptr . Get ( ) ) ;
}
return MoveTemp ( Result ) ;
}
void USetCollisionGeometryTool : : PrecomputeInputMeshes ( )
{
2021-06-20 17:01:49 -04:00
if ( InitialSourceMeshes . Num ( ) = = 1 )
{
UpdateActiveGroupLayer ( ) ;
}
UToolTarget * CollisionTarget = Targets [ Targets . Num ( ) - 1 ] ;
2022-01-29 14:37:53 -05:00
FTransformSRT3d TargetTransform ( UE : : ToolTarget : : GetLocalToWorldTransform ( CollisionTarget ) ) ;
2020-09-01 14:07:48 -04:00
InputMeshes . Reset ( ) ;
InputMeshes . SetNum ( SourceObjectIndices . Num ( ) ) ;
ParallelFor ( SourceObjectIndices . Num ( ) , [ & ] ( int32 k )
{
2021-06-20 17:01:49 -04:00
FDynamicMesh3 SourceMesh = InitialSourceMeshes [ k ] ;
2020-09-01 14:07:48 -04:00
if ( Settings - > bUseWorldSpace )
{
2022-01-29 14:37:53 -05:00
FTransformSRT3d ToWorld ( UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ k ] ) ) ;
2020-09-01 14:07:48 -04:00
MeshTransforms : : ApplyTransform ( SourceMesh , ToWorld ) ;
2022-05-12 12:08:26 -04:00
MeshTransforms : : ApplyTransformInverse ( SourceMesh , TargetTransform ) ;
2020-09-01 14:07:48 -04:00
}
SourceMesh . DiscardAttributes ( ) ;
2021-02-17 11:50:23 -04:00
InputMeshes [ k ] = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( MoveTemp ( SourceMesh ) ) ;
2020-09-01 14:07:48 -04:00
} ) ;
2021-02-17 11:50:23 -04:00
InputMeshesApproximator = MakeShared < FMeshSimpleShapeApproximation , ESPMode : : ThreadSafe > ( ) ;
2020-09-01 14:07:48 -04:00
InputMeshesApproximator - > InitializeSourceMeshes ( MakeRawPointerList < FDynamicMesh3 > ( InputMeshes ) ) ;
// build combined input
CombinedInputMeshes . Reset ( ) ;
FDynamicMesh3 CombinedMesh ;
CombinedMesh . EnableTriangleGroups ( ) ;
FDynamicMeshEditor Appender ( & CombinedMesh ) ;
FMeshIndexMappings TmpMappings ;
2021-02-17 11:50:23 -04:00
for ( const TSharedPtr < FDynamicMesh3 , ESPMode : : ThreadSafe > & InputMesh : InputMeshes )
2020-09-01 14:07:48 -04:00
{
TmpMappings . Reset ( ) ;
Appender . AppendMesh ( InputMesh . Get ( ) , TmpMappings ) ;
}
2021-02-17 11:50:23 -04:00
CombinedInputMeshes . Add ( MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( MoveTemp ( CombinedMesh ) ) ) ;
CombinedInputMeshesApproximator = MakeShared < FMeshSimpleShapeApproximation , ESPMode : : ThreadSafe > ( ) ;
2020-09-01 14:07:48 -04:00
CombinedInputMeshesApproximator - > InitializeSourceMeshes ( MakeRawPointerList < FDynamicMesh3 > ( CombinedInputMeshes ) ) ;
// build separated input meshes
SeparatedInputMeshes . Reset ( ) ;
InitializeDerivedMeshSet ( InputMeshes , SeparatedInputMeshes ,
[ & ] ( const FDynamicMesh3 * Mesh , int32 Tri0 , int32 Tri1 ) { return true ; } ) ;
2021-02-17 11:50:23 -04:00
SeparatedMeshesApproximator = MakeShared < FMeshSimpleShapeApproximation , ESPMode : : ThreadSafe > ( ) ;
2020-09-01 14:07:48 -04:00
SeparatedMeshesApproximator - > InitializeSourceMeshes ( MakeRawPointerList < FDynamicMesh3 > ( SeparatedInputMeshes ) ) ;
// build per-group input meshes
PerGroupInputMeshes . Reset ( ) ;
2021-06-20 17:01:49 -04:00
if ( ActiveGroupSet . IsValid ( ) )
{
check ( InputMeshes . Num ( ) = = 1 ) ;
InitializeDerivedMeshSet ( InputMeshes , PerGroupInputMeshes ,
[ & ] ( const FDynamicMesh3 * Mesh , int32 Tri0 , int32 Tri1 ) { return ActiveGroupSet - > GetTriangleGroup ( Tri0 ) = = ActiveGroupSet - > GetTriangleGroup ( Tri1 ) ; } ) ;
}
else
{
InitializeDerivedMeshSet ( InputMeshes , PerGroupInputMeshes ,
[ & ] ( const FDynamicMesh3 * Mesh , int32 Tri0 , int32 Tri1 ) { return Mesh - > GetTriangleGroup ( Tri0 ) = = Mesh - > GetTriangleGroup ( Tri1 ) ; } ) ;
}
2021-02-17 11:50:23 -04:00
PerGroupMeshesApproximator = MakeShared < FMeshSimpleShapeApproximation , ESPMode : : ThreadSafe > ( ) ;
2020-09-01 14:07:48 -04:00
PerGroupMeshesApproximator - > InitializeSourceMeshes ( MakeRawPointerList < FDynamicMesh3 > ( PerGroupInputMeshes ) ) ;
}
# undef LOCTEXT_NAMESPACE