2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
# include "MeshSpaceDeformerTool.h"
# include "InteractiveToolManager.h"
2019-11-07 10:33:41 -05:00
# include "InteractiveGizmoManager.h"
2021-12-09 14:46:09 -05:00
# include "SceneQueries/SceneSnappingManager.h"
2019-10-01 20:41:42 -04:00
# include "ToolBuilderUtil.h"
# include "SegmentTypes.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMeshAttributeSet.h"
2021-01-28 13:06:33 -04:00
# include "Mechanics/DragAlignmentMechanic.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/MeshNormals.h"
2019-11-07 10:33:41 -05:00
# include "MeshOpPreviewHelpers.h"
2019-10-01 20:41:42 -04:00
# include "ToolSceneQueriesUtil.h"
2019-11-07 10:33:41 -05:00
# include "ToolSetupUtil.h"
2019-10-01 20:41:42 -04:00
# include "Intersection/IntersectionUtil.h"
2019-11-07 10:33:41 -05:00
# include "PreviewMesh.h"
2019-10-01 20:41:42 -04:00
2020-10-09 22:42:26 -04:00
# include "BaseBehaviors/SingleClickBehavior.h"
# include "Selection/SelectClickedAction.h"
2019-11-07 10:33:41 -05:00
# include "BaseGizmos/GizmoComponents.h"
2021-05-20 16:39:39 -04:00
# include "BaseGizmos/TransformGizmoUtil.h"
2019-11-07 10:33:41 -05:00
# include "BaseGizmos/IntervalGizmo.h"
# include "MeshDescriptionToDynamicMesh.h"
# include "DynamicMeshToMeshDescription.h"
# include "CoreMinimal.h"
# include "Math/Matrix.h"
2019-10-01 20:41:42 -04:00
2021-03-24 11:11:02 -04:00
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
2021-12-06 12:42:19 -05:00
# include "ModelingToolTargetUtil.h"
2021-03-24 11:11:02 -04:00
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2019-10-01 20:41:42 -04:00
# define LOCTEXT_NAMESPACE "MeshSpaceDeformerTool"
/*
* ToolBuilder
*/
2021-03-24 11:11:02 -04:00
USingleSelectionMeshEditingTool * UMeshSpaceDeformerToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
2019-10-01 20:41:42 -04:00
{
2021-03-24 11:11:02 -04:00
return NewObject < UMeshSpaceDeformerTool > ( SceneState . ToolManager ) ;
2019-10-01 20:41:42 -04:00
}
2019-11-07 10:33:41 -05:00
TUniquePtr < FDynamicMeshOperator > USpaceDeformerOperatorFactory : : MakeNewOperator ( )
{
check ( SpaceDeformerTool ) ;
2021-01-28 13:06:33 -04:00
const ENonlinearOperationType OperationType = SpaceDeformerTool - > Settings - > SelectedOperationType ;
2019-11-07 10:33:41 -05:00
// Create the actual operator type based on the requested operation
TUniquePtr < FMeshSpaceDeformerOp > DeformerOp ;
switch ( OperationType )
{
case ENonlinearOperationType : : Bend :
{
DeformerOp = MakeUnique < FBendMeshOp > ( ) ;
2021-01-28 13:06:33 -04:00
static_cast < FBendMeshOp * > ( DeformerOp . Get ( ) ) - > BendDegrees = SpaceDeformerTool - > Settings - > BendDegrees ;
static_cast < FBendMeshOp * > ( DeformerOp . Get ( ) ) - > bLockBottom = SpaceDeformerTool - > Settings - > bLockBottom ;
2019-11-07 10:33:41 -05:00
break ;
}
case ENonlinearOperationType : : Flare :
{
DeformerOp = MakeUnique < FFlareMeshOp > ( ) ;
2021-01-28 13:06:33 -04:00
static_cast < FFlareMeshOp * > ( DeformerOp . Get ( ) ) - > FlarePercentY = SpaceDeformerTool - > Settings - > FlarePercentY ;
static_cast < FFlareMeshOp * > ( DeformerOp . Get ( ) ) - > FlarePercentX = SpaceDeformerTool - > Settings - > bLockXAndYFlaring ?
SpaceDeformerTool - > Settings - > FlarePercentY : SpaceDeformerTool - > Settings - > FlarePercentX ;
2021-09-16 20:58:43 -04:00
if ( SpaceDeformerTool - > Settings - > FlareProfileType = = EFlareProfileType : : SinMode )
{
static_cast < FFlareMeshOp * > ( DeformerOp . Get ( ) ) - > FlareType = FFlareMeshOp : : EFlareType : : SinFlare ;
}
else if ( SpaceDeformerTool - > Settings - > FlareProfileType = = EFlareProfileType : : SinSquaredMode )
{
static_cast < FFlareMeshOp * > ( DeformerOp . Get ( ) ) - > FlareType = FFlareMeshOp : : EFlareType : : SinSqrFlare ;
}
else
{
static_cast < FFlareMeshOp * > ( DeformerOp . Get ( ) ) - > FlareType = FFlareMeshOp : : EFlareType : : LinearFlare ;
}
2019-11-07 10:33:41 -05:00
break ;
}
case ENonlinearOperationType : : Twist :
{
DeformerOp = MakeUnique < FTwistMeshOp > ( ) ;
2021-01-28 13:06:33 -04:00
static_cast < FTwistMeshOp * > ( DeformerOp . Get ( ) ) - > TwistDegrees = SpaceDeformerTool - > Settings - > TwistDegrees ;
static_cast < FTwistMeshOp * > ( DeformerOp . Get ( ) ) - > bLockBottom = SpaceDeformerTool - > Settings - > bLockBottom ;
2019-11-07 10:33:41 -05:00
break ;
}
default :
check ( 0 ) ;
}
// Operator runs on another thread - copy data over that it needs.
SpaceDeformerTool - > UpdateOpParameters ( * DeformerOp ) ;
// give the operator
return DeformerOp ;
}
2021-01-28 13:06:33 -04:00
void UMeshSpaceDeformerToolActionPropertySet : : PostAction ( EMeshSpaceDeformerToolAction Action )
{
if ( ParentTool . IsValid ( ) )
{
ParentTool - > RequestAction ( Action ) ;
}
}
2019-11-07 10:33:41 -05:00
/*
* Tool
*/
2019-10-01 20:41:42 -04:00
UMeshSpaceDeformerTool : : UMeshSpaceDeformerTool ( )
{
2019-11-07 10:33:41 -05:00
}
bool UMeshSpaceDeformerTool : : CanAccept ( ) const
{
2020-11-24 18:42:39 -04:00
return Super : : CanAccept ( ) & & ( Preview = = nullptr | | Preview - > HaveValidResult ( ) ) ;
2019-11-07 10:33:41 -05:00
}
2019-10-01 20:41:42 -04:00
void UMeshSpaceDeformerTool : : Setup ( )
{
2021-01-28 13:06:33 -04:00
UInteractiveTool : : Setup ( ) ;
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
Settings = NewObject < UMeshSpaceDeformerToolProperties > ( this ) ;
Settings - > RestoreProperties ( this ) ;
AddToolPropertySource ( Settings ) ;
ToolActions = NewObject < UMeshSpaceDeformerToolActionPropertySet > ( this ) ;
ToolActions - > Initialize ( this ) ;
AddToolPropertySource ( ToolActions ) ;
2019-10-01 20:41:42 -04:00
2019-11-07 10:33:41 -05:00
// populate the OriginalDynamicMesh with a conversion of the input mesh.
2019-10-01 20:41:42 -04:00
{
2021-02-17 11:50:23 -04:00
OriginalDynamicMesh = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( ) ;
2019-11-07 10:33:41 -05:00
FMeshDescriptionToDynamicMesh Converter ;
2021-12-06 12:42:19 -05:00
Converter . Convert ( UE : : ToolTarget : : GetMeshDescription ( Target ) , * OriginalDynamicMesh ) ;
2019-10-01 20:41:42 -04:00
}
2019-11-07 10:33:41 -05:00
2021-03-24 11:11:02 -04:00
IPrimitiveComponentBackedTarget * TargetComponent = Cast < IPrimitiveComponentBackedTarget > ( Target ) ;
FTransform MeshTransform = TargetComponent - > GetWorldTransform ( ) ;
2021-01-28 13:06:33 -04:00
// Hide the mesh, and potentially put a semi-transparent copy in its place. We could
// update the materials and restore them later, but this seems safer.
2021-03-24 11:11:02 -04:00
TargetComponent - > SetOwnerVisibility ( false ) ;
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
OriginalMeshPreview = NewObject < UPreviewMesh > ( ) ;
2022-01-28 10:18:10 -05:00
OriginalMeshPreview - > CreateInWorld ( GetTargetWorld ( ) , MeshTransform ) ;
2021-10-07 22:25:54 -04:00
ToolSetupUtil : : ApplyRenderingConfigurationToPreview ( OriginalMeshPreview , Target ) ;
2021-01-28 13:06:33 -04:00
OriginalMeshPreview - > UpdatePreview ( OriginalDynamicMesh . Get ( ) ) ;
OriginalMeshPreview - > SetMaterial ( 0 , ToolSetupUtil : : GetCustomDepthOffsetMaterial ( GetToolManager ( ) , FLinearColor : : White ,
- 0.5 , // depth offset, 0.5% inward
0.4 ) ) ; // opacity
OriginalMeshPreview - > SetVisible ( Settings - > bShowOriginalMesh ) ;
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
// The gizmo gets initialized to the center point of the object-space bounding box,
// with the Z axis (along which the deformation acts) aligned to the longest of the
// bounding box dimensions, after scaling them with the transform.
FAxisAlignedBox3d BBox = OriginalDynamicMesh - > GetBounds ( ) ;
2021-12-09 15:02:36 -05:00
FVector3d Dimensions = BBox . IsEmpty ( ) ? FVector3d : : Zero ( ) : BBox . Max - BBox . Min ;
MeshCenter = BBox . IsEmpty ( ) ? FVector3d : : Zero ( ) : ( FVector3d ) MeshTransform . TransformPosition ( ( FVector ) BBox . Center ( ) ) ;
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
Dimensions = FVector3d ( MeshTransform . GetScale3D ( ) . GetAbs ( ) ) * Dimensions ;
double WorldMajorLength = 0 ;
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
// Prefer being aligned with the Z axis.
if ( Dimensions . Z > = Dimensions . Y & & Dimensions . Z > = Dimensions . X )
{
WorldMajorLength = Dimensions . Z ;
GizmoFrame = FFrame3d ( MeshCenter , FVector3d : : UnitX ( ) , FVector3d : : UnitY ( ) , FVector3d : : UnitZ ( ) ) ;
}
else if ( Dimensions . Y > = Dimensions . X )
{
WorldMajorLength = Dimensions . Y ;
GizmoFrame = FFrame3d ( MeshCenter , FVector3d : : UnitZ ( ) , FVector3d : : UnitX ( ) , FVector3d : : UnitY ( ) ) ;
}
else
{
WorldMajorLength = Dimensions . X ;
GizmoFrame = FFrame3d ( MeshCenter , FVector3d : : UnitY ( ) , FVector3d : : UnitZ ( ) , FVector3d : : UnitX ( ) ) ;
}
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
GizmoFrame . Rotate ( ( FQuaterniond ) MeshTransform . GetRotation ( ) ) ;
2019-11-07 10:33:41 -05:00
2021-01-28 13:06:33 -04:00
// The scaling of the modifier gizmo is somewhat arbitrary. We choose for it to be
// related to the major axis length.
ModifierGizmoLength = WorldMajorLength ;
2019-11-07 10:33:41 -05:00
2020-10-09 22:42:26 -04:00
// add click to set plane behavior
SetPointInWorldConnector = MakePimpl < FSelectClickedAction > ( ) ;
2021-12-09 14:46:09 -05:00
SetPointInWorldConnector - > SnapManager = USceneSnappingManager : : Find ( GetToolManager ( ) ) ;
2021-03-24 11:11:02 -04:00
SetPointInWorldConnector - > InvisibleComponentsToHitTest . Add ( TargetComponent - > GetOwnerComponent ( ) ) ;
2020-10-09 22:42:26 -04:00
SetPointInWorldConnector - > OnClickedPositionFunc = [ this ] ( const FHitResult & Hit )
{
2021-01-28 13:06:33 -04:00
SetGizmoFrameFromWorldPos ( Hit . ImpactPoint , Hit . ImpactNormal , Settings - > bAlignToNormalOnCtrlClick ) ;
2020-10-09 22:42:26 -04:00
} ;
USingleClickInputBehavior * ClickToSetPlaneBehavior = NewObject < USingleClickInputBehavior > ( ) ;
ClickToSetPlaneBehavior - > ModifierCheckFunc = FInputDeviceState : : IsCtrlKeyDown ;
ClickToSetPlaneBehavior - > Initialize ( SetPointInWorldConnector . Get ( ) ) ;
AddInputBehavior ( ClickToSetPlaneBehavior ) ;
2019-11-07 10:33:41 -05:00
// Create a new TransformGizmo and associated TransformProxy. The TransformProxy will not be the
// parent of any Components in this case, we just use it's transform and change delegate.
TransformProxy = NewObject < UTransformProxy > ( this ) ;
2021-01-28 13:06:33 -04:00
TransformProxy - > SetTransform ( GizmoFrame . ToFTransform ( ) ) ;
2021-05-20 16:39:39 -04:00
TransformGizmo = UE : : TransformGizmoUtil : : CreateCustomTransformGizmo ( GetToolManager ( ) ,
2020-01-27 20:11:15 -05:00
ETransformGizmoSubElements : : StandardTranslateRotate , this ) ;
2019-11-07 10:33:41 -05:00
TransformGizmo - > SetActiveTarget ( TransformProxy , GetToolManager ( ) ) ;
2021-01-28 13:06:33 -04:00
2019-11-07 10:33:41 -05:00
// listen for changes to the proxy and update the preview when that happens
TransformProxy - > OnTransformChanged . AddUObject ( this , & UMeshSpaceDeformerTool : : TransformProxyChanged ) ;
// create sources for the interval parameters
UpIntervalSource = NewObject < UGizmoLocalFloatParameterSource > ( this ) ;
DownIntervalSource = NewObject < UGizmoLocalFloatParameterSource > ( this ) ;
ForwardIntervalSource = NewObject < UGizmoLocalFloatParameterSource > ( this ) ;
2021-01-28 13:06:33 -04:00
// Initial Lengths for the interval handle
UpIntervalSource - > Value = WorldMajorLength / 2 ;
DownIntervalSource - > Value = - WorldMajorLength / 2 ;
ForwardIntervalSource - > Value = GetModifierGizmoValue ( ) ;
2019-11-07 10:33:41 -05:00
// Sync the properties panel to the interval handles.
2021-01-28 13:06:33 -04:00
Settings - > UpperBoundsInterval = UpIntervalSource - > Value ;
2021-02-09 16:25:32 -04:00
Settings - > LowerBoundsInterval = DownIntervalSource - > Value ;
2019-11-07 10:33:41 -05:00
// Wire up callbacks to update result mesh and the properties panel when these parameters are changed (by gizmo manipulation in viewport). Note this is just a one-way
// coupling (Sources to Properties). The OnPropertyModified() method provides the Properties to Souces coupling
UpIntervalSource - > OnParameterChanged . AddLambda ( [ this ] ( IGizmoFloatParameterSource * ParamSource , FGizmoFloatParameterChange Change ) - > void
2019-10-01 20:41:42 -04:00
{
2021-01-28 13:06:33 -04:00
Settings - > UpperBoundsInterval = Change . CurrentValue ;
UpdatePreview ( ) ;
2019-11-07 10:33:41 -05:00
} ) ;
DownIntervalSource - > OnParameterChanged . AddLambda ( [ this ] ( IGizmoFloatParameterSource * ParamSource , FGizmoFloatParameterChange Change ) - > void
{
2021-02-09 16:25:32 -04:00
Settings - > LowerBoundsInterval = Change . CurrentValue ;
2021-01-28 13:06:33 -04:00
UpdatePreview ( ) ;
2019-11-07 10:33:41 -05:00
} ) ;
ForwardIntervalSource - > OnParameterChanged . AddLambda ( [ this ] ( IGizmoFloatParameterSource * ParamSource , FGizmoFloatParameterChange Change ) - > void
{
2021-01-28 13:06:33 -04:00
ApplyModifierGizmoValue ( Change . CurrentValue ) ;
UpdatePreview ( ) ;
2019-11-07 10:33:41 -05:00
} ) ;
// add the interval gizmo
2021-05-20 16:39:39 -04:00
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > RegisterGizmoType ( UIntervalGizmo : : GizmoName , NewObject < UIntervalGizmoBuilder > ( ) ) ;
2019-11-07 10:33:41 -05:00
IntervalGizmo = GetToolManager ( ) - > GetPairedGizmoManager ( ) - > CreateGizmo < UIntervalGizmo > ( UIntervalGizmo : : GizmoName , TEXT ( " MeshSpaceDefomerInterval " ) , this ) ;
// wire in the transform and the interval sources.
IntervalGizmo - > SetActiveTarget ( TransformProxy , UpIntervalSource , DownIntervalSource , ForwardIntervalSource , GetToolManager ( ) ) ;
// use the statetarget to track details changes
StateTarget = IntervalGizmo - > StateTarget ;
2021-01-28 13:06:33 -04:00
// Set up the bent line visualizer
VisualizationRenderer . bDepthTested = false ;
VisualizationRenderer . LineColor = FLinearColor : : Yellow ;
VisualizationRenderer . LineThickness = 4.0 ;
VisualizationRenderer . SetTransform ( GizmoFrame . ToFTransform ( ) ) ;
2019-11-07 10:33:41 -05:00
// Set up the preview object
{
// create the operator factory
USpaceDeformerOperatorFactory * DeformerOperatorFactory = NewObject < USpaceDeformerOperatorFactory > ( this ) ;
DeformerOperatorFactory - > SpaceDeformerTool = this ; // set the back pointer
Preview = NewObject < UMeshOpPreviewWithBackgroundCompute > ( DeformerOperatorFactory , " Preview " ) ;
2022-01-28 10:18:10 -05:00
Preview - > Setup ( GetTargetWorld ( ) , DeformerOperatorFactory ) ;
2021-10-07 22:25:54 -04:00
ToolSetupUtil : : ApplyRenderingConfigurationToPreview ( Preview - > PreviewMesh , Target ) ;
2021-06-11 22:42:32 -04:00
Preview - > PreviewMesh - > SetTangentsMode ( EDynamicMeshComponentTangentsMode : : AutoCalculated ) ;
2019-11-07 10:33:41 -05:00
2021-01-13 10:23:16 -04:00
Preview - > SetIsMeshTopologyConstant ( true , EMeshRenderAttributeFlags : : Positions | EMeshRenderAttributeFlags : : VertexNormals ) ;
2019-11-07 10:33:41 -05:00
// Give the preview something to display
Preview - > PreviewMesh - > UpdatePreview ( OriginalDynamicMesh . Get ( ) ) ;
2021-01-28 13:06:33 -04:00
Preview - > PreviewMesh - > SetTransform ( MeshTransform ) ;
2019-11-07 10:33:41 -05:00
2021-06-11 13:33:08 -04:00
FComponentMaterialSet MaterialSet ;
MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Target ) ;
Preview - > ConfigureMaterials ( MaterialSet . Materials , ToolSetupUtil : : GetDefaultWorkingMaterial ( GetToolManager ( ) ) ) ;
2019-12-19 18:07:47 -05:00
2019-11-07 10:33:41 -05:00
// show the preview mesh
Preview - > SetVisibility ( true ) ;
// start the compute
2021-01-28 13:06:33 -04:00
UpdatePreview ( ) ;
2019-11-07 10:33:41 -05:00
}
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
DragAlignmentMechanic = NewObject < UDragAlignmentMechanic > ( this ) ;
DragAlignmentMechanic - > Setup ( this ) ;
// We want to align to the original mesh, even though it is hidden (our stand-in preview mesh that
// we use to display a transparent version does not get hit tested by our normal raycasts into
// the world).
2021-03-24 11:11:02 -04:00
TArray < const UPrimitiveComponent * > ComponentsToInclude { TargetComponent - > GetOwnerComponent ( ) } ;
2021-01-28 13:06:33 -04:00
DragAlignmentMechanic - > AddToGizmo ( TransformGizmo , nullptr , & ComponentsToInclude ) ;
DragAlignmentMechanic - > AddToGizmo ( IntervalGizmo , nullptr , & ComponentsToInclude ) ;
2020-09-24 00:43:27 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " Space Warp " ) ) ;
2020-09-24 00:43:27 -04:00
GetToolManager ( ) - > DisplayMessage (
2021-02-25 20:04:21 -04:00
LOCTEXT ( " MeshSpaceDeformerToolDescription " , " Deform the vertices of the selected Mesh using various spatial deformations. Use the in-viewport Gizmo to control the extents/strength of the deformation. Hold Ctrl while translating/rotating gizmo to align to world. " ) ,
2020-09-24 00:43:27 -04:00
EToolMessageLevel : : UserNotification ) ;
2019-10-01 20:41:42 -04:00
}
2022-01-28 18:40:54 -05:00
void UMeshSpaceDeformerTool : : OnShutdown ( EToolShutdownType ShutdownType )
2019-10-01 20:41:42 -04:00
{
2021-01-28 13:06:33 -04:00
Settings - > SaveProperties ( this ) ;
// Restore source mesh and remove our stand-in
2021-03-24 11:11:02 -04:00
Cast < IPrimitiveComponentBackedTarget > ( Target ) - > SetOwnerVisibility ( true ) ;
2021-01-28 13:06:33 -04:00
OriginalMeshPreview - > SetVisible ( false ) ;
OriginalMeshPreview - > Disconnect ( ) ;
OriginalMeshPreview = nullptr ;
2019-10-01 20:41:42 -04:00
2019-11-07 10:33:41 -05:00
if ( Preview ! = nullptr )
2019-10-01 20:41:42 -04:00
{
2019-11-07 10:33:41 -05:00
FDynamicMeshOpResult Result = Preview - > Shutdown ( ) ;
2019-10-01 20:41:42 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
2019-11-07 10:33:41 -05:00
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " MeshSpaceDeformer " , " Space Deformer " ) ) ;
FDynamicMesh3 * DynamicMeshResult = Result . Mesh . Get ( ) ;
check ( DynamicMeshResult ! = nullptr ) ;
2021-12-06 12:42:19 -05:00
UE : : ToolTarget : : CommitMeshDescriptionUpdateViaDynamicMesh ( Target , * DynamicMeshResult , true ) ;
2019-11-07 10:33:41 -05:00
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
}
2019-11-07 10:33:41 -05:00
2021-01-28 13:06:33 -04:00
DragAlignmentMechanic - > Shutdown ( ) ;
2019-11-07 10:33:41 -05:00
UInteractiveGizmoManager * GizmoManager = GetToolManager ( ) - > GetPairedGizmoManager ( ) ;
GizmoManager - > DestroyAllGizmosByOwner ( this ) ;
2021-05-20 16:39:39 -04:00
GizmoManager - > DeregisterGizmoType ( UIntervalGizmo : : GizmoName ) ;
2019-10-01 20:41:42 -04:00
}
2019-11-07 10:33:41 -05:00
void UMeshSpaceDeformerTool : : TransformProxyChanged ( UTransformProxy * Proxy , FTransform Transform )
2019-10-01 20:41:42 -04:00
{
2021-01-28 13:06:33 -04:00
GizmoFrame = FFrame3d ( Transform . GetLocation ( ) , Transform . GetRotation ( ) ) ;
VisualizationRenderer . SetTransform ( GizmoFrame . ToFTransform ( ) ) ;
UpdatePreview ( ) ;
2019-10-01 20:41:42 -04:00
}
2020-01-08 13:26:18 -05:00
void UMeshSpaceDeformerTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
2019-10-01 20:41:42 -04:00
{
2021-01-28 13:06:33 -04:00
UpIntervalSource - > Value = Settings - > UpperBoundsInterval ;
2021-02-09 16:25:32 -04:00
DownIntervalSource - > Value = Settings - > LowerBoundsInterval ;
2021-01-28 13:06:33 -04:00
ForwardIntervalSource - > Value = GetModifierGizmoValue ( ) ;
2019-10-01 20:41:42 -04:00
2021-01-28 13:06:33 -04:00
UpdatePreview ( ) ;
2019-11-07 10:33:41 -05:00
2021-01-28 13:06:33 -04:00
OriginalMeshPreview - > SetVisible ( Settings - > bShowOriginalMesh ) ;
2019-11-07 10:33:41 -05:00
}
void UMeshSpaceDeformerTool : : UpdateOpParameters ( FMeshSpaceDeformerOp & MeshSpaceDeformerOp ) const
{
2021-01-13 10:23:16 -04:00
MeshSpaceDeformerOp . OriginalMesh = OriginalDynamicMesh ;
2021-03-24 11:11:02 -04:00
MeshSpaceDeformerOp . SetTransform ( Cast < IPrimitiveComponentBackedTarget > ( Target ) - > GetWorldTransform ( ) ) ;
2021-01-13 10:23:16 -04:00
MeshSpaceDeformerOp . GizmoFrame = GizmoFrame ;
2019-10-01 20:41:42 -04:00
2019-11-07 10:33:41 -05:00
// set the bound range
2021-02-09 16:25:32 -04:00
MeshSpaceDeformerOp . UpperBoundsInterval = Settings - > UpperBoundsInterval ;
MeshSpaceDeformerOp . LowerBoundsInterval = Settings - > LowerBoundsInterval ;
2021-01-28 13:06:33 -04:00
}
2019-11-07 10:33:41 -05:00
2021-01-28 13:06:33 -04:00
void UMeshSpaceDeformerTool : : RequestAction ( EMeshSpaceDeformerToolAction ActionType )
{
if ( PendingAction = = EMeshSpaceDeformerToolAction : : NoAction )
{
PendingAction = ActionType ;
}
}
void UMeshSpaceDeformerTool : : ApplyAction ( EMeshSpaceDeformerToolAction ActionType )
{
if ( PendingAction = = EMeshSpaceDeformerToolAction : : ShiftToCenter )
{
SetGizmoFrameFromWorldPos ( ( FVector ) MeshCenter ) ;
}
2019-10-01 20:41:42 -04:00
}
2020-04-18 18:42:59 -04:00
void UMeshSpaceDeformerTool : : OnTick ( float DeltaTime )
2019-10-01 20:41:42 -04:00
{
2021-01-28 13:06:33 -04:00
// Deal with clicked button
if ( PendingAction ! = EMeshSpaceDeformerToolAction : : NoAction )
2020-10-09 22:42:26 -04:00
{
2021-01-28 13:06:33 -04:00
ApplyAction ( PendingAction ) ;
PendingAction = EMeshSpaceDeformerToolAction : : NoAction ;
2020-10-09 22:42:26 -04:00
}
2019-11-07 10:33:41 -05:00
if ( Preview ! = nullptr )
2019-10-01 20:41:42 -04:00
{
2019-11-07 10:33:41 -05:00
Preview - > Tick ( DeltaTime ) ;
2019-10-01 20:41:42 -04:00
}
}
2021-01-28 13:06:33 -04:00
void UMeshSpaceDeformerTool : : Render ( IToolsContextRenderAPI * RenderAPI )
2020-10-09 22:42:26 -04:00
{
2021-01-28 13:06:33 -04:00
DragAlignmentMechanic - > Render ( RenderAPI ) ;
2020-10-09 22:42:26 -04:00
2021-01-28 13:06:33 -04:00
if ( Settings - > bDrawVisualization & & Settings - > SelectedOperationType = = ENonlinearOperationType : : Bend )
2020-10-09 22:42:26 -04:00
{
2021-01-28 13:06:33 -04:00
VisualizationRenderer . BeginFrame ( RenderAPI , RenderAPI - > GetCameraState ( ) ) ;
for ( int32 i = 1 ; i < VisualizationPoints . Num ( ) ; + + i )
{
VisualizationRenderer . DrawLine ( VisualizationPoints [ i - 1 ] , VisualizationPoints [ i ] ) ;
}
VisualizationRenderer . EndFrame ( ) ;
2020-10-09 22:42:26 -04:00
}
else
{
2021-01-28 13:06:33 -04:00
}
}
void UMeshSpaceDeformerTool : : UpdatePreview ( )
{
if ( Settings - > SelectedOperationType = = ENonlinearOperationType : : Bend )
{
const int32 NUM_RENDER_POINTS = 30 ;
VisualizationPoints . SetNumUninitialized ( NUM_RENDER_POINTS ) ;
2021-02-09 16:25:32 -04:00
double BentLength = Settings - > UpperBoundsInterval - Settings - > LowerBoundsInterval ;
2021-01-28 13:06:33 -04:00
double ArcAngle = Settings - > BendDegrees * PI / 180 ;
double ArcRadius = BentLength / ArcAngle ;
2021-02-09 16:25:32 -04:00
double RotationCenterZ = Settings - > bLockBottom ? Settings - > LowerBoundsInterval : 0 ;
2021-01-28 13:06:33 -04:00
FVector2d RotationCenterYZ ( ArcRadius , RotationCenterZ ) ;
double PointSpacing = BentLength / ( NUM_RENDER_POINTS - 1 ) ;
for ( int32 i = 0 ; i < NUM_RENDER_POINTS ; + + i )
{
2021-02-09 16:25:32 -04:00
double OriginalZ = Settings - > LowerBoundsInterval + PointSpacing * i ;
2021-01-28 13:06:33 -04:00
FVector2d YZToRotate ( 0 , RotationCenterZ ) ;
// The negative here is because we are rotating clockwise in the direction of the positive Y axis
double AngleToRotate = - ArcAngle * ( OriginalZ - RotationCenterZ ) / BentLength ;
FMatrix2d RotationMatrix = FMatrix2d : : RotationRad ( AngleToRotate ) ;
FVector2d RotatedYZ = RotationMatrix * ( YZToRotate - RotationCenterYZ ) + RotationCenterYZ ;
VisualizationPoints [ i ] = FVector3d ( 0 , RotatedYZ . X , RotatedYZ . Y ) ;
}
2020-10-09 22:42:26 -04:00
}
2021-01-28 13:06:33 -04:00
if ( Preview )
2020-10-09 22:42:26 -04:00
{
Preview - > InvalidateResult ( ) ;
}
}
2021-01-28 13:06:33 -04:00
void UMeshSpaceDeformerTool : : SetGizmoFrameFromWorldPos ( const FVector & Position , const FVector & Normal , bool bAlignNormal )
{
2021-03-30 21:25:22 -04:00
GizmoFrame . Origin = ( FVector3d ) Position ;
2021-01-28 13:06:33 -04:00
if ( bAlignNormal )
{
// It's not clear whether aligning the Z axis to the normal is the right idea here. The Z axis
// is the main axis on which we operate. On the one hand, setting it to the normal gives the user
// greater control over its alignment. On the other hand, it seems likely that when clicking the object,
// the user would want the axis to lie along the object on the side they clicked, not pierce inwards.
// Still, it's hard to come up with a clean alternative.
FVector3d FrameZ ( Normal ) ;
2021-03-17 19:32:44 -04:00
FVector3d FrameY = UE : : Geometry : : Normalized ( FrameZ . Cross ( FVector3d : : UnitZ ( ) ) ) ; // orthogonal to world Z and frame Z
2021-03-30 21:25:22 -04:00
FVector3d FrameX = FrameY . Cross ( FrameZ ) ; // safe to not normalize because already orthogonal
GizmoFrame = FFrame3d ( ( FVector3d ) Position , FrameX , FrameY , FrameZ ) ;
2021-01-28 13:06:33 -04:00
}
TransformGizmo - > ReinitializeGizmoTransform ( GizmoFrame . ToFTransform ( ) ) ;
UpdatePreview ( ) ;
}
/**
* These two functions translate to and from the modifier gizmo length
* to the relevant operator parameters . They should be matched to each
* other .
*/
double UMeshSpaceDeformerTool : : GetModifierGizmoValue ( ) const
{
switch ( Settings - > SelectedOperationType )
{
case ENonlinearOperationType : : Bend :
return Settings - > BendDegrees * ModifierGizmoLength / 180 ;
case ENonlinearOperationType : : Flare :
return Settings - > FlarePercentY * ModifierGizmoLength / 100 ;
case ENonlinearOperationType : : Twist :
return Settings - > TwistDegrees * ModifierGizmoLength / 360 ;
}
// Shouldn't get here
check ( false ) ;
return 0 ;
}
void UMeshSpaceDeformerTool : : ApplyModifierGizmoValue ( double Value )
{
switch ( Settings - > SelectedOperationType )
{
case ENonlinearOperationType : : Bend :
Settings - > BendDegrees = 180 * Value / ModifierGizmoLength ;
break ;
case ENonlinearOperationType : : Flare :
Settings - > FlarePercentY = 100 * Value / ModifierGizmoLength ;
break ;
case ENonlinearOperationType : : Twist :
Settings - > TwistDegrees = 360 * Value / ModifierGizmoLength ;
break ;
default :
check ( false ) ;
}
}
2019-10-01 20:41:42 -04:00
# undef LOCTEXT_NAMESPACE