2020-06-23 18:40:00 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "MeshToVolumeTool.h"
|
|
|
|
|
#include "InteractiveToolManager.h"
|
|
|
|
|
#include "ToolBuilderUtil.h"
|
|
|
|
|
|
2021-06-13 00:36:02 -04:00
|
|
|
#include "DynamicMesh/DynamicMesh3.h"
|
2021-11-25 13:33:25 -05:00
|
|
|
#include "MeshSimplification.h"
|
2020-06-23 18:40:00 -04:00
|
|
|
#include "Util/ColorConstants.h"
|
|
|
|
|
#include "ToolSetupUtil.h"
|
2020-09-14 15:58:34 -04:00
|
|
|
#include "Selection/ToolSelectionUtil.h"
|
2021-06-11 22:42:32 -04:00
|
|
|
#include "ModelingToolTargetUtil.h"
|
|
|
|
|
|
2021-11-25 13:33:25 -05:00
|
|
|
#include "Engine/BlockingVolume.h"
|
|
|
|
|
#include "Components/BrushComponent.h"
|
|
|
|
|
#include "Engine/Polys.h"
|
2020-06-23 18:40:00 -04:00
|
|
|
#include "Model.h"
|
2021-08-16 07:51:37 -04:00
|
|
|
#include "BSPOps.h"
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2021-03-09 19:33:56 -04:00
|
|
|
using namespace UE::Geometry;
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2021-03-09 19:33:56 -04:00
|
|
|
#define LOCTEXT_NAMESPACE "UMeshToVolumeTool"
|
2020-06-23 18:40:00 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ToolBuilder
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool UMeshToVolumeToolBuilder::CanBuildTool(const FToolBuilderState& SceneState) const
|
|
|
|
|
{
|
2020-09-14 15:58:34 -04:00
|
|
|
// We don't want to allow this tool to run on selected volumes
|
2021-03-24 11:11:02 -04:00
|
|
|
return ToolBuilderUtil::CountSelectedActorsOfType<AVolume>(SceneState) == 0 && Super::CanBuildTool(SceneState);
|
2020-06-23 18:40:00 -04:00
|
|
|
}
|
|
|
|
|
|
2021-03-24 11:11:02 -04:00
|
|
|
USingleSelectionMeshEditingTool* UMeshToVolumeToolBuilder::CreateNewTool(const FToolBuilderState& SceneState) const
|
2020-06-23 18:40:00 -04:00
|
|
|
{
|
2021-03-24 11:11:02 -04:00
|
|
|
return NewObject<UMeshToVolumeTool>(SceneState.ToolManager);
|
2020-06-23 18:40:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Tool
|
|
|
|
|
*/
|
|
|
|
|
UMeshToVolumeTool::UMeshToVolumeTool()
|
|
|
|
|
{
|
|
|
|
|
SetToolDisplayName(LOCTEXT("MeshToVolumeToolName", "Mesh To Volume"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UMeshToVolumeTool::Setup()
|
|
|
|
|
{
|
|
|
|
|
UInteractiveTool::Setup();
|
|
|
|
|
|
|
|
|
|
PreviewMesh = NewObject<UPreviewMesh>(this);
|
|
|
|
|
PreviewMesh->bBuildSpatialDataStructure = false;
|
2021-06-11 22:42:32 -04:00
|
|
|
PreviewMesh->CreateInWorld(UE::ToolTarget::GetTargetActor(Target)->GetWorld(), FTransform::Identity);
|
|
|
|
|
PreviewMesh->SetTransform((FTransform)UE::ToolTarget::GetLocalToWorldTransform(Target));
|
2021-10-07 22:25:54 -04:00
|
|
|
ToolSetupUtil::ApplyRenderingConfigurationToPreview(PreviewMesh, nullptr);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2021-06-11 22:42:32 -04:00
|
|
|
PreviewMesh->SetTangentsMode(EDynamicMeshComponentTangentsMode::AutoCalculated);
|
|
|
|
|
PreviewMesh->ReplaceMesh(UE::ToolTarget::GetDynamicMeshCopy(Target));
|
|
|
|
|
|
|
|
|
|
FComponentMaterialSet MaterialSet = UE::ToolTarget::GetMaterialSet(Target);
|
2020-06-23 18:40:00 -04:00
|
|
|
PreviewMesh->SetMaterials(MaterialSet.Materials);
|
|
|
|
|
|
|
|
|
|
InputMesh.Copy(*PreviewMesh->GetMesh());
|
|
|
|
|
|
|
|
|
|
VolumeEdgesSet = NewObject<ULineSetComponent>(PreviewMesh->GetRootComponent());
|
|
|
|
|
VolumeEdgesSet->SetupAttachment(PreviewMesh->GetRootComponent());
|
|
|
|
|
VolumeEdgesSet->SetLineMaterial(ToolSetupUtil::GetDefaultLineComponentMaterial(GetToolManager()));
|
|
|
|
|
VolumeEdgesSet->RegisterComponent();
|
|
|
|
|
|
2021-06-11 22:42:32 -04:00
|
|
|
UE::ToolTarget::HideSourceObject(Target);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
|
|
|
|
Settings = NewObject<UMeshToVolumeToolProperties>(this);
|
|
|
|
|
Settings->RestoreProperties(this);
|
|
|
|
|
AddToolPropertySource(Settings);
|
|
|
|
|
|
|
|
|
|
Settings->WatchProperty(Settings->ConversionMode,
|
|
|
|
|
[this](EMeshToVolumeMode NewMode)
|
|
|
|
|
{ bVolumeValid = false; });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HandleSourcesProperties = NewObject<UOnAcceptHandleSourcesProperties>(this);
|
|
|
|
|
HandleSourcesProperties->RestoreProperties(this);
|
|
|
|
|
AddToolPropertySource(HandleSourcesProperties);
|
|
|
|
|
|
|
|
|
|
bVolumeValid = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GetToolManager()->DisplayMessage(
|
|
|
|
|
LOCTEXT("OnStartTool", "Convert a Static Mesh to a Volume, or update an existing Volume"),
|
|
|
|
|
EToolMessageLevel::UserNotification);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-28 18:40:54 -05:00
|
|
|
void UMeshToVolumeTool::OnShutdown(EToolShutdownType ShutdownType)
|
2020-06-23 18:40:00 -04:00
|
|
|
{
|
|
|
|
|
Settings->SaveProperties(this);
|
|
|
|
|
HandleSourcesProperties->SaveProperties(this);
|
|
|
|
|
|
|
|
|
|
PreviewMesh->SetVisible(false);
|
|
|
|
|
PreviewMesh->Disconnect();
|
|
|
|
|
PreviewMesh = nullptr;
|
|
|
|
|
|
2021-06-11 22:42:32 -04:00
|
|
|
UE::ToolTarget::ShowSourceObject(Target);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
|
|
|
|
if (ShutdownType == EToolShutdownType::Accept)
|
|
|
|
|
{
|
|
|
|
|
GetToolManager()->BeginUndoTransaction(LOCTEXT("MeshToVolumeToolTransactionName", "Create Volume"));
|
|
|
|
|
|
2021-06-11 22:42:32 -04:00
|
|
|
AActor* TargetOwnerActor = UE::ToolTarget::GetTargetActor(Target);
|
|
|
|
|
UWorld* TargetOwnerWorld = TargetOwnerActor->GetWorld();
|
|
|
|
|
FTransform SetTransform = (FTransform)UE::ToolTarget::GetLocalToWorldTransform(Target);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
|
|
|
|
AVolume* TargetVolume = nullptr;
|
|
|
|
|
|
|
|
|
|
if (Settings->TargetVolume.IsValid() == false)
|
|
|
|
|
{
|
|
|
|
|
FRotator Rotation(0.0f, 0.0f, 0.0f);
|
|
|
|
|
FActorSpawnParameters SpawnInfo;
|
|
|
|
|
FTransform NewActorTransform = FTransform::Identity;
|
|
|
|
|
UClass* VolumeClass = Settings->NewVolumeType.Get();
|
|
|
|
|
if (VolumeClass)
|
|
|
|
|
{
|
2021-03-24 11:11:02 -04:00
|
|
|
TargetVolume = (AVolume*)TargetOwnerWorld->SpawnActor(VolumeClass, &NewActorTransform, SpawnInfo);
|
2020-06-23 18:40:00 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-03-24 11:11:02 -04:00
|
|
|
TargetVolume = TargetOwnerWorld->SpawnActor<ABlockingVolume>(FVector::ZeroVector, Rotation, SpawnInfo);
|
2020-06-23 18:40:00 -04:00
|
|
|
}
|
|
|
|
|
TargetVolume->BrushType = EBrushType::Brush_Add;
|
|
|
|
|
UModel* Model = NewObject<UModel>(TargetVolume);
|
|
|
|
|
TargetVolume->Brush = Model;
|
|
|
|
|
TargetVolume->GetBrushComponent()->Brush = TargetVolume->Brush;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TargetVolume = Settings->TargetVolume.Get();
|
|
|
|
|
SetTransform = TargetVolume->GetActorTransform();
|
|
|
|
|
TargetVolume->Modify();
|
|
|
|
|
TargetVolume->GetBrushComponent()->Modify();
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 15:58:34 -04:00
|
|
|
UE::Conversion::DynamicMeshToVolume(InputMesh, Faces, TargetVolume);
|
2020-06-23 18:40:00 -04:00
|
|
|
TargetVolume->SetActorTransform(SetTransform);
|
|
|
|
|
TargetVolume->PostEditChange();
|
|
|
|
|
|
2020-09-14 15:58:34 -04:00
|
|
|
ToolSelectionUtil::SetNewActorSelection(GetToolManager(), TargetVolume);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
|
|
|
|
TArray<AActor*> Actors;
|
2021-06-11 22:42:32 -04:00
|
|
|
Actors.Add(TargetOwnerActor);
|
2020-06-23 18:40:00 -04:00
|
|
|
HandleSourcesProperties->ApplyMethod(Actors, GetToolManager());
|
|
|
|
|
|
|
|
|
|
GetToolManager()->EndUndoTransaction();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMeshToVolumeTool::OnTick(float DeltaTime)
|
|
|
|
|
{
|
|
|
|
|
if (bVolumeValid == false)
|
|
|
|
|
{
|
|
|
|
|
RecalculateVolume();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMeshToVolumeTool::Render(IToolsContextRenderAPI* RenderAPI)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UMeshToVolumeTool::UpdateLineSet()
|
|
|
|
|
{
|
|
|
|
|
FColor BoundaryEdgeColor(240, 15, 15);
|
|
|
|
|
float BoundaryEdgeThickness = 0.5;
|
|
|
|
|
float BoundaryEdgeDepthBias = 2.0f;
|
|
|
|
|
|
|
|
|
|
VolumeEdgesSet->Clear();
|
2020-09-14 15:58:34 -04:00
|
|
|
for (const UE::Conversion::FDynamicMeshFace& Face : Faces)
|
2020-06-23 18:40:00 -04:00
|
|
|
{
|
|
|
|
|
int32 NumV = Face.BoundaryLoop.Num();
|
|
|
|
|
for (int32 k = 0; k < NumV; ++k)
|
|
|
|
|
{
|
|
|
|
|
VolumeEdgesSet->AddLine(
|
|
|
|
|
(FVector)Face.BoundaryLoop[k], (FVector)Face.BoundaryLoop[(k+1)%NumV],
|
|
|
|
|
BoundaryEdgeColor, BoundaryEdgeThickness, BoundaryEdgeDepthBias);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMeshToVolumeTool::RecalculateVolume()
|
|
|
|
|
{
|
|
|
|
|
if (Settings->ConversionMode == EMeshToVolumeMode::MinimalPolygons)
|
|
|
|
|
{
|
2021-04-10 10:00:12 -04:00
|
|
|
// Since this tool is likely to be a sink, there isn't much reason to keep
|
|
|
|
|
// the group differentiations if they are coplanar.
|
|
|
|
|
bool bRespectGroupBoundaries = false;
|
|
|
|
|
|
2021-11-25 13:33:25 -05:00
|
|
|
// Apply minimal-planar simplification to remove extra vertices along straight edges
|
|
|
|
|
FDynamicMesh3 LocalMesh = InputMesh;
|
|
|
|
|
LocalMesh.DiscardAttributes();
|
|
|
|
|
FQEMSimplification PlanarSimplifier(&LocalMesh);
|
|
|
|
|
PlanarSimplifier.SimplifyToMinimalPlanar(0.1); // angle tolerance in degrees
|
|
|
|
|
|
|
|
|
|
UE::Conversion::GetPolygonFaces(LocalMesh, Faces, bRespectGroupBoundaries);
|
2020-06-23 18:40:00 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-09-14 15:58:34 -04:00
|
|
|
UE::Conversion::GetTriangleFaces(InputMesh, Faces);
|
2020-06-23 18:40:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateLineSet();
|
|
|
|
|
bVolumeValid = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|