Files
UnrealEngineUWP/Engine/Plugins/Experimental/MeshModelingToolset/Source/MeshModelingTools/Private/SplitMeshesTool.cpp
Ryan Schmidt b02f4829db ModelingTools: DynamicMeshActor support Tools and Settings.
- Move UCreateMeshObjectTypeProperties to ModelingComponents and update all include sites
- Added Editor Modeling Mode settings to Enable/Disable showing DynamicMeshActor creation options, and select default mesh object type. Removed CVarEnableDynamicMeshActors.
- Added optional 'Auto' output mesh type to UCreateMeshObjectTypeProperties. This can be used in Tools that have input objects and want to allow optional conversion, but default to 'just use input mesh object type'.
- Added ConvertMeshesTool, this does in-place conversion between Mesh Object types for a set of selected objects (Duplicate tool can also do this, but only for a single object, and functionality is expected to further diverge)
- Added SplitMeshesTool, decomposes a mesh into parts and creates a new output object for each part
- CombineMeshesTool now supports variable output object type. Cleaned up internals.

#rb none
#rnx
#jira none
#preflight 60d3bc76b4bb42000195eccf

[CL 16768010 by Ryan Schmidt in ue5-main branch]
2021-06-23 22:13:32 -04:00

251 lines
7.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SplitMeshesTool.h"
#include "ComponentSourceInterfaces.h"
#include "InteractiveToolManager.h"
#include "ToolTargetManager.h"
#include "ToolBuilderUtil.h"
#include "ToolSetupUtil.h"
#include "ModelingToolTargetUtil.h"
#include "ModelingObjectsCreationAPI.h"
#include "Selection/ToolSelectionUtil.h"
#include "Selections/MeshConnectedComponents.h"
#include "DynamicMesh/MeshTransforms.h"
#include "DynamicSubmesh3.h"
#include "ExplicitUseGeometryMathTypes.h" // using UE::Geometry::(math types)
using namespace UE::Geometry;
#define LOCTEXT_NAMESPACE "USplitMeshesTool"
/*
* ToolBuilder
*/
const FToolTargetTypeRequirements& USplitMeshesToolBuilder::GetTargetRequirements() const
{
static FToolTargetTypeRequirements TypeRequirements({
UMaterialProvider::StaticClass(),
UMeshDescriptionProvider::StaticClass(),
UPrimitiveComponentBackedTarget::StaticClass()
});
return TypeRequirements;
}
bool USplitMeshesToolBuilder::CanBuildTool(const FToolBuilderState& SceneState) const
{
return SceneState.TargetManager->CountSelectedAndTargetable(SceneState, GetTargetRequirements()) > 0;
}
UInteractiveTool* USplitMeshesToolBuilder::BuildTool(const FToolBuilderState& SceneState) const
{
USplitMeshesTool* NewTool = NewObject<USplitMeshesTool>(SceneState.ToolManager);
TArray<TObjectPtr<UToolTarget>> Targets = SceneState.TargetManager->BuildAllSelectedTargetable(SceneState, GetTargetRequirements());
NewTool->SetTargets(MoveTemp(Targets));
NewTool->SetWorld(SceneState.World);
return NewTool;
}
/*
* Tool
*/
void USplitMeshesTool::SetWorld(UWorld* World)
{
this->TargetWorld = World;
}
void USplitMeshesTool::Setup()
{
UInteractiveTool::Setup();
OutputTypeProperties = NewObject<UCreateMeshObjectTypeProperties>(this);
OutputTypeProperties->InitializeDefaultWithAuto();
OutputTypeProperties->OutputType = UCreateMeshObjectTypeProperties::AutoIdentifier;
OutputTypeProperties->RestoreProperties(this, TEXT("OutputTypeFromInputTool"));
OutputTypeProperties->WatchProperty(OutputTypeProperties->OutputType, [this](FString) { OutputTypeProperties->UpdatePropertyVisibility(); });
AddToolPropertySource(OutputTypeProperties);
BasicProperties = NewObject<USplitMeshesToolProperties>(this);
BasicProperties->RestoreProperties(this);
AddToolPropertySource(BasicProperties);
SourceMeshes.SetNum(Targets.Num());
for (int32 k = 0; k < Targets.Num(); ++k)
{
SourceMeshes[k].Mesh = UE::ToolTarget::GetDynamicMeshCopy(Targets[k], true);
SourceMeshes[k].Materials = UE::ToolTarget::GetMaterialSet(Targets[k]).Materials;
}
UpdateSplitMeshes();
SetToolDisplayName(LOCTEXT("ToolName", "Split"));
GetToolManager()->DisplayMessage(
LOCTEXT("OnStartTool", "Split Meshes into parts"),
EToolMessageLevel::UserNotification);
}
bool USplitMeshesTool::CanAccept() const
{
return Super::CanAccept();
}
void USplitMeshesTool::Shutdown(EToolShutdownType ShutdownType)
{
OutputTypeProperties->SaveProperties(this, TEXT("OutputTypeFromInputTool"));
BasicProperties->SaveProperties(this);
if (ShutdownType == EToolShutdownType::Accept)
{
GetToolManager()->BeginUndoTransaction(LOCTEXT("SplitMeshesToolTransactionName", "Split Meshes"));
TArray<AActor*> NewSelectedActors;
TSet<AActor*> DeleteActors;
for (int32 ti = 0; ti < Targets.Num(); ++ti)
{
FComponentsInfo& SplitInfo = SplitMeshes[ti];
if (SplitInfo.bNoComponents)
{
continue;
}
AActor* TargetActor = UE::ToolTarget::GetTargetActor(Targets[ti]);
check(TargetActor != nullptr);
DeleteActors.Add(TargetActor);
FTransform3d SourceTransform = UE::ToolTarget::GetLocalToWorldTransform(Targets[ti]);
FDynamicMesh3 SourceMesh = UE::ToolTarget::GetDynamicMeshCopy(Targets[ti], true);
FString AssetName = TargetActor->GetName();
FCreateMeshObjectParams BaseMeshObjectParams;
BaseMeshObjectParams.TargetWorld = TargetWorld;
if (OutputTypeProperties->OutputType == UCreateMeshObjectTypeProperties::AutoIdentifier)
{
UE::ToolTarget::ConfigureCreateMeshObjectParams(Targets[0], BaseMeshObjectParams);
}
else
{
OutputTypeProperties->ConfigureCreateMeshObjectParams(BaseMeshObjectParams);
}
int32 NumComponents = SplitInfo.Meshes.Num();
for (int32 k = 0; k < NumComponents; ++k)
{
FCreateMeshObjectParams NewMeshObjectParams = BaseMeshObjectParams;
NewMeshObjectParams.BaseName = FString::Printf(TEXT("%s_%d"), *AssetName, k);
FTransform3d PartTransform = SourceTransform;
PartTransform.SetTranslation(SourceTransform.GetTranslation() + SplitInfo.Origins[k]);
NewMeshObjectParams.Transform = (FTransform)PartTransform;
if (BasicProperties->bTransferMaterials)
{
NewMeshObjectParams.Materials = SplitInfo.Materials[k];
}
NewMeshObjectParams.SetMesh(MoveTemp(SplitInfo.Meshes[k]));
FCreateMeshObjectResult Result = UE::Modeling::CreateMeshObject(GetToolManager(), MoveTemp(NewMeshObjectParams));
if (Result.IsOK())
{
NewSelectedActors.Add(Result.NewActor);
}
}
}
for (AActor* DeleteActor : DeleteActors)
{
DeleteActor->Destroy();
}
ToolSelectionUtil::SetNewActorSelection(GetToolManager(), NewSelectedActors);
GetToolManager()->EndUndoTransaction();
}
}
void USplitMeshesTool::UpdateSplitMeshes()
{
SplitMeshes.Reset();
SplitMeshes.SetNum(SourceMeshes.Num());
NoSplitCount = 0;
for (int32 si = 0; si < SourceMeshes.Num(); ++si)
{
FComponentsInfo& SplitInfo = SplitMeshes[si];
const FDynamicMesh3* SourceMesh = &SourceMeshes[si].Mesh;
const TArray<UMaterialInterface*> SourceMaterials = SourceMeshes[si].Materials;
FMeshConnectedComponents MeshComponents(SourceMesh);
MeshComponents.FindConnectedTriangles();
int32 NumComponents = MeshComponents.Num();
if (NumComponents < 2)
{
SplitInfo.bNoComponents = true;
NoSplitCount++;
continue;
}
SplitInfo.bNoComponents = false;
SplitInfo.Meshes.SetNum(NumComponents);
SplitInfo.Materials.SetNum(NumComponents);
SplitInfo.Origins.SetNum(NumComponents);
for (int32 k = 0; k < NumComponents; ++k)
{
FDynamicSubmesh3 SubmeshCalc(SourceMesh, MeshComponents[k].Indices);
FDynamicMesh3& Submesh = SubmeshCalc.GetSubmesh();
TArray<UMaterialInterface*> NewMaterials;
// remap materials
FDynamicMeshMaterialAttribute* MaterialIDs = Submesh.HasAttributes() ? Submesh.Attributes()->GetMaterialID() : nullptr;
if (MaterialIDs)
{
TArray<int32> UniqueIDs;
for (int32 tid : Submesh.TriangleIndicesItr())
{
int32 MaterialID = MaterialIDs->GetValue(tid);
int32 Index = UniqueIDs.IndexOfByKey(MaterialID);
if (Index == INDEX_NONE)
{
int32 NewMaterialID = UniqueIDs.Num();
UniqueIDs.Add(MaterialID);
NewMaterials.Add(SourceMaterials[MaterialID]);
MaterialIDs->SetValue(tid, NewMaterialID);
}
else
{
MaterialIDs->SetValue(tid, Index);
}
}
}
// reposition mesh
FAxisAlignedBox3d Bounds = Submesh.GetBounds();
MeshTransforms::Translate(Submesh, -Bounds.Center());
SplitInfo.Meshes[k] = MoveTemp(Submesh);
SplitInfo.Materials[k] = MoveTemp(NewMaterials);
SplitInfo.Origins[k] = Bounds.Center();
}
}
if (NoSplitCount > 0)
{
GetToolManager()->DisplayMessage(
FText::Format(LOCTEXT("NoComponentsMessage", "{0} of {1} Input Meshes cannot be Split."), NoSplitCount, SourceMeshes.Num()), EToolMessageLevel::UserWarning);
}
else
{
GetToolManager()->DisplayMessage(FText(), EToolMessageLevel::UserWarning);
}
}
#undef LOCTEXT_NAMESPACE