2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
# include "UVProjectionTool.h"
# include "InteractiveToolManager.h"
2021-03-11 11:40:03 -04:00
# include "ToolTargetManager.h"
2021-12-09 14:46:09 -05:00
# include "SceneQueries/SceneSnappingManager.h"
2021-05-31 22:15:32 -04:00
# include "ToolBuilderUtil.h"
# include "ToolSetupUtil.h"
# include "BaseBehaviors/SingleClickBehavior.h"
# include "BaseGizmos/TransformGizmoUtil.h"
# include "ModelingToolTargetUtil.h"
# include "Selection/StoredMeshSelectionUtil.h"
# include "DynamicMesh/DynamicMesh3.h"
# include "DynamicMesh/DynamicMeshAABBTree3.h"
# include "DynamicMesh/MeshIndexUtil.h"
# include "MeshRegionBoundaryLoops.h"
# include "Parameterization/DynamicMeshUVEditor.h"
# include "Operations/MeshConvexHull.h"
# include "MinVolumeBox3.h"
2021-03-11 11:40:03 -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 "UUVProjectionTool"
/*
* ToolBuilder
*/
2021-05-31 22:15:32 -04:00
USingleSelectionMeshEditingTool * UUVProjectionToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
2021-03-11 11:40:03 -04:00
{
2021-05-31 22:15:32 -04:00
return NewObject < UUVProjectionTool > ( SceneState . ToolManager ) ;
2021-03-11 11:40:03 -04:00
}
2021-05-31 22:15:32 -04:00
/*
* Propert Sets
*/
void UUVProjectionToolEditActions : : PostAction ( EUVProjectionToolActions Action )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
if ( ParentTool . IsValid ( ) )
{
ParentTool - > RequestAction ( Action ) ;
}
2019-10-01 20:41:42 -04:00
}
/*
* Tool
*/
void UUVProjectionTool : : Setup ( )
{
UInteractiveTool : : Setup ( ) ;
2021-05-31 22:15:32 -04:00
UE : : ToolTarget : : HideSourceObject ( Target ) ;
2019-10-01 20:41:42 -04:00
2021-05-31 22:15:32 -04:00
BasicProperties = NewObject < UUVProjectionToolProperties > ( this ) ;
2020-01-27 20:11:15 -05:00
BasicProperties - > RestoreProperties ( this ) ;
2021-05-31 22:15:32 -04:00
BasicProperties - > GetOnModified ( ) . AddLambda ( [ this ] ( UObject * , FProperty * ) { Preview - > InvalidateResult ( ) ; } ) ;
2020-01-27 20:11:15 -05:00
2021-05-31 22:15:32 -04:00
// initialize input mesh
InitializeMesh ( ) ;
2019-10-01 20:41:42 -04:00
// initialize the PreviewMesh+BackgroundCompute object
UpdateNumPreviews ( ) ;
2021-05-31 22:15:32 -04:00
UVChannelProperties = NewObject < UMeshUVChannelProperties > ( this ) ;
UVChannelProperties - > RestoreProperties ( this ) ;
UVChannelProperties - > Initialize ( InputMesh . Get ( ) , false ) ;
UVChannelProperties - > ValidateSelection ( true ) ;
UVChannelProperties - > WatchProperty ( UVChannelProperties - > UVChannel , [ this ] ( const FString & NewValue )
{
2021-11-18 20:41:17 -05:00
MaterialSettings - > UpdateUVChannels ( UVChannelProperties - > UVChannelNamesList . IndexOfByKey ( UVChannelProperties - > UVChannel ) ,
UVChannelProperties - > UVChannelNamesList ) ;
2021-05-31 22:15:32 -04:00
Preview - > InvalidateResult ( ) ;
OnMaterialSettingsChanged ( ) ;
} ) ;
MaterialSettings = NewObject < UExistingMeshMaterialProperties > ( this ) ;
MaterialSettings - > RestoreProperties ( this ) ;
MaterialSettings - > GetOnModified ( ) . AddLambda ( [ this ] ( UObject * , FProperty * )
{
OnMaterialSettingsChanged ( ) ;
} ) ;
EditActions = NewObject < UUVProjectionToolEditActions > ( this ) ;
EditActions - > Initialize ( this ) ;
AddToolPropertySource ( UVChannelProperties ) ;
AddToolPropertySource ( BasicProperties ) ;
AddToolPropertySource ( EditActions ) ;
AddToolPropertySource ( MaterialSettings ) ;
OnMaterialSettingsChanged ( ) ;
2019-10-01 20:41:42 -04:00
// set up visualizers
ProjectionShapeVisualizer . LineColor = FLinearColor : : Red ;
ProjectionShapeVisualizer . LineThickness = 2.0 ;
2021-05-31 22:15:32 -04:00
// initialize Gizmo
2022-01-29 14:37:53 -05:00
FTransform3d GizmoPositionWorld ( WorldBounds . Center ( ) ) ;
2021-05-31 22:15:32 -04:00
TransformProxy = NewObject < UTransformProxy > ( this ) ;
TransformProxy - > SetTransform ( ( FTransform ) GizmoPositionWorld ) ;
TransformProxy - > OnTransformChanged . AddUObject ( this , & UUVProjectionTool : : TransformChanged ) ;
TransformGizmo = UE : : TransformGizmoUtil : : CreateCustomTransformGizmo (
GetToolManager ( ) , ETransformGizmoSubElements : : StandardTranslateRotate , this ) ;
TransformGizmo - > SetActiveTarget ( TransformProxy , GetToolManager ( ) ) ;
InitialDimensions = BasicProperties - > Dimensions ;
2021-12-02 15:04:36 -05:00
bInitialUniformDimensions = BasicProperties - > bUniformDimensions ;
2021-05-31 22:15:32 -04:00
InitialTransform = TransformGizmo - > GetGizmoTransform ( ) ;
2019-10-01 20:41:42 -04:00
2021-05-31 22:15:32 -04:00
ApplyInitializationMode ( ) ;
// start watching for dimensions changes
DimensionsWatcher = BasicProperties - > WatchProperty ( BasicProperties - > Dimensions , [ this ] ( FVector ) { bTransformModified = true ; } ) ;
2021-12-02 15:04:36 -05:00
DimensionsModeWatcher = BasicProperties - > WatchProperty ( BasicProperties - > bUniformDimensions , [ this ] ( bool ) { bTransformModified = true ; } ) ;
2021-05-31 22:15:32 -04:00
BasicProperties - > WatchProperty ( BasicProperties - > Initialization , [ this ] ( EUVProjectionToolInitializationMode NewMode ) { OnInitializationModeChanged ( ) ; } ) ;
bTransformModified = false ;
BasicProperties - > SilentUpdateWatched ( ) ;
// click to set plane behavior
SetPlaneCtrlClickBehaviorTarget = MakeUnique < FSelectClickedAction > ( ) ;
2021-12-09 14:46:09 -05:00
SetPlaneCtrlClickBehaviorTarget - > SnapManager = USceneSnappingManager : : Find ( GetToolManager ( ) ) ;
2021-05-31 22:15:32 -04:00
SetPlaneCtrlClickBehaviorTarget - > OnClickedPositionFunc = [ this ] ( const FHitResult & Hit )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
UpdatePlaneFromClick ( FVector3d ( Hit . ImpactPoint ) , FVector3d ( Hit . ImpactNormal ) , SetPlaneCtrlClickBehaviorTarget - > bShiftModifierToggle ) ;
} ;
SetPlaneCtrlClickBehaviorTarget - > InvisibleComponentsToHitTest . Add ( UE : : ToolTarget : : GetTargetComponent ( Target ) ) ;
ClickToSetPlaneBehavior = NewObject < USingleClickInputBehavior > ( ) ;
ClickToSetPlaneBehavior - > ModifierCheckFunc = FInputDeviceState : : IsCtrlKeyDown ;
ClickToSetPlaneBehavior - > Modifiers . RegisterModifier ( FSelectClickedAction : : ShiftModifier , FInputDeviceState : : IsShiftKeyDown ) ;
ClickToSetPlaneBehavior - > Initialize ( SetPlaneCtrlClickBehaviorTarget . Get ( ) ) ;
AddInputBehavior ( ClickToSetPlaneBehavior ) ;
// probably already done
Preview - > InvalidateResult ( ) ;
2020-09-24 00:43:27 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " UV Projection " ) ) ;
2020-09-24 00:43:27 -04:00
GetToolManager ( ) - > DisplayMessage (
2021-05-31 22:15:32 -04:00
LOCTEXT ( " UVProjectionToolDescription " , " Generate UVs for a Mesh by projecting onto simple geometric shapes. Ctrl+click to reposition shape. Face selections can be made in the PolyEdit and TriEdit Tools. " ) ,
2020-09-24 00:43:27 -04:00
EToolMessageLevel : : UserNotification ) ;
2019-10-01 20:41:42 -04:00
}
void UUVProjectionTool : : UpdateNumPreviews ( )
{
2021-05-31 22:15:32 -04:00
OperatorFactory = NewObject < UUVProjectionOperatorFactory > ( ) ;
OperatorFactory - > Tool = this ;
Preview = NewObject < UMeshOpPreviewWithBackgroundCompute > ( OperatorFactory ) ;
2022-01-28 10:18:10 -05:00
Preview - > Setup ( GetTargetWorld ( ) , OperatorFactory ) ;
2021-10-07 22:25:54 -04:00
ToolSetupUtil : : ApplyRenderingConfigurationToPreview ( Preview - > PreviewMesh , Target ) ;
2021-05-31 22:15:32 -04:00
Preview - > OnMeshUpdated . AddUObject ( this , & UUVProjectionTool : : OnMeshUpdated ) ;
2021-06-11 22:42:32 -04:00
Preview - > PreviewMesh - > SetTangentsMode ( EDynamicMeshComponentTangentsMode : : AutoCalculated ) ;
2021-05-31 22:15:32 -04:00
FComponentMaterialSet MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Target , false ) ;
Preview - > ConfigureMaterials ( MaterialSet . Materials ,
ToolSetupUtil : : GetDefaultWorkingMaterial ( GetToolManager ( ) )
) ;
Preview - > PreviewMesh - > UpdatePreview ( InputMesh . Get ( ) ) ;
Preview - > PreviewMesh - > SetTransform ( ( FTransform ) WorldTransform ) ;
Preview - > SetVisibility ( true ) ;
EdgeRenderer = NewObject < UPreviewGeometry > ( this ) ;
2022-01-28 10:18:10 -05:00
EdgeRenderer - > CreateInWorld ( GetTargetWorld ( ) , ( FTransform ) WorldTransform ) ;
2021-05-31 22:15:32 -04:00
// if we have an ROI, show its borders
if ( TriangleROI - > Num ( ) > 0 )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
FDynamicMesh3 * UseMesh = InputMesh . Get ( ) ;
FMeshRegionBoundaryLoops BoundaryLoops ( UseMesh , * TriangleROI , true ) ;
TSet < int32 > BorderEdges ;
for ( const FEdgeLoop & Loop : BoundaryLoops . GetLoops ( ) )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
BorderEdges . Append ( Loop . Edges ) ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
const FColor ROIBorderColor ( 240 , 15 , 240 ) ;
const float ROIBorderThickness = 4.0f ;
const float ROIBorderDepthBias = 0.1f * ( float ) ( WorldBounds . DiagonalLength ( ) * 0.01 ) ;
EdgeRenderer - > CreateOrUpdateLineSet ( TEXT ( " ROIBorders " ) , UseMesh - > MaxEdgeID ( ) , [ & ] ( int32 eid , TArray < FRenderableLine > & LinesOut ) {
if ( BorderEdges . Contains ( eid ) )
{
FVector3d A , B ;
UseMesh - > GetEdgeV ( eid , A , B ) ;
LinesOut . Add ( FRenderableLine ( ( FVector ) A , ( FVector ) B , ROIBorderColor , ROIBorderThickness , ROIBorderDepthBias ) ) ;
}
} , 1 ) ;
2019-10-01 20:41:42 -04:00
}
}
2022-01-28 18:40:54 -05:00
void UUVProjectionTool : : OnShutdown ( EToolShutdownType ShutdownType )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
UVChannelProperties - > SaveProperties ( this ) ;
BasicProperties - > SavedDimensions = BasicProperties - > Dimensions ;
2021-12-02 15:04:36 -05:00
BasicProperties - > bSavedUniformDimensions = BasicProperties - > bUniformDimensions ;
2021-05-31 22:15:32 -04:00
BasicProperties - > SavedTransform = TransformGizmo - > GetGizmoTransform ( ) ;
2020-01-27 20:11:15 -05:00
BasicProperties - > SaveProperties ( this ) ;
MaterialSettings - > SaveProperties ( this ) ;
2021-05-31 22:15:32 -04:00
EdgeRenderer - > Disconnect ( ) ;
2019-10-01 20:41:42 -04:00
2021-05-31 22:15:32 -04:00
// Restore (unhide) the source meshes
UE : : ToolTarget : : ShowSourceObject ( Target ) ;
FDynamicMeshOpResult Result = Preview - > Shutdown ( ) ;
2019-10-01 20:41:42 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
2021-05-31 22:15:32 -04:00
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " UVProjectionToolTransactionName " , " Project UVs " ) ) ;
FDynamicMesh3 * NewDynamicMesh = Result . Mesh . Get ( ) ;
if ( ensure ( NewDynamicMesh ) )
{
UE : : ToolTarget : : CommitDynamicMeshUVUpdate ( Target , NewDynamicMesh ) ;
}
GetToolManager ( ) - > EndUndoTransaction ( ) ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DestroyAllGizmosByOwner ( this ) ;
TransformGizmo = nullptr ;
TransformProxy = nullptr ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
void UUVProjectionTool : : RequestAction ( EUVProjectionToolActions ActionType )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
if ( bHavePendingAction )
{
return ;
}
PendingAction = ActionType ;
bHavePendingAction = true ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
2019-10-04 14:13:21 -04:00
TUniquePtr < FDynamicMeshOperator > UUVProjectionOperatorFactory : : MakeNewOperator ( )
2019-10-01 20:41:42 -04:00
{
2019-10-04 14:13:21 -04:00
TUniquePtr < FUVProjectionOp > Op = MakeUnique < FUVProjectionOp > ( ) ;
2021-05-31 22:15:32 -04:00
Op - > ProjectionMethod = Tool - > BasicProperties - > ProjectionType ;
2019-10-01 20:41:42 -04:00
2021-05-31 22:15:32 -04:00
Op - > MeshToProjectionSpace = Tool - > WorldTransform ;
Op - > ProjectionBox = Tool - > GetProjectionBox ( ) ;
2021-12-02 15:04:36 -05:00
Op - > CylinderSplitAngle = Tool - > BasicProperties - > CylinderSplitAngle ;
Op - > BlendWeight = Tool - > BasicProperties - > ExpMapNormalBlending ;
Op - > SmoothingRounds = Tool - > BasicProperties - > ExpMapSmoothingSteps ;
Op - > SmoothingAlpha = Tool - > BasicProperties - > ExpMapSmoothingAlpha ;
2021-05-31 22:15:32 -04:00
2021-12-02 15:04:36 -05:00
Op - > UVRotationAngleDeg = Tool - > BasicProperties - > Rotation ;
Op - > UVScale = ( FVector2f ) Tool - > BasicProperties - > Scale ;
Op - > UVTranslate = ( FVector2f ) Tool - > BasicProperties - > Translation ;
2019-10-01 20:41:42 -04:00
2021-05-31 22:15:32 -04:00
Op - > OriginalMesh = Tool - > InputMesh ;
Op - > TriangleROI = Tool - > TriangleROI ;
Op - > UseUVLayer = Tool - > UVChannelProperties - > GetSelectedChannelIndex ( true ) ;
Op - > SetResultTransform ( Tool - > WorldTransform ) ;
2019-10-01 20:41:42 -04:00
return Op ;
}
2021-05-31 22:15:32 -04:00
void UUVProjectionTool : : InitializeMesh ( )
{
InputMesh = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( ) ;
* InputMesh = UE : : ToolTarget : : GetDynamicMeshCopy ( Target ) ;
WorldTransform = UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
// initialize triangle ROI if one exists
TriangleROI = MakeShared < TArray < int32 > , ESPMode : : ThreadSafe > ( ) ;
ModelingTools: replace StorableSelection mechanism with new UPersistentMeshSelection and UPersistentMeshSelectionManager context object.
- UPersistentMeshSelection is largely a port of UGroupTopologyStorableSelection, with the actual selection data moved to FGenericMeshSelection
- UPersistentMeshSelectionManager is meant to be used as a ContextObject in a ToolsContext, also contains utility functions to register/unregister/find context object
- Selection is no longer passed as part of FToolBuilderState. Instead Tools access the selection via ContextObject
- UPersistentMeshSelectionManager currently supports a single active selection. Selection changes are transacted via an FChange.
- When not inside a Tool, Selection is visualized with a pink border outline. Currently vertex selection is not visualized.
- Usage model is that on Tool Accept/Complete, prior to Tool Shutdown, any existing selection is cleared, and Tool may set a new Output selection which becomes the active selection
- StoredMeshSelectionUtil.h has utility functions to get current selection, set output selection, and clear it
- SingleSelectionMeshEditingTool already made input selection available to subclasses, port that capability to new architecture
- convert EditMeshPolygonsTool to be a SingleSelectionMeshEditingTool, use provided Input selection and set Output selection as appropriate
- ModelingToolsEditorMode clears active selection where appropriate, eg if selected object changes. However the behavior here will need further improvement, currently relies on questionable event handling from the TypedElement system
#rb semion.piskarev
#rnx
#jira none
#preflight 6136cbbfd9c85a0001fc3b56
#ROBOMERGE-AUTHOR: ryan.schmidt
#ROBOMERGE-SOURCE: CL 17441056 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v870-17433530)
[CL 17441061 by ryan schmidt in ue5-release-engine-test branch]
2021-09-06 23:05:07 -04:00
if ( USingleSelectionMeshEditingTool : : HasInputSelection ( ) )
2021-05-31 22:15:32 -04:00
{
ModelingTools: replace StorableSelection mechanism with new UPersistentMeshSelection and UPersistentMeshSelectionManager context object.
- UPersistentMeshSelection is largely a port of UGroupTopologyStorableSelection, with the actual selection data moved to FGenericMeshSelection
- UPersistentMeshSelectionManager is meant to be used as a ContextObject in a ToolsContext, also contains utility functions to register/unregister/find context object
- Selection is no longer passed as part of FToolBuilderState. Instead Tools access the selection via ContextObject
- UPersistentMeshSelectionManager currently supports a single active selection. Selection changes are transacted via an FChange.
- When not inside a Tool, Selection is visualized with a pink border outline. Currently vertex selection is not visualized.
- Usage model is that on Tool Accept/Complete, prior to Tool Shutdown, any existing selection is cleared, and Tool may set a new Output selection which becomes the active selection
- StoredMeshSelectionUtil.h has utility functions to get current selection, set output selection, and clear it
- SingleSelectionMeshEditingTool already made input selection available to subclasses, port that capability to new architecture
- convert EditMeshPolygonsTool to be a SingleSelectionMeshEditingTool, use provided Input selection and set Output selection as appropriate
- ModelingToolsEditorMode clears active selection where appropriate, eg if selected object changes. However the behavior here will need further improvement, currently relies on questionable event handling from the TypedElement system
#rb semion.piskarev
#rnx
#jira none
#preflight 6136cbbfd9c85a0001fc3b56
#ROBOMERGE-AUTHOR: ryan.schmidt
#ROBOMERGE-SOURCE: CL 17441056 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v870-17433530)
[CL 17441061 by ryan schmidt in ue5-release-engine-test branch]
2021-09-06 23:05:07 -04:00
UE : : Geometry : : GetStoredSelectionAsTriangles ( GetInputSelection ( ) , * InputMesh , * TriangleROI ) ;
2021-05-31 22:15:32 -04:00
TriangleROISet . Append ( * TriangleROI ) ;
}
VertexROI = MakeShared < TArray < int32 > , ESPMode : : ThreadSafe > ( ) ;
UE : : Geometry : : TriangleToVertexIDs ( InputMesh . Get ( ) , * TriangleROI , * VertexROI ) ;
InputMeshROISpatial = MakeShared < FDynamicMeshAABBTree3 , ESPMode : : ThreadSafe > ( InputMesh . Get ( ) , false ) ;
if ( TriangleROI - > Num ( ) > 0 )
{
InputMeshROISpatial - > Build ( * TriangleROI ) ;
}
else
{
InputMeshROISpatial - > Build ( ) ;
}
WorldBounds = ( VertexROI - > Num ( ) > 0 ) ?
FAxisAlignedBox3d : : MakeBoundsFromIndices ( * VertexROI , [ this ] ( int32 Index ) { return WorldTransform . TransformPosition ( InputMesh - > GetVertex ( Index ) ) ; } )
: FAxisAlignedBox3d : : MakeBoundsFromIndices ( InputMesh - > VertexIndicesItr ( ) , [ this ] ( int32 Index ) { return WorldTransform . TransformPosition ( InputMesh - > GetVertex ( Index ) ) ; } ) ;
BasicProperties - > Dimensions = ( FVector ) WorldBounds . Diagonal ( ) ;
}
2021-12-02 15:04:36 -05:00
FOrientedBox3d UUVProjectionTool : : GetProjectionBox ( ) const
2021-05-31 22:15:32 -04:00
{
2021-12-02 15:04:36 -05:00
const FFrame3d BoxFrame ( TransformProxy - > GetTransform ( ) ) ;
const FVector3d BoxDimensions = 0.5 * ( BasicProperties - > bUniformDimensions
? FVector3d ( BasicProperties - > Dimensions . X , BasicProperties - > Dimensions . X , BasicProperties - > Dimensions . X )
: static_cast < FVector3d > ( BasicProperties - > Dimensions ) ) ;
return FOrientedBox3d ( BoxFrame , BoxDimensions ) ;
2021-05-31 22:15:32 -04:00
}
2019-10-01 20:41:42 -04:00
void UUVProjectionTool : : Render ( IToolsContextRenderAPI * RenderAPI )
{
ProjectionShapeVisualizer . bDepthTested = false ;
ProjectionShapeVisualizer . BeginFrame ( RenderAPI , CameraState ) ;
2021-08-26 09:31:28 -04:00
UE : : Geometry : : FOrientedBox3d PrimBox = GetProjectionBox ( ) ;
2021-05-31 22:15:32 -04:00
FVector MinCorner = ( FVector ) - PrimBox . Extents ;
FVector MaxCorner = ( FVector ) PrimBox . Extents ;
float Width = MaxCorner . X - MinCorner . X ;
float Depth = MaxCorner . Y - MinCorner . Y ;
float Height = MaxCorner . Z - MinCorner . Z ;
FTransform UseTransform = PrimBox . Frame . ToFTransform ( ) ;
if ( BasicProperties - > ProjectionType = = EUVProjectionMethod : : Cylinder )
{
UseTransform . SetScale3D ( FVector ( Width , Depth , 1.0f ) ) ;
}
ProjectionShapeVisualizer . SetTransform ( UseTransform ) ;
switch ( BasicProperties - > ProjectionType )
{
case EUVProjectionMethod : : Box :
ProjectionShapeVisualizer . DrawWireBox ( FBox ( MinCorner , MaxCorner ) ) ;
break ;
case EUVProjectionMethod : : Cylinder :
ProjectionShapeVisualizer . DrawWireCylinder ( FVector ( 0 , 0 , - Height * 0.5f ) , FVector ( 0 , 0 , 1 ) , 0.5f , Height , 16 ) ;
break ;
case EUVProjectionMethod : : Plane :
ProjectionShapeVisualizer . DrawSquare ( FVector ( 0 , 0 , 0 ) , FVector ( Width , 0 , 0 ) , FVector ( 0 , Depth , 0 ) ) ;
break ;
case EUVProjectionMethod : : ExpMap :
ProjectionShapeVisualizer . DrawSquare ( FVector ( 0 , 0 , 0 ) , FVector ( Width , 0 , 0 ) , FVector ( 0 , Depth , 0 ) ) ;
break ;
2019-10-01 20:41:42 -04:00
}
ProjectionShapeVisualizer . EndFrame ( ) ;
}
2020-04-18 18:42:59 -04:00
void UUVProjectionTool : : OnTick ( float DeltaTime )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
if ( bHavePendingAction )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
ApplyAction ( PendingAction ) ;
bHavePendingAction = false ;
PendingAction = EUVProjectionToolActions : : NoAction ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
Preview - > Tick ( DeltaTime ) ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
void UUVProjectionTool : : OnMaterialSettingsChanged ( )
2019-10-01 20:41:42 -04:00
{
MaterialSettings - > UpdateMaterials ( ) ;
2020-03-05 14:27:21 -05:00
2021-05-31 22:15:32 -04:00
UMaterialInterface * OverrideMaterial = MaterialSettings - > GetActiveOverrideMaterial ( ) ;
if ( OverrideMaterial ! = nullptr )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
Preview - > OverrideMaterial = OverrideMaterial ;
}
else
{
Preview - > OverrideMaterial = nullptr ;
2019-10-01 20:41:42 -04:00
}
}
2021-05-31 22:15:32 -04:00
void UUVProjectionTool : : OnMeshUpdated ( UMeshOpPreviewWithBackgroundCompute * PreviewCompute )
{
const FColor UVSeamColor ( 15 , 240 , 15 ) ;
const float UVSeamThickness = 2.0f ;
const float UVSeamDepthBias = 0.1f * ( float ) ( WorldBounds . DiagonalLength ( ) * 0.01 ) ;
const FDynamicMesh3 * UseMesh = Preview - > PreviewMesh - > GetMesh ( ) ;
const FDynamicMeshUVOverlay * UVOverlay = UseMesh - > Attributes ( ) - > GetUVLayer ( UVChannelProperties - > GetSelectedChannelIndex ( true ) ) ;
2021-12-02 15:04:36 -05:00
auto AppendSeamEdge = [ UseMesh , UVSeamColor , UVSeamThickness , UVSeamDepthBias ] ( int32 eid , TArray < FRenderableLine > & LinesOut ) {
2021-05-31 22:15:32 -04:00
FVector3d A , B ;
UseMesh - > GetEdgeV ( eid , A , B ) ;
LinesOut . Add ( FRenderableLine ( ( FVector ) A , ( FVector ) B , UVSeamColor , UVSeamThickness , UVSeamDepthBias ) ) ;
} ;
if ( TriangleROI - > Num ( ) > 0 )
{
EdgeRenderer - > CreateOrUpdateLineSet ( TEXT ( " UVSeams " ) , UseMesh - > MaxEdgeID ( ) , [ & ] ( int32 eid , TArray < FRenderableLine > & LinesOut ) {
FIndex2i EdgeT = UseMesh - > GetEdgeT ( eid ) ;
2021-07-27 18:18:06 -04:00
if ( UseMesh - > IsEdge ( eid ) & & TriangleROISet . Contains ( EdgeT . A ) & & TriangleROISet . Contains ( EdgeT . B ) & & UVOverlay - > IsSeamEdge ( eid ) )
2021-05-31 22:15:32 -04:00
{
AppendSeamEdge ( eid , LinesOut ) ;
}
} , 1 ) ;
}
else
{
EdgeRenderer - > CreateOrUpdateLineSet ( TEXT ( " UVSeams " ) , UseMesh - > MaxEdgeID ( ) , [ & ] ( int32 eid , TArray < FRenderableLine > & LinesOut ) {
2021-07-27 18:18:06 -04:00
if ( UseMesh - > IsEdge ( eid ) & & UVOverlay - > IsSeamEdge ( eid ) )
2021-05-31 22:15:32 -04:00
{
AppendSeamEdge ( eid , LinesOut ) ;
}
} , 1 ) ;
}
}
2022-01-07 00:14:44 -05:00
void UUVProjectionTool : : UpdatePlaneFromClick ( const FVector3d & Position , const FVector3d & Normal , bool bTransitionOnly )
2021-05-31 22:15:32 -04:00
{
FFrame3d CurrentFrame ( TransformProxy - > GetTransform ( ) ) ;
CurrentFrame . Origin = Position ;
2022-01-07 00:14:44 -05:00
if ( bTransitionOnly = = false )
2021-05-31 22:15:32 -04:00
{
CurrentFrame . AlignAxis ( 2 , Normal ) ;
}
TransformGizmo - > SetNewGizmoTransform ( CurrentFrame . ToFTransform ( ) ) ;
Preview - > InvalidateResult ( ) ;
bTransformModified = true ;
2020-03-05 14:27:21 -05:00
}
2019-10-01 20:41:42 -04:00
void UUVProjectionTool : : TransformChanged ( UTransformProxy * Proxy , FTransform Transform )
{
2021-05-31 22:15:32 -04:00
Preview - > InvalidateResult ( ) ;
bTransformModified = true ;
2019-10-01 20:41:42 -04:00
}
bool UUVProjectionTool : : CanAccept ( ) const
{
2021-05-31 22:15:32 -04:00
if ( ! Preview - > HaveValidResult ( ) )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
return false ;
2019-10-01 20:41:42 -04:00
}
2020-11-24 18:42:39 -04:00
return Super : : CanAccept ( ) ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
void UUVProjectionTool : : OnInitializationModeChanged ( )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
bool bWasTransformModified = bTransformModified ;
if ( ! bTransformModified )
2019-10-01 20:41:42 -04:00
{
2021-05-31 22:15:32 -04:00
ApplyInitializationMode ( ) ;
bTransformModified = bWasTransformModified ;
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
}
2019-10-01 20:41:42 -04:00
2021-05-31 22:15:32 -04:00
void UUVProjectionTool : : ApplyInitializationMode ( )
{
switch ( BasicProperties - > Initialization )
{
case EUVProjectionToolInitializationMode : : Default :
BasicProperties - > Dimensions = InitialDimensions ;
TransformGizmo - > SetNewGizmoTransform ( InitialTransform ) ;
break ;
case EUVProjectionToolInitializationMode : : UsePrevious :
{
bool bHavePrevious = ( BasicProperties - > SavedDimensions ! = FVector : : ZeroVector ) ;
BasicProperties - > Dimensions = ( bHavePrevious ) ? BasicProperties - > SavedDimensions : InitialDimensions ;
TransformGizmo - > SetNewGizmoTransform ( ( bHavePrevious ) ? BasicProperties - > SavedTransform : InitialTransform ) ;
}
break ;
case EUVProjectionToolInitializationMode : : AutoFit :
ApplyAction_AutoFit ( false ) ;
break ;
case EUVProjectionToolInitializationMode : : AutoFitAlign :
ApplyAction_AutoFit ( true ) ;
break ;
}
2019-10-01 20:41:42 -04:00
}
2021-05-31 22:15:32 -04:00
void UUVProjectionTool : : ApplyAction ( EUVProjectionToolActions ActionType )
{
switch ( ActionType )
{
case EUVProjectionToolActions : : AutoFit :
ApplyAction_AutoFit ( false ) ;
break ;
case EUVProjectionToolActions : : AutoFitAlign :
ApplyAction_AutoFit ( true ) ;
break ;
case EUVProjectionToolActions : : Reset :
ApplyAction_Reset ( ) ;
break ;
2021-12-02 15:04:36 -05:00
case EUVProjectionToolActions : : NoAction :
break ;
2021-05-31 22:15:32 -04:00
}
}
void UUVProjectionTool : : ApplyAction_AutoFit ( bool bAlign )
{
// get current transform
FFrame3d AlignFrame ( TransformGizmo - > GetGizmoTransform ( ) ) ;
TArray < FVector3d > Points ;
if ( VertexROI - > Num ( ) > 0 )
{
CollectVertexPositions ( * InputMesh , * VertexROI , Points ) ;
}
else
{
CollectVertexPositions ( * InputMesh , InputMesh - > VertexIndicesItr ( ) , Points ) ;
}
// auto-compute orientation if desired
if ( bAlign )
{
if ( BasicProperties - > ProjectionType = = EUVProjectionMethod : : Plane | | BasicProperties - > ProjectionType = = EUVProjectionMethod : : Box | | BasicProperties - > ProjectionType = = EUVProjectionMethod : : Cylinder )
{
// compute min-volume box
2021-08-26 09:31:28 -04:00
UE : : Geometry : : FOrientedBox3d MinBoundingBox ;
2021-05-31 22:15:32 -04:00
FMinVolumeBox3d MinBoxCalc ;
bool bMinBoxOK = MinBoxCalc . SolveSubsample ( Points . Num ( ) , 1000 ,
[ & ] ( int32 Index ) { return WorldTransform . TransformPosition ( Points [ Index ] ) ; } , false , nullptr ) ;
if ( bMinBoxOK & & MinBoxCalc . IsSolutionAvailable ( ) )
{
MinBoxCalc . GetResult ( MinBoundingBox ) ;
}
else
{
2021-08-26 09:31:28 -04:00
MinBoundingBox = UE : : Geometry : : FOrientedBox3d ( WorldBounds ) ;
2021-05-31 22:15:32 -04:00
}
AlignFrame = MinBoundingBox . Frame ;
}
else if ( BasicProperties - > ProjectionType = = EUVProjectionMethod : : ExpMap )
{
int32 VertexID ;
if ( TriangleROI - > Num ( ) > 0 )
{
FDynamicMeshUVEditor : : EstimateGeodesicCenterFrameVertex ( * InputMesh , * TriangleROI , AlignFrame , VertexID ) ;
AlignFrame . Transform ( WorldTransform ) ;
}
else
{
FDynamicMeshUVEditor : : EstimateGeodesicCenterFrameVertex ( * InputMesh , AlignFrame , VertexID ) ;
AlignFrame . Transform ( WorldTransform ) ;
}
}
}
// fit bounds to current frame
FAxisAlignedBox3d FitBounds = FAxisAlignedBox3d : : MakeBoundsFromIndices ( Points . Num ( ) , [ this , & Points , & AlignFrame ] ( int32 Index )
{
return AlignFrame . ToFramePoint ( WorldTransform . TransformPosition ( Points [ Index ] ) ) ; }
) ;
if ( BasicProperties - > ProjectionType = = EUVProjectionMethod : : Plane | | BasicProperties - > ProjectionType = = EUVProjectionMethod : : Box | | BasicProperties - > ProjectionType = = EUVProjectionMethod : : Cylinder )
{
FVector3d ShiftCenter = AlignFrame . FromFramePoint ( FitBounds . Center ( ) ) ;
AlignFrame . Origin = ShiftCenter ;
}
BasicProperties - > Dimensions = 2.0f * ( FVector ) FitBounds . Extents ( ) ;
if ( DimensionsWatcher > = 0 )
{
BasicProperties - > SilentUpdateWatcherAtIndex ( DimensionsWatcher ) ;
}
2021-12-02 15:04:36 -05:00
if ( DimensionsModeWatcher > = 0 )
{
BasicProperties - > SilentUpdateWatcherAtIndex ( DimensionsModeWatcher ) ;
}
2021-05-31 22:15:32 -04:00
// update Gizmo
TransformGizmo - > SetNewGizmoTransform ( AlignFrame . ToFTransform ( ) ) ;
}
void UUVProjectionTool : : ApplyAction_Reset ( )
{
bool bWasTransformModified = bTransformModified ;
ApplyInitializationMode ( ) ;
bTransformModified = bWasTransformModified ;
}
2019-10-01 20:41:42 -04:00
# undef LOCTEXT_NAMESPACE