Files
UnrealEngineUWP/Engine/Plugins/Experimental/MeshModelingToolsetExp/Source/MeshModelingToolsExp/Private/WeldMeshEdgesTool.cpp
tyson brochu 819b7b59cf If a ToolTarget's MeshComponent has no MeshDescription, return an empty but valid one. Harden various tools to not crash on empty meshes.
#jira UE-135710
#rnx
#rb jimmy.andrews
#preflight 61b24e173d544d1a435f6792

#ROBOMERGE-AUTHOR: tyson.brochu
#ROBOMERGE-SOURCE: CL 18422162 in //UE5/Release-5.0/... via CL 18423015
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v897-18405271)

[CL 18423313 by tyson brochu in ue5-release-engine-test branch]
2021-12-09 15:02:36 -05:00

232 lines
6.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "WeldMeshEdgesTool.h"
#include "InteractiveToolManager.h"
#include "ToolBuilderUtil.h"
#include "ToolSetupUtil.h"
#include "ModelingToolTargetUtil.h"
#include "PreviewMesh.h"
#include "Drawing/MeshElementsVisualizer.h"
#include "DynamicMesh/DynamicMesh3.h"
#include "DynamicMesh/Operations/MergeCoincidentMeshEdges.h"
using namespace UE::Geometry;
#define LOCTEXT_NAMESPACE "UWeldMeshEdgesTool"
/*
* ToolBuilder
*/
USingleSelectionMeshEditingTool* UWeldMeshEdgesToolBuilder::CreateNewTool(const FToolBuilderState& SceneState) const
{
return NewObject<UWeldMeshEdgesTool>(SceneState.ToolManager);
}
class FWeldMeshEdgesOp : public FDynamicMeshOperator
{
public:
// parameters set by the tool
TSharedPtr<FDynamicMesh3, ESPMode::ThreadSafe> SourceMesh;
double Tolerance;
bool bOnlyUnique;
public:
FWeldMeshEdgesOp() : FDynamicMeshOperator() {}
virtual void CalculateResult(FProgressCancel* Progress) override
{
if ((Progress && Progress->Cancelled()) || !SourceMesh)
{
return;
}
if (SourceMesh->TriangleCount() == 0 || SourceMesh->VertexCount() == 0)
{
return;
}
ResultMesh->Copy(*SourceMesh, true, true, true, true);
FMergeCoincidentMeshEdges Merger(ResultMesh.Get());
Merger.MergeVertexTolerance = Tolerance;
Merger.MergeSearchTolerance = 2 * Merger.MergeVertexTolerance;
Merger.OnlyUniquePairs = bOnlyUnique;
if (Merger.Apply() == false)
{
ResultMesh->Copy(*SourceMesh, true, true, true, true);
}
else if (ResultMesh->CheckValidity(true, EValidityCheckFailMode::ReturnOnly) == false)
{
ResultMesh->Copy(*SourceMesh, true, true, true, true);
}
}
void SetTransform(const FTransform& Transform)
{
ResultTransform = (UE::Geometry::FTransform3d)Transform;
}
};
TUniquePtr<FDynamicMeshOperator> UWeldMeshEdgesOperatorFactory::MakeNewOperator()
{
check(WeldMeshEdgesTool);
TUniquePtr<FWeldMeshEdgesOp> MeshOp = MakeUnique<FWeldMeshEdgesOp>();
WeldMeshEdgesTool->UpdateOpParameters(*MeshOp);
return MeshOp;
}
/*
* Tool
*/
UWeldMeshEdgesTool::UWeldMeshEdgesTool()
{
SetToolDisplayName(LOCTEXT("WeldMeshEdgesToolName", "Weld Edges"));
}
void UWeldMeshEdgesTool::Setup()
{
UInteractiveTool::Setup();
SourceMesh = MakeShared<FDynamicMesh3, ESPMode::ThreadSafe>(UE::ToolTarget::GetDynamicMeshCopy(Target, true));
FTransform MeshTransform = (FTransform)UE::ToolTarget::GetLocalToWorldTransform(Target);
OperatorFactory = NewObject<UWeldMeshEdgesOperatorFactory>(this);
OperatorFactory->WeldMeshEdgesTool = this;
PreviewCompute = NewObject<UMeshOpPreviewWithBackgroundCompute>(OperatorFactory);
PreviewCompute->Setup(this->TargetWorld, OperatorFactory);
ToolSetupUtil::ApplyRenderingConfigurationToPreview(PreviewCompute->PreviewMesh, Target);
// Give the preview something to display
PreviewCompute->PreviewMesh->SetTransform(MeshTransform);
PreviewCompute->PreviewMesh->SetTangentsMode(EDynamicMeshComponentTangentsMode::ExternallyProvided);
PreviewCompute->PreviewMesh->UpdatePreview(SourceMesh.Get());
FComponentMaterialSet MaterialSet = UE::ToolTarget::GetMaterialSet(Target);
PreviewCompute->ConfigureMaterials(MaterialSet.Materials,
ToolSetupUtil::GetDefaultWorkingMaterial(GetToolManager()) );
PreviewCompute->SetVisibility(true);
UE::ToolTarget::HideSourceObject(Target);
Settings = NewObject<UWeldMeshEdgesToolProperties>(this);
Settings->RestoreProperties(this);
AddToolPropertySource(Settings);
Settings->WatchProperty(Settings->Tolerance, [this](float) { PreviewCompute->InvalidateResult(); });
Settings->WatchProperty(Settings->bOnlyUnique, [this](bool) { PreviewCompute->InvalidateResult(); });
// create mesh display
MeshElementsDisplay = NewObject<UMeshElementsVisualizer>(this);
MeshElementsDisplay->CreateInWorld(PreviewCompute->PreviewMesh->GetWorld(), PreviewCompute->PreviewMesh->GetTransform());
if (ensure(MeshElementsDisplay->Settings))
{
MeshElementsDisplay->Settings->bShowUVSeams = false;
MeshElementsDisplay->Settings->bShowNormalSeams = false;
MeshElementsDisplay->Settings->bShowColorSeams = false;
MeshElementsDisplay->Settings->RestoreProperties(this, TEXT("WeldEdges"));
AddToolPropertySource(MeshElementsDisplay->Settings);
}
MeshElementsDisplay->SetMeshAccessFunction([this](UMeshElementsVisualizer::ProcessDynamicMeshFunc ProcessFunc) {
PreviewCompute->ProcessCurrentMesh(ProcessFunc);
});
PreviewCompute->OnMeshUpdated.AddLambda([this](UMeshOpPreviewWithBackgroundCompute* Compute)
{
Compute->ProcessCurrentMesh([&](const FDynamicMesh3& ReadMesh)
{
MeshElementsDisplay->NotifyMeshChanged();
});
});
PreviewCompute->InvalidateResult();
SetToolDisplayName(LOCTEXT("ToolName", "Weld Edges"));
GetToolManager()->DisplayMessage(
LOCTEXT("WeldMeshEdgesToolDescription", "Weld overlapping/identical border edges of the selected Mesh, by merging the vertices."),
EToolMessageLevel::UserNotification);
}
void UWeldMeshEdgesTool::Shutdown(EToolShutdownType ShutdownType)
{
Settings->SaveProperties(this);
UE::ToolTarget::ShowSourceObject(Target);
if (ensure(MeshElementsDisplay->Settings))
{
MeshElementsDisplay->Settings->SaveProperties(this, TEXT("WeldEdges"));
}
MeshElementsDisplay->Disconnect();
if (PreviewCompute)
{
FDynamicMeshOpResult Result = PreviewCompute->Shutdown();
if (ShutdownType == EToolShutdownType::Accept)
{
GetToolManager()->BeginUndoTransaction(LOCTEXT("WeldMeshEdgesToolTransactionName", "Weld Edges"));
FDynamicMesh3* DynamicMeshResult = Result.Mesh.Get();
if (ensure(DynamicMeshResult != nullptr))
{
// todo: have not actually modified topology here, but groups-only update is not supported yet
UE::ToolTarget::CommitDynamicMeshUpdate(Target, *DynamicMeshResult, true);
}
GetToolManager()->EndUndoTransaction();
}
}
}
bool UWeldMeshEdgesTool::CanAccept() const
{
return Super::CanAccept() && (PreviewCompute == nullptr || PreviewCompute->HaveValidResult());
}
void UWeldMeshEdgesTool::OnTick(float DeltaTime)
{
PreviewCompute->Tick(DeltaTime);
MeshElementsDisplay->OnTick(DeltaTime);
}
void UWeldMeshEdgesTool::UpdateOpParameters(FWeldMeshEdgesOp& Op) const
{
Op.bOnlyUnique = Settings->bOnlyUnique;
Op.Tolerance = Settings->Tolerance;
Op.SourceMesh = SourceMesh;
FTransform LocalToWorld = (FTransform)UE::ToolTarget::GetLocalToWorldTransform(Target);
Op.SetTransform(LocalToWorld);
}
#undef LOCTEXT_NAMESPACE