2020-01-08 17:11:23 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-12-19 18:07:47 -05:00
# include "EditPivotTool.h"
# include "InteractiveToolManager.h"
# include "InteractiveGizmoManager.h"
# include "ToolBuilderUtil.h"
# include "ToolSetupUtil.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMesh3.h"
2021-02-25 20:03:29 -04:00
# include "Mechanics/DragAlignmentMechanic.h"
2020-01-27 20:11:15 -05:00
# include "MeshAdapterTransforms.h"
# include "MeshDescriptionAdapter.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/MeshTransforms.h"
2019-12-19 18:07:47 -05:00
# include "BaseBehaviors/ClickDragBehavior.h"
2020-10-22 19:19:16 -04:00
# include "ToolSceneQueriesUtil.h"
2021-02-25 05:39:27 -04:00
# include "Physics/ComponentCollisionUtil.h"
2019-12-19 18:07:47 -05:00
# include "BaseGizmos/GizmoComponents.h"
2021-05-20 16:39:39 -04:00
# include "BaseGizmos/TransformGizmoUtil.h"
2019-12-19 18:07:47 -05:00
# include "Components/PrimitiveComponent.h"
2021-06-15 02:46:37 -04:00
# include "Components/InstancedStaticMeshComponent.h"
2019-12-19 18:07:47 -05:00
# include "Engine/World.h"
2021-03-11 11:40:03 -04:00
# include "TargetInterfaces/MeshDescriptionCommitter.h"
# include "TargetInterfaces/MeshDescriptionProvider.h"
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
# include "ToolTargetManager.h"
2021-06-22 11:55:16 -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 ;
2019-12-19 18:07:47 -05:00
# define LOCTEXT_NAMESPACE "UEditPivotTool"
/*
* ToolBuilder
*/
2021-11-23 09:42:40 -05:00
UMultiSelectionMeshEditingTool * UEditPivotToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
2021-03-11 11:40:03 -04:00
{
2021-11-23 09:42:40 -05:00
return NewObject < UEditPivotTool > ( SceneState . ToolManager ) ;
2019-12-19 18:07:47 -05:00
}
2020-01-27 20:11:15 -05:00
void UEditPivotToolActionPropertySet : : PostAction ( EEditPivotToolActions Action )
{
if ( ParentTool . IsValid ( ) )
{
ParentTool - > RequestAction ( Action ) ;
}
}
2019-12-19 18:07:47 -05:00
/*
* Tool
*/
UEditPivotTool : : UEditPivotTool ( )
{
}
void UEditPivotTool : : Setup ( )
{
UInteractiveTool : : Setup ( ) ;
UClickDragInputBehavior * ClickDragBehavior = NewObject < UClickDragInputBehavior > ( this ) ;
ClickDragBehavior - > Initialize ( this ) ;
AddInputBehavior ( ClickDragBehavior ) ;
TransformProps = NewObject < UEditPivotToolProperties > ( ) ;
AddToolPropertySource ( TransformProps ) ;
2020-01-27 20:11:15 -05:00
EditPivotActions = NewObject < UEditPivotToolActionPropertySet > ( this ) ;
EditPivotActions - > Initialize ( this ) ;
AddToolPropertySource ( EditPivotActions ) ;
2019-12-19 18:07:47 -05:00
ResetActiveGizmos ( ) ;
SetActiveGizmos_Single ( false ) ;
UpdateSetPivotModes ( true ) ;
2021-02-25 20:03:29 -04:00
DragAlignmentMechanic = NewObject < UDragAlignmentMechanic > ( this ) ;
DragAlignmentMechanic - > Setup ( this ) ;
DragAlignmentMechanic - > AddToGizmo ( ActiveGizmos [ 0 ] . TransformGizmo ) ;
2020-01-27 20:11:15 -05:00
Precompute ( ) ;
2019-12-19 18:07:47 -05:00
2020-01-27 20:11:15 -05:00
FText AllTheWarnings = LOCTEXT ( " EditPivotWarning " , " WARNING: This Tool will Modify the selected StaticMesh Assets! If you do not wish to modify the original Assets, please make copies in the Content Browser first! " ) ;
// detect and warn about any meshes in selection that correspond to same source data
2021-03-11 11:40:03 -04:00
bool bSharesSources = GetMapToSharedSourceData ( MapToFirstOccurrences ) ;
2020-01-27 20:11:15 -05:00
if ( bSharesSources )
{
2021-06-15 02:46:37 -04:00
AllTheWarnings = FText : : Format ( FTextFormat : : FromString ( " {0} \n \n {1} " ) , AllTheWarnings , LOCTEXT ( " EditPivotSharedAssetsWarning " , " WARNING: Multiple selected meshes share the same source Asset! Each Asset can only have one baked pivot, some results will be incorrect. " ) ) ;
}
bool bHasISMCs = false ;
for ( int32 k = 0 ; k < Targets . Num ( ) ; + + k )
{
2021-06-22 11:55:16 -04:00
if ( Cast < UInstancedStaticMeshComponent > ( UE : : ToolTarget : : GetTargetComponent ( Targets [ k ] ) ) ! = nullptr )
2021-06-15 02:46:37 -04:00
{
bHasISMCs = true ;
}
}
if ( bHasISMCs )
{
AllTheWarnings = FText : : Format ( FTextFormat : : FromString ( " {0} \n \n {1} " ) , AllTheWarnings , LOCTEXT ( " EditPivotISMCWarning " , " WARNING: Some selected objects are Instanced Components. Pivot of Instances will be modified, instead of Asset. " ) ) ;
2020-01-27 20:11:15 -05:00
}
GetToolManager ( ) - > DisplayMessage ( AllTheWarnings , EToolMessageLevel : : UserWarning ) ;
2020-03-10 14:00:36 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " Edit Pivot " ) ) ;
2020-03-10 14:00:36 -04:00
GetToolManager ( ) - > DisplayMessage (
2021-02-25 20:03:29 -04:00
LOCTEXT ( " OnStartTool " , " This tool edits the Pivot (Origin) of the input assets. Hold Ctrl while using the gizmo to align to scene. Enable Snap Dragging and click+drag to place gizmo directly into clicked position. " ) ,
2020-03-10 14:00:36 -04:00
EToolMessageLevel : : UserNotification ) ;
2019-12-19 18:07:47 -05:00
}
2022-01-28 18:40:54 -05:00
void UEditPivotTool : : OnShutdown ( EToolShutdownType ShutdownType )
2019-12-19 18:07:47 -05:00
{
2021-02-25 20:03:29 -04:00
DragAlignmentMechanic - > Shutdown ( ) ;
2019-12-19 18:07:47 -05:00
FFrame3d CurPivotFrame ( ActiveGizmos [ 0 ] . TransformProxy - > GetTransform ( ) ) ;
2021-11-23 09:42:40 -05:00
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DestroyAllGizmosByOwner ( this ) ;
2019-12-19 18:07:47 -05:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
UpdateAssets ( CurPivotFrame ) ;
}
}
2020-07-16 08:23:15 -04:00
void VertexIteration ( const FMeshDescription * Mesh , TFunctionRef < void ( int32 , const FVector & ) > ApplyFunc )
2020-01-27 20:11:15 -05:00
{
2021-05-05 15:07:25 -04:00
TArrayView < const FVector3f > VertexPositions = Mesh - > GetVertexPositions ( ) . GetRawArray ( ) ;
2020-01-27 20:11:15 -05:00
2020-07-16 08:23:15 -04:00
for ( const FVertexID VertexID : Mesh - > Vertices ( ) . GetElementIDs ( ) )
2020-01-27 20:11:15 -05:00
{
2022-02-02 07:59:31 -05:00
const FVector Position = ( FVector ) VertexPositions [ VertexID ] ;
2020-01-27 20:11:15 -05:00
ApplyFunc ( VertexID . GetValue ( ) , Position ) ;
}
}
void UEditPivotTool : : Precompute ( )
{
ObjectBounds = FAxisAlignedBox3d : : Empty ( ) ;
WorldBounds = FAxisAlignedBox3d : : Empty ( ) ;
2021-03-11 11:40:03 -04:00
int NumComponents = Targets . Num ( ) ;
2020-01-27 20:11:15 -05:00
if ( NumComponents = = 1 )
{
2021-06-22 11:55:16 -04:00
Transform = UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ 0 ] ) ;
2020-01-27 20:11:15 -05:00
2021-06-22 11:55:16 -04:00
const FMeshDescription * Mesh = UE : : ToolTarget : : GetMeshDescription ( Targets [ 0 ] ) ;
2020-01-27 20:11:15 -05:00
VertexIteration ( Mesh , [ & ] ( int32 VertexID , const FVector & Position ) {
2021-03-30 21:25:22 -04:00
ObjectBounds . Contain ( ( FVector3d ) Position ) ;
WorldBounds . Contain ( Transform . TransformPosition ( ( FVector3d ) Position ) ) ;
2020-01-27 20:11:15 -05:00
} ) ;
}
else
{
2022-01-29 14:37:53 -05:00
Transform = FTransform3d : : Identity ;
2021-03-11 11:40:03 -04:00
for ( int k = 0 ; k < NumComponents ; + + k )
2020-01-27 20:11:15 -05:00
{
2022-01-29 14:37:53 -05:00
FTransform3d CurTransform = UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ k ] ) ;
2021-06-22 11:55:16 -04:00
const FMeshDescription * Mesh = UE : : ToolTarget : : GetMeshDescription ( Targets [ k ] ) ;
2020-01-27 20:11:15 -05:00
VertexIteration ( Mesh , [ & ] ( int32 VertexID , const FVector & Position ) {
2021-03-30 21:25:22 -04:00
ObjectBounds . Contain ( CurTransform . TransformPosition ( ( FVector3d ) Position ) ) ;
WorldBounds . Contain ( CurTransform . TransformPosition ( ( FVector3d ) Position ) ) ;
2020-01-27 20:11:15 -05:00
} ) ;
}
}
}
void UEditPivotTool : : RequestAction ( EEditPivotToolActions ActionType )
{
if ( PendingAction = = EEditPivotToolActions : : NoAction )
{
PendingAction = ActionType ;
}
}
2019-12-19 18:07:47 -05:00
2020-04-18 18:42:59 -04:00
void UEditPivotTool : : OnTick ( float DeltaTime )
2019-12-19 18:07:47 -05:00
{
2020-01-27 20:11:15 -05:00
if ( PendingAction ! = EEditPivotToolActions : : NoAction )
{
ApplyAction ( PendingAction ) ;
PendingAction = EEditPivotToolActions : : NoAction ;
}
2019-12-19 18:07:47 -05:00
}
void UEditPivotTool : : Render ( IToolsContextRenderAPI * RenderAPI )
{
2021-02-25 20:03:29 -04:00
DragAlignmentMechanic - > Render ( RenderAPI ) ;
2019-12-19 18:07:47 -05:00
}
2020-01-08 13:26:18 -05:00
void UEditPivotTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
2019-12-19 18:07:47 -05:00
{
}
void UEditPivotTool : : UpdateSetPivotModes ( bool bEnableSetPivot )
{
for ( FEditPivotTarget & Target : ActiveGizmos )
{
Target . TransformProxy - > bSetPivotMode = bEnableSetPivot ;
}
}
void UEditPivotTool : : RegisterActions ( FInteractiveToolActionSet & ActionSet )
{
}
2020-01-27 20:11:15 -05:00
void UEditPivotTool : : ApplyAction ( EEditPivotToolActions ActionType )
{
switch ( ActionType )
{
case EEditPivotToolActions : : Center :
case EEditPivotToolActions : : Bottom :
case EEditPivotToolActions : : Top :
case EEditPivotToolActions : : Left :
case EEditPivotToolActions : : Right :
case EEditPivotToolActions : : Front :
case EEditPivotToolActions : : Back :
SetPivotToBoxPoint ( ActionType ) ;
break ;
2021-04-13 10:27:54 -04:00
case EEditPivotToolActions : : WorldOrigin :
SetPivotToWorldOrigin ( ) ;
break ;
2020-01-27 20:11:15 -05:00
}
}
void UEditPivotTool : : SetPivotToBoxPoint ( EEditPivotToolActions ActionPoint )
{
FAxisAlignedBox3d UseBox = ( EditPivotActions - > bUseWorldBox ) ? WorldBounds : ObjectBounds ;
FVector3d Point = UseBox . Center ( ) ;
if ( ActionPoint = = EEditPivotToolActions : : Bottom | | ActionPoint = = EEditPivotToolActions : : Top )
{
Point . Z = ( ActionPoint = = EEditPivotToolActions : : Bottom ) ? UseBox . Min . Z : UseBox . Max . Z ;
}
else if ( ActionPoint = = EEditPivotToolActions : : Left | | ActionPoint = = EEditPivotToolActions : : Right )
{
Point . Y = ( ActionPoint = = EEditPivotToolActions : : Left ) ? UseBox . Min . Y : UseBox . Max . Y ;
}
else if ( ActionPoint = = EEditPivotToolActions : : Back | | ActionPoint = = EEditPivotToolActions : : Front )
{
Point . X = ( ActionPoint = = EEditPivotToolActions : : Front ) ? UseBox . Min . X : UseBox . Max . X ;
}
FTransform NewTransform ;
if ( EditPivotActions - > bUseWorldBox = = false )
{
FFrame3d LocalFrame ( Point ) ;
LocalFrame . Transform ( Transform ) ;
NewTransform = LocalFrame . ToFTransform ( ) ;
}
else
{
NewTransform = FTransform ( ( FVector ) Point ) ;
}
ActiveGizmos [ 0 ] . TransformGizmo - > SetNewGizmoTransform ( NewTransform ) ;
}
2019-12-19 18:07:47 -05:00
2021-04-13 10:27:54 -04:00
void UEditPivotTool : : SetPivotToWorldOrigin ( )
{
ActiveGizmos [ 0 ] . TransformGizmo - > SetNewGizmoTransform ( FTransform ( ) ) ;
}
2019-12-19 18:07:47 -05:00
void UEditPivotTool : : SetActiveGizmos_Single ( bool bLocalRotations )
{
check ( ActiveGizmos . Num ( ) = = 0 ) ;
FEditPivotTarget Transformable ;
Transformable . TransformProxy = NewObject < UTransformProxy > ( this ) ;
Transformable . TransformProxy - > bRotatePerObject = bLocalRotations ;
2021-03-11 11:40:03 -04:00
for ( int32 ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2019-12-19 18:07:47 -05:00
{
2021-06-22 11:55:16 -04:00
Transformable . TransformProxy - > AddComponent ( UE : : ToolTarget : : GetTargetComponent ( Targets [ ComponentIdx ] ) ) ;
2019-12-19 18:07:47 -05:00
}
2021-11-23 09:42:40 -05:00
Transformable . TransformGizmo = UE : : TransformGizmoUtil : : CreateCustomTransformGizmo ( GetToolManager ( ) - > GetPairedGizmoManager ( ) ,
2020-01-27 20:11:15 -05:00
ETransformGizmoSubElements : : StandardTranslateRotate , this
) ;
2020-09-24 00:43:27 -04:00
Transformable . TransformGizmo - > SetActiveTarget ( Transformable . TransformProxy , GetToolManager ( ) ) ;
2019-12-19 18:07:47 -05:00
2020-01-27 20:11:15 -05:00
Transformable . TransformGizmo - > bUseContextCoordinateSystem = false ;
Transformable . TransformGizmo - > CurrentCoordinateSystem = EToolContextCoordinateSystem : : Local ;
2019-12-19 18:07:47 -05:00
ActiveGizmos . Add ( Transformable ) ;
}
void UEditPivotTool : : ResetActiveGizmos ( )
{
2021-11-23 09:42:40 -05:00
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DestroyAllGizmosByOwner ( this ) ;
2019-12-19 18:07:47 -05:00
ActiveGizmos . Reset ( ) ;
}
// does not make sense that CanBeginClickDragSequence() returns a RayHit? Needs to be an out-argument...
FInputRayHit UEditPivotTool : : CanBeginClickDragSequence ( const FInputDeviceRay & PressPos )
{
if ( TransformProps - > bEnableSnapDragging = = false | | ActiveGizmos . Num ( ) = = 0 )
{
return FInputRayHit ( ) ;
}
2021-02-25 20:03:29 -04:00
FHitResult Result ;
2021-12-09 14:46:09 -05:00
bool bWorldHit = ToolSceneQueriesUtil : : FindNearestVisibleObjectHit ( this , Result , PressPos . WorldRay ) ;
2019-12-19 18:07:47 -05:00
2021-02-25 20:03:29 -04:00
if ( ! bWorldHit )
2019-12-19 18:07:47 -05:00
{
2021-02-25 20:03:29 -04:00
return FInputRayHit ( ) ;
2019-12-19 18:07:47 -05:00
}
2021-02-25 20:03:29 -04:00
return FInputRayHit ( Result . Distance , Result . ImpactNormal ) ;
2019-12-19 18:07:47 -05:00
}
void UEditPivotTool : : OnClickPress ( const FInputDeviceRay & PressPos )
{
FInputRayHit HitPos = CanBeginClickDragSequence ( PressPos ) ;
check ( HitPos . bHit ) ;
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " TransformToolTransformTxnName " , " SnapDrag " ) ) ;
FEditPivotTarget & ActiveTarget = ActiveGizmos [ 0 ] ;
USceneComponent * GizmoComponent = ActiveTarget . TransformGizmo - > GetGizmoActor ( ) - > GetRootComponent ( ) ;
StartDragTransform = GizmoComponent - > GetComponentToWorld ( ) ;
}
void UEditPivotTool : : OnClickDrag ( const FInputDeviceRay & DragPos )
{
bool bRotate = ( TransformProps - > RotationMode ! = EEditPivotSnapDragRotationMode : : Ignore ) ;
float NormalSign = ( TransformProps - > RotationMode = = EEditPivotSnapDragRotationMode : : AlignFlipped ) ? - 1.0f : 1.0f ;
FHitResult Result ;
2021-12-09 14:46:09 -05:00
bool bWorldHit = ToolSceneQueriesUtil : : FindNearestVisibleObjectHit ( this , Result , DragPos . WorldRay ) ;
2019-12-19 18:07:47 -05:00
if ( bWorldHit = = false )
{
return ;
}
FVector HitPos = Result . ImpactPoint ;
2021-10-20 22:12:32 -04:00
FVector TargetNormal = ( NormalSign ) * Result . Normal ;
2019-12-19 18:07:47 -05:00
FQuaterniond AlignRotation = ( bRotate ) ?
2021-03-30 21:25:22 -04:00
FQuaterniond ( FVector3d : : UnitZ ( ) , ( FVector3d ) TargetNormal ) : FQuaterniond : : Identity ( ) ;
2019-12-19 18:07:47 -05:00
FTransform NewTransform = StartDragTransform ;
NewTransform . SetRotation ( ( FQuat ) AlignRotation ) ;
NewTransform . SetTranslation ( HitPos ) ;
FEditPivotTarget & ActiveTarget = ActiveGizmos [ 0 ] ;
2021-02-25 20:03:29 -04:00
ActiveTarget . TransformGizmo - > SetNewGizmoTransform ( NewTransform ) ;
2019-12-19 18:07:47 -05:00
}
void UEditPivotTool : : OnClickRelease ( const FInputDeviceRay & ReleasePos )
{
OnTerminateDragSequence ( ) ;
}
void UEditPivotTool : : OnTerminateDragSequence ( )
{
FEditPivotTarget & ActiveTarget = ActiveGizmos [ 0 ] ;
USceneComponent * GizmoComponent = ActiveTarget . TransformGizmo - > GetGizmoActor ( ) - > GetRootComponent ( ) ;
FTransform EndDragtransform = GizmoComponent - > GetComponentToWorld ( ) ;
TUniquePtr < FComponentWorldTransformChange > Change = MakeUnique < FComponentWorldTransformChange > ( StartDragTransform , EndDragtransform ) ;
GetToolManager ( ) - > EmitObjectChange ( GizmoComponent , MoveTemp ( Change ) ,
LOCTEXT ( " TransformToolTransformTxnName " , " SnapDrag " ) ) ;
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
void UEditPivotTool : : UpdateAssets ( const FFrame3d & NewPivotWorldFrame )
{
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " EditPivotToolTransactionName " , " Edit Pivot " ) ) ;
FTransform NewWorldTransform = NewPivotWorldFrame . ToFTransform ( ) ;
2022-05-12 12:08:26 -04:00
FTransform NewWorldInverse = NewPivotWorldFrame . ToInverseFTransform ( ) ;
2020-01-27 20:11:15 -05:00
TArray < FTransform > OriginalTransforms ;
2021-03-11 11:40:03 -04:00
for ( int32 ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2019-12-19 18:07:47 -05:00
{
2021-06-22 11:55:16 -04:00
OriginalTransforms . Add ( ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ ComponentIdx ] ) ) ;
2019-12-19 18:07:47 -05:00
}
2021-03-11 11:40:03 -04:00
for ( int32 ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-01-27 20:11:15 -05:00
{
2021-06-22 11:55:16 -04:00
UPrimitiveComponent * Component = UE : : ToolTarget : : GetTargetComponent ( Targets [ ComponentIdx ] ) ;
2021-06-15 02:46:37 -04:00
Component - > Modify ( ) ;
2021-06-22 11:55:16 -04:00
UInstancedStaticMeshComponent * InstancedComponent = Cast < UInstancedStaticMeshComponent > ( Component ) ;
2021-06-15 02:46:37 -04:00
if ( InstancedComponent ! = nullptr )
{
// For ISMC, we will not bake in a mesh transform, instead we will update the instance transforms relative to the new pivot
// TODO: this could be optional, and another alternative would be to bake the pivot to the mesh and then update
// all the instance transforms so they stay in the same position?
// save world transforms
int32 NumInstances = InstancedComponent - > GetInstanceCount ( ) ;
TArray < FTransform > WorldTransforms ;
WorldTransforms . SetNum ( NumInstances ) ;
for ( int32 k = 0 ; k < NumInstances ; + + k )
{
InstancedComponent - > GetInstanceTransform ( k , WorldTransforms [ k ] , true ) ;
}
// update position to new pivot
InstancedComponent - > SetWorldTransform ( NewWorldTransform ) ;
// restore world transforms, which will compute new local transforms such that the instances do not move in the world
for ( int32 k = 0 ; k < NumInstances ; + + k )
{
InstancedComponent - > UpdateInstanceTransform ( k , WorldTransforms [ k ] , true , true , false ) ;
}
}
else if ( MapToFirstOccurrences [ ComponentIdx ] = = ComponentIdx )
2020-01-27 20:11:15 -05:00
{
2022-01-29 14:37:53 -05:00
FTransformSRT3d ToBake ( OriginalTransforms [ ComponentIdx ] * NewWorldInverse ) ;
2021-10-11 17:00:25 -04:00
// to preserve scale, after baking the first transform, we will also need to bake an inverse scale transform
// this bake will need to be applied separately only in cases where FTransform3d cannot correctly represent the combination of the two transforms
// TODO: we could skip the extra bake step if the bake functions could take a general matrix
2022-01-29 14:37:53 -05:00
FTransformSRT3d SeparateBakeScale = FTransformSRT3d : : Identity ( ) ;
2021-10-11 17:00:25 -04:00
bool bNeedSeparateScale = false ;
// ScaledNewWorldTransform is the pivot widget's transform with the scale of the original component transform
FTransform ScaledNewWorldTransform = NewWorldTransform ;
// Note: this section only needed if we want to preserve the original mesh scale
// Basically our goal is, given the original actor transform A = Ta Ra Sa, and gizmo transform G = Tg Rg:
// Try to keep the mesh in the same place w/ new actor transform, Tg Rg Sa (the gizmo transform w/ original actor scale)
// To keep the mesh unmoved, we then have:
// (New actor transform: Tg Rg Sa) * (Baked transform: Sa^-1 Rg^-1 Tg^-1 Ta Ra Sa) = (Original actor transform: Ta Ra Sa)
// This cannot in general be represented as a single transform, so it requires us to bake the Sa^-1 separately ...
// but in special cases where Rg^-1 Ra Sa == Sa Rg^-1 Ra, the baked scales cancel and we can instead bake a single transform with no scale
{
FVector3d Scale = ( FVector3d ) OriginalTransforms [ ComponentIdx ] . GetScale3D ( ) ;
FQuaterniond Rotation = ToBake . GetRotation ( ) ;
bool AxisZero [ 3 ] { FMath : : IsNearlyZero ( Rotation . X , DOUBLE_KINDA_SMALL_NUMBER ) ,
FMath : : IsNearlyZero ( Rotation . Y , DOUBLE_KINDA_SMALL_NUMBER ) ,
FMath : : IsNearlyZero ( Rotation . Z , DOUBLE_KINDA_SMALL_NUMBER ) } ;
int Zeros = ( int ) AxisZero [ 0 ] + ( int ) AxisZero [ 1 ] + ( int ) AxisZero [ 2 ] ;
bool bEqXY = FMath : : IsNearlyEqual ( Scale . X , Scale . Y ) ;
bool bEqYZ = FMath : : IsNearlyEqual ( Scale . Y , Scale . Z ) ;
bool bCanCombinedScales =
Zeros = = 3 | | // no rotation (quaternion x,y,z == axis scaled by sin(angle/2) == 0 when angle is 0)
( bEqXY & & bEqYZ ) | | // uniform scale
( Zeros = = 2 & & ( // rotation is around a major axis &&
( ! AxisZero [ 0 ] & & bEqYZ ) | | // (scales on dimensions-moved-by-rotation are equal)
( ! AxisZero [ 1 ] & & FMath : : IsNearlyEqual ( Scale . X , Scale . Z ) ) | |
( ! AxisZero [ 2 ] & & bEqXY )
) ) ;
bNeedSeparateScale = ! bCanCombinedScales ;
2022-01-29 14:37:53 -05:00
FVector3d InvScale = FTransformSRT3d : : GetSafeScaleReciprocal ( OriginalTransforms [ ComponentIdx ] . GetScale3D ( ) ) ;
2021-10-11 17:00:25 -04:00
if ( ! bNeedSeparateScale )
{
ToBake . SetScale ( FVector3d : : One ( ) ) ; // clear scale; it will be fully captured by the new transform
ToBake . SetTranslation ( ToBake . GetTranslation ( ) * InvScale ) ;
ScaledNewWorldTransform . SetScale3D ( OriginalTransforms [ ComponentIdx ] . GetScale3D ( ) ) ;
}
else if ( InvScale . X ! = 0 & & InvScale . Y ! = 0 & & InvScale . Z ! = 0 ) // Scale was inverted correctly
{
// non-uniform scale is incompatible with new pivot orientation; need to bake additional counter-scale into the mesh
SeparateBakeScale . SetScale ( InvScale ) ;
ScaledNewWorldTransform . SetScale3D ( OriginalTransforms [ ComponentIdx ] . GetScale3D ( ) ) ;
}
// else do nothing -- scale is not invertible and must be baked
}
2020-01-27 20:11:15 -05:00
2021-02-25 05:39:27 -04:00
// transform simple collision geometry
2021-06-22 11:55:16 -04:00
if ( UE : : Geometry : : ComponentTypeSupportsCollision ( Component ) )
2020-01-27 20:11:15 -05:00
{
2021-06-22 11:55:16 -04:00
UE : : Geometry : : TransformSimpleCollision ( Component , ToBake ) ;
2021-10-11 17:00:25 -04:00
if ( bNeedSeparateScale )
{
UE : : Geometry : : TransformSimpleCollision ( Component , SeparateBakeScale ) ;
}
2021-06-22 11:55:16 -04:00
}
ModelingTools: Add support for reading and writing to a specific LOD via IMeshDescriptionProvider/Committer. Refactor various other aspects of MeshDescription access. Update MeshTransferTool to be able to transfer from and to specific LODs.
Add new MeshTargetInterfaceTypes.h file, move EStaticMeshEditingLOD there and rename to EMeshLODIdentifier. Add FGetMeshParameters and FCommitMeshParameters types.
IMeshDescriptionProvider::GetMeshDescription() now takes FGetMeshParameters to optionally specify LOD.
Added IMeshDescriptionProvider::GetMeshDescriptionCopy() function, to handle copy-case.
removed IMeshDescriptionProvider::CalculateAutoGeneratedAttributes(). This was only being used to force Tangents computation, which can now be done via GetMeshDescriptionCopy() and FGetMeshParameters.bWantMeshTangents option
IMeshDescriptionCommitter commit functions now take a FCommitMeshParameters to optionally specify target LOD.
StaticMeshComponentToolTarget::GetMeshDescriptionCopy() added, optionally computes auto-generated MeshDescription attributes on the copy
StaticMesh(Component)ToolTarget updated to support FCommitMeshParameters target-LOD.
SkeletalMesh, Volume, and DynamicMesh ToolTargets updated for new APIs but do not currently support any of the new LOD parameters. These should never be called w/ LOD parameters in the current codebase, ensures added to catch any errors (they would be non-fatal).
UE::ToolTarget::GetMeshDescription() and GetMeshDescriptionCopy() in now take FGetMeshParameters argument.
Removed bWantMeshTangents param to GetMeshDescriptionCopy(), now done via FGetMeshParameters. Updated call sites.
TransferMeshesTool now supports specifying read and write LOD (numbered or HiRes) for StaticMeshComponent source/target, via above functions.
TransferMeshesTool can now also target a new LOD in a StaticMeshComponent, index is 1 larger than current maximum source LOD.
#rb lonnie.li, rinat.abdrashitov
#rnx
#jira none
#preflight 61b8d56b2e65a1df046aa5e1
#ROBOMERGE-AUTHOR: ryan.schmidt
#ROBOMERGE-SOURCE: CL 18461686 in //UE5/Release-5.0/... via CL 18461725
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v899-18417669)
[CL 18461778 by ryan schmidt in ue5-release-engine-test branch]
2021-12-14 18:40:01 -05:00
FMeshDescription SourceMesh ( UE : : ToolTarget : : GetMeshDescriptionCopy ( Targets [ ComponentIdx ] ) ) ;
2021-06-22 11:55:16 -04:00
FMeshDescriptionEditableTriangleMeshAdapter EditableMeshDescAdapter ( & SourceMesh ) ;
MeshAdapterTransforms : : ApplyTransform ( EditableMeshDescAdapter , ToBake ) ;
2021-10-11 17:00:25 -04:00
if ( bNeedSeparateScale )
{
MeshAdapterTransforms : : ApplyTransform ( EditableMeshDescAdapter , SeparateBakeScale ) ;
}
2021-06-22 11:55:16 -04:00
// todo: support vertex-only update
UE : : ToolTarget : : CommitMeshDescriptionUpdate ( Targets [ ComponentIdx ] , & SourceMesh ) ;
2020-01-27 20:11:15 -05:00
2021-10-11 17:00:25 -04:00
Component - > SetWorldTransform ( ScaledNewWorldTransform ) ;
2020-01-27 20:11:15 -05:00
}
else
{
2022-05-12 12:08:26 -04:00
// try to invert baked transform -- note that this may not be a correct inverse if there is rotation + non-uniform scale,
// but it's the best we can do given we can not bake a separate custom scale when this is not the first occurrence
2020-01-27 20:11:15 -05:00
FTransform Baked = OriginalTransforms [ MapToFirstOccurrences [ ComponentIdx ] ] * NewWorldInverse ;
Component - > SetWorldTransform ( Baked . Inverse ( ) * OriginalTransforms [ ComponentIdx ] ) ;
}
2021-06-22 11:55:16 -04:00
AActor * OwnerActor = UE : : ToolTarget : : GetTargetActor ( Targets [ ComponentIdx ] ) ;
if ( OwnerActor )
{
OwnerActor - > MarkComponentsRenderStateDirty ( ) ;
OwnerActor - > UpdateComponentTransforms ( ) ;
}
2020-01-27 20:11:15 -05:00
}
// hack to ensure user sees the updated pivot immediately: request re-select of the original selection
FSelectedOjectsChangeList NewSelection ;
NewSelection . ModificationType = ESelectedObjectsModificationType : : Replace ;
2021-03-11 11:40:03 -04:00
for ( int OrigMeshIdx = 0 ; OrigMeshIdx < Targets . Num ( ) ; OrigMeshIdx + + )
2020-01-27 20:11:15 -05:00
{
2021-06-22 11:55:16 -04:00
AActor * OwnerActor = UE : : ToolTarget : : GetTargetActor ( Targets [ OrigMeshIdx ] ) ;
if ( OwnerActor )
{
NewSelection . Actors . Add ( OwnerActor ) ;
}
2020-01-27 20:11:15 -05:00
}
GetToolManager ( ) - > RequestSelectionChange ( NewSelection ) ;
2019-12-19 18:07:47 -05:00
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
# undef LOCTEXT_NAMESPACE