2020-08-11 01:36:57 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "BaseTools/BaseCreateFromSelectedTool.h"
# include "InteractiveToolManager.h"
# include "ToolBuilderUtil.h"
# include "ToolSetupUtil.h"
2021-05-20 16:39:39 -04:00
# include "BaseGizmos/TransformGizmoUtil.h"
2020-08-11 01:36:57 -04:00
2023-12-15 15:50:51 -05:00
# include "Components/StaticMeshComponent.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/MeshNormals.h"
# include "DynamicMesh/MeshTransforms.h"
2020-08-11 01:36:57 -04:00
# include "DynamicMeshToMeshDescription.h"
2021-06-02 15:58:00 -04:00
# include "ModelingObjectsCreationAPI.h"
2023-12-15 15:50:51 -05:00
# include "Physics/ComponentCollisionUtil.h"
2020-08-11 01:36:57 -04:00
# include "Selection/ToolSelectionUtil.h"
2023-12-15 15:50:51 -05:00
# include "ShapeApproximation/SimpleShapeSet3.h"
2020-08-11 01:36:57 -04:00
2021-03-11 11:40:03 -04:00
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
# include "TargetInterfaces/MaterialProvider.h"
2021-03-23 14:51:49 -04:00
# include "TargetInterfaces/AssetBackedTarget.h"
2021-03-11 11:40:03 -04:00
# include "ToolTargetManager.h"
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
# include "ModelingToolTargetUtil.h"
2020-08-11 01:36:57 -04:00
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(BaseCreateFromSelectedTool)
2020-08-11 01:36:57 -04:00
# define LOCTEXT_NAMESPACE "UBaseCreateFromSelectedTool"
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2020-08-11 01:36:57 -04:00
/*
* ToolBuilder
*/
bool UBaseCreateFromSelectedToolBuilder : : CanBuildTool ( const FToolBuilderState & SceneState ) const
{
2021-03-11 11:40:03 -04:00
int32 ComponentCount = SceneState . TargetManager - > CountSelectedAndTargetable ( SceneState , GetTargetRequirements ( ) ) ;
2021-06-02 15:58:00 -04:00
return ComponentCount > = MinComponentsSupported ( ) & & ( ! MaxComponentsSupported ( ) . IsSet ( ) | | ComponentCount < = MaxComponentsSupported ( ) . GetValue ( ) ) ;
2020-08-11 01:36:57 -04:00
}
2021-11-23 19:17:30 -05:00
UMultiSelectionMeshEditingTool * UBaseCreateFromSelectedToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
{
// Subclasses must override this method.
check ( false ) ;
return nullptr ;
}
2020-08-11 01:36:57 -04:00
/*
* Tool
*/
void UBaseCreateFromSelectedTool : : Setup ( )
{
UInteractiveTool : : Setup ( ) ;
// hide input StaticMeshComponents
2021-03-11 11:40:03 -04:00
for ( int32 ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-08-11 01:36:57 -04:00
{
2021-11-23 09:42:40 -05:00
UE : : ToolTarget : : HideSourceObject ( Targets [ ComponentIdx ] ) ;
2020-08-11 01:36:57 -04:00
}
// initialize our properties
SetupProperties ( ) ;
TransformProperties = NewObject < UTransformInputsToolProperties > ( this ) ;
TransformProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( TransformProperties ) ;
2020-10-22 19:19:16 -04:00
2021-06-23 22:14:55 -04:00
OutputTypeProperties = NewObject < UCreateMeshObjectTypeProperties > ( this ) ;
OutputTypeProperties - > InitializeDefaultWithAuto ( ) ;
OutputTypeProperties - > OutputType = UCreateMeshObjectTypeProperties : : AutoIdentifier ;
OutputTypeProperties - > RestoreProperties ( this , TEXT ( " OutputTypeFromInputTool " ) ) ;
OutputTypeProperties - > WatchProperty ( OutputTypeProperties - > OutputType , [ this ] ( FString ) { OutputTypeProperties - > UpdatePropertyVisibility ( ) ; } ) ;
AddToolPropertySource ( OutputTypeProperties ) ;
2020-10-22 19:19:16 -04:00
HandleSourcesProperties = NewObject < UBaseCreateFromSelectedHandleSourceProperties > ( this ) ;
2020-08-11 01:36:57 -04:00
HandleSourcesProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( HandleSourcesProperties ) ;
2023-12-15 15:50:51 -05:00
if ( SupportsCollisionTransfer ( ) )
{
CollisionProperties = NewObject < UBaseCreateFromSelectedCollisionProperties > ( this ) ;
CollisionProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( CollisionProperties ) ;
}
2021-06-23 22:14:55 -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 , nullptr ) ;
2020-08-11 01:36:57 -04:00
SetPreviewCallbacks ( ) ;
2021-02-05 16:33:02 -04:00
Preview - > OnMeshUpdated . AddLambda (
[ this ] ( const UMeshOpPreviewWithBackgroundCompute * UpdatedPreview )
{
UpdateAcceptWarnings ( UpdatedPreview - > HaveEmptyResult ( ) ? EAcceptWarning : : EmptyForbidden : EAcceptWarning : : NoWarning ) ;
}
) ;
2020-08-11 01:36:57 -04:00
SetTransformGizmos ( ) ;
ConvertInputsAndSetPreviewMaterials ( true ) ;
2020-10-22 19:19:16 -04:00
// output name fields
2021-10-28 11:24:32 -04:00
HandleSourcesProperties - > OutputNewName = PrefixWithSourceNameIfSingleSelection ( GetCreatedAssetName ( ) ) ;
HandleSourcesProperties - > WatchProperty ( HandleSourcesProperties - > OutputWriteTo , [ & ] ( EBaseCreateFromSelectedTargetType NewType )
2020-10-22 19:19:16 -04:00
{
2021-10-28 11:24:32 -04:00
SetToolPropertySourceEnabled ( OutputTypeProperties , ( NewType = = EBaseCreateFromSelectedTargetType : : NewObject ) ) ;
if ( NewType = = EBaseCreateFromSelectedTargetType : : NewObject )
2020-10-22 19:19:16 -04:00
{
2021-10-28 11:24:32 -04:00
HandleSourcesProperties - > OutputExistingName = TEXT ( " " ) ;
2021-02-03 19:00:42 -04:00
UpdateGizmoVisibility ( ) ;
2020-10-22 19:19:16 -04:00
}
else
{
2021-10-28 11:24:32 -04:00
int32 Index = ( HandleSourcesProperties - > OutputWriteTo = = EBaseCreateFromSelectedTargetType : : FirstInputObject ) ? 0 : Targets . Num ( ) - 1 ;
2021-11-23 09:42:40 -05:00
HandleSourcesProperties - > OutputExistingName = UE : : Modeling : : GetComponentAssetBaseName ( UE : : ToolTarget : : GetTargetComponent ( Targets [ Index ] ) , false ) ;
2021-03-09 21:27:22 -04:00
2021-02-03 19:00:42 -04:00
// Reset the hidden gizmo to its initial position
2021-11-23 09:42:40 -05:00
const FTransform ComponentTransform = ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ Index ] ) ;
2021-02-03 19:00:42 -04:00
TransformGizmos [ Index ] - > SetNewGizmoTransform ( ComponentTransform , true ) ;
UpdateGizmoVisibility ( ) ;
2020-10-22 19:19:16 -04:00
}
} ) ;
2020-08-11 01:36:57 -04:00
Preview - > InvalidateResult ( ) ;
}
2021-03-09 21:27:22 -04:00
int32 UBaseCreateFromSelectedTool : : GetHiddenGizmoIndex ( ) const
{
2021-10-28 11:24:32 -04:00
if ( HandleSourcesProperties - > OutputWriteTo = = EBaseCreateFromSelectedTargetType : : NewObject )
2021-03-09 21:27:22 -04:00
{
return - 1 ;
}
else
{
2021-10-28 11:24:32 -04:00
return ( HandleSourcesProperties - > OutputWriteTo = = EBaseCreateFromSelectedTargetType : : FirstInputObject ) ? 0 : Targets . Num ( ) - 1 ;
2021-03-09 21:27:22 -04:00
}
}
2020-08-11 01:36:57 -04:00
void UBaseCreateFromSelectedTool : : OnTick ( float DeltaTime )
{
Preview - > Tick ( DeltaTime ) ;
}
void UBaseCreateFromSelectedTool : : UpdateGizmoVisibility ( )
{
2021-02-03 19:00:42 -04:00
for ( int32 GizmoIndex = 0 ; GizmoIndex < TransformGizmos . Num ( ) ; GizmoIndex + + )
2020-08-11 01:36:57 -04:00
{
2021-09-29 23:20:44 -04:00
UCombinedTransformGizmo * Gizmo = TransformGizmos [ GizmoIndex ] ;
2021-10-29 22:42:08 -04:00
Gizmo - > SetVisibility ( TransformProperties - > bShowTransformGizmo & & GizmoIndex ! = GetHiddenGizmoIndex ( ) ) ;
2020-08-11 01:36:57 -04:00
}
}
2021-02-03 19:00:42 -04:00
2020-08-11 01:36:57 -04:00
void UBaseCreateFromSelectedTool : : SetTransformGizmos ( )
{
UInteractiveGizmoManager * GizmoManager = GetToolManager ( ) - > GetPairedGizmoManager ( ) ;
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-08-11 01:36:57 -04:00
{
UTransformProxy * Proxy = TransformProxies . Add_GetRef ( NewObject < UTransformProxy > ( this ) ) ;
2021-09-29 23:20:44 -04:00
UCombinedTransformGizmo * Gizmo = TransformGizmos . Add_GetRef ( UE : : TransformGizmoUtil : : Create3AxisTransformGizmo ( GizmoManager , this ) ) ;
2021-11-23 09:42:40 -05:00
Proxy - > SetTransform ( ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ ComponentIdx ] ) ) ;
2020-09-24 00:43:27 -04:00
Gizmo - > SetActiveTarget ( Proxy , GetToolManager ( ) ) ;
2020-08-11 01:36:57 -04:00
Proxy - > OnTransformChanged . AddUObject ( this , & UBaseCreateFromSelectedTool : : TransformChanged ) ;
}
UpdateGizmoVisibility ( ) ;
}
void UBaseCreateFromSelectedTool : : TransformChanged ( UTransformProxy * Proxy , FTransform Transform )
{
Preview - > InvalidateResult ( ) ;
}
FText UBaseCreateFromSelectedTool : : GetActionName ( ) const
{
return LOCTEXT ( " BaseCreateFromSelectedTool " , " Generated Mesh " ) ;
}
TArray < UMaterialInterface * > UBaseCreateFromSelectedTool : : GetOutputMaterials ( ) const
{
return Preview - > StandardMaterials ;
}
2021-06-02 15:58:00 -04:00
void UBaseCreateFromSelectedTool : : GenerateAsset ( const FDynamicMeshOpResult & OpResult )
2020-08-11 01:36:57 -04:00
{
2021-06-02 15:58:00 -04:00
if ( OpResult . Mesh . Get ( ) = = nullptr ) return ;
2020-08-11 01:36:57 -04:00
FTransform3d NewTransform ;
2021-03-11 11:40:03 -04:00
if ( Targets . Num ( ) = = 1 ) // in the single-selection case, shove the result back into the original component space
2020-08-11 01:36:57 -04:00
{
2022-05-12 12:08:26 -04:00
FTransform3d FromSourceComponentSpace = UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ 0 ] ) ;
2022-10-09 23:35:03 -04:00
MeshTransforms : : ApplyTransform ( * OpResult . Mesh , OpResult . Transform , true ) ;
2022-08-30 14:40:56 -04:00
MeshTransforms : : ApplyTransformInverse ( * OpResult . Mesh , FromSourceComponentSpace , true ) ;
2021-11-23 09:42:40 -05:00
NewTransform = UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ 0 ] ) ;
2020-08-11 01:36:57 -04:00
}
else // in the multi-selection case, center the pivot for the combined result
{
2021-08-23 22:08:34 -04:00
FVector3d Center = OpResult . Mesh - > GetBounds ( ) . Center ( ) ;
2021-06-02 15:58:00 -04:00
double Rescale = OpResult . Transform . GetScale ( ) . X ;
2020-08-11 01:36:57 -04:00
FTransform3d LocalTransform ( - Center * Rescale ) ;
2022-01-29 14:37:53 -05:00
LocalTransform . SetScale3D ( FVector3d ( Rescale , Rescale , Rescale ) ) ;
2022-08-30 14:40:56 -04:00
MeshTransforms : : ApplyTransform ( * OpResult . Mesh , LocalTransform , true ) ;
2021-06-02 15:58:00 -04:00
NewTransform = OpResult . Transform ;
2022-01-29 14:37:53 -05:00
NewTransform . SetScale3D ( FVector3d : : One ( ) ) ;
2020-08-11 01:36:57 -04:00
NewTransform . SetTranslation ( NewTransform . GetTranslation ( ) + NewTransform . TransformVector ( Center * Rescale ) ) ;
}
2020-10-29 13:38:15 -04:00
// max len explicitly enforced here, would ideally notify user
2021-10-28 11:24:32 -04:00
FString UseBaseName = HandleSourcesProperties - > OutputNewName . Left ( 250 ) ;
2020-10-29 13:38:15 -04:00
if ( UseBaseName . IsEmpty ( ) )
{
UseBaseName = PrefixWithSourceNameIfSingleSelection ( GetCreatedAssetName ( ) ) ;
}
2020-08-11 01:36:57 -04:00
2021-06-02 15:58:00 -04:00
FCreateMeshObjectParams NewMeshObjectParams ;
2022-01-28 10:18:10 -05:00
NewMeshObjectParams . TargetWorld = GetTargetWorld ( ) ;
2021-06-02 15:58:00 -04:00
NewMeshObjectParams . Transform = ( FTransform ) NewTransform ;
NewMeshObjectParams . BaseName = UseBaseName ;
NewMeshObjectParams . Materials = GetOutputMaterials ( ) ;
NewMeshObjectParams . SetMesh ( OpResult . Mesh . Get ( ) ) ;
2021-06-23 22:14:55 -04:00
if ( OutputTypeProperties - > OutputType = = UCreateMeshObjectTypeProperties : : AutoIdentifier )
{
UE : : ToolTarget : : ConfigureCreateMeshObjectParams ( Targets [ 0 ] , NewMeshObjectParams ) ;
}
else
{
OutputTypeProperties - > ConfigureCreateMeshObjectParams ( NewMeshObjectParams ) ;
}
2023-12-15 15:50:51 -05:00
bool bOutputSupportsCustomCollision = NewMeshObjectParams . TypeHint ! = ECreateObjectTypeHint : : Volume ;
if ( SupportsCollisionTransfer ( ) & & CollisionProperties - > bTransferCollision & & bOutputSupportsCustomCollision )
{
for ( int32 TargetIdx = 0 ; TargetIdx < Targets . Num ( ) ; + + TargetIdx )
{
if ( ! KeepCollisionFrom ( TargetIdx ) )
{
continue ;
}
UPrimitiveComponent * SourceComponent = UE : : ToolTarget : : GetTargetComponent ( Targets [ TargetIdx ] ) ;
if ( UE : : Geometry : : ComponentTypeSupportsCollision ( SourceComponent , UE : : Geometry : : EComponentCollisionSupportLevel : : ReadOnly ) )
{
NewMeshObjectParams . bEnableCollision = true ;
FComponentCollisionSettings CollisionSettings = UE : : Geometry : : GetCollisionSettings ( SourceComponent ) ;
// flag will be set to match the last selection that had collision
NewMeshObjectParams . CollisionMode = ( ECollisionTraceFlag ) CollisionSettings . CollisionTypeFlag ;
FSimpleShapeSet3d ShapeSet ;
FTransform Transform = FTransform : : Identity ;
if ( Targets . Num ( ) > 1 )
{
// Note: NewTransform in the multi-target case is constructed to have uniform scale, so should have a valid inverse
Transform = TransformProxies [ TargetIdx ] - > GetTransform ( ) * NewTransform . Inverse ( ) ;
}
if ( UE : : Geometry : : GetCollisionShapes ( SourceComponent , ShapeSet ) )
{
if ( ! NewMeshObjectParams . CollisionShapeSet . IsSet ( ) )
{
NewMeshObjectParams . CollisionShapeSet . Emplace ( ) ;
}
NewMeshObjectParams . CollisionShapeSet - > Append ( ShapeSet , Transform ) ;
}
}
}
}
2021-06-02 15:58:00 -04:00
FCreateMeshObjectResult Result = UE : : Modeling : : CreateMeshObject ( GetToolManager ( ) , MoveTemp ( NewMeshObjectParams ) ) ;
if ( Result . IsOK ( ) & & Result . NewActor ! = nullptr )
2020-08-11 01:36:57 -04:00
{
2021-06-02 15:58:00 -04:00
ToolSelectionUtil : : SetNewActorSelection ( GetToolManager ( ) , Result . NewActor ) ;
2020-08-11 01:36:57 -04:00
}
}
2020-10-22 19:19:16 -04:00
2021-03-11 11:40:03 -04:00
void UBaseCreateFromSelectedTool : : UpdateAsset ( const FDynamicMeshOpResult & Result , UToolTarget * UpdateTarget )
2020-10-22 19:19:16 -04:00
{
check ( Result . Mesh . Get ( ) ! = nullptr ) ;
2021-11-23 09:42:40 -05:00
FTransform3d TargetToWorld = UE : : ToolTarget : : GetLocalToWorldTransform ( UpdateTarget ) ;
2020-10-22 19:19:16 -04:00
2021-02-03 19:00:42 -04:00
FTransform3d ResultTransform = Result . Transform ;
2022-08-30 14:40:56 -04:00
MeshTransforms : : ApplyTransform ( * Result . Mesh , ResultTransform , true ) ;
MeshTransforms : : ApplyTransformInverse ( * Result . Mesh , TargetToWorld , true ) ;
2020-10-22 19:19:16 -04:00
2021-12-06 12:42:19 -05:00
UE : : ToolTarget : : CommitMeshDescriptionUpdateViaDynamicMesh ( UpdateTarget , * Result . Mesh , true ) ;
2020-10-22 19:19:16 -04:00
FComponentMaterialSet MaterialSet ;
MaterialSet . Materials = GetOutputMaterials ( ) ;
2024-02-15 23:10:02 -05:00
// apply updated materials to both asset and component, to ensure that they appear in the result
// TODO: consider adding a method to the material provider interface that more-directly handles this use case
2021-11-23 09:42:40 -05:00
Cast < IMaterialProvider > ( UpdateTarget ) - > CommitMaterialSetUpdate ( MaterialSet , true ) ;
2024-02-15 23:10:02 -05:00
Cast < IMaterialProvider > ( UpdateTarget ) - > CommitMaterialSetUpdate ( MaterialSet , false ) ;
2020-10-22 19:19:16 -04:00
}
2020-08-11 01:36:57 -04:00
FString UBaseCreateFromSelectedTool : : PrefixWithSourceNameIfSingleSelection ( const FString & AssetName ) const
{
2021-03-11 11:40:03 -04:00
if ( Targets . Num ( ) = = 1 )
2020-08-11 01:36:57 -04:00
{
2021-11-23 09:42:40 -05:00
FString CurName = UE : : Modeling : : GetComponentAssetBaseName ( UE : : ToolTarget : : GetTargetComponent ( Targets [ 0 ] ) ) ;
2020-10-22 19:19:16 -04:00
return FString : : Printf ( TEXT ( " %s_%s " ) , * CurName , * AssetName ) ;
2020-08-11 01:36:57 -04:00
}
else
{
return AssetName ;
}
}
void UBaseCreateFromSelectedTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
{
2021-10-29 22:42:08 -04:00
if ( Property & & ( Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UTransformInputsToolProperties , bShowTransformGizmo ) ) )
2020-08-11 01:36:57 -04:00
{
UpdateGizmoVisibility ( ) ;
}
else if ( Property & &
( PropertySet = = HandleSourcesProperties
) )
{
// nothing
}
else
{
Preview - > InvalidateResult ( ) ;
}
}
2022-01-28 18:40:54 -05:00
void UBaseCreateFromSelectedTool : : OnShutdown ( EToolShutdownType ShutdownType )
2020-08-11 01:36:57 -04:00
{
SaveProperties ( ) ;
HandleSourcesProperties - > SaveProperties ( this ) ;
2023-12-15 15:50:51 -05:00
if ( SupportsCollisionTransfer ( ) )
{
CollisionProperties - > SaveProperties ( this ) ;
}
2021-06-23 22:14:55 -04:00
OutputTypeProperties - > SaveProperties ( this , TEXT ( " OutputTypeFromInputTool " ) ) ;
2020-08-11 01:36:57 -04:00
TransformProperties - > SaveProperties ( this ) ;
FDynamicMeshOpResult Result = Preview - > Shutdown ( ) ;
// Restore (unhide) the source meshes
2021-03-11 11:40:03 -04:00
for ( int32 ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-08-11 01:36:57 -04:00
{
2021-11-23 09:42:40 -05:00
UE : : ToolTarget : : ShowSourceObject ( Targets [ ComponentIdx ] ) ;
2020-08-11 01:36:57 -04:00
}
2020-11-24 18:42:39 -04:00
2020-08-11 01:36:57 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
2023-12-15 15:50:51 -05:00
// Test if we need to pre-update the collision shapes, if we are updating an asset and have multiple targets
// Note: For static meshes, this must be done as a separate transaction due to a long-standing bug where undo/redo
// will crash if an asset updates both its collision and geometry in the same transaction
// TODO: If/when that static mesh bug is fixed, this collision updating code can be separated out into the UpdateAsset() method
2024-02-09 13:15:25 -05:00
constexpr bool bWorkaroundForCrashIfConvexAndMeshModifiedInSameTransaction = false ;
2023-12-15 15:50:51 -05:00
bool bAlreadyOpenedMainTransaction = false ;
if ( SupportsCollisionTransfer ( ) & & HandleSourcesProperties - > OutputWriteTo ! = EBaseCreateFromSelectedTargetType : : NewObject & & Targets . Num ( ) > 1 )
{
int32 KeepTargetIndex = ( HandleSourcesProperties - > OutputWriteTo = = EBaseCreateFromSelectedTargetType : : FirstInputObject ) ? 0 : ( Targets . Num ( ) - 1 ) ;
UPrimitiveComponent * TargetComponent = UE : : ToolTarget : : GetTargetComponent ( Targets [ KeepTargetIndex ] ) ;
if ( CollisionProperties - > bTransferCollision & & UE : : Geometry : : ComponentTypeSupportsCollision ( TargetComponent , UE : : Geometry : : EComponentCollisionSupportLevel : : ReadWrite ) )
{
bool bHasAddedShapes = false ;
FSimpleShapeSet3d AccumulateShapes ;
UE : : Geometry : : GetCollisionShapes ( TargetComponent , AccumulateShapes ) ;
FTransform3d TargetToWorld = UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ KeepTargetIndex ] ) ;
FTransformSequence3d InvKeepTargetTransform ;
InvKeepTargetTransform . AppendInverse ( TargetToWorld ) ;
for ( int32 TargetIdx = 0 ; TargetIdx < Targets . Num ( ) ; + + TargetIdx )
{
if ( TargetIdx = = KeepTargetIndex | | ! KeepCollisionFrom ( TargetIdx ) )
{
continue ;
}
UPrimitiveComponent * SourceComponent = UE : : ToolTarget : : GetTargetComponent ( Targets [ TargetIdx ] ) ;
FSimpleShapeSet3d ShapeSet ;
if ( UE : : Geometry : : ComponentTypeSupportsCollision ( SourceComponent , UE : : Geometry : : EComponentCollisionSupportLevel : : ReadOnly ) & &
UE : : Geometry : : GetCollisionShapes ( SourceComponent , ShapeSet ) )
{
bHasAddedShapes = true ;
// Create a best-effort transform sequence to take the collision shapes from their proxy transform space to world, and then back to the local space of the target
// Note because transforms cannot be fully applied to some collision shape types (e.g. spheres), this will still give weird results in non-uniform scale cases (but this is somewhat unavoidable)
FTransformSequence3d TransformSeq ;
TransformSeq . Append ( TransformProxies [ TargetIdx ] - > GetTransform ( ) ) ;
TransformSeq . Append ( InvKeepTargetTransform ) ;
AccumulateShapes . Append ( ShapeSet , TransformSeq ) ;
}
}
if ( bHasAddedShapes )
{
2024-02-09 13:15:25 -05:00
bool bWorkaroundNotNeeded = ! bWorkaroundForCrashIfConvexAndMeshModifiedInSameTransaction | ! Cast < UStaticMeshComponent > ( TargetComponent ) ; // slightly odd conditional to workaround compiler warning
if ( bWorkaroundNotNeeded )
2023-12-15 15:50:51 -05:00
{
// If we're not operating on a static mesh, we can open the main transaction here so the collision transaction becomes part of it ...
// for static mesh, we need the collision update to be a separate transaction to avoid crashing on undo/redo :(
bAlreadyOpenedMainTransaction = true ;
GetToolManager ( ) - > BeginUndoTransaction ( GetActionName ( ) ) ;
}
GetToolManager ( ) - > BeginUndoTransaction ( FText : : Format ( LOCTEXT ( " SplitTransactionCollisionUpdatePart " , " Update Collision ({0}) " ) , GetActionName ( ) ) ) ;
TargetComponent - > Modify ( ) ;
FComponentCollisionSettings Settings = GetCollisionSettings ( TargetComponent ) ;
UE : : Geometry : : SetSimpleCollision ( TargetComponent , & AccumulateShapes , Settings ) ;
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
}
}
if ( ! bAlreadyOpenedMainTransaction )
{
GetToolManager ( ) - > BeginUndoTransaction ( GetActionName ( ) ) ;
}
2020-08-11 01:36:57 -04:00
// Generate the result
2020-10-22 19:19:16 -04:00
AActor * KeepActor = nullptr ;
2021-10-28 11:24:32 -04:00
if ( HandleSourcesProperties - > OutputWriteTo = = EBaseCreateFromSelectedTargetType : : NewObject )
2020-10-22 19:19:16 -04:00
{
GenerateAsset ( Result ) ;
}
else
{
2021-10-28 11:24:32 -04:00
int32 TargetIndex = ( HandleSourcesProperties - > OutputWriteTo = = EBaseCreateFromSelectedTargetType : : FirstInputObject ) ? 0 : ( Targets . Num ( ) - 1 ) ;
2021-11-23 09:42:40 -05:00
KeepActor = UE : : ToolTarget : : GetTargetActor ( Targets [ TargetIndex ] ) ;
2020-10-22 19:19:16 -04:00
2021-03-11 11:40:03 -04:00
UpdateAsset ( Result , Targets [ TargetIndex ] ) ;
2020-10-22 19:19:16 -04:00
}
2020-08-11 01:36:57 -04:00
TArray < AActor * > Actors ;
2021-03-11 11:40:03 -04:00
for ( int32 ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-08-11 01:36:57 -04:00
{
2021-11-23 09:42:40 -05:00
AActor * Actor = UE : : ToolTarget : : GetTargetActor ( Targets [ ComponentIdx ] ) ;
2021-10-25 20:05:28 -04:00
Actors . Add ( Actor ) ;
2020-08-11 01:36:57 -04:00
}
2021-10-25 20:05:28 -04:00
HandleSourcesProperties - > ApplyMethod ( Actors , GetToolManager ( ) , KeepActor ) ;
2020-08-11 01:36:57 -04:00
2020-10-22 19:19:16 -04:00
if ( KeepActor ! = nullptr )
{
// select the actor we kept
ToolSelectionUtil : : SetNewActorSelection ( GetToolManager ( ) , KeepActor ) ;
}
2020-08-11 01:36:57 -04:00
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
UInteractiveGizmoManager * GizmoManager = GetToolManager ( ) - > GetPairedGizmoManager ( ) ;
GizmoManager - > DestroyAllGizmosByOwner ( this ) ;
}
bool UBaseCreateFromSelectedTool : : CanAccept ( ) const
{
2021-02-05 16:33:02 -04:00
return Super : : CanAccept ( ) & & Preview - > HaveValidNonEmptyResult ( ) ;
2020-08-11 01:36:57 -04:00
}
# undef LOCTEXT_NAMESPACE
2022-09-28 01:06:15 -04:00