You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb none #rnx #jira none #preflight 60d16a58367e6700015e9020 [CL 16744001 by Ryan Schmidt in ue5-main branch]
550 lines
18 KiB
C++
550 lines
18 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "RemoveOccludedTrianglesTool.h"
|
|
#include "InteractiveToolManager.h"
|
|
#include "ToolBuilderUtil.h"
|
|
|
|
#include "ToolSetupUtil.h"
|
|
|
|
#include "DynamicMesh/DynamicMesh3.h"
|
|
#include "Polygroups/PolygroupUtil.h"
|
|
#include "BaseBehaviors/MultiClickSequenceInputBehavior.h"
|
|
#include "Selection/SelectClickedAction.h"
|
|
|
|
#include "MeshDescriptionToDynamicMesh.h"
|
|
#include "DynamicMeshToMeshDescription.h"
|
|
|
|
#include "InteractiveGizmoManager.h"
|
|
|
|
#include "Misc/MessageDialog.h"
|
|
|
|
|
|
#if WITH_EDITOR
|
|
#include "Misc/ScopedSlowTask.h"
|
|
#endif
|
|
|
|
#include "TargetInterfaces/MaterialProvider.h"
|
|
#include "TargetInterfaces/MeshDescriptionCommitter.h"
|
|
#include "TargetInterfaces/MeshDescriptionProvider.h"
|
|
#include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
|
|
#include "ToolTargetManager.h"
|
|
|
|
#include "ExplicitUseGeometryMathTypes.h" // using UE::Geometry::(math types)
|
|
using namespace UE::Geometry;
|
|
|
|
#define LOCTEXT_NAMESPACE "URemoveOccludedTrianglesTool"
|
|
|
|
/*
|
|
* ToolBuilder
|
|
*/
|
|
|
|
|
|
const FToolTargetTypeRequirements& URemoveOccludedTrianglesToolBuilder::GetTargetRequirements() const
|
|
{
|
|
static FToolTargetTypeRequirements TypeRequirements({
|
|
UMaterialProvider::StaticClass(),
|
|
UMeshDescriptionCommitter::StaticClass(),
|
|
UMeshDescriptionProvider::StaticClass(),
|
|
UPrimitiveComponentBackedTarget::StaticClass()
|
|
});
|
|
return TypeRequirements;
|
|
}
|
|
|
|
bool URemoveOccludedTrianglesToolBuilder::CanBuildTool(const FToolBuilderState& SceneState) const
|
|
{
|
|
return SceneState.TargetManager->CountSelectedAndTargetable(SceneState, GetTargetRequirements()) > 0;
|
|
}
|
|
|
|
UInteractiveTool* URemoveOccludedTrianglesToolBuilder::BuildTool(const FToolBuilderState& SceneState) const
|
|
{
|
|
URemoveOccludedTrianglesTool* NewTool = NewObject<URemoveOccludedTrianglesTool>(SceneState.ToolManager);
|
|
|
|
TArray<TObjectPtr<UToolTarget>> Targets = SceneState.TargetManager->BuildAllSelectedTargetable(SceneState, GetTargetRequirements());
|
|
NewTool->SetTargets(MoveTemp(Targets));
|
|
NewTool->SetWorld(SceneState.World);
|
|
|
|
return NewTool;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Tool
|
|
*/
|
|
|
|
URemoveOccludedTrianglesToolProperties::URemoveOccludedTrianglesToolProperties()
|
|
{
|
|
|
|
}
|
|
|
|
URemoveOccludedTrianglesAdvancedProperties::URemoveOccludedTrianglesAdvancedProperties()
|
|
{
|
|
}
|
|
|
|
|
|
URemoveOccludedTrianglesTool::URemoveOccludedTrianglesTool()
|
|
{
|
|
SetToolDisplayName(LOCTEXT("ProjectToTargetToolName", "Jacket"));
|
|
}
|
|
|
|
void URemoveOccludedTrianglesTool::SetWorld(UWorld* World)
|
|
{
|
|
this->TargetWorld = World;
|
|
}
|
|
|
|
void URemoveOccludedTrianglesTool::Setup()
|
|
{
|
|
UInteractiveTool::Setup();
|
|
|
|
// hide input StaticMeshComponent
|
|
for (int Idx = 0; Idx < Targets.Num(); Idx++)
|
|
{
|
|
TargetComponentInterface(Idx)->SetOwnerVisibility(false);
|
|
}
|
|
|
|
|
|
// find components with the same source asset
|
|
TArray<int32> MapToFirstOccurrences;
|
|
bool bAnyHasSameSource = GetMapToSharedSourceData(MapToFirstOccurrences);
|
|
TargetToPreviewIdx.SetNum(Targets.Num());
|
|
PreviewToTargetIdx.Reset();
|
|
for (int32 ComponentIdx = 0; ComponentIdx < MapToFirstOccurrences.Num(); ComponentIdx++)
|
|
{
|
|
if (MapToFirstOccurrences[ComponentIdx] == ComponentIdx)
|
|
{
|
|
int32 NumPreviews = PreviewToTargetIdx.Num();
|
|
PreviewToTargetIdx.Add(ComponentIdx);
|
|
TargetToPreviewIdx[ComponentIdx] = NumPreviews;
|
|
}
|
|
else
|
|
{
|
|
TargetToPreviewIdx[ComponentIdx] = TargetToPreviewIdx[MapToFirstOccurrences[ComponentIdx]];
|
|
}
|
|
}
|
|
|
|
if (bAnyHasSameSource)
|
|
{
|
|
GetToolManager()->DisplayMessage(
|
|
LOCTEXT("JacketingMultipleAssetWithSameSource", "WARNING: Multiple meshes in your selection use the same source asset! Triangles will be conservatively removed from these meshes only when they are occluded in every selected instance."),
|
|
EToolMessageLevel::UserWarning);
|
|
}
|
|
|
|
// initialize the PreviewMesh+BackgroundCompute object
|
|
SetupPreviews();
|
|
|
|
BasicProperties = NewObject<URemoveOccludedTrianglesToolProperties>(this, TEXT("Remove Occluded Triangle Settings"));
|
|
AdvancedProperties = NewObject<URemoveOccludedTrianglesAdvancedProperties>(this, TEXT("Advanced Settings"));
|
|
MakePolygroupLayerProperties();
|
|
|
|
BasicProperties->WatchProperty(BasicProperties->Action,
|
|
[this](EOccludedAction Action) { SetToolPropertySourceEnabled(PolygroupLayersProperties, Action == EOccludedAction::SetNewGroup); }
|
|
);
|
|
|
|
// initialize our properties
|
|
AddToolPropertySource(BasicProperties);
|
|
AddToolPropertySource(PolygroupLayersProperties);
|
|
AddToolPropertySource(AdvancedProperties);
|
|
|
|
for (UMeshOpPreviewWithBackgroundCompute* Preview : Previews)
|
|
{
|
|
Preview->InvalidateResult();
|
|
}
|
|
|
|
GetToolManager()->DisplayMessage(
|
|
LOCTEXT("RemoveOccludedTrianglesToolDescription", "Remove triangles that are fully contained within the selected Meshes, and hence cannot be visible with opaque shading."),
|
|
EToolMessageLevel::UserNotification);
|
|
}
|
|
|
|
|
|
void URemoveOccludedTrianglesTool::MakePolygroupLayerProperties()
|
|
{
|
|
PolygroupLayersProperties = NewObject<UPolygroupLayersProperties>(this, TEXT("Polygroup Layer"));
|
|
auto GetGroupLayerNames = [](const FDynamicMesh3& Mesh)
|
|
{
|
|
TSet<FName> Names;
|
|
|
|
if (Mesh.Attributes())
|
|
{
|
|
for (int32 LayerIdx = 0; LayerIdx < Mesh.Attributes()->NumPolygroupLayers(); LayerIdx++)
|
|
{
|
|
FName Name = Mesh.Attributes()->GetPolygroupLayer(LayerIdx)->GetName();
|
|
Names.Add(Name);
|
|
}
|
|
}
|
|
|
|
return Names;
|
|
};
|
|
check(OriginalDynamicMeshes.Num() > 0);
|
|
TSet<FName> CommonLayerNames = GetGroupLayerNames(*OriginalDynamicMeshes[0]);
|
|
for (int32 Idx = 1; Idx < OriginalDynamicMeshes.Num(); Idx++)
|
|
{
|
|
CommonLayerNames = CommonLayerNames.Intersect(GetGroupLayerNames(*OriginalDynamicMeshes[Idx]));
|
|
}
|
|
PolygroupLayersProperties->InitializeGroupLayers(CommonLayerNames);
|
|
}
|
|
|
|
|
|
void URemoveOccludedTrianglesTool::SetupPreviews()
|
|
{
|
|
int32 NumTargets = Targets.Num();
|
|
int32 NumPreviews = PreviewToTargetIdx.Num();
|
|
|
|
#if WITH_EDITOR
|
|
static const FText SlowTaskText = LOCTEXT("RemoveOccludedTrianglesInit", "Building mesh occlusion data...");
|
|
|
|
FScopedSlowTask SlowTask(NumTargets, SlowTaskText);
|
|
SlowTask.MakeDialog();
|
|
|
|
// Declare progress shortcut lambdas
|
|
auto EnterProgressFrame = [&SlowTask](float Progress)
|
|
{
|
|
SlowTask.EnterProgressFrame(Progress);
|
|
};
|
|
#else
|
|
auto EnterProgressFrame = [](float Progress) {};
|
|
#endif
|
|
|
|
// create a "magic pink" secondary material to mark occluded faces (to be used if we are setting a new triangle group instead of removing faces)
|
|
UMaterialInterface* OccludedMaterial = ToolSetupUtil::GetSelectionMaterial(FLinearColor(0.9f, 0.1f, 0.9f), GetToolManager());
|
|
|
|
OccludedGroupIDs.Init(-1, NumPreviews);
|
|
OccludedGroupLayers.Init(-1, NumPreviews);
|
|
|
|
OccluderTrees.SetNum(NumTargets);
|
|
OccluderWindings.SetNum(NumTargets);
|
|
OccluderTransforms.SetNum(NumTargets);
|
|
|
|
OriginalDynamicMeshes.SetNum(NumPreviews);
|
|
PreviewToCopyIdx.Reset(); PreviewToCopyIdx.SetNum(NumPreviews);
|
|
for (int32 TargetIdx = 0; TargetIdx < NumTargets; TargetIdx++)
|
|
{
|
|
EnterProgressFrame(1);
|
|
|
|
int PreviewIdx = TargetToPreviewIdx[TargetIdx];
|
|
|
|
// used to choose which triangles need to use the special "OccludedMaterial" secondary material, when the Occluded Action == SetNewGroup
|
|
auto IsOccludedGroupFn = [this, PreviewIdx](const FDynamicMesh3* Mesh, int32 TriangleID)
|
|
{
|
|
int GroupID = OccludedGroupIDs[PreviewIdx];
|
|
if (GroupID >= 0)
|
|
{
|
|
int LayerIndex = OccludedGroupLayers[PreviewIdx];
|
|
if (LayerIndex < 0)
|
|
{
|
|
return Mesh->GetTriangleGroup(TriangleID) == GroupID;
|
|
}
|
|
else
|
|
{
|
|
check(Mesh->HasAttributes() && Mesh->Attributes()->NumPolygroupLayers() > LayerIndex);
|
|
return Mesh->Attributes()->GetPolygroupLayer(LayerIndex)->GetValue(TriangleID) == GroupID;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
bool bHasConverted = OriginalDynamicMeshes[PreviewIdx].IsValid();
|
|
|
|
if (!bHasConverted)
|
|
{
|
|
URemoveOccludedTrianglesOperatorFactory *OpFactory = NewObject<URemoveOccludedTrianglesOperatorFactory>();
|
|
OpFactory->Tool = this;
|
|
OpFactory->PreviewIdx = PreviewIdx;
|
|
OriginalDynamicMeshes[PreviewIdx] = MakeShared<FDynamicMesh3, ESPMode::ThreadSafe>();
|
|
FMeshDescriptionToDynamicMesh Converter;
|
|
Converter.Convert(TargetMeshProviderInterface(TargetIdx)->GetMeshDescription(), *OriginalDynamicMeshes[PreviewIdx]);
|
|
|
|
UMeshOpPreviewWithBackgroundCompute* Preview = Previews.Add_GetRef(NewObject<UMeshOpPreviewWithBackgroundCompute>(OpFactory, "Preview"));
|
|
Preview->Setup(this->TargetWorld, OpFactory);
|
|
Preview->PreviewMesh->SetTangentsMode(EDynamicMeshComponentTangentsMode::AutoCalculated);
|
|
|
|
FComponentMaterialSet MaterialSet;
|
|
TargetMaterialInterface(TargetIdx)->GetMaterialSet(MaterialSet);
|
|
Preview->ConfigureMaterials(MaterialSet.Materials,
|
|
ToolSetupUtil::GetDefaultWorkingMaterial(GetToolManager())
|
|
);
|
|
|
|
Preview->PreviewMesh->SetTransform(TargetComponentInterface(TargetIdx)->GetWorldTransform());
|
|
Preview->PreviewMesh->UpdatePreview(OriginalDynamicMeshes[PreviewIdx].Get());
|
|
Preview->SetVisibility(true);
|
|
|
|
OccluderTrees[TargetIdx] = MakeShared<FDynamicMeshAABBTree3, ESPMode::ThreadSafe>(OriginalDynamicMeshes[PreviewIdx].Get());
|
|
OccluderWindings[TargetIdx] = MakeShared<TFastWindingTree<FDynamicMesh3>, ESPMode::ThreadSafe>(OccluderTrees[TargetIdx].Get());
|
|
OccluderTransforms[TargetIdx] = (UE::Geometry::FTransform3d)TargetComponentInterface(TargetIdx)->GetWorldTransform();
|
|
|
|
// configure secondary render material
|
|
Preview->SecondaryMaterial = OccludedMaterial;
|
|
|
|
// Set occluded layer index and group IDs
|
|
Previews[PreviewIdx]->OnOpCompleted.AddLambda([this, PreviewIdx](const FDynamicMeshOperator* UncastOp) {
|
|
const FRemoveOccludedTrianglesOp* Op = static_cast<const FRemoveOccludedTrianglesOp*>(UncastOp);
|
|
OccludedGroupIDs[PreviewIdx] = Op->CreatedGroupID;
|
|
OccludedGroupLayers[PreviewIdx] = Op->CreatedGroupLayerIndex;
|
|
});
|
|
|
|
// enable secondary triangle buffers
|
|
Preview->PreviewMesh->EnableSecondaryTriangleBuffers(MoveTemp(IsOccludedGroupFn));
|
|
}
|
|
else
|
|
{
|
|
// already did the conversion for a full UMeshOpPreviewWithBackgroundCompute -- just make a light version of that and hook it up to copy the other's work
|
|
int CopyIdx = PreviewCopies.Num();
|
|
UPreviewMesh* PreviewMesh = PreviewCopies.Add_GetRef(NewObject<UPreviewMesh>(this));
|
|
PreviewMesh->CreateInWorld(this->TargetWorld, TargetComponentInterface(TargetIdx)->GetWorldTransform());
|
|
|
|
PreviewToCopyIdx[PreviewIdx].Add(CopyIdx);
|
|
|
|
PreviewMesh->UpdatePreview(OriginalDynamicMeshes[PreviewIdx].Get());
|
|
|
|
FComponentMaterialSet MaterialSet;
|
|
TargetMaterialInterface(TargetIdx)->GetMaterialSet(MaterialSet);
|
|
PreviewMesh->SetMaterials(MaterialSet.Materials);
|
|
|
|
PreviewMesh->SetVisible(true);
|
|
|
|
OccluderTrees[TargetIdx] = OccluderTrees[PreviewToTargetIdx[PreviewIdx]];
|
|
OccluderWindings[TargetIdx] = OccluderWindings[PreviewToTargetIdx[PreviewIdx]];
|
|
OccluderTransforms[TargetIdx] = (UE::Geometry::FTransform3d)TargetComponentInterface(TargetIdx)->GetWorldTransform();
|
|
|
|
PreviewMesh->SetSecondaryRenderMaterial(OccludedMaterial);
|
|
PreviewMesh->EnableSecondaryTriangleBuffers(MoveTemp(IsOccludedGroupFn));
|
|
|
|
Previews[PreviewIdx]->OnMeshUpdated.AddLambda([this, CopyIdx](UMeshOpPreviewWithBackgroundCompute* Compute) {
|
|
PreviewCopies[CopyIdx]->UpdatePreview(Compute->PreviewMesh->GetPreviewDynamicMesh());
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void URemoveOccludedTrianglesTool::Shutdown(EToolShutdownType ShutdownType)
|
|
{
|
|
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;
|
|
}
|
|
|
|
// Restore (unhide) the source meshes
|
|
for (int ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
|
|
{
|
|
TargetComponentInterface(ComponentIdx)->SetOwnerVisibility(true);
|
|
}
|
|
|
|
// clear all the preview copies
|
|
for (UPreviewMesh* PreviewMesh : PreviewCopies)
|
|
{
|
|
PreviewMesh->SetVisible(false);
|
|
PreviewMesh->Disconnect();
|
|
PreviewMesh = nullptr;
|
|
}
|
|
PreviewCopies.Empty();
|
|
|
|
TArray<FDynamicMeshOpResult> Results;
|
|
for (UMeshOpPreviewWithBackgroundCompute* Preview : Previews)
|
|
{
|
|
Results.Add(Preview->Shutdown());
|
|
}
|
|
if (ShutdownType == EToolShutdownType::Accept)
|
|
{
|
|
GenerateAsset(Results);
|
|
}
|
|
}
|
|
|
|
TUniquePtr<FDynamicMeshOperator> URemoveOccludedTrianglesOperatorFactory::MakeNewOperator()
|
|
{
|
|
TUniquePtr<FRemoveOccludedTrianglesOp> Op = MakeUnique<FRemoveOccludedTrianglesOp>();
|
|
Op->NormalOffset = Tool->AdvancedProperties->NormalOffset;
|
|
Op->bSetTriangleGroupInsteadOfRemoving = Tool->BasicProperties->Action == EOccludedAction::SetNewGroup;
|
|
Op->ActiveGroupLayer = Tool->PolygroupLayersProperties->ActiveGroupLayer;
|
|
Op->bActiveGroupLayerIsDefault = !Tool->PolygroupLayersProperties->HasSelectedPolygroup();
|
|
|
|
switch (Tool->BasicProperties->OcclusionTestMethod)
|
|
{
|
|
case EOcclusionCalculationUIMode::GeneralizedWindingNumber:
|
|
Op->InsideMode = EOcclusionCalculationMode::FastWindingNumber;
|
|
break;
|
|
case EOcclusionCalculationUIMode::RaycastOcclusionSamples:
|
|
Op->InsideMode = EOcclusionCalculationMode::SimpleOcclusionTest;
|
|
break;
|
|
default:
|
|
ensure(false); // all cases should be handled
|
|
}
|
|
switch (Tool->BasicProperties->TriangleSampling)
|
|
{
|
|
case EOcclusionTriangleSamplingUIMode::Vertices:
|
|
Op->TriangleSamplingMethod = EOcclusionTriangleSampling::Vertices;
|
|
break;
|
|
// Centroids sampling not exposed in UI for now
|
|
// case EOcclusionTriangleSamplingUIMode::Centroids:
|
|
// Op->TriangleSamplingMethod = EOcclusionTriangleSampling::Centroids;
|
|
// break;
|
|
case EOcclusionTriangleSamplingUIMode::VerticesAndCentroids:
|
|
Op->TriangleSamplingMethod = EOcclusionTriangleSampling::VerticesAndCentroids;
|
|
break;
|
|
default:
|
|
ensure(false);
|
|
}
|
|
Op->WindingIsoValue = Tool->BasicProperties->WindingIsoValue;
|
|
|
|
int ComponentIndex = Tool->PreviewToTargetIdx[PreviewIdx];
|
|
FTransform LocalToWorld = Tool->TargetComponentInterface(ComponentIndex)->GetWorldTransform();
|
|
Op->OriginalMesh = Tool->OriginalDynamicMeshes[PreviewIdx];
|
|
|
|
if (Tool->BasicProperties->bOnlySelfOcclude)
|
|
{
|
|
int32 TargetIdx = Tool->PreviewToTargetIdx[PreviewIdx];
|
|
Op->OccluderTrees.Add(Tool->OccluderTrees[TargetIdx]);
|
|
Op->OccluderWindings.Add(Tool->OccluderWindings[TargetIdx]);
|
|
Op->OccluderTransforms.Add(UE::Geometry::FTransform3d::Identity());
|
|
}
|
|
else
|
|
{
|
|
Op->OccluderTrees = Tool->OccluderTrees;
|
|
Op->OccluderWindings = Tool->OccluderWindings;
|
|
Op->OccluderTransforms = Tool->OccluderTransforms;
|
|
}
|
|
|
|
Op->AddRandomRays = Tool->BasicProperties->AddRandomRays;
|
|
|
|
Op->AddTriangleSamples = Tool->BasicProperties->AddTriangleSamples;
|
|
|
|
Op->ShrinkRemoval = Tool->BasicProperties->ShrinkRemoval;
|
|
|
|
Op->MinAreaConnectedComponent = Tool->BasicProperties->MinAreaIsland;
|
|
|
|
Op->MinTriCountConnectedComponent = Tool->BasicProperties->MinTriCountIsland;
|
|
|
|
Op->SetTransform(LocalToWorld);
|
|
|
|
Op->MeshTransforms.Add((UE::Geometry::FTransform3d)LocalToWorld);
|
|
for (int32 CopyIdx : Tool->PreviewToCopyIdx[PreviewIdx])
|
|
{
|
|
Op->MeshTransforms.Add((UE::Geometry::FTransform3d)Tool->PreviewCopies[CopyIdx]->GetTransform());
|
|
}
|
|
|
|
return Op;
|
|
}
|
|
|
|
void URemoveOccludedTrianglesTool::OnTick(float DeltaTime)
|
|
{
|
|
for (UMeshOpPreviewWithBackgroundCompute* Preview : Previews)
|
|
{
|
|
Preview->Tick(DeltaTime);
|
|
}
|
|
// copy working material state to corresponding copies
|
|
for (int PreviewIdx = 0; PreviewIdx < Previews.Num(); PreviewIdx++)
|
|
{
|
|
UMeshOpPreviewWithBackgroundCompute* Preview = Previews[PreviewIdx];
|
|
bool bIsWorking = Preview->IsUsingWorkingMaterial();
|
|
for (int CopyIdx : PreviewToCopyIdx[PreviewIdx])
|
|
{
|
|
if (bIsWorking)
|
|
{
|
|
PreviewCopies[CopyIdx]->SetOverrideRenderMaterial(Preview->WorkingMaterial);
|
|
PreviewCopies[CopyIdx]->ClearSecondaryRenderMaterial();
|
|
}
|
|
else
|
|
{
|
|
PreviewCopies[CopyIdx]->ClearOverrideRenderMaterial();
|
|
PreviewCopies[CopyIdx]->SetSecondaryRenderMaterial(Preview->SecondaryMaterial);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
void URemoveOccludedTrianglesTool::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
|
{
|
|
for (UMeshOpPreviewWithBackgroundCompute* Preview : Previews)
|
|
{
|
|
Preview->InvalidateResult();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void URemoveOccludedTrianglesTool::OnPropertyModified(UObject* PropertySet, FProperty* Property)
|
|
{
|
|
for (UMeshOpPreviewWithBackgroundCompute* Preview : Previews)
|
|
{
|
|
Preview->InvalidateResult();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool URemoveOccludedTrianglesTool::CanAccept() const
|
|
{
|
|
for (UMeshOpPreviewWithBackgroundCompute* Preview : Previews)
|
|
{
|
|
if (!Preview->HaveValidResult())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return Super::CanAccept();
|
|
}
|
|
|
|
|
|
void URemoveOccludedTrianglesTool::GenerateAsset(const TArray<FDynamicMeshOpResult>& Results)
|
|
{
|
|
GetToolManager()->BeginUndoTransaction(LOCTEXT("RemoveOccludedTrianglesToolTransactionName", "Remove Occluded Triangles"));
|
|
|
|
check(Results.Num() == Previews.Num());
|
|
|
|
// check if we entirely remove away any meshes
|
|
bool bWantDestroy = false;
|
|
for (int32 PreviewIdx = 0; PreviewIdx < Previews.Num(); PreviewIdx++)
|
|
{
|
|
bWantDestroy = bWantDestroy || (Results[PreviewIdx].Mesh.Get()->TriangleCount() == 0);
|
|
}
|
|
// if so ask user what to do
|
|
if (bWantDestroy)
|
|
{
|
|
FText Title = LOCTEXT("RemoveOccludedDestroyTitle", "Delete mesh components?");
|
|
EAppReturnType::Type Ret = FMessageDialog::Open(EAppMsgType::YesNo,
|
|
LOCTEXT("RemoveOccludedDestroyQuestion", "Jacketing has removed all triangles from some meshes. Actually destroy these mesh components?"), &Title);
|
|
if (Ret == EAppReturnType::No)
|
|
{
|
|
bWantDestroy = false;
|
|
}
|
|
}
|
|
|
|
for (int32 PreviewIdx = 0; PreviewIdx < Previews.Num(); PreviewIdx++)
|
|
{
|
|
check(Results[PreviewIdx].Mesh.Get() != nullptr);
|
|
int ComponentIdx = PreviewToTargetIdx[PreviewIdx];
|
|
|
|
if (Results[PreviewIdx].Mesh.Get()->TriangleCount() == 0)
|
|
{
|
|
if (bWantDestroy)
|
|
{
|
|
for (int TargetIdx = 0; TargetIdx < Targets.Num(); TargetIdx++)
|
|
{
|
|
if (TargetToPreviewIdx[TargetIdx] == PreviewIdx)
|
|
{
|
|
TargetComponentInterface(TargetIdx)->GetOwnerComponent()->DestroyComponent();
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
TargetMeshCommitterInterface(ComponentIdx)->CommitMeshDescription([&Results, &PreviewIdx, this](const IMeshDescriptionCommitter::FCommitterParams& CommitParams)
|
|
{
|
|
FDynamicMeshToMeshDescription Converter;
|
|
Converter.Convert(Results[PreviewIdx].Mesh.Get(), *CommitParams.MeshDescriptionOut);
|
|
});
|
|
}
|
|
|
|
GetToolManager()->EndUndoTransaction();
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|