2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
# include "DynamicMeshSculptTool.h"
2020-01-27 20:11:15 -05:00
# include "Containers/Map.h"
2021-01-20 00:15:28 -04:00
# include "Async/Async.h"
2019-10-01 20:41:42 -04:00
# include "InteractiveToolManager.h"
# include "InteractiveGizmoManager.h"
# include "ToolBuilderUtil.h"
# include "SubRegionRemesher.h"
# include "ProjectionTargets.h"
# include "MeshConstraints.h"
# include "MeshConstraintsUtil.h"
# include "MeshWeights.h"
2021-05-22 01:32:46 -04:00
# include "DynamicMesh/MeshNormals.h"
# include "DynamicMesh/MeshIndexUtil.h"
2019-10-01 20:41:42 -04:00
# include "Drawing/MeshDebugDrawing.h"
# include "PreviewMesh.h"
# include "ToolSetupUtil.h"
2019-11-11 16:57:51 -05:00
# include "ToolSceneQueriesUtil.h"
2021-06-11 22:42:32 -04:00
# include "ModelingToolTargetUtil.h"
2019-10-01 20:41:42 -04:00
# include "Changes/MeshVertexChange.h"
# include "Changes/MeshChange.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMeshChangeTracker.h"
2019-10-01 20:41:42 -04:00
2019-10-24 14:46:56 -04:00
# include "ToolDataVisualizer.h"
# include "Components/PrimitiveComponent.h"
# include "Generators/SphereGenerator.h"
2019-09-12 13:55:17 -04:00
2020-04-18 18:42:59 -04:00
# include "Sculpting/KelvinletBrushOp.h"
2019-11-05 17:20:52 -05:00
# include "InteractiveGizmoManager.h"
# include "BaseGizmos/GizmoComponents.h"
2021-05-20 16:39:39 -04:00
# include "BaseGizmos/TransformGizmoUtil.h"
2020-01-27 20:11:15 -05:00
# include "UObject/ObjectMacros.h"
2020-03-13 13:40:51 -04:00
# include "Materials/Material.h"
# include "Materials/MaterialInstanceDynamic.h"
2019-10-01 20:41:42 -04:00
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2019-10-01 20:41:42 -04:00
2021-03-09 19:33:56 -04:00
# define LOCTEXT_NAMESPACE "UDynamicMeshSculptTool"
2020-04-18 18:42:59 -04:00
2021-01-20 00:15:28 -04:00
namespace
{
// probably should be something defined for the whole tool framework...
# if WITH_EDITOR
static EAsyncExecution DynamicSculptToolAsyncExecTarget = EAsyncExecution : : LargeThreadPool ;
# else
static EAsyncExecution DynamicSculptToolAsyncExecTarget = EAsyncExecution : : ThreadPool ;
# endif
}
2020-04-18 18:42:59 -04:00
2019-10-01 20:41:42 -04:00
/*
* ToolBuilder
*/
UMeshSurfacePointTool * UDynamicMeshSculptToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
{
UDynamicMeshSculptTool * SculptTool = NewObject < UDynamicMeshSculptTool > ( SceneState . ToolManager ) ;
SculptTool - > SetEnableRemeshing ( this - > bEnableRemeshing ) ;
SculptTool - > SetWorld ( SceneState . World ) ;
return SculptTool ;
}
2020-03-10 16:59:50 -04:00
2021-01-20 00:15:28 -04:00
void UDynamicSculptToolActions : : DiscardAttributes ( )
{
ParentTool - > DiscardAttributes ( ) ;
}
2019-10-01 20:41:42 -04:00
/*
* Tool
*/
UDynamicMeshSculptTool : : UDynamicMeshSculptTool ( )
{
// initialize parameters
bEnableRemeshing = true ;
}
void UDynamicMeshSculptTool : : SetWorld ( UWorld * World )
{
this - > TargetWorld = World ;
}
2020-01-27 20:11:15 -05:00
namespace
{
2019-10-01 20:41:42 -04:00
const FString BrushIndicatorGizmoType = TEXT ( " BrushIndicatorGizmoType " ) ;
2020-01-27 20:11:15 -05:00
}
2019-10-01 20:41:42 -04:00
void UDynamicMeshSculptTool : : Setup ( )
{
UMeshSurfacePointTool : : Setup ( ) ;
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " DynaSculpt " ) ) ;
2019-10-01 20:41:42 -04:00
// create dynamic mesh component to use for live preview
2021-06-11 22:42:32 -04:00
DynamicMeshComponent = NewObject < UOctreeDynamicMeshComponent > ( UE : : ToolTarget : : GetTargetActor ( Target ) ) ;
2021-06-17 19:18:41 -04:00
DynamicMeshComponent - > SetShadowsEnabled ( false ) ;
2021-06-11 22:42:32 -04:00
DynamicMeshComponent - > SetupAttachment ( UE : : ToolTarget : : GetTargetActor ( Target ) - > GetRootComponent ( ) ) ;
2019-10-01 20:41:42 -04:00
DynamicMeshComponent - > RegisterComponent ( ) ;
2021-10-07 22:25:54 -04:00
ToolSetupUtil : : ApplyRenderingConfigurationToPreview ( DynamicMeshComponent , Target ) ;
2019-10-18 13:12:29 -04:00
// initialize from LOD-0 MeshDescription
2021-06-11 22:42:32 -04:00
DynamicMeshComponent - > SetMesh ( UE : : ToolTarget : : GetDynamicMeshCopy ( Target ) ) ;
2019-10-18 13:12:29 -04:00
// transform mesh to world space because handling scaling inside brush is a mess
2020-04-18 18:42:59 -04:00
// Note: this transform does not include translation ( so only the 3x3 transform)
2021-06-11 22:42:32 -04:00
InitialTargetTransform = UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
2019-10-18 13:12:29 -04:00
// clamp scaling because if we allow zero-scale we cannot invert this transform on Accept
InitialTargetTransform . ClampMinimumScale ( 0.01 ) ;
2019-10-31 15:35:28 -04:00
FVector3d Translation = InitialTargetTransform . GetTranslation ( ) ;
InitialTargetTransform . SetTranslation ( FVector3d : : Zero ( ) ) ;
2019-10-18 13:12:29 -04:00
DynamicMeshComponent - > ApplyTransform ( InitialTargetTransform , false ) ;
// since we moved to World coords there is not a current transform anymore.
2022-01-29 14:37:53 -05:00
CurTargetTransform = FTransformSRT3d ( Translation ) ;
2019-10-18 13:12:29 -04:00
DynamicMeshComponent - > SetWorldTransform ( ( FTransform ) CurTargetTransform ) ;
2019-10-01 20:41:42 -04:00
// copy material if there is one
2021-06-11 22:42:32 -04:00
FComponentMaterialSet MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Target ) ;
if ( MaterialSet . Materials . Num ( ) > 0 )
2019-10-01 20:41:42 -04:00
{
2021-06-11 22:42:32 -04:00
DynamicMeshComponent - > SetMaterial ( 0 , MaterialSet . Materials [ 0 ] ) ;
2019-10-01 20:41:42 -04:00
}
OnDynamicMeshComponentChangedHandle = DynamicMeshComponent - > OnMeshChanged . Add (
FSimpleMulticastDelegate : : FDelegate : : CreateUObject ( this , & UDynamicMeshSculptTool : : OnDynamicMeshComponentChanged ) ) ;
// do we always want to keep vertex normals updated? Perhaps should discard vertex normals before baking?
2019-10-18 13:12:29 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-01 20:41:42 -04:00
FMeshNormals : : QuickComputeVertexNormals ( * Mesh ) ;
// switch to vertex normals for testing
//DynamicMeshComponent->GetMesh()->DiscardAttributes();
2019-10-18 13:12:29 -04:00
// initialize target mesh
2019-10-01 20:41:42 -04:00
UpdateTarget ( ) ;
bTargetDirty = false ;
2021-01-20 00:15:28 -04:00
PendingTargetUpdate . Wait ( ) ;
2019-10-01 20:41:42 -04:00
2019-10-18 13:12:29 -04:00
// initialize brush radius range interval, brush properties
2021-08-23 22:08:34 -04:00
double MaxDimension = DynamicMeshComponent - > GetMesh ( ) - > GetBounds ( true ) . MaxDim ( ) ;
2019-10-01 20:41:42 -04:00
BrushRelativeSizeRange = FInterval1d ( MaxDimension * 0.01 , MaxDimension ) ;
2022-01-12 18:35:55 -05:00
BrushProperties = NewObject < UDynamicMeshBrushProperties > ( this ) ;
2021-10-28 13:24:28 -04:00
BrushProperties - > BrushSize . InitializeWorldSizeRange (
TInterval < float > ( ( float ) BrushRelativeSizeRange . Min , ( float ) BrushRelativeSizeRange . Max ) ) ;
2019-10-01 20:41:42 -04:00
CalculateBrushRadius ( ) ;
2019-10-18 13:12:29 -04:00
// initialize other properties
2022-01-12 18:35:55 -05:00
SculptProperties = NewObject < UDynamicMeshBrushSculptProperties > ( this ) ;
2020-04-18 18:42:59 -04:00
KelvinBrushProperties = NewObject < UKelvinBrushProperties > ( this ) ;
2020-01-27 20:11:15 -05:00
2020-03-13 13:40:51 -04:00
RemeshProperties = NewObject < UBrushRemeshProperties > ( this ) ;
2020-03-10 16:59:50 -04:00
RemeshProperties - > RestoreProperties ( this ) ;
2019-10-01 20:41:42 -04:00
InitialEdgeLength = EstimateIntialSafeTargetLength ( * Mesh , 5000 ) ;
2019-10-18 13:12:29 -04:00
// hide input Component
2021-06-11 22:42:32 -04:00
UE : : ToolTarget : : HideSourceObject ( Target ) ;
2019-10-01 20:41:42 -04:00
// init state flags flags
bInDrag = false ;
bHaveRemeshed = false ;
bRemeshPending = false ;
bStampPending = false ;
ActiveVertexChange = nullptr ;
// register and spawn brush indicator gizmo
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > RegisterGizmoType ( BrushIndicatorGizmoType , NewObject < UBrushStampIndicatorBuilder > ( ) ) ;
BrushIndicator = GetToolManager ( ) - > GetPairedGizmoManager ( ) - > CreateGizmo < UBrushStampIndicator > ( BrushIndicatorGizmoType , FString ( ) , this ) ;
2019-10-24 14:46:56 -04:00
BrushIndicatorMesh = MakeDefaultSphereMesh ( this , TargetWorld ) ;
2019-10-01 20:41:42 -04:00
BrushIndicator - > AttachedComponent = BrushIndicatorMesh - > GetRootComponent ( ) ;
2020-03-13 13:40:51 -04:00
BrushIndicator - > LineThickness = 1.0 ;
BrushIndicator - > bDrawIndicatorLines = true ;
BrushIndicator - > bDrawRadiusCircle = false ;
BrushIndicator - > LineColor = FLinearColor ( 0.9f , 0.4f , 0.4f ) ;
2019-10-01 20:41:42 -04:00
// initialize our properties
AddToolPropertySource ( BrushProperties ) ;
2020-03-13 13:40:51 -04:00
AddToolPropertySource ( SculptProperties ) ;
2020-03-19 10:59:23 -04:00
// add brush-specific properties
SculptMaxBrushProperties = NewObject < USculptMaxBrushProperties > ( ) ;
SculptMaxBrushProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( SculptMaxBrushProperties ) ;
2020-04-18 18:42:59 -04:00
AddToolPropertySource ( KelvinBrushProperties ) ;
KelvinBrushProperties - > RestoreProperties ( this ) ;
2020-03-19 10:59:23 -04:00
GizmoProperties = NewObject < UFixedPlaneBrushProperties > ( ) ;
GizmoProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( GizmoProperties ) ;
2019-10-01 20:41:42 -04:00
if ( this - > bEnableRemeshing )
{
2020-01-27 20:11:15 -05:00
SculptProperties - > bIsRemeshingEnabled = true ;
2019-10-01 20:41:42 -04:00
AddToolPropertySource ( RemeshProperties ) ;
2021-01-20 00:15:28 -04:00
SculptToolActions = NewObject < UDynamicSculptToolActions > ( ) ;
SculptToolActions - > Initialize ( this ) ;
AddToolPropertySource ( SculptToolActions ) ;
2019-10-01 20:41:42 -04:00
}
BrushProperties - > RestoreProperties ( this ) ;
CalculateBrushRadius ( ) ;
SculptProperties - > RestoreProperties ( this ) ;
2020-03-13 13:40:51 -04:00
// disable tool-specific properties
SetToolPropertySourceEnabled ( GizmoProperties , false ) ;
2020-03-19 10:59:23 -04:00
SetToolPropertySourceEnabled ( SculptMaxBrushProperties , false ) ;
2020-04-18 18:42:59 -04:00
SetToolPropertySourceEnabled ( KelvinBrushProperties , false ) ;
2020-03-13 13:40:51 -04:00
2019-10-01 20:41:42 -04:00
ViewProperties = NewObject < UMeshEditingViewProperties > ( ) ;
ViewProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( ViewProperties ) ;
2020-03-13 13:40:51 -04:00
// register watchers
2019-10-01 20:41:42 -04:00
ShowWireframeWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > bShowWireframe ; } ,
2020-03-13 13:40:51 -04:00
[ this ] ( bool bNewValue ) { DynamicMeshComponent - > bExplicitShowWireframe = bNewValue ; } , ViewProperties - > bShowWireframe ) ;
2019-10-01 20:41:42 -04:00
MaterialModeWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > MaterialMode ; } ,
[ this ] ( EMeshEditingMaterialModes NewMode ) { UpdateMaterialMode ( NewMode ) ; } , EMeshEditingMaterialModes : : ExistingMaterial ) ;
2021-04-01 17:33:33 -04:00
CustomMaterialWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > CustomMaterial ; } ,
[ this ] ( TWeakObjectPtr < UMaterialInterface > NewMaterial ) { UpdateCustomMaterial ( NewMaterial ) ; } , ViewProperties - > CustomMaterial ) ;
2020-03-13 13:40:51 -04:00
FlatShadingWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > bFlatShading ; } ,
[ this ] ( bool bNewValue ) { UpdateFlatShadingSetting ( bNewValue ) ; } , ViewProperties - > bFlatShading ) ;
ColorWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > Color ; } ,
[ this ] ( FLinearColor NewColor ) { UpdateColorSetting ( NewColor ) ; } , ViewProperties - > Color ) ;
ImageWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > Image ; } ,
[ this ] ( UTexture2D * NewImage ) { UpdateImageSetting ( NewImage ) ; } , ViewProperties - > Image ) ;
2021-04-01 17:33:33 -04:00
TransparentColorWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > TransparentMaterialColor ; } ,
[ this ] ( FLinearColor NewColor ) { UpdateColorSetting ( NewColor ) ; } , ViewProperties - > TransparentMaterialColor ) ;
OpacityWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > Opacity ; } ,
[ this ] ( double Opacity ) { UpdateOpacitySetting ( Opacity ) ; } , ViewProperties - > Opacity ) ;
TwoSidedWatcher . Initialize (
[ this ] ( ) { return ViewProperties - > bTwoSided ; } ,
[ this ] ( bool bOn ) { UpdateTwoSidedSetting ( bOn ) ; } , ViewProperties - > bTwoSided ) ;
2020-03-13 13:40:51 -04:00
BrushTypeWatcher . Initialize (
[ this ] ( ) { return SculptProperties - > PrimaryBrushType ; } ,
[ this ] ( EDynamicMeshSculptBrushType NewBrushType ) { UpdateBrushType ( NewBrushType ) ; } , SculptProperties - > PrimaryBrushType ) ;
GizmoPositionWatcher . Initialize (
[ this ] ( ) { return GizmoProperties - > Position ; } ,
[ this ] ( FVector NewPosition ) { UpdateGizmoFromProperties ( ) ; } , GizmoProperties - > Position ) ;
GizmoRotationWatcher . Initialize (
[ this ] ( ) { return GizmoProperties - > Rotation ; } ,
[ this ] ( FQuat NewRotation ) { UpdateGizmoFromProperties ( ) ; } , GizmoProperties - > Rotation ) ;
2021-10-08 10:28:45 -04:00
DynamicMeshComponent - > bExplicitShowWireframe = ViewProperties - > bShowWireframe ;
2019-10-01 20:41:42 -04:00
2019-11-05 17:20:52 -05:00
// create proxy for plane gizmo, but not gizmo itself, as it only appears in FixedPlane brush mode
// listen for changes to the proxy and update the plane when that happens
PlaneTransformProxy = NewObject < UTransformProxy > ( this ) ;
PlaneTransformProxy - > OnTransformChanged . AddUObject ( this , & UDynamicMeshSculptTool : : PlaneTransformChanged ) ;
2019-10-01 20:41:42 -04:00
if ( bEnableRemeshing )
{
PrecomputeRemeshInfo ( ) ;
if ( bHaveUVSeams )
{
GetToolManager ( ) - > DisplayMessage (
2021-10-01 08:21:22 -04:00
LOCTEXT ( " UVSeamWarning " , " This mesh has UV seams which may limit remeshing. Consider clearing the UV layers using \" Discard Attributes \" or the Remesh Tool. " ) ,
2019-10-01 20:41:42 -04:00
EToolMessageLevel : : UserWarning ) ;
2020-01-27 20:11:15 -05:00
}
2019-10-01 20:41:42 -04:00
else if ( bHaveNormalSeams )
{
GetToolManager ( ) - > DisplayMessage (
2021-10-01 08:21:22 -04:00
LOCTEXT ( " NormalSeamWarning " , " This mesh has Hard Normal seams which may limit remeshing. Consider clearing Hard Normals using \" Discard Attributes, \" or the Remesh or Normals Tool. " ) ,
2019-10-01 20:41:42 -04:00
EToolMessageLevel : : UserWarning ) ;
}
}
2020-03-13 13:40:51 -04:00
UpdateBrushType ( SculptProperties - > PrimaryBrushType ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : Shutdown ( EToolShutdownType ShutdownType )
{
2020-11-24 18:42:39 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept & & AreAllTargetsValid ( ) = = false )
{
UE_LOG ( LogTemp , Error , TEXT ( " Tool Target has become Invalid (possibly it has been Force Deleted). Aborting Tool. " ) ) ;
ShutdownType = EToolShutdownType : : Cancel ;
}
2019-10-01 20:41:42 -04:00
BrushIndicatorMesh - > Disconnect ( ) ;
BrushIndicatorMesh = nullptr ;
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DestroyAllGizmosByOwner ( this ) ;
BrushIndicator = nullptr ;
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DeregisterGizmoType ( BrushIndicatorGizmoType ) ;
if ( DynamicMeshComponent ! = nullptr )
{
DynamicMeshComponent - > OnMeshChanged . Remove ( OnDynamicMeshComponentChangedHandle ) ;
2021-06-11 22:42:32 -04:00
UE : : ToolTarget : : ShowSourceObject ( Target ) ;
2019-10-01 20:41:42 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
2019-10-18 13:12:29 -04:00
// safe to do this here because we are about to destroy componeont
DynamicMeshComponent - > ApplyTransform ( InitialTargetTransform , true ) ;
2019-10-01 20:41:42 -04:00
// this block bakes the modified DynamicMeshComponent back into the StaticMeshComponent inside an undo transaction
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " SculptMeshToolTransactionName " , " Sculpt Mesh " ) ) ;
2021-06-11 22:42:32 -04:00
DynamicMeshComponent - > ProcessMesh ( [ & ] ( const FDynamicMesh3 & ReadMesh )
2019-10-01 20:41:42 -04:00
{
2021-06-11 22:42:32 -04:00
UE : : ToolTarget : : CommitDynamicMeshUpdate ( Target , ReadMesh , bHaveRemeshed ) ;
2019-10-01 20:41:42 -04:00
} ) ;
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
DynamicMeshComponent - > UnregisterComponent ( ) ;
DynamicMeshComponent - > DestroyComponent ( ) ;
DynamicMeshComponent = nullptr ;
}
BrushProperties - > SaveProperties ( this ) ;
SculptProperties - > SaveProperties ( this ) ;
2020-04-18 18:42:59 -04:00
KelvinBrushProperties - > SaveProperties ( this ) ;
2019-10-01 20:41:42 -04:00
ViewProperties - > SaveProperties ( this ) ;
2019-11-05 20:26:40 -05:00
GizmoProperties - > SaveProperties ( this ) ;
2020-03-19 10:59:23 -04:00
SculptMaxBrushProperties - > SaveProperties ( this ) ;
2020-03-10 16:59:50 -04:00
RemeshProperties - > SaveProperties ( this ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : OnDynamicMeshComponentChanged ( )
{
bNormalUpdatePending = true ;
bTargetDirty = true ;
}
2020-01-07 15:54:23 -05:00
void UDynamicMeshSculptTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
2019-10-01 20:41:42 -04:00
{
CalculateBrushRadius ( ) ;
}
bool UDynamicMeshSculptTool : : HitTest ( const FRay & Ray , FHitResult & OutHit )
{
2021-03-30 21:25:22 -04:00
FRay3d LocalRay ( CurTargetTransform . InverseTransformPosition ( ( FVector3d ) Ray . Origin ) ,
CurTargetTransform . InverseTransformVector ( ( FVector3d ) Ray . Direction ) ) ;
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( LocalRay . Direction ) ;
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2020-01-27 20:11:15 -05:00
2019-11-03 22:43:57 -05:00
int HitTID = FindHitSculptMeshTriangle ( LocalRay ) ;
2019-10-01 20:41:42 -04:00
if ( HitTID ! = IndexConstants : : InvalidID )
{
FTriangle3d Triangle ;
Mesh - > GetTriVertices ( HitTID , Triangle . V [ 0 ] , Triangle . V [ 1 ] , Triangle . V [ 2 ] ) ;
FIntrRay3Triangle3d Query ( LocalRay , Triangle ) ;
Query . Find ( ) ;
OutHit . FaceIndex = HitTID ;
OutHit . Distance = Query . RayParameter ;
2019-10-18 13:12:29 -04:00
OutHit . Normal = ( FVector ) CurTargetTransform . TransformNormal ( Mesh - > GetTriNormal ( HitTID ) ) ;
OutHit . ImpactPoint = ( FVector ) CurTargetTransform . TransformPosition ( LocalRay . PointAt ( Query . RayParameter ) ) ;
2019-10-01 20:41:42 -04:00
return true ;
}
return false ;
}
void UDynamicMeshSculptTool : : OnBeginDrag ( const FRay & Ray )
{
bSmoothing = GetShiftToggle ( ) ;
bInvert = GetCtrlToggle ( ) ;
FHitResult OutHit ;
if ( HitTest ( Ray , OutHit ) )
{
2021-03-30 21:25:22 -04:00
BrushStartCenterWorld = ( FVector3d ) Ray . PointAt ( OutHit . Distance ) + ( double ) BrushProperties - > Depth * CurrentBrushRadius * ( FVector3d ) Ray . Direction ;
2019-10-01 20:41:42 -04:00
bInDrag = true ;
2021-03-30 21:25:22 -04:00
ActiveDragPlane = FFrame3d ( BrushStartCenterWorld , - ( FVector3d ) Ray . Direction ) ;
ActiveDragPlane . RayPlaneIntersection ( ( FVector3d ) Ray . Origin , ( FVector3d ) Ray . Direction , 2 , LastHitPosWorld ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosWorld = LastHitPosWorld ;
2019-10-18 13:12:29 -04:00
LastBrushPosNormalWorld = ActiveDragPlane . Z ( ) ;
LastBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastHitPosWorld ) ;
2019-10-18 13:04:19 -04:00
LastSmoothBrushPosLocal = LastBrushPosLocal ;
2019-10-01 20:41:42 -04:00
BeginChange ( bEnableRemeshing = = false ) ;
UpdateROI ( LastBrushPosLocal ) ;
if ( SculptProperties - > PrimaryBrushType = = EDynamicMeshSculptBrushType : : Plane )
{
2020-03-13 13:40:51 -04:00
ActiveFixedBrushPlane = ComputeROIBrushPlane ( LastBrushPosLocal , false , false ) ;
}
else if ( SculptProperties - > PrimaryBrushType = = EDynamicMeshSculptBrushType : : PlaneViewAligned )
{
AlignBrushToView ( ) ;
ActiveFixedBrushPlane = ComputeROIBrushPlane ( LastBrushPosLocal , false , true ) ;
2019-10-01 20:41:42 -04:00
}
// apply initial stamp
PendingStampRay = Ray ;
bStampPending = true ;
}
}
2021-01-27 01:53:01 -04:00
2019-12-19 18:07:47 -05:00
void UDynamicMeshSculptTool : : UpdateROI ( const FVector3d & BrushPos )
2019-10-01 20:41:42 -04:00
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateROI ) ;
2019-10-01 20:41:42 -04:00
float RadiusSqr = CurrentBrushRadius * CurrentBrushRadius ;
FAxisAlignedBox3d BrushBox (
BrushPos - CurrentBrushRadius * FVector3d : : One ( ) ,
BrushPos + CurrentBrushRadius * FVector3d : : One ( ) ) ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FDynamicMeshOctree3 * Octree = DynamicMeshComponent - > GetOctree ( ) ;
2021-01-27 01:53:01 -04:00
// find set of triangles in brush bounding box
UpdateROITriBuffer . Reset ( ) ;
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateROI_1RangeQuery ) ;
Octree - > ParallelRangeQuery ( BrushBox , UpdateROITriBuffer ) ;
}
// collect set of vertices inside brush sphere, from that box
VertexROIBuilder . Initialize ( Mesh - > MaxVertexID ( ) ) ;
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateROI_2Collect ) ;
for ( int32 TriIdx : UpdateROITriBuffer )
2019-10-01 20:41:42 -04:00
{
2021-01-27 01:53:01 -04:00
FIndex3i TriV = Mesh - > GetTriangle ( TriIdx ) ;
for ( int j = 0 ; j < 3 ; + + j )
2019-10-01 20:41:42 -04:00
{
2021-01-27 01:53:01 -04:00
if ( VertexROIBuilder . Contains ( TriV [ j ] ) = = false )
{
//const FVector3d& Position = Mesh->GetVertexRef(TriV[j]);
FVector3d Position = Mesh - > GetVertex ( TriV [ j ] ) ;
2021-03-30 21:25:22 -04:00
if ( DistanceSquared ( BrushPos , Position ) < RadiusSqr )
2021-01-27 01:53:01 -04:00
{
VertexROIBuilder . Add ( TriV [ j ] ) ;
}
}
2019-10-01 20:41:42 -04:00
}
}
2021-01-27 01:53:01 -04:00
VertexROI . Reset ( ) ;
VertexROIBuilder . SwapValuesWith ( VertexROI ) ;
}
2019-10-01 20:41:42 -04:00
2021-01-27 01:53:01 -04:00
// find triangle ROI as full one-rings of all vertices (this is surprisingly expensive...)
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateROI_3TriangleROI ) ;
TriangleROIBuilder . Initialize ( Mesh - > MaxTriangleID ( ) ) ;
for ( int32 vid : VertexROI )
{
Mesh - > EnumerateVertexEdges ( vid , [ & ] ( int32 eid )
{
FDynamicMesh3 : : FEdge Edge = Mesh - > GetEdge ( eid ) ;
TriangleROIBuilder . Add ( Edge . Tri . A ) ;
if ( Edge . Tri . B ! = IndexConstants : : InvalidID ) TriangleROIBuilder . Add ( Edge . Tri . B ) ;
} ) ;
}
TriangleROI . Reset ( ) ;
TriangleROIBuilder . Collect ( TriangleROI ) ;
}
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : OnUpdateDrag ( const FRay & WorldRay )
{
if ( bInDrag )
{
PendingStampRay = WorldRay ;
bStampPending = true ;
}
}
void UDynamicMeshSculptTool : : CalculateBrushRadius ( )
{
2021-10-28 13:24:28 -04:00
CurrentBrushRadius = BrushProperties - > BrushSize . GetWorldRadius ( ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : ApplyStamp ( const FRay & WorldRay )
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_ApplyStamp ) ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FDynamicMeshOctree3 * Octree = DynamicMeshComponent - > GetOctree ( ) ;
2019-10-01 20:41:42 -04:00
2020-01-27 20:11:15 -05:00
// update brush type history. apologies for convoluted logic.
2019-10-01 20:41:42 -04:00
StampTimestamp + + ;
if ( LastStampType ! = PendingStampType )
{
if ( BrushTypeHistoryIndex ! = BrushTypeHistory . Num ( ) - 1 )
{
if ( LastStampType ! = EDynamicMeshSculptBrushType : : LastValue )
{
BrushTypeHistory . Add ( LastStampType ) ;
}
BrushTypeHistoryIndex = BrushTypeHistory . Num ( ) - 1 ;
}
LastStampType = PendingStampType ;
if ( BrushTypeHistory . Num ( ) = = 0 | | BrushTypeHistory [ BrushTypeHistory . Num ( ) - 1 ] ! = PendingStampType )
{
BrushTypeHistory . Add ( PendingStampType ) ;
BrushTypeHistoryIndex = BrushTypeHistory . Num ( ) - 1 ;
}
}
CalculateBrushRadius ( ) ;
2021-01-27 01:53:01 -04:00
TFuture < void > DirtyOctreeFuture = Async ( DynamicSculptToolAsyncExecTarget , [ & ] ( )
2019-10-01 20:41:42 -04:00
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_ApplyStamp_DirtyOctree ) ;
Octree - > NotifyPendingModification ( TriangleROI ) ;
} ) ;
2019-10-01 20:41:42 -04:00
2021-01-27 01:53:01 -04:00
TFuture < void > SaveROIFuture = Async ( DynamicSculptToolAsyncExecTarget , [ & ] ( )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_ApplyStamp_SaveActiveROI ) ;
SaveActiveROI ( ) ;
} ) ;
// TODO:
// - we can begin Octree->RemoveTriangles below as soon as we have (1) finished
// marking dirty box in DirtyOctreeFuture and (2) updated brush position. Unfortunately
// right now that happens inside each brush func :(
EDynamicMeshSculptBrushType ApplyBrushType = ( bSmoothing ) ?
EDynamicMeshSculptBrushType : : Smooth : SculptProperties - > PrimaryBrushType ;
bool bBrushApplied = false ;
switch ( ApplyBrushType )
2019-10-01 20:41:42 -04:00
{
case EDynamicMeshSculptBrushType : : Offset :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyOffsetBrush ( WorldRay , false ) ;
2020-03-13 13:40:51 -04:00
break ;
case EDynamicMeshSculptBrushType : : SculptView :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyOffsetBrush ( WorldRay , true ) ;
2019-10-01 20:41:42 -04:00
break ;
case EDynamicMeshSculptBrushType : : SculptMax :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplySculptMaxBrush ( WorldRay ) ;
2019-10-01 20:41:42 -04:00
break ;
case EDynamicMeshSculptBrushType : : Move :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyMoveBrush ( WorldRay ) ;
2019-10-01 20:41:42 -04:00
break ;
2020-04-18 18:42:59 -04:00
case EDynamicMeshSculptBrushType : : PullKelvin :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyPullKelvinBrush ( WorldRay ) ;
2020-04-18 18:42:59 -04:00
break ;
case EDynamicMeshSculptBrushType : : PullSharpKelvin :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyPullSharpKelvinBrush ( WorldRay ) ;
2020-04-18 18:42:59 -04:00
break ;
2019-10-18 13:04:19 -04:00
case EDynamicMeshSculptBrushType : : Smooth :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplySmoothBrush ( WorldRay ) ;
2019-10-18 13:04:19 -04:00
break ;
2019-10-01 20:41:42 -04:00
case EDynamicMeshSculptBrushType : : Pinch :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyPinchBrush ( WorldRay ) ;
2019-10-01 20:41:42 -04:00
break ;
2020-04-18 18:42:59 -04:00
case EDynamicMeshSculptBrushType : : TwistKelvin :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyTwistKelvinBrush ( WorldRay ) ;
2020-04-18 18:42:59 -04:00
break ;
2019-10-01 20:41:42 -04:00
case EDynamicMeshSculptBrushType : : Inflate :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyInflateBrush ( WorldRay ) ;
2019-10-01 20:41:42 -04:00
break ;
2020-04-18 18:42:59 -04:00
case EDynamicMeshSculptBrushType : : ScaleKelvin :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyScaleKelvinBrush ( WorldRay ) ;
2020-04-18 18:42:59 -04:00
break ;
2019-10-01 20:41:42 -04:00
case EDynamicMeshSculptBrushType : : Flatten :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyFlattenBrush ( WorldRay ) ;
2019-10-01 20:41:42 -04:00
break ;
case EDynamicMeshSculptBrushType : : Plane :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyPlaneBrush ( WorldRay ) ;
2019-10-01 20:41:42 -04:00
break ;
2020-03-13 13:40:51 -04:00
case EDynamicMeshSculptBrushType : : PlaneViewAligned :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyPlaneBrush ( WorldRay ) ;
2020-03-13 13:40:51 -04:00
break ;
2019-11-05 17:20:52 -05:00
case EDynamicMeshSculptBrushType : : FixedPlane :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyFixedPlaneBrush ( WorldRay ) ;
2019-11-05 17:20:52 -05:00
break ;
2020-03-17 22:32:24 -04:00
case EDynamicMeshSculptBrushType : : Resample :
2021-01-27 01:53:01 -04:00
bBrushApplied = ApplyResampleBrush ( WorldRay ) ;
2020-03-17 22:32:24 -04:00
break ;
2020-01-27 20:11:15 -05:00
case EDynamicMeshSculptBrushType : : LastValue :
break ;
2019-10-01 20:41:42 -04:00
}
2021-01-27 01:53:01 -04:00
// wait for ROI to finish saving before we update positions
SaveROIFuture . Wait ( ) ;
DirtyOctreeFuture . Wait ( ) ;
// we are going to reinsert these later
TFuture < void > OctreeRemoveFuture = Async ( DynamicSculptToolAsyncExecTarget , [ & ] ( )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_ApplyStamp_OctreeRemove ) ;
Octree - > RemoveTriangles ( TriangleROI , false ) ; // already marked dirty above
} ) ;
// Update the mesh positions to match those in the position buffer
if ( bBrushApplied )
{
SyncMeshWithPositionBuffer ( Mesh ) ;
}
// we don't stricty have to wait here, we could return this future
OctreeRemoveFuture . Wait ( ) ;
2019-10-01 20:41:42 -04:00
}
double UDynamicMeshSculptTool : : CalculateBrushFalloff ( double Distance )
{
2020-03-13 13:40:51 -04:00
double f = FMathd : : Clamp ( 1.0 - BrushProperties - > BrushFalloffAmount , 0.0 , 1.0 ) ;
2019-10-01 20:41:42 -04:00
double d = Distance / CurrentBrushRadius ;
double w = 1 ;
2020-03-13 13:40:51 -04:00
if ( d > f )
2019-10-01 20:41:42 -04:00
{
2020-03-13 13:40:51 -04:00
d = FMathd : : Clamp ( ( d - f ) / ( 1.0 - f ) , 0.0 , 1.0 ) ;
w = ( 1.0 - d * d ) ;
2019-10-01 20:41:42 -04:00
w = w * w * w ;
}
return w ;
}
2020-04-18 18:42:59 -04:00
void UDynamicMeshSculptTool : : SyncMeshWithPositionBuffer ( FDynamicMesh3 * Mesh )
{
const int NumV = ROIPositionBuffer . Num ( ) ;
checkSlow ( VertexROI . Num ( ) < = NumV ) ;
2021-01-27 01:53:01 -04:00
// only if remeshing is disabled?
if ( ActiveVertexChange ! = nullptr )
{
for ( int k = 0 ; k < NumV ; + + k )
{
int VertIdx = VertexROI [ k ] ;
ActiveVertexChange - > UpdateVertex ( VertIdx , Mesh - > GetVertex ( VertIdx ) , ROIPositionBuffer [ k ] ) ;
}
}
ParallelFor ( NumV , [ & ] ( int32 k )
2020-04-18 18:42:59 -04:00
{
int VertIdx = VertexROI [ k ] ;
const FVector3d & NewPos = ROIPositionBuffer [ k ] ;
GeometryProcessing: clean up mesh timestamps.
- remove FDynamicMesh3::Timestamp (unused), rename Shape/Topology Timestamps to Shape/TopologyChangeStamp, change to atomic<uint32>
- add FDynamicMesh3::bEnableShapeChangeStamp, default to false, to disable ShapeChange tracking. Add ::SetShapeChangeStampEnabled() and ::HasShapeChangeStampEnabled() to configure.
- replace FDynamicMesh3::UpdateTimestamps() with UpdateChangeStamps()
- add bTrackChange param to FDynamicMesh3::SetVertex(), optionally updates ShapeChangeStamp (if enabled). Default true. Remove SetVertex_NoTimeStampUpdate(), update call sites.
- add FDynamicMesh3::GetChangeStamp(), returns combination of Shape and Topology stamps as uint64
- rename TTriangleMeshAdapter::GetTimestamp() to GetChangeStamp(), update usages
- remove TPointSetAdapter::Timestamp() (was not used in code)
- update TMeshAABBTree3 to use GetChangeStamp(), update internal checks to call IsValid() instead
- update TFastWindingTree w/ similar changes
- update calls in UVEditor, may require further updates
#rb semion.piskarev
#rnx
#jira none
#preflight 6126904c72e9eb00011434fe
#ROBOMERGE-SOURCE: CL 17310271 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v861-17282326)
[CL 17315112 by ryan schmidt in ue5-release-engine-test branch]
2021-08-26 06:57:55 -04:00
Mesh - > SetVertex ( VertIdx , NewPos , false ) ;
2021-01-27 01:53:01 -04:00
} ) ;
GeometryProcessing: clean up mesh timestamps.
- remove FDynamicMesh3::Timestamp (unused), rename Shape/Topology Timestamps to Shape/TopologyChangeStamp, change to atomic<uint32>
- add FDynamicMesh3::bEnableShapeChangeStamp, default to false, to disable ShapeChange tracking. Add ::SetShapeChangeStampEnabled() and ::HasShapeChangeStampEnabled() to configure.
- replace FDynamicMesh3::UpdateTimestamps() with UpdateChangeStamps()
- add bTrackChange param to FDynamicMesh3::SetVertex(), optionally updates ShapeChangeStamp (if enabled). Default true. Remove SetVertex_NoTimeStampUpdate(), update call sites.
- add FDynamicMesh3::GetChangeStamp(), returns combination of Shape and Topology stamps as uint64
- rename TTriangleMeshAdapter::GetTimestamp() to GetChangeStamp(), update usages
- remove TPointSetAdapter::Timestamp() (was not used in code)
- update TMeshAABBTree3 to use GetChangeStamp(), update internal checks to call IsValid() instead
- update TFastWindingTree w/ similar changes
- update calls in UVEditor, may require further updates
#rb semion.piskarev
#rnx
#jira none
#preflight 6126904c72e9eb00011434fe
#ROBOMERGE-SOURCE: CL 17310271 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v861-17282326)
[CL 17315112 by ryan schmidt in ue5-release-engine-test branch]
2021-08-26 06:57:55 -04:00
Mesh - > UpdateChangeStamps ( true , false ) ;
2020-04-18 18:42:59 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplySmoothBrush ( const FRay & WorldRay )
2019-10-01 20:41:42 -04:00
{
2020-03-19 10:59:23 -04:00
bool bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , true ) ;
2019-10-01 20:41:42 -04:00
if ( bHit = = false )
{
2021-01-27 01:53:01 -04:00
return false ;
2019-10-01 20:41:42 -04:00
}
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-18 13:04:19 -04:00
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
ParallelFor ( NumV , [ this , Mesh , NewBrushPosLocal ] ( int k )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:04:19 -04:00
int VertIdx = VertexROI [ k ] ;
2019-10-01 20:41:42 -04:00
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( OrigPos , NewBrushPosLocal ) ) ;
2019-10-01 20:41:42 -04:00
FVector3d SmoothedPos = ( SculptProperties - > bPreserveUVFlow ) ?
2020-04-29 21:57:36 -04:00
FMeshWeights : : CotanCentroidSafe ( * Mesh , VertIdx , 10.0 ) : FMeshWeights : : UniformCentroid ( * Mesh , VertIdx ) ;
2019-10-01 20:41:42 -04:00
2021-03-17 19:32:44 -04:00
FVector3d NewPos = UE : : Geometry : : Lerp ( OrigPos , SmoothedPos , Falloff * SculptProperties - > SmoothBrushSpeed ) ;
2019-10-01 20:41:42 -04:00
2019-10-18 13:04:19 -04:00
ROIPositionBuffer [ k ] = NewPos ;
} ) ;
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyMoveBrush ( const FRay & WorldRay )
2019-10-01 20:41:42 -04:00
{
2020-04-18 18:42:59 -04:00
UpdateBrushPositionOnActivePlane ( WorldRay ) ;
2019-10-01 20:41:42 -04:00
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
2019-10-01 20:41:42 -04:00
FVector3d MoveVec = NewBrushPosLocal - LastBrushPosLocal ;
2019-10-18 13:04:19 -04:00
if ( MoveVec . SquaredLength ( ) < = 0 )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:12:29 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return false ;
2019-10-01 20:41:42 -04:00
}
2019-10-18 13:04:19 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
ParallelFor ( NumV , [ this , Mesh , NewBrushPosLocal , MoveVec ] ( int k )
{
int VertIdx = VertexROI [ k ] ;
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
double PrevDist = ( OrigPos - LastBrushPosLocal ) . Length ( ) ;
double NewDist = ( OrigPos - NewBrushPosLocal ) . Length ( ) ;
double UseDist = FMath : : Min ( PrevDist , NewDist ) ;
2019-12-19 18:07:47 -05:00
double Falloff = CalculateBrushFalloff ( UseDist ) * ActivePressure ;
2019-10-18 13:04:19 -04:00
FVector3d NewPos = OrigPos + Falloff * MoveVec ;
ROIPositionBuffer [ k ] = NewPos ;
} ) ;
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyOffsetBrush ( const FRay & WorldRay , bool bUseViewDirection )
2019-10-01 20:41:42 -04:00
{
2020-03-19 10:59:23 -04:00
UpdateBrushPositionOnTargetMesh ( WorldRay , bUseViewDirection ) ;
2020-03-13 13:40:51 -04:00
if ( bUseViewDirection )
{
AlignBrushToView ( ) ;
}
2019-10-01 20:41:42 -04:00
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
2020-03-13 13:40:51 -04:00
FVector3d LocalNormal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
2019-10-01 20:41:42 -04:00
double Direction = ( bInvert ) ? - 1.0 : 1.0 ;
2020-03-26 17:20:25 -04:00
double UseSpeed = 0.5 * Direction * FMathd : : Sqrt ( CurrentBrushRadius ) * ( SculptProperties - > PrimaryBrushSpeed ) * ActivePressure ;
2020-03-19 10:59:23 -04:00
double MaxOffset = CurrentBrushRadius ;
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-18 13:04:19 -04:00
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
2020-03-13 13:40:51 -04:00
ParallelFor ( NumV , [ & ] ( int k )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:04:19 -04:00
int VertIdx = VertexROI [ k ] ;
2019-10-01 20:41:42 -04:00
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
FVector3d BasePos , BaseNormal ;
2019-10-25 13:34:18 -04:00
if ( GetTargetMeshNearest ( OrigPos , ( double ) ( 4 * CurrentBrushRadius ) , BasePos , BaseNormal ) = = false )
{
ROIPositionBuffer [ k ] = OrigPos ;
}
else
{
2020-03-13 13:40:51 -04:00
FVector3d MoveVec = ( bUseViewDirection ) ? ( UseSpeed * LocalNormal ) : ( UseSpeed * BaseNormal ) ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( OrigPos , NewBrushPosLocal ) ) ;
2019-10-25 13:34:18 -04:00
FVector3d NewPos = OrigPos + Falloff * MoveVec ;
ROIPositionBuffer [ k ] = NewPos ;
}
2019-10-18 13:04:19 -04:00
} ) ;
2019-10-01 20:41:42 -04:00
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplySculptMaxBrush ( const FRay & WorldRay )
2019-10-01 20:41:42 -04:00
{
2020-03-19 10:59:23 -04:00
UpdateBrushPositionOnTargetMesh ( WorldRay , true ) ;
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
2019-10-01 20:41:42 -04:00
double Direction = ( bInvert ) ? - 1.0 : 1.0 ;
2020-01-27 20:11:15 -05:00
double UseSpeed = Direction * FMathd : : Sqrt ( CurrentBrushRadius ) * ( SculptProperties - > PrimaryBrushSpeed ) * ActivePressure ;
2020-03-19 10:59:23 -04:00
double MaxOffset = CurrentBrushRadius * SculptMaxBrushProperties - > MaxHeight ;
if ( SculptMaxBrushProperties - > bFreezeCurrentHeight & & SculptMaxFixedHeight > = 0 )
{
MaxOffset = SculptMaxFixedHeight ;
}
SculptMaxFixedHeight = MaxOffset ;
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-18 13:04:19 -04:00
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
ParallelFor ( NumV , [ this , Mesh , NewBrushPosLocal , UseSpeed , MaxOffset ] ( int k )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:04:19 -04:00
int VertIdx = VertexROI [ k ] ;
2019-10-01 20:41:42 -04:00
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
FVector3d BasePos , BaseNormal ;
2019-10-25 13:34:18 -04:00
if ( GetTargetMeshNearest ( OrigPos , ( double ) ( 2 * CurrentBrushRadius ) , BasePos , BaseNormal ) = = false )
2019-10-01 20:41:42 -04:00
{
2019-10-25 13:34:18 -04:00
ROIPositionBuffer [ k ] = OrigPos ;
2019-10-01 20:41:42 -04:00
}
2019-10-25 13:34:18 -04:00
else
{
FVector3d MoveVec = UseSpeed * BaseNormal ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( OrigPos , NewBrushPosLocal ) ) ;
2019-10-25 13:34:18 -04:00
FVector3d NewPos = OrigPos + Falloff * MoveVec ;
2019-10-01 20:41:42 -04:00
2019-10-25 13:34:18 -04:00
FVector3d DeltaPos = NewPos - BasePos ;
if ( DeltaPos . SquaredLength ( ) > MaxOffset * MaxOffset )
{
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( DeltaPos ) ;
2019-10-25 13:34:18 -04:00
NewPos = BasePos + MaxOffset * DeltaPos ;
}
ROIPositionBuffer [ k ] = NewPos ;
}
2019-10-18 13:04:19 -04:00
} ) ;
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyPinchBrush ( const FRay & WorldRay )
2019-10-01 20:41:42 -04:00
{
2020-03-19 10:59:23 -04:00
UpdateBrushPositionOnTargetMesh ( WorldRay , true ) ;
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
2020-03-13 13:40:51 -04:00
FVector3d OffsetBrushPosLocal = NewBrushPosLocal - BrushProperties - > Depth * CurrentBrushRadius * BrushNormalLocal ;
2019-10-01 20:41:42 -04:00
2019-10-18 13:04:19 -04:00
// hardcoded lazybrush...
2019-10-18 13:12:29 -04:00
FVector3d NewSmoothBrushPosLocal = ( 0.75f ) * LastSmoothBrushPosLocal + ( 0.25f ) * NewBrushPosLocal ;
2019-10-01 20:41:42 -04:00
2019-10-18 13:04:19 -04:00
double Direction = ( bInvert ) ? - 1.0 : 1.0 ;
2020-01-27 20:11:15 -05:00
double UseSpeed = Direction * FMathd : : Sqrt ( CurrentBrushRadius ) * ( SculptProperties - > PrimaryBrushSpeed * 0.05 ) * ActivePressure ;
2019-10-18 13:04:19 -04:00
FVector3d MotionVec = NewSmoothBrushPosLocal - LastSmoothBrushPosLocal ;
bool bHaveMotion = ( MotionVec . Length ( ) > FMathf : : ZeroTolerance ) ;
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( MotionVec ) ;
2019-10-18 13:04:19 -04:00
FLine3d MoveLine ( LastSmoothBrushPosLocal , MotionVec ) ;
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-18 13:04:19 -04:00
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
ParallelFor ( NumV , [ this , Mesh , NewBrushPosLocal , OffsetBrushPosLocal , bHaveMotion , MotionVec , UseSpeed ] ( int k )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:04:19 -04:00
int VertIdx = VertexROI [ k ] ;
2019-10-01 20:41:42 -04:00
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
FVector3d Delta = OffsetBrushPosLocal - OrigPos ;
2019-10-18 13:04:19 -04:00
2019-10-01 20:41:42 -04:00
FVector3d MoveVec = UseSpeed * Delta ;
2020-01-27 20:11:15 -05:00
// pinch uses 1/x falloff, shifted so that
2021-03-30 21:25:22 -04:00
double Dist = Distance ( OrigPos , NewBrushPosLocal ) ;
double NormalizedDistance = Dist / CurrentBrushRadius + FMathf : : ZeroTolerance ;
2019-10-18 13:04:19 -04:00
double Falloff = ( 1.0 / NormalizedDistance ) - 1.0 ;
Falloff = FMathd : : Clamp ( Falloff , 0.0 , 1.0 ) ;
2019-10-01 20:41:42 -04:00
2019-10-18 13:04:19 -04:00
if ( bHaveMotion & & Falloff < 0.8f )
{
2021-03-17 19:32:44 -04:00
double AnglePower = 1.0 - FMathd : : Abs ( UE : : Geometry : : Normalized ( MoveVec ) . Dot ( MotionVec ) ) ;
2019-10-18 13:04:19 -04:00
Falloff * = AnglePower ;
}
2019-10-01 20:41:42 -04:00
FVector3d NewPos = OrigPos + Falloff * MoveVec ;
2019-10-18 13:04:19 -04:00
ROIPositionBuffer [ k ] = NewPos ;
} ) ;
2019-10-01 20:41:42 -04:00
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2019-10-18 13:04:19 -04:00
LastSmoothBrushPosLocal = NewSmoothBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2020-03-13 13:40:51 -04:00
FFrame3d UDynamicMeshSculptTool : : ComputeROIBrushPlane ( const FVector3d & BrushCenter , bool bIgnoreDepth , bool bViewAligned )
2019-10-01 20:41:42 -04:00
{
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FVector3d AverageNormal ( 0 , 0 , 0 ) ;
FVector3d AveragePos ( 0 , 0 , 0 ) ;
double WeightSum = 0 ;
for ( int TriID : TriangleROI )
{
FVector3d Centroid = Mesh - > GetTriCentroid ( TriID ) ;
2021-03-30 21:25:22 -04:00
double Weight = CalculateBrushFalloff ( Distance ( BrushCenter , Centroid ) ) ;
2019-10-01 20:41:42 -04:00
AverageNormal + = Weight * Mesh - > GetTriNormal ( TriID ) ;
AveragePos + = Weight * Centroid ;
WeightSum + = Weight ;
}
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( AverageNormal ) ;
2019-10-01 20:41:42 -04:00
AveragePos / = WeightSum ;
2020-03-13 13:40:51 -04:00
if ( bViewAligned )
{
2021-03-30 21:25:22 -04:00
AverageNormal = - ( FVector3d ) CameraState . Forward ( ) ;
2020-03-13 13:40:51 -04:00
}
2019-10-01 20:41:42 -04:00
FFrame3d Result = FFrame3d ( AveragePos , AverageNormal ) ;
2019-10-18 13:04:19 -04:00
if ( bIgnoreDepth = = false )
{
2020-03-13 13:40:51 -04:00
Result . Origin - = BrushProperties - > Depth * CurrentBrushRadius * Result . Z ( ) ;
2019-10-18 13:04:19 -04:00
}
2019-10-01 20:41:42 -04:00
return Result ;
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyPlaneBrush ( const FRay & WorldRay )
2019-10-01 20:41:42 -04:00
{
2020-03-19 10:59:23 -04:00
bool bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , true ) ;
2019-10-01 20:41:42 -04:00
if ( bHit = = false )
{
2021-01-27 01:53:01 -04:00
return false ;
2019-10-01 20:41:42 -04:00
}
2020-03-13 13:40:51 -04:00
static const double PlaneSigns [ 3 ] = { 0 , - 1 , 1 } ;
ModelingTools: Ongoing Sculpting improvements:
- new UMeshSculptBrushOpProps baseclass for per-BrushOp Property Sets, added such a PropertySet for each BrushOp
- separate Strength/Depth/Falloff for each BrushOp so that they can have different settings. Currently cannot be in a shared base PropSet class because of different UProp Category strings
- UMeshSculptToolBase now supports registering BrushOp factory paired w/ ToolProps, rewrote VertexSculpt to use this to handle switching active BrushOp and visible PropSet
- removed UPlaneBrushProperties, vertex sculpt no longer uses USculptMaxBrushProperties (still used by dynamic sculpt)
- moved UMeshSurfacePointTool implementation up to UMeshSculptToolBase
- UMeshSculptToolBase now has OnBeginStroke() / OnEndStroke()API for subclasses to use to handle stroke (instead of overriding drag functions)
- Moved some setup to UMeshSculptToolBase. It can now initializes the target Component, can apply to Simple or Octree variants,
- moved Primary/Secondary BrushOp and active Falloff to UMeshSculptToolBase
- Support for various falloff types implemented in StampFalloffs.h, new EMeshSculptFalloffType exposed in VertexSculpt properties
- moved target component Transforms to UMeshSculptToolBase
- moved Brush Frames to UMeshSculptToolBase. Now storing Frames instead of Point+Normal, moved functions to update position for various stamp types
- UMeshSculptToolBase now has API for hit-testing against Sculpt and Base mesh, VertexSculpt implements
- UMeshSculptToolBase now has APIs for accessing transforms, current DMesh and BaseMesh, active stroke Depth/Strength/Falloff properties,
- moved Brush Target Plane (eg for Move), Stamp Plane (eg for Flatten), and StrokePlane (eg for Plane brushes) to UMeshSculptToolBase, and relevant calcuation APIs
- base USculptBrushProperties now has Lazyness parameter, implemented lazy-brush in base sculpt tool
#rb none
#rnx
#ROBOMERGE-SOURCE: CL 13044097 via CL 13044098 via CL 13044099
#ROBOMERGE-BOT: RELEASE (Release-Engine-Staging -> Main) (v686-13045012)
[CL 13048205 by ryan schmidt in Main branch]
2020-04-27 12:51:59 -04:00
double PlaneSign = PlaneSigns [ 0 ] ;
2020-03-13 13:40:51 -04:00
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
2020-01-27 20:11:15 -05:00
double UseSpeed = FMathd : : Sqrt ( CurrentBrushRadius ) * FMathd : : Sqrt ( SculptProperties - > PrimaryBrushSpeed ) * 0.05 * ActivePressure ;
2019-10-18 13:04:19 -04:00
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-18 13:04:19 -04:00
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
2019-10-01 20:41:42 -04:00
2020-03-13 13:40:51 -04:00
ParallelFor ( NumV , [ & ] ( int k )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:04:19 -04:00
int VertIdx = VertexROI [ k ] ;
2019-10-01 20:41:42 -04:00
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
FVector3d PlanePos = ActiveFixedBrushPlane . ToPlane ( OrigPos , 2 ) ;
FVector3d Delta = PlanePos - OrigPos ;
2020-03-13 13:40:51 -04:00
double Dot = Delta . Dot ( ActiveFixedBrushPlane . Z ( ) ) ;
FVector3d NewPos = OrigPos ;
if ( Dot * PlaneSign > = 0 )
{
FVector3d MoveVec = UseSpeed * Delta ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( OrigPos , NewBrushPosLocal ) ) ;
2020-03-13 13:40:51 -04:00
NewPos = OrigPos + Falloff * MoveVec ;
}
2019-10-18 13:04:19 -04:00
ROIPositionBuffer [ k ] = NewPos ;
} ) ;
2019-10-01 20:41:42 -04:00
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyFixedPlaneBrush ( const FRay & WorldRay )
2019-11-05 17:20:52 -05:00
{
2020-03-19 10:59:23 -04:00
bool bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , true ) ;
2019-11-05 17:20:52 -05:00
if ( bHit = = false )
{
2021-01-27 01:53:01 -04:00
return false ;
2019-11-05 17:20:52 -05:00
}
2020-03-13 13:40:51 -04:00
static const double PlaneSigns [ 3 ] = { 0 , - 1 , 1 } ;
ModelingTools: Ongoing Sculpting improvements:
- new UMeshSculptBrushOpProps baseclass for per-BrushOp Property Sets, added such a PropertySet for each BrushOp
- separate Strength/Depth/Falloff for each BrushOp so that they can have different settings. Currently cannot be in a shared base PropSet class because of different UProp Category strings
- UMeshSculptToolBase now supports registering BrushOp factory paired w/ ToolProps, rewrote VertexSculpt to use this to handle switching active BrushOp and visible PropSet
- removed UPlaneBrushProperties, vertex sculpt no longer uses USculptMaxBrushProperties (still used by dynamic sculpt)
- moved UMeshSurfacePointTool implementation up to UMeshSculptToolBase
- UMeshSculptToolBase now has OnBeginStroke() / OnEndStroke()API for subclasses to use to handle stroke (instead of overriding drag functions)
- Moved some setup to UMeshSculptToolBase. It can now initializes the target Component, can apply to Simple or Octree variants,
- moved Primary/Secondary BrushOp and active Falloff to UMeshSculptToolBase
- Support for various falloff types implemented in StampFalloffs.h, new EMeshSculptFalloffType exposed in VertexSculpt properties
- moved target component Transforms to UMeshSculptToolBase
- moved Brush Frames to UMeshSculptToolBase. Now storing Frames instead of Point+Normal, moved functions to update position for various stamp types
- UMeshSculptToolBase now has API for hit-testing against Sculpt and Base mesh, VertexSculpt implements
- UMeshSculptToolBase now has APIs for accessing transforms, current DMesh and BaseMesh, active stroke Depth/Strength/Falloff properties,
- moved Brush Target Plane (eg for Move), Stamp Plane (eg for Flatten), and StrokePlane (eg for Plane brushes) to UMeshSculptToolBase, and relevant calcuation APIs
- base USculptBrushProperties now has Lazyness parameter, implemented lazy-brush in base sculpt tool
#rb none
#rnx
#ROBOMERGE-SOURCE: CL 13044097 via CL 13044098 via CL 13044099
#ROBOMERGE-BOT: RELEASE (Release-Engine-Staging -> Main) (v686-13045012)
[CL 13048205 by ryan schmidt in Main branch]
2020-04-27 12:51:59 -04:00
double PlaneSign = PlaneSigns [ 0 ] ;
2020-03-13 13:40:51 -04:00
2019-11-05 17:20:52 -05:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
2020-01-27 20:11:15 -05:00
double UseSpeed = CurrentBrushRadius * FMathd : : Sqrt ( SculptProperties - > PrimaryBrushSpeed ) * 0.1 * ActivePressure ;
2019-11-05 17:20:52 -05:00
FFrame3d FixedPlaneLocal (
2021-03-30 21:25:22 -04:00
CurTargetTransform . InverseTransformPosition ( ( FVector3d ) GizmoProperties - > Position ) ,
2020-03-13 13:40:51 -04:00
CurTargetTransform . GetRotation ( ) . Inverse ( ) * ( FQuaterniond ) GizmoProperties - > Rotation ) ;
2019-11-05 17:20:52 -05:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
2020-03-13 13:40:51 -04:00
ParallelFor ( NumV , [ & ] ( int k )
2019-11-05 17:20:52 -05:00
{
int VertIdx = VertexROI [ k ] ;
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
FVector3d PlanePos = FixedPlaneLocal . ToPlane ( OrigPos , 2 ) ;
FVector3d Delta = PlanePos - OrigPos ;
2020-03-13 13:40:51 -04:00
double Dot = Delta . Dot ( FixedPlaneLocal . Z ( ) ) ;
FVector3d NewPos = OrigPos ;
if ( Dot * PlaneSign > = 0 )
{
2021-03-17 19:32:44 -04:00
double MaxDist = UE : : Geometry : : Normalize ( Delta ) ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( OrigPos , NewBrushPosLocal ) ) ;
2020-03-13 13:40:51 -04:00
FVector3d MoveVec = Falloff * UseSpeed * Delta ;
NewPos = ( MoveVec . SquaredLength ( ) > MaxDist * MaxDist ) ?
PlanePos : OrigPos + Falloff * MoveVec ;
}
2019-11-05 17:20:52 -05:00
ROIPositionBuffer [ k ] = NewPos ;
} ) ;
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-11-05 17:20:52 -05:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-11-05 17:20:52 -05:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyFlattenBrush ( const FRay & WorldRay )
2019-10-01 20:41:42 -04:00
{
2020-03-19 10:59:23 -04:00
bool bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , true ) ;
2019-10-01 20:41:42 -04:00
if ( bHit = = false )
{
2021-01-27 01:53:01 -04:00
return false ;
2019-10-01 20:41:42 -04:00
}
2020-03-19 10:59:23 -04:00
static const double PlaneSigns [ 3 ] = { 0 , - 1 , 1 } ;
ModelingTools: Ongoing Sculpting improvements:
- new UMeshSculptBrushOpProps baseclass for per-BrushOp Property Sets, added such a PropertySet for each BrushOp
- separate Strength/Depth/Falloff for each BrushOp so that they can have different settings. Currently cannot be in a shared base PropSet class because of different UProp Category strings
- UMeshSculptToolBase now supports registering BrushOp factory paired w/ ToolProps, rewrote VertexSculpt to use this to handle switching active BrushOp and visible PropSet
- removed UPlaneBrushProperties, vertex sculpt no longer uses USculptMaxBrushProperties (still used by dynamic sculpt)
- moved UMeshSurfacePointTool implementation up to UMeshSculptToolBase
- UMeshSculptToolBase now has OnBeginStroke() / OnEndStroke()API for subclasses to use to handle stroke (instead of overriding drag functions)
- Moved some setup to UMeshSculptToolBase. It can now initializes the target Component, can apply to Simple or Octree variants,
- moved Primary/Secondary BrushOp and active Falloff to UMeshSculptToolBase
- Support for various falloff types implemented in StampFalloffs.h, new EMeshSculptFalloffType exposed in VertexSculpt properties
- moved target component Transforms to UMeshSculptToolBase
- moved Brush Frames to UMeshSculptToolBase. Now storing Frames instead of Point+Normal, moved functions to update position for various stamp types
- UMeshSculptToolBase now has API for hit-testing against Sculpt and Base mesh, VertexSculpt implements
- UMeshSculptToolBase now has APIs for accessing transforms, current DMesh and BaseMesh, active stroke Depth/Strength/Falloff properties,
- moved Brush Target Plane (eg for Move), Stamp Plane (eg for Flatten), and StrokePlane (eg for Plane brushes) to UMeshSculptToolBase, and relevant calcuation APIs
- base USculptBrushProperties now has Lazyness parameter, implemented lazy-brush in base sculpt tool
#rb none
#rnx
#ROBOMERGE-SOURCE: CL 13044097 via CL 13044098 via CL 13044099
#ROBOMERGE-BOT: RELEASE (Release-Engine-Staging -> Main) (v686-13045012)
[CL 13048205 by ryan schmidt in Main branch]
2020-04-27 12:51:59 -04:00
double PlaneSign = PlaneSigns [ 0 ] ;
2020-03-19 10:59:23 -04:00
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
2019-10-18 13:04:19 -04:00
2020-01-27 20:11:15 -05:00
double UseSpeed = FMathd : : Sqrt ( CurrentBrushRadius ) * FMathd : : Sqrt ( SculptProperties - > PrimaryBrushSpeed ) * 0.05 * ActivePressure ;
2020-03-13 13:40:51 -04:00
FFrame3d StampFlattenPlane = ComputeROIBrushPlane ( NewBrushPosLocal , true , false ) ;
//StampFlattenPlane.Origin -= BrushProperties->Depth * CurrentBrushRadius * StampFlattenPlane.Z();
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-18 13:04:19 -04:00
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
2019-10-01 20:41:42 -04:00
2020-03-19 10:59:23 -04:00
ParallelFor ( NumV , [ & ] ( int k )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:04:19 -04:00
int VertIdx = VertexROI [ k ] ;
2019-10-01 20:41:42 -04:00
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
FVector3d PlanePos = StampFlattenPlane . ToPlane ( OrigPos , 2 ) ;
FVector3d Delta = PlanePos - OrigPos ;
2020-03-19 10:59:23 -04:00
double Dot = Delta . Dot ( StampFlattenPlane . Z ( ) ) ;
FVector3d NewPos = OrigPos ;
if ( Dot * PlaneSign > = 0 )
{
2021-03-17 19:32:44 -04:00
double MaxDist = UE : : Geometry : : Normalize ( Delta ) ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( OrigPos , NewBrushPosLocal ) ) ;
2020-03-19 10:59:23 -04:00
FVector3d MoveVec = Falloff * UseSpeed * Delta ;
NewPos = ( MoveVec . SquaredLength ( ) > MaxDist * MaxDist ) ?
PlanePos : OrigPos + Falloff * MoveVec ;
}
2019-10-01 20:41:42 -04:00
2019-10-18 13:04:19 -04:00
ROIPositionBuffer [ k ] = NewPos ;
} ) ;
2019-10-01 20:41:42 -04:00
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyInflateBrush ( const FRay & WorldRay )
2019-10-01 20:41:42 -04:00
{
2020-03-19 10:59:23 -04:00
bool bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , true ) ;
2019-10-01 20:41:42 -04:00
if ( bHit = = false )
{
2021-01-27 01:53:01 -04:00
return false ;
2019-10-01 20:41:42 -04:00
}
2019-10-18 13:12:29 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
2019-10-01 20:41:42 -04:00
double Direction = ( bInvert ) ? - 1.0 : 1.0 ;
2020-01-27 20:11:15 -05:00
double UseSpeed = Direction * CurrentBrushRadius * SculptProperties - > PrimaryBrushSpeed * 0.05 * ActivePressure ;
2019-10-18 13:04:19 -04:00
2019-10-01 20:41:42 -04:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2019-10-18 13:04:19 -04:00
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
2019-10-01 20:41:42 -04:00
// calculate vertex normals
ParallelFor ( VertexROI . Num ( ) , [ this , Mesh ] ( int Index ) {
int VertIdx = VertexROI [ Index ] ;
FVector3d Normal = FMeshNormals : : ComputeVertexNormal ( * Mesh , VertIdx ) ;
Mesh - > SetVertexNormal ( VertIdx , ( FVector3f ) Normal ) ;
} ) ;
2020-01-27 20:11:15 -05:00
ParallelFor ( VertexROI . Num ( ) , [ this , Mesh , UseSpeed , NewBrushPosLocal ] ( int k )
2019-10-01 20:41:42 -04:00
{
2019-10-18 13:04:19 -04:00
int VertIdx = VertexROI [ k ] ;
2019-10-01 20:41:42 -04:00
FVector3d OrigPos = Mesh - > GetVertex ( VertIdx ) ;
FVector3d Normal = ( FVector3d ) Mesh - > GetVertexNormal ( VertIdx ) ;
FVector3d MoveVec = UseSpeed * Normal ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( OrigPos , NewBrushPosLocal ) ) ;
2019-10-01 20:41:42 -04:00
FVector3d NewPos = OrigPos + Falloff * MoveVec ;
2019-10-18 13:04:19 -04:00
ROIPositionBuffer [ k ] = NewPos ;
2019-10-01 20:41:42 -04:00
} ) ;
2020-03-17 22:32:24 -04:00
ScheduleRemeshPass ( ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
2020-03-17 22:32:24 -04:00
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyResampleBrush ( const FRay & WorldRay )
2020-03-17 22:32:24 -04:00
{
2020-03-19 10:59:23 -04:00
UpdateBrushPositionOnTargetMesh ( WorldRay , true ) ;
2020-03-17 22:32:24 -04:00
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d LocalNormal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
double UseSpeed = FMathd : : Sqrt ( CurrentBrushRadius ) * ( SculptProperties - > PrimaryBrushSpeed ) * ActivePressure ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
int NumV = VertexROI . Num ( ) ;
ROIPositionBuffer . SetNum ( NumV , false ) ;
ParallelFor ( NumV , [ & ] ( int k )
{
2021-01-27 01:53:01 -04:00
ROIPositionBuffer [ k ] = Mesh - > GetVertex ( VertexROI [ k ] ) ;
2020-03-17 22:32:24 -04:00
} ) ;
ScheduleRemeshPass ( ) ;
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2020-03-17 22:32:24 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyPullKelvinBrush ( const FRay & WorldRay )
2020-04-18 18:42:59 -04:00
{
UpdateBrushPositionOnActivePlane ( WorldRay ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d MoveVec = NewBrushPosLocal - LastBrushPosLocal ;
if ( MoveVec . SquaredLength ( ) < = 0 )
{
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return false ;
2020-04-18 18:42:59 -04:00
}
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FKelvinletBrushOp KelvinBrushOp ( * Mesh ) ;
const EKelvinletBrushMode KelvinMode = EKelvinletBrushMode : : PullKelvinlet ;
2021-10-28 13:24:28 -04:00
FKelvinletBrushOp : : FKelvinletBrushOpProperties KelvinletBrushOpProperties ( KelvinMode , * KelvinBrushProperties , CurrentBrushRadius , BrushProperties - > BrushFalloffAmount ) ;
2020-04-18 18:42:59 -04:00
KelvinletBrushOpProperties . Direction = FVector ( MoveVec . X , MoveVec . Y , MoveVec . Z ) ; //FVector(BrushNormalLocal.X, BrushNormalLocal.Y, BrushNormalLocal.Z);
KelvinletBrushOpProperties . Size * = 0.6 ;
FMatrix ToBrush ; ToBrush . SetIdentity ( ) ; ToBrush . SetOrigin ( - FVector ( NewBrushPosLocal . X , NewBrushPosLocal . Y , NewBrushPosLocal . Z ) ) ; // ToBrush.
KelvinBrushOp . ApplyBrush ( KelvinletBrushOpProperties , ToBrush , VertexROI , ROIPositionBuffer ) ;
ScheduleRemeshPass ( ) ;
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2020-04-18 18:42:59 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyPullSharpKelvinBrush ( const FRay & WorldRay )
2020-04-18 18:42:59 -04:00
{
UpdateBrushPositionOnActivePlane ( WorldRay ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d MoveVec = NewBrushPosLocal - LastBrushPosLocal ;
if ( MoveVec . SquaredLength ( ) < = 0 )
{
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return false ;
2020-04-18 18:42:59 -04:00
}
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FKelvinletBrushOp KelvinBrushOp ( * Mesh ) ;
const EKelvinletBrushMode KelvinMode = EKelvinletBrushMode : : SharpPullKelvinlet ;
2021-10-28 13:24:28 -04:00
FKelvinletBrushOp : : FKelvinletBrushOpProperties KelvinletBrushOpProperties ( KelvinMode , * KelvinBrushProperties , CurrentBrushRadius , BrushProperties - > BrushFalloffAmount ) ;
2020-04-18 18:42:59 -04:00
KelvinletBrushOpProperties . Direction = FVector ( MoveVec . X , MoveVec . Y , MoveVec . Z ) ; //FVector(BrushNormalLocal.X, BrushNormalLocal.Y, BrushNormalLocal.Z);
KelvinletBrushOpProperties . Size * = 0.6 ;
FMatrix ToBrush ; ToBrush . SetIdentity ( ) ; ToBrush . SetOrigin ( - FVector ( NewBrushPosLocal . X , NewBrushPosLocal . Y , NewBrushPosLocal . Z ) ) ; // ToBrush.
KelvinBrushOp . ApplyBrush ( KelvinletBrushOpProperties , ToBrush , VertexROI , ROIPositionBuffer ) ;
ScheduleRemeshPass ( ) ;
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2020-04-18 18:42:59 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyTwistKelvinBrush ( const FRay & WorldRay )
2020-04-18 18:42:59 -04:00
{
UpdateBrushPositionOnTargetMesh ( WorldRay , true ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
double Direction = ( bInvert ) ? - 1.0 : 1.0 ;
double UseSpeed = Direction * FMathd : : Sqrt ( CurrentBrushRadius ) * ( SculptProperties - > PrimaryBrushSpeed ) * ActivePressure ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FKelvinletBrushOp KelvinBrushOp ( * Mesh ) ;
2021-10-28 13:24:28 -04:00
FKelvinletBrushOp : : FKelvinletBrushOpProperties KelvinletBrushOpProperties ( EKelvinletBrushMode : : TwistKelvinlet , * KelvinBrushProperties , CurrentBrushRadius , BrushProperties - > BrushFalloffAmount ) ;
2020-04-18 18:42:59 -04:00
KelvinletBrushOpProperties . Direction = UseSpeed * FVector ( BrushNormalLocal . X , BrushNormalLocal . Y , BrushNormalLocal . Z ) ; // twist about local normal
KelvinletBrushOpProperties . Size * = 0.35 ; // reduce the core size of this brush.
FMatrix ToBrush ; ToBrush . SetIdentity ( ) ; ToBrush . SetOrigin ( - FVector ( NewBrushPosLocal . X , NewBrushPosLocal . Y , NewBrushPosLocal . Z ) ) ; // ToBrush.
KelvinBrushOp . ApplyBrush ( KelvinletBrushOpProperties , ToBrush , VertexROI , ROIPositionBuffer ) ;
ScheduleRemeshPass ( ) ;
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2020-04-18 18:42:59 -04:00
}
2021-01-27 01:53:01 -04:00
bool UDynamicMeshSculptTool : : ApplyScaleKelvinBrush ( const FRay & WorldRay )
2020-04-18 18:42:59 -04:00
{
UpdateBrushPositionOnSculptMesh ( WorldRay , true ) ;
FVector3d NewBrushPosLocal = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
FVector3d BrushNormalLocal = CurTargetTransform . InverseTransformNormal ( LastBrushPosNormalWorld ) ;
FVector3d OffsetBrushPosLocal = NewBrushPosLocal - BrushProperties - > Depth * CurrentBrushRadius * BrushNormalLocal ;
double Direction = ( bInvert ) ? - 1.0 : 1.0 ;
double UseSpeed = Direction * FMath : : Sqrt ( CurrentBrushRadius ) * SculptProperties - > PrimaryBrushSpeed * 0.025 * ActivePressure ; ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FKelvinletBrushOp KelvinBrushOp ( * Mesh ) ;
2021-10-28 13:24:28 -04:00
FKelvinletBrushOp : : FKelvinletBrushOpProperties KelvinletBrushOpProperties ( EKelvinletBrushMode : : ScaleKelvinlet , * KelvinBrushProperties , CurrentBrushRadius , BrushProperties - > BrushFalloffAmount ) ;
2020-04-18 18:42:59 -04:00
KelvinletBrushOpProperties . Direction = FVector ( UseSpeed , 0. , 0. ) ; // it is a bit iffy, but we only use the first component for the scale
KelvinletBrushOpProperties . Size * = 0.35 ;
FMatrix ToBrush ; ToBrush . SetIdentity ( ) ; ToBrush . SetOrigin ( - FVector ( OffsetBrushPosLocal . X , OffsetBrushPosLocal . Y , OffsetBrushPosLocal . Z ) ) ; // ToBrush.
KelvinBrushOp . ApplyBrush ( KelvinletBrushOpProperties , ToBrush , VertexROI , ROIPositionBuffer ) ;
ScheduleRemeshPass ( ) ;
LastBrushPosLocal = NewBrushPosLocal ;
2021-01-27 01:53:01 -04:00
return true ;
2020-04-18 18:42:59 -04:00
}
2020-03-17 22:32:24 -04:00
2021-05-06 18:29:00 -04:00
bool UDynamicMeshSculptTool : : IsHitTriangleBackFacing ( int32 TriangleID , const FDynamicMesh3 * QueryMesh )
2019-11-03 22:43:57 -05:00
{
2021-05-06 18:29:00 -04:00
if ( TriangleID ! = IndexConstants : : InvalidID )
2019-11-03 22:43:57 -05:00
{
FViewCameraState StateOut ;
GetToolManager ( ) - > GetContextQueriesAPI ( ) - > GetCurrentViewState ( StateOut ) ;
2021-03-30 21:25:22 -04:00
FVector3d LocalEyePosition ( CurTargetTransform . InverseTransformPosition ( ( FVector3d ) StateOut . Position ) ) ;
2021-05-06 18:29:00 -04:00
FVector3d Normal , Centroid ;
double Area ;
QueryMesh - > GetTriInfo ( TriangleID , Normal , Area , Centroid ) ;
return ( Normal . Dot ( ( Centroid - LocalEyePosition ) ) > = 0 ) ;
2019-11-03 22:43:57 -05:00
}
2021-05-06 18:29:00 -04:00
return false ;
}
int UDynamicMeshSculptTool : : FindHitSculptMeshTriangle ( const FRay3d & LocalRay )
{
int32 HitTID = DynamicMeshComponent - > GetOctree ( ) - > FindNearestHitObject ( LocalRay ) ;
if ( BrushProperties - > bHitBackFaces = = false & & IsHitTriangleBackFacing ( HitTID , DynamicMeshComponent - > GetMesh ( ) ) )
{
HitTID = IndexConstants : : InvalidID ;
}
return HitTID ;
2019-11-03 22:43:57 -05:00
}
int UDynamicMeshSculptTool : : FindHitTargetMeshTriangle ( const FRay3d & LocalRay )
{
2021-01-20 00:15:28 -04:00
PendingTargetUpdate . Wait ( ) ;
2021-05-06 18:29:00 -04:00
int32 HitTID = BrushTargetMeshSpatial . FindNearestHitTriangle ( LocalRay ) ;
if ( BrushProperties - > bHitBackFaces = = false & & IsHitTriangleBackFacing ( HitTID , & BrushTargetMesh ) )
2019-11-03 22:43:57 -05:00
{
2021-05-06 18:29:00 -04:00
HitTID = IndexConstants : : InvalidID ;
2019-11-03 22:43:57 -05:00
}
return HitTID ;
}
2019-10-01 20:41:42 -04:00
bool UDynamicMeshSculptTool : : UpdateBrushPositionOnActivePlane ( const FRay & WorldRay )
{
2019-10-18 13:12:29 -04:00
FVector3d NewHitPosWorld ;
2021-03-30 21:25:22 -04:00
ActiveDragPlane . RayPlaneIntersection ( ( FVector3d ) WorldRay . Origin , ( FVector3d ) WorldRay . Direction , 2 , NewHitPosWorld ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosWorld = NewHitPosWorld ;
2019-10-18 13:12:29 -04:00
LastBrushPosNormalWorld = ActiveDragPlane . Z ( ) ;
2019-10-01 20:41:42 -04:00
return true ;
}
2020-03-19 10:59:23 -04:00
bool UDynamicMeshSculptTool : : UpdateBrushPositionOnTargetMesh ( const FRay & WorldRay , bool bFallbackToViewPlane )
2019-10-01 20:41:42 -04:00
{
2021-01-20 00:15:28 -04:00
PendingTargetUpdate . Wait ( ) ;
2021-03-30 21:25:22 -04:00
FRay3d LocalRay ( CurTargetTransform . InverseTransformPosition ( ( FVector3d ) WorldRay . Origin ) ,
CurTargetTransform . InverseTransformVector ( ( FVector3d ) WorldRay . Direction ) ) ;
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( LocalRay . Direction ) ;
2019-10-01 20:41:42 -04:00
2020-03-19 10:59:23 -04:00
const FDynamicMesh3 * TargetMesh = BrushTargetMeshSpatial . GetMesh ( ) ;
2019-11-03 22:43:57 -05:00
int HitTID = FindHitTargetMeshTriangle ( LocalRay ) ;
2019-10-01 20:41:42 -04:00
if ( HitTID ! = IndexConstants : : InvalidID )
{
FTriangle3d Triangle ;
TargetMesh - > GetTriVertices ( HitTID , Triangle . V [ 0 ] , Triangle . V [ 1 ] , Triangle . V [ 2 ] ) ;
FIntrRay3Triangle3d Query ( LocalRay , Triangle ) ;
Query . Find ( ) ;
2019-10-18 13:12:29 -04:00
LastBrushPosNormalWorld = CurTargetTransform . TransformNormal ( TargetMesh - > GetTriNormal ( HitTID ) ) ;
LastBrushPosWorld = CurTargetTransform . TransformPosition ( LocalRay . PointAt ( Query . RayParameter ) ) ;
2019-10-01 20:41:42 -04:00
return true ;
}
2020-03-19 10:59:23 -04:00
if ( bFallbackToViewPlane )
{
2021-03-30 21:25:22 -04:00
FFrame3d BrushPlane ( LastBrushPosWorld , ( FVector3d ) CameraState . Forward ( ) ) ;
2020-03-19 10:59:23 -04:00
FVector3d NewHitPosWorld ;
2021-03-30 21:25:22 -04:00
BrushPlane . RayPlaneIntersection ( ( FVector3d ) WorldRay . Origin , ( FVector3d ) WorldRay . Direction , 2 , NewHitPosWorld ) ;
2020-03-19 10:59:23 -04:00
LastBrushPosWorld = NewHitPosWorld ;
LastBrushPosNormalWorld = ActiveDragPlane . Z ( ) ;
return true ;
}
2019-10-01 20:41:42 -04:00
return false ;
}
2020-03-19 10:59:23 -04:00
bool UDynamicMeshSculptTool : : UpdateBrushPositionOnSculptMesh ( const FRay & WorldRay , bool bFallbackToViewPlane )
2019-10-01 20:41:42 -04:00
{
2021-03-30 21:25:22 -04:00
FRay3d LocalRay ( CurTargetTransform . InverseTransformPosition ( ( FVector3d ) WorldRay . Origin ) ,
CurTargetTransform . InverseTransformVector ( ( FVector3d ) WorldRay . Direction ) ) ;
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( LocalRay . Direction ) ;
2019-10-01 20:41:42 -04:00
2019-11-03 22:43:57 -05:00
int HitTID = FindHitSculptMeshTriangle ( LocalRay ) ;
2019-10-01 20:41:42 -04:00
if ( HitTID ! = IndexConstants : : InvalidID )
{
const FDynamicMesh3 * SculptMesh = DynamicMeshComponent - > GetMesh ( ) ;
FTriangle3d Triangle ;
SculptMesh - > GetTriVertices ( HitTID , Triangle . V [ 0 ] , Triangle . V [ 1 ] , Triangle . V [ 2 ] ) ;
FIntrRay3Triangle3d Query ( LocalRay , Triangle ) ;
Query . Find ( ) ;
2019-10-18 13:12:29 -04:00
LastBrushPosNormalWorld = CurTargetTransform . TransformNormal ( SculptMesh - > GetTriNormal ( HitTID ) ) ;
LastBrushPosWorld = CurTargetTransform . TransformPosition ( LocalRay . PointAt ( Query . RayParameter ) ) ;
2020-12-04 19:51:25 -04:00
LastBrushTriangleID = HitTID ;
2019-10-01 20:41:42 -04:00
return true ;
}
2020-03-19 10:59:23 -04:00
if ( bFallbackToViewPlane )
{
2021-03-30 21:25:22 -04:00
FFrame3d BrushPlane ( LastBrushPosWorld , ( FVector3d ) CameraState . Forward ( ) ) ;
2020-03-19 10:59:23 -04:00
FVector3d NewHitPosWorld ;
2021-03-30 21:25:22 -04:00
BrushPlane . RayPlaneIntersection ( ( FVector3d ) WorldRay . Origin , ( FVector3d ) WorldRay . Direction , 2 , NewHitPosWorld ) ;
2020-03-19 10:59:23 -04:00
LastBrushPosWorld = NewHitPosWorld ;
LastBrushPosNormalWorld = ActiveDragPlane . Z ( ) ;
2020-12-04 19:51:25 -04:00
LastBrushTriangleID = - 1 ;
2020-03-19 10:59:23 -04:00
return true ;
}
2019-10-01 20:41:42 -04:00
return false ;
}
2020-03-13 13:40:51 -04:00
void UDynamicMeshSculptTool : : AlignBrushToView ( )
{
2021-03-30 21:25:22 -04:00
LastBrushPosNormalWorld = - ( FVector3d ) CameraState . Forward ( ) ;
2020-03-13 13:40:51 -04:00
}
bool UDynamicMeshSculptTool : : UpdateBrushPosition ( const FRay & WorldRay )
{
// This is an unfortunate hack necessary because we haven't refactored brushes properly yet
if ( bSmoothing )
{
2020-03-19 10:59:23 -04:00
return UpdateBrushPositionOnSculptMesh ( WorldRay , false ) ;
2020-03-13 13:40:51 -04:00
}
bool bHit = false ;
switch ( SculptProperties - > PrimaryBrushType )
{
case EDynamicMeshSculptBrushType : : Offset :
case EDynamicMeshSculptBrushType : : SculptMax :
case EDynamicMeshSculptBrushType : : Pinch :
2020-03-17 22:32:24 -04:00
case EDynamicMeshSculptBrushType : : Resample :
2020-03-19 10:59:23 -04:00
bHit = UpdateBrushPositionOnTargetMesh ( WorldRay , false ) ;
2020-03-13 13:40:51 -04:00
break ;
case EDynamicMeshSculptBrushType : : SculptView :
case EDynamicMeshSculptBrushType : : PlaneViewAligned :
2020-03-19 10:59:23 -04:00
bHit = UpdateBrushPositionOnTargetMesh ( WorldRay , false ) ;
2020-03-13 13:40:51 -04:00
AlignBrushToView ( ) ;
break ;
case EDynamicMeshSculptBrushType : : Move :
//return UpdateBrushPositionOnActivePlane(WorldRay);
2020-03-19 10:59:23 -04:00
bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , false ) ;
2020-03-13 13:40:51 -04:00
break ;
case EDynamicMeshSculptBrushType : : Smooth :
case EDynamicMeshSculptBrushType : : Inflate :
case EDynamicMeshSculptBrushType : : Flatten :
case EDynamicMeshSculptBrushType : : Plane :
case EDynamicMeshSculptBrushType : : FixedPlane :
2020-03-19 10:59:23 -04:00
bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , false ) ;
2020-03-13 13:40:51 -04:00
break ;
default :
UE_LOG ( LogTemp , Warning , TEXT ( " UDynamicMeshSculptTool: unknown brush type in UpdateBrushPosition " ) ) ;
2020-03-19 10:59:23 -04:00
bHit = UpdateBrushPositionOnSculptMesh ( WorldRay , false ) ;
2020-03-13 13:40:51 -04:00
break ;
}
return bHit ;
}
2019-10-01 20:41:42 -04:00
void UDynamicMeshSculptTool : : OnEndDrag ( const FRay & Ray )
{
bInDrag = false ;
2020-01-27 20:11:15 -05:00
// cancel these! otherwise change record could become invalid
2019-10-01 20:41:42 -04:00
bStampPending = false ;
bRemeshPending = false ;
// update spatial
bTargetDirty = true ;
// close change record
EndChange ( ) ;
2021-01-27 01:53:01 -04:00
// destroy active remesher. Should we do this every stroke?? need to do it on undo/redo...
if ( ActiveRemesher )
{
ActiveRemesher = nullptr ;
}
2019-10-01 20:41:42 -04:00
}
2020-03-19 10:59:23 -04:00
FInputRayHit UDynamicMeshSculptTool : : BeginHoverSequenceHitTest ( const FInputDeviceRay & PressPos )
{
return UMeshSurfacePointTool : : BeginHoverSequenceHitTest ( PressPos ) ;
}
2019-10-01 20:41:42 -04:00
bool UDynamicMeshSculptTool : : OnUpdateHover ( const FInputDeviceRay & DevicePos )
{
2021-02-03 14:57:28 -04:00
// 4.26 HOTFIX: update LastWorldRay position so that we have it for updating WorkPlane position
UMeshSurfacePointTool : : LastWorldRay = DevicePos . WorldRay ;
2019-10-01 20:41:42 -04:00
PendingStampType = SculptProperties - > PrimaryBrushType ;
if ( bInDrag )
{
2019-10-18 13:12:29 -04:00
FVector3d NewHitPosWorld ;
2021-03-30 21:25:22 -04:00
ActiveDragPlane . RayPlaneIntersection ( ( FVector3d ) DevicePos . WorldRay . Origin , ( FVector3d ) DevicePos . WorldRay . Direction , 2 , NewHitPosWorld ) ;
2019-10-01 20:41:42 -04:00
LastBrushPosWorld = NewHitPosWorld ;
2019-10-18 13:12:29 -04:00
LastBrushPosNormalWorld = ActiveDragPlane . Z ( ) ;
2019-10-01 20:41:42 -04:00
}
else
{
2020-03-13 13:40:51 -04:00
UpdateBrushPosition ( DevicePos . WorldRay ) ;
//FHitResult OutHit;
//if (HitTest(DevicePos.WorldRay, OutHit))
//{
// LastBrushPosWorld = DevicePos.WorldRay.PointAt(OutHit.Distance + BrushProperties->Depth*CurrentBrushRadius);
// LastBrushPosNormalWorld = OutHit.Normal;
//}
2019-10-01 20:41:42 -04:00
}
return true ;
}
2020-03-20 12:44:53 -04:00
2019-10-01 20:41:42 -04:00
void UDynamicMeshSculptTool : : Render ( IToolsContextRenderAPI * RenderAPI )
{
UMeshSurfacePointTool : : Render ( RenderAPI ) ;
2020-06-23 18:40:00 -04:00
// Cache here for usage during interaction, should probably happen in ::Tick() or elsewhere
2020-03-13 13:40:51 -04:00
GetToolManager ( ) - > GetContextQueriesAPI ( ) - > GetCurrentViewState ( CameraState ) ;
2019-10-01 20:41:42 -04:00
2020-06-23 18:40:00 -04:00
FViewCameraState RenderCameraState = RenderAPI - > GetCameraState ( ) ;
2021-10-28 13:24:28 -04:00
//BrushIndicator->Update( (float)this->CurrentBrushRadius, (FVector)this->LastBrushPosWorld, (FVector)this->LastBrushPosNormalWorld, 1.0f-BrushProperties->BrushFalloffAmount);
BrushIndicator - > Update ( ( float ) this - > CurrentBrushRadius , ( FVector ) this - > LastBrushPosWorld , ( FVector ) this - > LastBrushPosNormalWorld , 0.5f ) ;
2020-03-20 12:44:53 -04:00
if ( BrushIndicatorMaterial )
{
2020-06-23 18:40:00 -04:00
double FixedDimScale = ToolSceneQueriesUtil : : CalculateDimensionFromVisualAngleD ( RenderCameraState , LastBrushPosWorld , 1.5f ) ;
2020-03-20 12:44:53 -04:00
BrushIndicatorMaterial - > SetScalarParameterValue ( TEXT ( " FalloffWidth " ) , FixedDimScale ) ;
}
2019-11-05 17:20:52 -05:00
if ( SculptProperties - > PrimaryBrushType = = EDynamicMeshSculptBrushType : : FixedPlane )
{
FPrimitiveDrawInterface * PDI = RenderAPI - > GetPrimitiveDrawInterface ( ) ;
FColor GridColor ( 128 , 128 , 128 , 32 ) ;
2020-06-23 18:40:00 -04:00
float GridThickness = 0.5f * RenderCameraState . GetPDIScalingFactor ( ) ;
2019-11-05 17:20:52 -05:00
int NumGridLines = 10 ;
2022-02-14 18:32:46 -05:00
FFrame3d DrawFrame ( GizmoProperties - > Position , GizmoProperties - > Rotation ) ;
2020-06-23 18:40:00 -04:00
MeshDebugDraw : : DrawSimpleFixedScreenAreaGrid ( RenderCameraState , DrawFrame , NumGridLines , 45.0 , GridThickness , GridColor , false , PDI , FTransform : : Identity ) ;
2019-11-05 17:20:52 -05:00
}
2019-10-01 20:41:42 -04:00
}
2020-04-18 18:42:59 -04:00
void UDynamicMeshSculptTool : : OnTick ( float DeltaTime )
2019-10-01 20:41:42 -04:00
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_OnTick ) ;
2019-10-01 20:41:42 -04:00
2019-12-19 18:07:47 -05:00
ActivePressure = GetCurrentDevicePressure ( ) ;
2021-01-28 20:34:25 -04:00
// Allow a tick to pass between application of brush stamps. If we do not do this then on large stamps
// that take a significant fraction of a second to compute, frames will be skipped and the editor will appear
// frozen, but when the user releases the mouse, sculpting has clearly happened
static int TICK_SKIP_HACK = 0 ;
if ( TICK_SKIP_HACK + + % 2 = = 0 )
{
return ;
}
2019-10-18 13:04:19 -04:00
2019-10-01 20:41:42 -04:00
ShowWireframeWatcher . CheckAndUpdate ( ) ;
MaterialModeWatcher . CheckAndUpdate ( ) ;
2021-04-01 17:33:33 -04:00
CustomMaterialWatcher . CheckAndUpdate ( ) ;
2020-03-13 13:40:51 -04:00
FlatShadingWatcher . CheckAndUpdate ( ) ;
ColorWatcher . CheckAndUpdate ( ) ;
2021-04-01 17:33:33 -04:00
TransparentColorWatcher . CheckAndUpdate ( ) ;
OpacityWatcher . CheckAndUpdate ( ) ;
TwoSidedWatcher . CheckAndUpdate ( ) ;
2020-03-13 13:40:51 -04:00
ImageWatcher . CheckAndUpdate ( ) ;
BrushTypeWatcher . CheckAndUpdate ( ) ;
GizmoPositionWatcher . CheckAndUpdate ( ) ;
GizmoRotationWatcher . CheckAndUpdate ( ) ;
2019-10-01 20:41:42 -04:00
2019-11-05 17:20:52 -05:00
bool bGizmoVisible = ( SculptProperties - > PrimaryBrushType = = EDynamicMeshSculptBrushType : : FixedPlane )
& & ( GizmoProperties - > bShowGizmo ) ;
UpdateFixedPlaneGizmoVisibility ( bGizmoVisible ) ;
GizmoProperties - > bPropertySetEnabled = ( SculptProperties - > PrimaryBrushType = = EDynamicMeshSculptBrushType : : FixedPlane ) ;
2020-03-13 13:40:51 -04:00
if ( PendingWorkPlaneUpdate ! = EPendingWorkPlaneUpdate : : NoUpdatePending )
2019-11-05 17:20:52 -05:00
{
2021-02-03 14:57:28 -04:00
// raycast into scene and current sculpt and place plane at closest hit point
FRay CursorWorldRay = UMeshSurfacePointTool : : LastWorldRay ;
FHitResult Result ;
2021-12-09 14:46:09 -05:00
bool bWorldHit = ToolSceneQueriesUtil : : FindNearestVisibleObjectHit ( this , Result , CursorWorldRay ) ;
2021-03-30 21:25:22 -04:00
FRay3d LocalRay ( CurTargetTransform . InverseTransformPosition ( ( FVector3d ) CursorWorldRay . Origin ) ,
CurTargetTransform . InverseTransformVector ( ( FVector3d ) CursorWorldRay . Direction ) ) ;
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( LocalRay . Direction ) ;
2021-02-03 14:57:28 -04:00
bool bObjectHit = ( FindHitSculptMeshTriangle ( LocalRay ) ! = IndexConstants : : InvalidID ) ;
if ( bWorldHit & &
( bObjectHit = = false | | ( CursorWorldRay . GetParameter ( Result . ImpactPoint ) < CursorWorldRay . GetParameter ( ( FVector ) LastBrushPosWorld ) ) ) )
{
SetFixedSculptPlaneFromWorldPos ( Result . ImpactPoint , Result . ImpactNormal , PendingWorkPlaneUpdate ) ;
}
else
{
SetFixedSculptPlaneFromWorldPos ( ( FVector ) LastBrushPosWorld , ( FVector ) LastBrushPosNormalWorld , PendingWorkPlaneUpdate ) ;
}
2020-03-13 13:40:51 -04:00
PendingWorkPlaneUpdate = EPendingWorkPlaneUpdate : : NoUpdatePending ;
2019-11-05 17:20:52 -05:00
}
2019-10-01 20:41:42 -04:00
// if user changed to not-frozen, we need to update the target
if ( bCachedFreezeTarget ! = SculptProperties - > bFreezeTarget )
{
UpdateTarget ( ) ;
2021-01-20 00:15:28 -04:00
PendingTargetUpdate . Wait ( ) ;
2019-10-01 20:41:42 -04:00
}
bool bMeshModified = false ;
bool bMeshShapeModified = false ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FDynamicMeshOctree3 * Octree = DynamicMeshComponent - > GetOctree ( ) ;
//Octree->CheckValidity(EValidityCheckFailMode::Check, false, true);
//
// Apply stamp
2020-01-27 20:11:15 -05:00
//
2019-10-01 20:41:42 -04:00
2021-01-20 00:15:28 -04:00
bool bROIUpdatePending = false ;
bool bOctreeUpdatePending = false ;
2021-01-27 01:53:01 -04:00
TFuture < void > InitializeRemesher ;
2022-02-02 01:48:37 -05:00
TFuture < void > PrecomputeRemeshROI ;
2019-10-01 20:41:42 -04:00
if ( bStampPending )
{
2021-01-27 01:53:01 -04:00
// if we don't have an active remesher for this brush stroke, create one
if ( ActiveRemesher = = nullptr )
{
InitializeRemesher = Async ( DynamicSculptToolAsyncExecTarget , [ & ] ( )
{
InitializeActiveRemesher ( ) ;
} ) ;
}
2019-10-01 20:41:42 -04:00
2021-01-27 01:53:01 -04:00
// initialize ROI for current brush position
// TODO: does this break move brush??
UpdateBrushPosition ( PendingStampRay ) ;
FVector3d BrushPos = CurTargetTransform . InverseTransformPosition ( LastBrushPosWorld ) ;
UpdateROI ( BrushPos ) ;
2019-10-01 20:41:42 -04:00
2021-01-27 01:53:01 -04:00
// once we know ROI we can speculatively start initializing remesh ROI
2022-02-02 01:48:37 -05:00
PrecomputeRemeshROI = Async ( DynamicSculptToolAsyncExecTarget , [ & ] ( )
2021-01-27 01:53:01 -04:00
{
// make sure our remesher is initialized
InitializeRemesher . Wait ( ) ;
// initialize the ROI
PrecomputeRemesherROI ( ) ;
} ) ;
// apply brush stamp to ROI
2019-10-01 20:41:42 -04:00
ApplyStamp ( PendingStampRay ) ;
2021-01-27 01:53:01 -04:00
bStampPending = ( bInDrag ) ? true : false ;
2019-10-01 20:41:42 -04:00
bNormalUpdatePending = true ;
2021-01-20 00:15:28 -04:00
bROIUpdatePending = true ;
2019-10-01 20:41:42 -04:00
bMeshModified = true ;
bMeshShapeModified = true ;
2021-01-20 00:15:28 -04:00
bOctreeUpdatePending = true ;
2019-10-01 20:41:42 -04:00
2021-01-27 01:53:01 -04:00
if ( bRemeshPending )
2019-10-01 20:41:42 -04:00
{
2021-01-27 01:53:01 -04:00
check ( bInDrag = = true ) ; // this would break undo otherwise!
// make sure our remesher is initialized
InitializeRemesher . Wait ( ) ;
// make sure our ROI is computed
PrecomputeRemeshROI . Wait ( ) ;
// remesh the ROI (this removes all ROI triangles from octree)
if ( ActiveRemesher )
{
RemeshROIPass_ActiveRemesher ( true ) ;
}
else
{
check ( false ) ; // broken now
RemeshROIPass ( ) ;
}
// accumulate new triangles into TriangleROI
for ( int32 tid : RemeshFinalTriangleROI )
{
TriangleROI . Add ( tid ) ;
}
bMeshModified = true ;
bMeshShapeModified = true ;
bRemeshPending = false ;
bNormalUpdatePending = true ;
bROIUpdatePending = true ;
bOctreeUpdatePending = true ;
bHaveRemeshed = true ;
2019-10-01 20:41:42 -04:00
}
}
2021-01-27 01:53:01 -04:00
check ( bRemeshPending = = false ) ; // should never happen...
2019-10-01 20:41:42 -04:00
2021-01-27 01:53:01 -04:00
// launch octree update that inserts/reinserts all triangles in TriangleROI
2021-01-20 00:15:28 -04:00
TFuture < void > UpdateOctreeFuture ;
if ( bOctreeUpdatePending )
{
// reinsert new ROI into octree
UpdateOctreeFuture = Async ( DynamicSculptToolAsyncExecTarget , [ & ] ( ) {
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_OctreeReinsert ) ;
2021-01-20 00:15:28 -04:00
Octree - > ReinsertTriangles ( TriangleROI ) ;
//Octree->CheckValidity(EValidityCheckFailMode::Check, false, true);
} ) ;
bOctreeUpdatePending = false ;
}
2019-10-01 20:41:42 -04:00
//Octree->CheckValidity(EValidityCheckFailMode::Check, false, true);
if ( bNormalUpdatePending )
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateNormals ) ;
2019-10-01 20:41:42 -04:00
if ( Mesh - > HasAttributes ( ) & & Mesh - > Attributes ( ) - > PrimaryNormals ( ) ! = nullptr )
{
2021-01-20 00:15:28 -04:00
RecalculateNormals_Overlay ( TriangleROI ) ;
2019-10-01 20:41:42 -04:00
}
else
{
2021-01-20 00:15:28 -04:00
RecalculateNormals_PerVertex ( TriangleROI ) ;
2019-10-01 20:41:42 -04:00
}
bNormalUpdatePending = false ;
bMeshModified = true ;
}
2021-01-20 00:15:28 -04:00
// next steps need to wait for octree update to finish
UpdateOctreeFuture . Wait ( ) ;
// launch async target update task
if ( bTargetDirty )
{
2021-01-27 01:53:01 -04:00
UpdateTarget ( ) ;
2021-01-20 00:15:28 -04:00
bTargetDirty = false ;
}
2021-01-27 01:53:01 -04:00
// update render data
2019-10-01 20:41:42 -04:00
if ( bMeshModified )
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateRenderMesh ) ;
2019-10-01 20:41:42 -04:00
DynamicMeshComponent - > NotifyMeshUpdated ( ) ;
GetToolManager ( ) - > PostInvalidation ( ) ;
bMeshModified = false ;
}
2022-02-02 01:48:37 -05:00
// Allow futures to finish in case bRemeshPending == false
InitializeRemesher . Wait ( ) ;
PrecomputeRemeshROI . Wait ( ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : PrecomputeRemeshInfo ( )
{
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
// check if we have any open boundary edges
bHaveMeshBoundaries = false ;
for ( int eid : Mesh - > EdgeIndicesItr ( ) )
{
if ( Mesh - > IsBoundaryEdge ( eid ) )
{
bHaveMeshBoundaries = true ;
break ;
}
}
// check if we have any UV seams
bHaveUVSeams = false ;
bHaveNormalSeams = false ;
if ( Mesh - > HasAttributes ( ) )
{
FDynamicMeshAttributeSet * Attribs = Mesh - > Attributes ( ) ;
for ( int k = 0 ; k < Attribs - > NumUVLayers ( ) ; + + k )
{
bHaveUVSeams = bHaveUVSeams | | Attribs - > GetUVLayer ( k ) - > HasInteriorSeamEdges ( ) ;
}
bHaveNormalSeams = Attribs - > PrimaryNormals ( ) - > HasInteriorSeamEdges ( ) ;
}
}
2020-03-17 22:32:24 -04:00
void UDynamicMeshSculptTool : : ScheduleRemeshPass ( )
{
if ( bEnableRemeshing & & RemeshProperties ! = nullptr & & RemeshProperties - > bEnableRemeshing )
{
bRemeshPending = true ;
}
}
2021-01-27 01:53:01 -04:00
/**
* This is an internal class we will use to just hold onto a FSubRegionRemesher instance
* between brush stamps . Perhaps does not need to exist .
*/
class FPersistentStampRemesher
{
public :
FDynamicMesh3 * Mesh ;
TUniquePtr < FSubRegionRemesher > Remesher ;
FPersistentStampRemesher ( FDynamicMesh3 * MeshIn )
{
this - > Mesh = MeshIn ;
Remesher = MakeUnique < FSubRegionRemesher > ( MeshIn ) ;
}
} ;
2020-01-27 20:11:15 -05:00
/*
Split Collapse Vertices Pinned Flip
2020-04-18 18:42:59 -04:00
Fixed FALSE FALSE TRUE FALSE
Refine TRUE FALSE TRUE FALSE
Free TRUE TRUE FALSE FALSE
Ignore TRUE TRUE FALSE TRUE
2020-01-27 20:11:15 -05:00
*/
2019-10-01 20:41:42 -04:00
2020-03-17 22:32:24 -04:00
void UDynamicMeshSculptTool : : ConfigureRemesher ( FSubRegionRemesher & Remesher )
2019-10-01 20:41:42 -04:00
{
2020-02-22 18:14:58 -05:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
2020-03-17 22:32:24 -04:00
const double SizeRange = 5 ;
double LengthMultiplier = ( RemeshProperties - > TriangleSize > = 0 ) ?
FMathd : : Lerp ( 1.0 , 5.0 , FMathd : : Pow ( ( double ) RemeshProperties - > TriangleSize / SizeRange , 2.0 ) )
: FMathd : : Lerp ( 0.25 , 1.0 , 1.0 - FMathd : : Pow ( FMathd : : Abs ( ( double ) RemeshProperties - > TriangleSize ) / SizeRange , 2.0 ) ) ;
double TargetEdgeLength = LengthMultiplier * InitialEdgeLength ;
2019-10-18 13:04:19 -04:00
Remesher . SetTargetEdgeLength ( TargetEdgeLength ) ;
2019-10-01 20:41:42 -04:00
2020-03-17 22:32:24 -04:00
double DetailT = ( double ) ( RemeshProperties - > PreserveDetail ) / 5.0 ;
2020-01-27 20:11:15 -05:00
double UseSmoothing = RemeshProperties - > SmoothingStrength * 0.25 ;
2020-03-17 22:32:24 -04:00
UseSmoothing * = FMathd : : Lerp ( 1.0 , 0.25 , DetailT ) ;
2019-10-18 13:04:19 -04:00
Remesher . SmoothSpeedT = UseSmoothing ;
// this is a temporary tweak for Pinch brush. Remesh params should be per-brush!
2019-10-01 20:41:42 -04:00
if ( SculptProperties - > PrimaryBrushType = = EDynamicMeshSculptBrushType : : Pinch & & bSmoothing = = false )
{
2019-10-18 13:04:19 -04:00
Remesher . MinEdgeLength = TargetEdgeLength * 0.1 ;
2020-02-22 18:14:58 -05:00
Remesher . CustomSmoothSpeedF = [ this , UseSmoothing ] ( const FDynamicMesh3 & Mesh , int vID )
2019-10-18 13:04:19 -04:00
{
FVector3d Pos = Mesh . GetVertex ( vID ) ;
2021-03-30 21:25:22 -04:00
double Falloff = CalculateBrushFalloff ( Distance ( Pos , ( FVector3d ) LastBrushPosLocal ) ) ;
2019-10-18 13:04:19 -04:00
return ( 1.0f - Falloff ) * UseSmoothing ;
} ;
}
2020-03-17 22:32:24 -04:00
else if ( bSmoothing & & SculptProperties - > bDetailPreservingSmooth )
2019-10-18 13:04:19 -04:00
{
2020-03-17 22:32:24 -04:00
// this is the case where we don't want remeshing in smoothing
2020-03-19 10:59:23 -04:00
Remesher . MaxEdgeLength = 3 * InitialEdgeLength ;
Remesher . MinEdgeLength = InitialEdgeLength * 0.05 ;
2019-10-01 20:41:42 -04:00
}
2020-03-17 22:32:24 -04:00
else
{
if ( RemeshProperties - > PreserveDetail > 0 )
{
Remesher . MinEdgeLength * = FMathd : : Lerp ( 1.0 , 0.1 , DetailT ) ;
Remesher . CustomSmoothSpeedF = [ this , UseSmoothing , DetailT ] ( const FDynamicMesh3 & Mesh , int vID )
{
FVector3d Pos = Mesh . GetVertex ( vID ) ;
2021-03-30 21:25:22 -04:00
double FalloffT = 1.0 - CalculateBrushFalloff ( Distance ( Pos , ( FVector3d ) LastBrushPosLocal ) ) ;
2020-03-17 22:32:24 -04:00
FalloffT = FMathd : : Lerp ( 1.0 , FalloffT , DetailT ) ;
return FalloffT * UseSmoothing ;
} ;
}
}
2019-10-01 20:41:42 -04:00
2020-06-23 18:40:00 -04:00
if ( SculptProperties - > bPreserveUVFlow )
{
Remesher . SmoothType = FRemesher : : ESmoothTypes : : MeanValue ;
Remesher . FlipMetric = FRemesher : : EFlipMetric : : MinEdgeLength ;
}
else
{
Remesher . SmoothType = FRemesher : : ESmoothTypes : : Uniform ;
Remesher . FlipMetric = FRemesher : : EFlipMetric : : OptimalValence ;
}
2019-10-01 20:41:42 -04:00
Remesher . bEnableCollapses = RemeshProperties - > bCollapses ;
Remesher . bEnableFlips = RemeshProperties - > bFlips ;
Remesher . bEnableSplits = RemeshProperties - > bSplits ;
Remesher . bPreventNormalFlips = RemeshProperties - > bPreventNormalFlips ;
2020-01-27 20:11:15 -05:00
FMeshConstraints Constraints ;
2019-10-01 20:41:42 -04:00
bool bConstraintAllowSplits = true ;
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_Configure_Constraints ) ;
2019-10-01 20:41:42 -04:00
2020-01-27 20:11:15 -05:00
FMeshConstraintsUtil : : ConstrainAllBoundariesAndSeams ( Constraints , * Mesh ,
( EEdgeRefineFlags ) RemeshProperties - > MeshBoundaryConstraint ,
( EEdgeRefineFlags ) RemeshProperties - > GroupBoundaryConstraint ,
( EEdgeRefineFlags ) RemeshProperties - > MaterialBoundaryConstraint ,
bConstraintAllowSplits , ! RemeshProperties - > bPreserveSharpEdges ) ;
2021-01-21 16:22:06 -04:00
Remesher . SetExternalConstraints ( MoveTemp ( Constraints ) ) ;
2019-10-01 20:41:42 -04:00
}
2020-01-27 20:11:15 -05:00
}
2019-10-01 20:41:42 -04:00
2021-01-27 01:53:01 -04:00
void UDynamicMeshSculptTool : : InitializeRemesherROI ( FSubRegionRemesher & Remesher )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_Configure_InitializeROI ) ;
Remesher . SetInitialVertexROI ( this - > VertexROI ) ;
Remesher . InitializeFromVertexROI ( ) ;
}
void UDynamicMeshSculptTool : : InitializeActiveRemesher ( )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_InitializeActiveRemesher ) ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
ActiveRemesher = MakeShared < FPersistentStampRemesher > ( Mesh ) ;
ConfigureRemesher ( * ActiveRemesher - > Remesher ) ;
}
void UDynamicMeshSculptTool : : PrecomputeRemesherROI ( )
{
FSubRegionRemesher & Remesher = * ActiveRemesher - > Remesher ;
Remesher . Reset ( ) ;
InitializeRemesherROI ( Remesher ) ;
}
void UDynamicMeshSculptTool : : RemeshROIPass_ActiveRemesher ( bool bHasPrecomputedROI )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROIActive ) ;
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FDynamicMeshOctree3 * Octree = DynamicMeshComponent - > GetOctree ( ) ;
FSubRegionRemesher & Remesher = * ActiveRemesher - > Remesher ;
if ( bHasPrecomputedROI = = false )
{
PrecomputeRemesherROI ( ) ;
}
// remove initial triangles
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_CopyROIStep ) ;
RemeshRemovedTriangles = Remesher . GetCurrentTriangleROI ( ) ;
}
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_OctreeRemoveStep ) ;
Octree - > RemoveTriangles ( RemeshRemovedTriangles , true ) ;
}
if ( ActiveMeshChange ! = nullptr )
{
Remesher . SetMeshChangeTracker ( ActiveMeshChange ) ;
}
bool bIsUniformSmooth = ( Remesher . SmoothType = = FRemesher : : ESmoothTypes : : Uniform ) ;
for ( int k = 0 ; k < RemeshProperties - > Iterations ; + + k )
{
if ( ( bIsUniformSmooth = = false ) & & ( k > 1 ) )
{
Remesher . bEnableFlips = false ;
}
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_UpdateStep ) ;
Remesher . UpdateROI ( ) ;
if ( ActiveMeshChange ! = nullptr )
{
// [TODO] would like to only save vertices here, as triangles will be saved by Remesher as necessary.
// However currently FDynamicMeshChangeTracker cannot independently save vertices, only vertices
// that are part of saved triangles will be included in the output FDynamicMeshChange
Remesher . SaveActiveROI ( ActiveMeshChange ) ;
//ActiveMeshChange->VerifySaveState(); // useful for debugging
}
Remesher . BeginTrackRemovedTrisInPass ( ) ;
}
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_RemeshStep ) ;
Remesher . BasicRemeshPass ( ) ;
}
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_OctreeStep ) ;
const TSet < int32 > & TrisRemovedInPass = Remesher . EndTrackRemovedTrisInPass ( ) ;
Octree - > RemoveTriangles ( TrisRemovedInPass ) ;
for ( int32 tid : TrisRemovedInPass )
{
RemeshRemovedTriangles . Add ( tid ) ;
}
}
}
//UE_LOG(LogTemp, Warning, TEXT("Triangle Count %d after update"), Mesh->TriangleCount());
RemeshFinalTriangleROI = Remesher . ExtractFinalTriangleROI ( ) ;
}
2020-01-27 20:11:15 -05:00
void UDynamicMeshSculptTool : : RemeshROIPass ( )
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI ) ;
2020-01-27 20:11:15 -05:00
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FDynamicMeshOctree3 * Octree = DynamicMeshComponent - > GetOctree ( ) ;
2021-01-20 00:15:28 -04:00
2020-02-22 18:14:58 -05:00
FSubRegionRemesher Remesher ( Mesh ) ;
2021-01-27 01:53:01 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_Configure ) ;
ConfigureRemesher ( Remesher ) ;
InitializeRemesherROI ( Remesher ) ;
}
2020-01-27 20:11:15 -05:00
2021-01-20 00:15:28 -04:00
// remove initial triangles
RemeshRemovedTriangles = Remesher . GetCurrentTriangleROI ( ) ;
Octree - > RemoveTriangles ( RemeshRemovedTriangles ) ;
2020-03-26 17:20:25 -04:00
if ( ActiveMeshChange ! = nullptr )
{
Remesher . SetMeshChangeTracker ( ActiveMeshChange ) ;
}
2020-01-27 20:11:15 -05:00
bool bIsUniformSmooth = ( Remesher . SmoothType = = FRemesher : : ESmoothTypes : : Uniform ) ;
2019-10-01 20:41:42 -04:00
for ( int k = 0 ; k < 5 ; + + k )
{
2020-01-27 20:11:15 -05:00
if ( ( bIsUniformSmooth = = false ) & & ( k > 1 ) )
2019-10-01 20:41:42 -04:00
{
2020-01-27 20:11:15 -05:00
Remesher . bEnableFlips = false ;
2019-10-01 20:41:42 -04:00
}
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_UpdateStep ) ;
2019-10-01 20:41:42 -04:00
Remesher . UpdateROI ( ) ;
if ( ActiveMeshChange ! = nullptr )
{
2020-03-26 17:20:25 -04:00
// [TODO] would like to only save vertices here, as triangles will be saved by Remesher as necessary.
// However currently FDynamicMeshChangeTracker cannot independently save vertices, only vertices
// that are part of saved triangles will be included in the output FDynamicMeshChange
2019-10-01 20:41:42 -04:00
Remesher . SaveActiveROI ( ActiveMeshChange ) ;
//ActiveMeshChange->VerifySaveState(); // useful for debugging
}
Remesher . BeginTrackRemovedTrisInPass ( ) ;
}
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_RemeshROI_RemeshStep ) ;
2019-10-01 20:41:42 -04:00
Remesher . BasicRemeshPass ( ) ;
}
{
const TSet < int32 > & TrisRemovedInPass = Remesher . EndTrackRemovedTrisInPass ( ) ;
Octree - > RemoveTriangles ( TrisRemovedInPass ) ;
2021-01-20 00:15:28 -04:00
for ( int32 tid : TrisRemovedInPass )
{
RemeshRemovedTriangles . Add ( tid ) ;
}
2019-10-01 20:41:42 -04:00
}
}
//UE_LOG(LogTemp, Warning, TEXT("Triangle Count %d after update"), Mesh->TriangleCount());
2021-01-20 00:15:28 -04:00
RemeshFinalTriangleROI = Remesher . ExtractFinalTriangleROI ( ) ;
2019-10-01 20:41:42 -04:00
}
2021-01-20 00:15:28 -04:00
void UDynamicMeshSculptTool : : RecalculateNormals_PerVertex ( const TSet < int32 > & Triangles )
2019-10-01 20:41:42 -04:00
{
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
int MaxVertexID = Mesh - > MaxVertexID ( ) ;
if ( NormalsVertexFlags . Num ( ) < MaxVertexID )
{
NormalsVertexFlags . Init ( false , MaxVertexID * 2 ) ;
}
{
NormalsBuffer . Reset ( ) ;
2021-01-20 00:15:28 -04:00
for ( int TriangleID : Triangles )
2019-10-01 20:41:42 -04:00
{
2021-01-20 00:15:28 -04:00
if ( Mesh - > IsTriangle ( TriangleID ) )
2019-10-01 20:41:42 -04:00
{
2021-01-20 00:15:28 -04:00
FIndex3i TriV = Mesh - > GetTriangle ( TriangleID ) ;
for ( int j = 0 ; j < 3 ; + + j )
2019-10-01 20:41:42 -04:00
{
2021-01-20 00:15:28 -04:00
int vid = TriV [ j ] ;
if ( NormalsVertexFlags [ vid ] = = false )
{
NormalsBuffer . Add ( vid ) ;
NormalsVertexFlags [ vid ] = true ;
}
2019-10-01 20:41:42 -04:00
}
}
}
}
{
ParallelFor ( NormalsBuffer . Num ( ) , [ & ] ( int k ) {
int vid = NormalsBuffer [ k ] ;
FVector3d NewNormal = FMeshNormals : : ComputeVertexNormal ( * Mesh , vid ) ;
Mesh - > SetVertexNormal ( vid , ( FVector3f ) NewNormal ) ;
NormalsVertexFlags [ vid ] = false ;
} ) ;
}
}
2021-01-20 00:15:28 -04:00
void UDynamicMeshSculptTool : : RecalculateNormals_Overlay ( const TSet < int32 > & Triangles )
2019-10-01 20:41:42 -04:00
{
FDynamicMesh3 * Mesh = DynamicMeshComponent - > GetMesh ( ) ;
FDynamicMeshNormalOverlay * Normals = Mesh - > HasAttributes ( ) ? Mesh - > Attributes ( ) - > PrimaryNormals ( ) : nullptr ;
check ( Normals ! = nullptr ) ;
int MaxElementID = Normals - > MaxElementID ( ) ;
if ( NormalsVertexFlags . Num ( ) < MaxElementID )
{
NormalsVertexFlags . Init ( false , MaxElementID * 2 ) ;
}
{
NormalsBuffer . Reset ( ) ;
2021-01-20 00:15:28 -04:00
for ( int TriangleID : Triangles )
2019-10-01 20:41:42 -04:00
{
2021-01-20 00:15:28 -04:00
if ( Mesh - > IsTriangle ( TriangleID ) )
2019-10-01 20:41:42 -04:00
{
2021-01-20 00:15:28 -04:00
FIndex3i TriElems = Normals - > GetTriangle ( TriangleID ) ;
2021-10-01 08:21:22 -04:00
if ( TriElems . A = = FDynamicMesh3 : : InvalidID )
{
continue ;
}
2021-01-20 00:15:28 -04:00
for ( int j = 0 ; j < 3 ; + + j )
2019-10-01 20:41:42 -04:00
{
2021-01-20 00:15:28 -04:00
int elemid = TriElems [ j ] ;
if ( NormalsVertexFlags [ elemid ] = = false )
{
NormalsBuffer . Add ( elemid ) ;
NormalsVertexFlags [ elemid ] = true ;
}
2019-10-01 20:41:42 -04:00
}
}
}
}
{
ParallelFor ( NormalsBuffer . Num ( ) , [ & ] ( int k ) {
int elemid = NormalsBuffer [ k ] ;
FVector3d NewNormal = FMeshNormals : : ComputeOverlayNormal ( * Mesh , Normals , elemid ) ;
Normals - > SetElement ( elemid , ( FVector3f ) NewNormal ) ;
NormalsVertexFlags [ elemid ] = false ;
} ) ;
}
}
2021-01-27 01:53:01 -04:00
2019-10-01 20:41:42 -04:00
void UDynamicMeshSculptTool : : UpdateTarget ( )
{
if ( SculptProperties ! = nullptr )
{
bCachedFreezeTarget = SculptProperties - > bFreezeTarget ;
if ( SculptProperties - > bFreezeTarget )
{
return ; // do not update frozen target
}
}
2022-02-02 15:56:53 -05:00
// Allow any in-progress update to finish before starting a new one
PendingTargetUpdate . Wait ( ) ;
2021-01-20 00:15:28 -04:00
// TODO: could have a second set of target meshes, and swap between them while we update the other one
PendingTargetUpdate = Async ( DynamicSculptToolAsyncExecTarget , [ this ] ( )
{
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateTarget ) ;
2021-01-20 00:15:28 -04:00
BrushTargetMesh . Copy ( * DynamicMeshComponent - > GetMesh ( ) , false , false , false , false ) ;
TFuture < void > TargetSpatialUpdate = Async ( DynamicSculptToolAsyncExecTarget , [ this ] ( ) {
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateTarget_Spatial ) ;
2021-01-20 00:15:28 -04:00
BrushTargetMeshSpatial . SetMesh ( & BrushTargetMesh , true ) ;
} ) ;
TFuture < void > TargetNormalsUpdate = Async ( DynamicSculptToolAsyncExecTarget , [ this ] ( ) {
2021-01-27 01:53:01 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DynamicMeshSculptTool_UpdateTarget_Normals ) ;
2021-01-20 00:15:28 -04:00
BrushTargetNormals . SetMesh ( & BrushTargetMesh ) ;
BrushTargetNormals . ComputeVertexNormals ( ) ;
} ) ;
TargetSpatialUpdate . Wait ( ) ;
TargetNormalsUpdate . Wait ( ) ;
} ) ;
2019-10-01 20:41:42 -04:00
}
bool UDynamicMeshSculptTool : : GetTargetMeshNearest ( const FVector3d & Position , double SearchRadius , FVector3d & TargetPosOut , FVector3d & TargetNormalOut )
{
2021-01-20 00:15:28 -04:00
PendingTargetUpdate . Wait ( ) ;
2019-10-01 20:41:42 -04:00
double fDistSqr ;
int NearTID = BrushTargetMeshSpatial . FindNearestTriangle ( Position , fDistSqr , SearchRadius ) ;
if ( NearTID < = 0 )
{
return false ;
}
FTriangle3d Triangle ;
BrushTargetMesh . GetTriVertices ( NearTID , Triangle . V [ 0 ] , Triangle . V [ 1 ] , Triangle . V [ 2 ] ) ;
FDistPoint3Triangle3d Query ( Position , Triangle ) ;
Query . Get ( ) ;
FIndex3i Tri = BrushTargetMesh . GetTriangle ( NearTID ) ;
TargetNormalOut =
Query . TriangleBaryCoords . X * BrushTargetNormals [ Tri . A ]
+ Query . TriangleBaryCoords . Y * BrushTargetNormals [ Tri . B ]
+ Query . TriangleBaryCoords . Z * BrushTargetNormals [ Tri . C ] ;
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( TargetNormalOut ) ;
2019-10-01 20:41:42 -04:00
TargetPosOut = Query . ClosestTrianglePoint ;
return true ;
}
double UDynamicMeshSculptTool : : EstimateIntialSafeTargetLength ( const FDynamicMesh3 & Mesh , int MinTargetTriCount )
{
double AreaSum = 0 ;
for ( int tid : Mesh . TriangleIndicesItr ( ) )
{
AreaSum + = Mesh . GetTriArea ( tid ) ;
}
int TriCount = Mesh . TriangleCount ( ) ;
double TargetTriArea = 1.0 ;
if ( TriCount < MinTargetTriCount )
{
TargetTriArea = AreaSum / ( double ) MinTargetTriCount ;
}
else
{
TargetTriArea = AreaSum / ( double ) TriCount ;
}
double EdgeLen = TriangleUtil : : EquilateralEdgeLengthForArea ( TargetTriArea ) ;
return ( double ) FMath : : RoundToInt ( EdgeLen * 100.0 ) / 100.0 ;
}
2019-10-24 14:46:56 -04:00
UPreviewMesh * UDynamicMeshSculptTool : : MakeDefaultSphereMesh ( UObject * Parent , UWorld * World , int Resolution /*= 32*/ )
{
UPreviewMesh * SphereMesh = NewObject < UPreviewMesh > ( Parent ) ;
SphereMesh - > CreateInWorld ( World , FTransform : : Identity ) ;
FSphereGenerator SphereGen ;
SphereGen . NumPhi = SphereGen . NumTheta = Resolution ;
SphereGen . Generate ( ) ;
FDynamicMesh3 Mesh ( & SphereGen ) ;
SphereMesh - > UpdatePreview ( & Mesh ) ;
2020-03-20 12:44:53 -04:00
BrushIndicatorMaterial = ToolSetupUtil : : GetDefaultBrushVolumeMaterial ( GetToolManager ( ) ) ;
if ( BrushIndicatorMaterial )
{
SphereMesh - > SetMaterial ( BrushIndicatorMaterial ) ;
}
2019-10-24 14:46:56 -04:00
return SphereMesh ;
}
2019-10-01 20:41:42 -04:00
void UDynamicMeshSculptTool : : IncreaseBrushRadiusAction ( )
2021-10-28 13:24:28 -04:00
{
BrushProperties - > BrushSize . IncreaseRadius ( false ) ;
2021-12-10 17:49:08 -05:00
NotifyOfPropertyChangeByTool ( BrushProperties ) ;
2021-12-10 21:24:31 -05:00
CalculateBrushRadius ( ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : DecreaseBrushRadiusAction ( )
{
2021-10-28 13:24:28 -04:00
BrushProperties - > BrushSize . DecreaseRadius ( false ) ;
2021-12-10 17:49:08 -05:00
NotifyOfPropertyChangeByTool ( BrushProperties ) ;
2021-12-10 21:24:31 -05:00
CalculateBrushRadius ( ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : IncreaseBrushRadiusSmallStepAction ( )
{
2021-10-28 13:24:28 -04:00
BrushProperties - > BrushSize . IncreaseRadius ( true ) ;
2021-12-10 17:49:08 -05:00
NotifyOfPropertyChangeByTool ( BrushProperties ) ;
2021-12-10 21:24:31 -05:00
CalculateBrushRadius ( ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : DecreaseBrushRadiusSmallStepAction ( )
{
2021-10-28 13:24:28 -04:00
BrushProperties - > BrushSize . DecreaseRadius ( true ) ;
2021-12-10 17:49:08 -05:00
NotifyOfPropertyChangeByTool ( BrushProperties ) ;
2021-12-10 21:24:31 -05:00
CalculateBrushRadius ( ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : IncreaseBrushSpeedAction ( )
{
2020-01-27 20:11:15 -05:00
SculptProperties - > PrimaryBrushSpeed = FMath : : Clamp ( SculptProperties - > PrimaryBrushSpeed + 0.05f , 0.0f , 1.0f ) ;
2021-12-10 17:49:08 -05:00
NotifyOfPropertyChangeByTool ( SculptProperties ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : DecreaseBrushSpeedAction ( )
{
2020-01-27 20:11:15 -05:00
SculptProperties - > PrimaryBrushSpeed = FMath : : Clamp ( SculptProperties - > PrimaryBrushSpeed - 0.05f , 0.0f , 1.0f ) ;
2021-12-10 17:49:08 -05:00
NotifyOfPropertyChangeByTool ( SculptProperties ) ;
2019-10-01 20:41:42 -04:00
}
void UDynamicMeshSculptTool : : NextHistoryBrushModeAction ( )
{
int MaxHistory = BrushTypeHistory . Num ( ) - 1 ;
if ( BrushTypeHistoryIndex < MaxHistory )
{
BrushTypeHistoryIndex + + ;
SculptProperties - > PrimaryBrushType = BrushTypeHistory [ BrushTypeHistoryIndex ] ;
LastStampType = SculptProperties - > PrimaryBrushType ;
}
}
void UDynamicMeshSculptTool : : PreviousHistoryBrushModeAction ( )
{
if ( BrushTypeHistoryIndex > 0 )
{
BrushTypeHistoryIndex - - ;
SculptProperties - > PrimaryBrushType = BrushTypeHistory [ BrushTypeHistoryIndex ] ;
LastStampType = SculptProperties - > PrimaryBrushType ;
}
}
void UDynamicMeshSculptTool : : RegisterActions ( FInteractiveToolActionSet & ActionSet )
{
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : IncreaseBrushSize ,
2020-01-27 20:11:15 -05:00
TEXT ( " SculptIncreaseRadius " ) ,
2019-10-01 20:41:42 -04:00
LOCTEXT ( " SculptIncreaseRadius " , " Increase Sculpt Radius " ) ,
LOCTEXT ( " SculptIncreaseRadiusTooltip " , " Increase radius of sculpting brush " ) ,
EModifierKey : : None , EKeys : : RightBracket ,
[ this ] ( ) { IncreaseBrushRadiusAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : DecreaseBrushSize ,
2020-01-27 20:11:15 -05:00
TEXT ( " SculptDecreaseRadius " ) ,
2019-10-01 20:41:42 -04:00
LOCTEXT ( " SculptDecreaseRadius " , " Decrease Sculpt Radius " ) ,
LOCTEXT ( " SculptDecreaseRadiusTooltip " , " Decrease radius of sculpting brush " ) ,
EModifierKey : : None , EKeys : : LeftBracket ,
[ this ] ( ) { DecreaseBrushRadiusAction ( ) ; } ) ;
2020-03-13 13:40:51 -04:00
2019-11-08 10:47:08 -05:00
//ActionSet.RegisterAction(this, (int32)EStandardToolActions::BaseClientDefinedActionID + 10,
// TEXT("NextBrushHistoryState"),
// LOCTEXT("SculptNextBrushHistoryState", "Next Brush History State"),
// LOCTEXT("SculptSculptNextBrushHistoryStateTooltip", "Cycle to next Brush History state"),
// EModifierKey::Shift, EKeys::Q,
// [this]() { NextHistoryBrushModeAction(); });
2019-10-01 20:41:42 -04:00
2019-11-08 10:47:08 -05:00
//ActionSet.RegisterAction(this, (int32)EStandardToolActions::BaseClientDefinedActionID + 11,
// TEXT("PreviousBrushHistoryState"),
// LOCTEXT("SculptPreviousBrushHistoryState", "Previous Brush History State"),
// LOCTEXT("SculptPreviousBrushHistoryStateTooltip", "Cycle to previous Brush History state"),
// EModifierKey::Shift, EKeys::A,
// [this]() { PreviousHistoryBrushModeAction(); });
2019-10-01 20:41:42 -04:00
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 50 ,
TEXT ( " SculptIncreaseSize " ) ,
LOCTEXT ( " SculptIncreaseSize " , " Increase Size " ) ,
LOCTEXT ( " SculptIncreaseSizeTooltip " , " Increase Brush Size " ) ,
2020-03-13 13:40:51 -04:00
EModifierKey : : None , EKeys : : D ,
2019-10-01 20:41:42 -04:00
[ this ] ( ) { IncreaseBrushRadiusAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 51 ,
TEXT ( " SculptDecreaseSize " ) ,
LOCTEXT ( " SculptDecreaseSize " , " Decrease Size " ) ,
LOCTEXT ( " SculptDecreaseSizeTooltip " , " Decrease Brush Size " ) ,
2020-03-13 13:40:51 -04:00
EModifierKey : : None , EKeys : : S ,
2019-10-01 20:41:42 -04:00
[ this ] ( ) { DecreaseBrushRadiusAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 52 ,
TEXT ( " SculptIncreaseSizeSmallStep " ) ,
LOCTEXT ( " SculptIncreaseSize " , " Increase Size " ) ,
LOCTEXT ( " SculptIncreaseSizeTooltip " , " Increase Brush Size " ) ,
2020-03-13 13:40:51 -04:00
EModifierKey : : Shift , EKeys : : D ,
2019-10-01 20:41:42 -04:00
[ this ] ( ) { IncreaseBrushRadiusSmallStepAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 53 ,
TEXT ( " SculptDecreaseSizeSmallStemp " ) ,
LOCTEXT ( " SculptDecreaseSize " , " Decrease Size " ) ,
LOCTEXT ( " SculptDecreaseSizeTooltip " , " Decrease Brush Size " ) ,
2020-03-13 13:40:51 -04:00
EModifierKey : : Shift , EKeys : : S ,
2019-10-01 20:41:42 -04:00
[ this ] ( ) { DecreaseBrushRadiusSmallStepAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 60 ,
TEXT ( " SculptIncreaseSpeed " ) ,
LOCTEXT ( " SculptIncreaseSpeed " , " Increase Speed " ) ,
LOCTEXT ( " SculptIncreaseSpeedTooltip " , " Increase Brush Speed " ) ,
2020-03-13 13:40:51 -04:00
EModifierKey : : None , EKeys : : E ,
2019-10-01 20:41:42 -04:00
[ this ] ( ) { IncreaseBrushSpeedAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 61 ,
TEXT ( " SculptDecreaseSpeed " ) ,
LOCTEXT ( " SculptDecreaseSpeed " , " Decrease Speed " ) ,
LOCTEXT ( " SculptDecreaseSpeedTooltip " , " Decrease Brush Speed " ) ,
2020-03-13 13:40:51 -04:00
EModifierKey : : None , EKeys : : W ,
2019-10-01 20:41:42 -04:00
[ this ] ( ) { DecreaseBrushSpeedAction ( ) ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : ToggleWireframe ,
TEXT ( " ToggleWireframe " ) ,
LOCTEXT ( " ToggleWireframe " , " Toggle Wireframe " ) ,
LOCTEXT ( " ToggleWireframeTooltip " , " Toggle visibility of wireframe overlay " ) ,
EModifierKey : : Alt , EKeys : : W ,
[ this ] ( ) { ViewProperties - > bShowWireframe = ! ViewProperties - > bShowWireframe ; } ) ;
2019-11-05 17:20:52 -05:00
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 100 ,
2020-03-13 13:40:51 -04:00
TEXT ( " SetSculptWorkSurfacePosNormal " ) ,
LOCTEXT ( " SetSculptWorkSurfacePosNormal " , " Reorient Work Surface " ) ,
LOCTEXT ( " SetSculptWorkSurfacePosNormalTooltip " , " Move the Sculpting Work Plane/Surface to Position and Normal of World hit point under cursor " ) ,
EModifierKey : : Shift , EKeys : : T ,
[ this ] ( ) { PendingWorkPlaneUpdate = EPendingWorkPlaneUpdate : : MoveToHitPositionNormal ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 101 ,
TEXT ( " SetSculptWorkSurfacePos " ) ,
LOCTEXT ( " SetSculptWorkSurfacePos " , " Reposition Work Surface " ) ,
LOCTEXT ( " SetSculptWorkSurfacePosTooltip " , " Move the Sculpting Work Plane/Surface to World hit point under cursor (keep current Orientation) " ) ,
EModifierKey : : None , EKeys : : T ,
[ this ] ( ) { PendingWorkPlaneUpdate = EPendingWorkPlaneUpdate : : MoveToHitPosition ; } ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 102 ,
TEXT ( " SetSculptWorkSurfaceView " ) ,
LOCTEXT ( " SetSculptWorkSurfaceView " , " View-Align Work Surface " ) ,
LOCTEXT ( " SetSculptWorkSurfaceViewTooltip " , " Move the Sculpting Work Plane/Surface to World hit point under cursor and align to View " ) ,
EModifierKey : : Control | EModifierKey : : Shift , EKeys : : T ,
[ this ] ( ) { PendingWorkPlaneUpdate = EPendingWorkPlaneUpdate : : MoveToHitPositionViewAligned ; } ) ;
2019-11-05 17:20:52 -05:00
2019-10-01 20:41:42 -04:00
}
//
// Change Tracking
//
void UDynamicMeshSculptTool : : BeginChange ( bool bIsVertexChange )
{
check ( ActiveVertexChange = = nullptr ) ;
check ( ActiveMeshChange = = nullptr ) ;
2020-01-27 20:11:15 -05:00
if ( bIsVertexChange )
2019-10-01 20:41:42 -04:00
{
ActiveVertexChange = new FMeshVertexChangeBuilder ( ) ;
}
else
{
ActiveMeshChange = new FDynamicMeshChangeTracker ( DynamicMeshComponent - > GetMesh ( ) ) ;
ActiveMeshChange - > BeginChange ( ) ;
}
}
void UDynamicMeshSculptTool : : EndChange ( )
{
if ( ActiveVertexChange ! = nullptr )
{
2021-01-20 00:15:28 -04:00
GetToolManager ( ) - > EmitObjectChange ( DynamicMeshComponent , MoveTemp ( ActiveVertexChange - > Change ) , LOCTEXT ( " MeshSculptChange " , " Brush Stroke " ) ) ;
2019-10-01 20:41:42 -04:00
delete ActiveVertexChange ;
ActiveVertexChange = nullptr ;
}
if ( ActiveMeshChange ! = nullptr )
{
FMeshChange * NewMeshChange = new FMeshChange ( ) ;
NewMeshChange - > DynamicMeshChange = ActiveMeshChange - > EndChange ( ) ;
//NewMeshChange->DynamicMeshChange->CheckValidity();
TUniquePtr < FMeshChange > NewChange ( NewMeshChange ) ;
GetToolManager ( ) - > EmitObjectChange ( DynamicMeshComponent , MoveTemp ( NewChange ) , LOCTEXT ( " MeshSculptChange " , " Brush Stroke " ) ) ;
delete ActiveMeshChange ;
ActiveMeshChange = nullptr ;
}
}
void UDynamicMeshSculptTool : : SaveActiveROI ( )
{
if ( ActiveMeshChange ! = nullptr )
{
2020-03-26 17:20:25 -04:00
// must save triangles containing vertex ROI or they will not be included in emitted mesh change (due to limitations of change tracker)
ActiveMeshChange - > SaveVertexOneRingTriangles ( VertexROI , true ) ;
2019-10-01 20:41:42 -04:00
}
}
void UDynamicMeshSculptTool : : UpdateMaterialMode ( EMeshEditingMaterialModes MaterialMode )
{
if ( MaterialMode = = EMeshEditingMaterialModes : : ExistingMaterial )
{
2019-12-19 18:07:47 -05:00
DynamicMeshComponent - > ClearOverrideRenderMaterial ( ) ;
2021-06-17 19:18:41 -04:00
DynamicMeshComponent - > SetShadowsEnabled ( UE : : ToolTarget : : GetTargetComponent ( Target ) - > bCastDynamicShadow ) ;
ActiveOverrideMaterial = nullptr ;
2020-01-27 20:11:15 -05:00
}
2020-03-13 13:40:51 -04:00
else
2020-01-27 20:11:15 -05:00
{
2020-03-13 13:40:51 -04:00
if ( MaterialMode = = EMeshEditingMaterialModes : : Custom )
2021-04-01 17:33:33 -04:00
{
if ( ViewProperties - > CustomMaterial . IsValid ( ) )
{
ActiveOverrideMaterial = UMaterialInstanceDynamic : : Create ( ViewProperties - > CustomMaterial . Get ( ) , this ) ;
}
else
{
DynamicMeshComponent - > ClearOverrideRenderMaterial ( ) ;
ActiveOverrideMaterial = nullptr ;
}
}
else if ( MaterialMode = = EMeshEditingMaterialModes : : CustomImage )
2019-10-01 20:41:42 -04:00
{
2020-03-13 13:40:51 -04:00
ActiveOverrideMaterial = ToolSetupUtil : : GetCustomImageBasedSculptMaterial ( GetToolManager ( ) , ViewProperties - > Image ) ;
if ( ViewProperties - > Image ! = nullptr )
{
ActiveOverrideMaterial - > SetTextureParameterValue ( TEXT ( " ImageTexture " ) , ViewProperties - > Image ) ;
}
2019-10-01 20:41:42 -04:00
}
2021-04-01 17:33:33 -04:00
else if ( MaterialMode = = EMeshEditingMaterialModes : : Transparent )
{
ActiveOverrideMaterial = ToolSetupUtil : : GetTransparentSculptMaterial ( GetToolManager ( ) ,
ViewProperties - > TransparentMaterialColor , ViewProperties - > Opacity , ViewProperties - > bTwoSided ) ;
}
2020-03-13 13:40:51 -04:00
else
{
UMaterialInterface * SculptMaterial = nullptr ;
switch ( MaterialMode )
{
case EMeshEditingMaterialModes : : Diffuse :
SculptMaterial = ToolSetupUtil : : GetDefaultSculptMaterial ( GetToolManager ( ) ) ;
break ;
case EMeshEditingMaterialModes : : Grey :
SculptMaterial = ToolSetupUtil : : GetImageBasedSculptMaterial ( GetToolManager ( ) , ToolSetupUtil : : ImageMaterialType : : DefaultBasic ) ;
break ;
case EMeshEditingMaterialModes : : Soft :
SculptMaterial = ToolSetupUtil : : GetImageBasedSculptMaterial ( GetToolManager ( ) , ToolSetupUtil : : ImageMaterialType : : DefaultSoft ) ;
break ;
case EMeshEditingMaterialModes : : TangentNormal :
SculptMaterial = ToolSetupUtil : : GetImageBasedSculptMaterial ( GetToolManager ( ) , ToolSetupUtil : : ImageMaterialType : : TangentNormalFromView ) ;
break ;
2020-12-04 19:51:25 -04:00
case EMeshEditingMaterialModes : : VertexColor :
SculptMaterial = ToolSetupUtil : : GetVertexColorMaterial ( GetToolManager ( ) ) ;
break ;
2020-03-13 13:40:51 -04:00
}
if ( SculptMaterial ! = nullptr )
{
ActiveOverrideMaterial = UMaterialInstanceDynamic : : Create ( SculptMaterial , this ) ;
}
}
if ( ActiveOverrideMaterial ! = nullptr )
{
DynamicMeshComponent - > SetOverrideRenderMaterial ( ActiveOverrideMaterial ) ;
ActiveOverrideMaterial - > SetScalarParameterValue ( TEXT ( " FlatShading " ) , ( ViewProperties - > bFlatShading ) ? 1.0f : 0.0f ) ;
}
2021-06-17 19:18:41 -04:00
DynamicMeshComponent - > SetShadowsEnabled ( false ) ;
2019-10-01 20:41:42 -04:00
}
}
2020-03-13 13:40:51 -04:00
void UDynamicMeshSculptTool : : UpdateFlatShadingSetting ( bool bNewValue )
2019-11-05 17:20:52 -05:00
{
2020-03-13 13:40:51 -04:00
if ( ActiveOverrideMaterial ! = nullptr )
{
ActiveOverrideMaterial - > SetScalarParameterValue ( TEXT ( " FlatShading " ) , ( bNewValue ) ? 1.0f : 0.0f ) ;
}
}
void UDynamicMeshSculptTool : : UpdateColorSetting ( FLinearColor NewColor )
{
if ( ActiveOverrideMaterial ! = nullptr )
{
ActiveOverrideMaterial - > SetVectorParameterValue ( TEXT ( " Color " ) , NewColor ) ;
}
}
2021-04-01 17:33:33 -04:00
void UDynamicMeshSculptTool : : UpdateOpacitySetting ( double Opacity )
{
if ( ActiveOverrideMaterial ! = nullptr )
{
ActiveOverrideMaterial - > SetScalarParameterValue ( TEXT ( " Opacity " ) , Opacity ) ;
}
}
void UDynamicMeshSculptTool : : UpdateTwoSidedSetting ( bool bOn )
{
ActiveOverrideMaterial = ToolSetupUtil : : GetTransparentSculptMaterial ( GetToolManager ( ) ,
ViewProperties - > TransparentMaterialColor , ViewProperties - > Opacity , bOn ) ;
if ( ActiveOverrideMaterial )
{
DynamicMeshComponent - > SetOverrideRenderMaterial ( ActiveOverrideMaterial ) ;
}
}
void UDynamicMeshSculptTool : : UpdateCustomMaterial ( TWeakObjectPtr < UMaterialInterface > NewMaterial )
{
if ( ViewProperties - > MaterialMode = = EMeshEditingMaterialModes : : Custom )
{
if ( NewMaterial . IsValid ( ) )
{
ActiveOverrideMaterial = UMaterialInstanceDynamic : : Create ( NewMaterial . Get ( ) , this ) ;
DynamicMeshComponent - > SetOverrideRenderMaterial ( ActiveOverrideMaterial ) ;
}
else
{
DynamicMeshComponent - > ClearOverrideRenderMaterial ( ) ;
ActiveOverrideMaterial = nullptr ;
}
}
}
2020-03-13 13:40:51 -04:00
void UDynamicMeshSculptTool : : UpdateImageSetting ( UTexture2D * NewImage )
{
if ( ActiveOverrideMaterial ! = nullptr )
{
ActiveOverrideMaterial - > SetTextureParameterValue ( TEXT ( " ImageTexture " ) , NewImage ) ;
}
}
void UDynamicMeshSculptTool : : UpdateBrushType ( EDynamicMeshSculptBrushType BrushType )
{
2020-05-03 16:02:33 -04:00
static const FText BaseMessage = LOCTEXT ( " OnStartSculptTool " , " Hold Shift to Smooth, Ctrl to Invert (where applicable). [/] and S/D change Size (+Shift to small-step), W/E changes Strength. " ) ;
2020-03-13 13:40:51 -04:00
FTextBuilder Builder ;
Builder . AppendLine ( BaseMessage ) ;
SetToolPropertySourceEnabled ( GizmoProperties , false ) ;
2020-03-19 10:59:23 -04:00
SetToolPropertySourceEnabled ( SculptMaxBrushProperties , false ) ;
2020-03-13 13:40:51 -04:00
if ( BrushType = = EDynamicMeshSculptBrushType : : FixedPlane )
{
Builder . AppendLine ( LOCTEXT ( " FixedPlaneTip " , " Use T to reposition Work Plane at cursor, Shift+T to align to Normal, Ctrl+Shift+T to align to View " ) ) ;
SetToolPropertySourceEnabled ( GizmoProperties , true ) ;
}
2020-03-19 10:59:23 -04:00
if ( BrushType = = EDynamicMeshSculptBrushType : : SculptMax )
{
SetToolPropertySourceEnabled ( SculptMaxBrushProperties , true ) ;
}
2020-03-13 13:40:51 -04:00
GetToolManager ( ) - > DisplayMessage ( Builder . ToText ( ) , EToolMessageLevel : : UserNotification ) ;
}
void UDynamicMeshSculptTool : : SetFixedSculptPlaneFromWorldPos ( const FVector & Position , const FVector & Normal , EPendingWorkPlaneUpdate UpdateType )
{
if ( UpdateType = = EPendingWorkPlaneUpdate : : MoveToHitPositionNormal )
{
UpdateFixedSculptPlanePosition ( Position ) ;
FFrame3d CurFrame ( FVector : : ZeroVector , GizmoProperties - > Rotation ) ;
CurFrame . AlignAxis ( 2 , ( FVector3d ) Normal ) ;
UpdateFixedSculptPlaneRotation ( ( FQuat ) CurFrame . Rotation ) ;
}
else if ( UpdateType = = EPendingWorkPlaneUpdate : : MoveToHitPositionViewAligned )
{
UpdateFixedSculptPlanePosition ( Position ) ;
FFrame3d CurFrame ( FVector : : ZeroVector , GizmoProperties - > Rotation ) ;
CurFrame . AlignAxis ( 2 , - ( FVector3d ) CameraState . Forward ( ) ) ;
UpdateFixedSculptPlaneRotation ( ( FQuat ) CurFrame . Rotation ) ;
}
else
{
UpdateFixedSculptPlanePosition ( Position ) ;
}
2019-11-05 17:20:52 -05:00
if ( PlaneTransformGizmo ! = nullptr )
{
2020-03-13 13:40:51 -04:00
PlaneTransformGizmo - > SetNewGizmoTransform ( FTransform ( GizmoProperties - > Rotation , GizmoProperties - > Position ) ) ;
2019-11-05 17:20:52 -05:00
}
}
void UDynamicMeshSculptTool : : PlaneTransformChanged ( UTransformProxy * Proxy , FTransform Transform )
{
2020-03-13 13:40:51 -04:00
UpdateFixedSculptPlaneRotation ( Transform . GetRotation ( ) ) ;
2019-11-05 17:20:52 -05:00
UpdateFixedSculptPlanePosition ( Transform . GetLocation ( ) ) ;
}
void UDynamicMeshSculptTool : : UpdateFixedSculptPlanePosition ( const FVector & Position )
{
2019-11-05 20:26:40 -05:00
GizmoProperties - > Position = Position ;
2020-03-13 13:40:51 -04:00
GizmoPositionWatcher . SilentUpdate ( ) ;
}
void UDynamicMeshSculptTool : : UpdateFixedSculptPlaneRotation ( const FQuat & Rotation )
{
GizmoProperties - > Rotation = Rotation ;
GizmoRotationWatcher . SilentUpdate ( ) ;
}
void UDynamicMeshSculptTool : : UpdateGizmoFromProperties ( )
{
if ( PlaneTransformGizmo ! = nullptr )
{
PlaneTransformGizmo - > SetNewGizmoTransform ( FTransform ( GizmoProperties - > Rotation , GizmoProperties - > Position ) ) ;
}
2019-11-05 17:20:52 -05:00
}
void UDynamicMeshSculptTool : : UpdateFixedPlaneGizmoVisibility ( bool bVisible )
{
if ( bVisible = = false )
{
if ( PlaneTransformGizmo ! = nullptr )
{
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DestroyGizmo ( PlaneTransformGizmo ) ;
PlaneTransformGizmo = nullptr ;
}
}
else
{
if ( PlaneTransformGizmo = = nullptr )
{
2021-05-20 16:39:39 -04:00
PlaneTransformGizmo = UE : : TransformGizmoUtil : : CreateCustomTransformGizmo ( GetToolManager ( ) ,
2020-01-27 20:11:15 -05:00
ETransformGizmoSubElements : : StandardTranslateRotate , this ) ;
2020-03-13 13:40:51 -04:00
PlaneTransformGizmo - > bUseContextCoordinateSystem = false ;
PlaneTransformGizmo - > CurrentCoordinateSystem = EToolContextCoordinateSystem : : Local ;
2019-11-05 17:20:52 -05:00
PlaneTransformGizmo - > SetActiveTarget ( PlaneTransformProxy , GetToolManager ( ) ) ;
2020-09-24 00:43:27 -04:00
PlaneTransformGizmo - > ReinitializeGizmoTransform ( FTransform ( GizmoProperties - > Rotation , GizmoProperties - > Position ) ) ;
2019-11-05 17:20:52 -05:00
}
}
}
2021-01-20 00:15:28 -04:00
void UDynamicMeshSculptTool : : DiscardAttributes ( )
{
2021-02-17 11:50:23 -04:00
TSharedPtr < FDynamicMesh3 , ESPMode : : ThreadSafe > BeforeMesh = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( * DynamicMeshComponent - > GetMesh ( ) ) ;
TSharedPtr < FDynamicMesh3 , ESPMode : : ThreadSafe > AfterMesh = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( * BeforeMesh ) ;
2021-10-01 08:21:22 -04:00
// Reset attributes and compute per-vertex normals
// (we need to clear rather than permanently discard the attributes because UDynamicMesh::EditMeshInternal would automatically add them back anyway)
2021-01-20 00:15:28 -04:00
AfterMesh - > DiscardAttributes ( ) ;
2021-10-01 08:21:22 -04:00
AfterMesh - > EnableAttributes ( ) ;
FMeshNormals : : InitializeOverlayToPerVertexNormals ( AfterMesh - > Attributes ( ) - > PrimaryNormals ( ) , false ) ;
2021-01-20 00:15:28 -04:00
TUniquePtr < FMeshReplacementChange > ReplaceChange = MakeUnique < FMeshReplacementChange > ( BeforeMesh , AfterMesh ) ;
DynamicMeshComponent - > ApplyChange ( ReplaceChange . Get ( ) , false ) ;
// other internals are still valid?
GetToolManager ( ) - > EmitObjectChange ( DynamicMeshComponent , MoveTemp ( ReplaceChange ) , LOCTEXT ( " SculptDiscardAttribsChange " , " Discard Attributes " ) ) ;
2021-10-01 08:21:22 -04:00
// The tool's warning messages about seams are no longer relevant after discarding attributes, so clear warning messages
GetToolManager ( ) - > DisplayMessage ( FText ( ) , EToolMessageLevel : : UserWarning ) ;
2021-01-20 00:15:28 -04:00
}
2019-10-01 20:41:42 -04:00
# undef LOCTEXT_NAMESPACE