You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Reduce surface area of MeshDescriptionProvider/Committer, replace with UE::ToolTarget:: calls where possible. Add new UE::ToolTarget::CommitMeshDescriptionUpdateViaDynamicMesh() function. This is being used for now to avoid potential regressions as UE::ToolTarget::CommitDynamicMeshUpdate will preferentially use DynamicMeshCommitter, and I am not certain it is functionally equivalent in all cases. Add new UE::ToolTarget::CommitDynamicMeshNormalsUpdate(), similar to existing UV version Add new Move-variant of UE::ToolTarget::CommitMeshDescriptionUpdate(), uses new Move-variant of IMeshDescriptionCommitter::CommitMeshDescription. Make existing IMeshDescriptionCommitter::CommitMeshDescription callback interface protected, to prevent usage of this function at public API level (will be removed in future). Tool updates should not change, just using cleaner APIs. EditNormalsTool now uses CommitDynamicMeshNormalsUpdate(), which does go via DynamicMeshCommitter preferentially, where it previously went via MeshDescriptionCommitter. In light testing the results appear equivalent. AttributeEditorTool now operates on MeshDescription copies in various update functions. These are not performance-critical. #rb rinat.abdrashitov #rnx #preflight 61ae45998358693a22c28d1b #ROBOMERGE-AUTHOR: ryan.schmidt #ROBOMERGE-SOURCE: CL 18384350 in //UE5/Release-5.0/... via CL 18384361 #ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v896-18170469) [CL 18384373 by ryan schmidt in ue5-release-engine-test branch]
350 lines
11 KiB
C++
350 lines
11 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "BaseTools/BaseCreateFromSelectedTool.h"
|
|
#include "InteractiveToolManager.h"
|
|
#include "ToolBuilderUtil.h"
|
|
#include "ToolSetupUtil.h"
|
|
#include "BaseGizmos/TransformGizmoUtil.h"
|
|
|
|
#include "DynamicMesh/MeshNormals.h"
|
|
#include "DynamicMesh/MeshTransforms.h"
|
|
#include "DynamicMeshToMeshDescription.h"
|
|
|
|
#include "ModelingObjectsCreationAPI.h"
|
|
#include "Selection/ToolSelectionUtil.h"
|
|
|
|
#include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
|
|
#include "TargetInterfaces/MaterialProvider.h"
|
|
#include "TargetInterfaces/AssetBackedTarget.h"
|
|
#include "ToolTargetManager.h"
|
|
#include "ModelingToolTargetUtil.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "UBaseCreateFromSelectedTool"
|
|
|
|
using namespace UE::Geometry;
|
|
|
|
/*
|
|
* ToolBuilder
|
|
*/
|
|
|
|
bool UBaseCreateFromSelectedToolBuilder::CanBuildTool(const FToolBuilderState& SceneState) const
|
|
{
|
|
int32 ComponentCount = SceneState.TargetManager->CountSelectedAndTargetable(SceneState, GetTargetRequirements());
|
|
return ComponentCount >= MinComponentsSupported() && (!MaxComponentsSupported().IsSet() || ComponentCount <= MaxComponentsSupported().GetValue());
|
|
}
|
|
|
|
UMultiSelectionMeshEditingTool* UBaseCreateFromSelectedToolBuilder::CreateNewTool(const FToolBuilderState& SceneState) const
|
|
{
|
|
// Subclasses must override this method.
|
|
check(false);
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
/*
|
|
* Tool
|
|
*/
|
|
|
|
void UBaseCreateFromSelectedTool::Setup()
|
|
{
|
|
UInteractiveTool::Setup();
|
|
|
|
// hide input StaticMeshComponents
|
|
for (int32 ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
|
|
{
|
|
UE::ToolTarget::HideSourceObject(Targets[ComponentIdx]);
|
|
}
|
|
|
|
// initialize our properties
|
|
|
|
SetupProperties();
|
|
TransformProperties = NewObject<UTransformInputsToolProperties>(this);
|
|
TransformProperties->RestoreProperties(this);
|
|
AddToolPropertySource(TransformProperties);
|
|
|
|
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);
|
|
|
|
HandleSourcesProperties = NewObject<UBaseCreateFromSelectedHandleSourceProperties>(this);
|
|
HandleSourcesProperties->RestoreProperties(this);
|
|
AddToolPropertySource(HandleSourcesProperties);
|
|
|
|
Preview = NewObject<UMeshOpPreviewWithBackgroundCompute>(this);
|
|
Preview->Setup(this->TargetWorld, this);
|
|
ToolSetupUtil::ApplyRenderingConfigurationToPreview(Preview->PreviewMesh, nullptr);
|
|
|
|
SetPreviewCallbacks();
|
|
Preview->OnMeshUpdated.AddLambda(
|
|
[this](const UMeshOpPreviewWithBackgroundCompute* UpdatedPreview)
|
|
{
|
|
UpdateAcceptWarnings(UpdatedPreview->HaveEmptyResult() ? EAcceptWarning::EmptyForbidden : EAcceptWarning::NoWarning);
|
|
}
|
|
);
|
|
|
|
SetTransformGizmos();
|
|
|
|
ConvertInputsAndSetPreviewMaterials(true);
|
|
|
|
// output name fields
|
|
HandleSourcesProperties->OutputNewName = PrefixWithSourceNameIfSingleSelection(GetCreatedAssetName());
|
|
HandleSourcesProperties->WatchProperty(HandleSourcesProperties->OutputWriteTo, [&](EBaseCreateFromSelectedTargetType NewType)
|
|
{
|
|
SetToolPropertySourceEnabled(OutputTypeProperties, (NewType == EBaseCreateFromSelectedTargetType::NewObject));
|
|
if (NewType == EBaseCreateFromSelectedTargetType::NewObject)
|
|
{
|
|
HandleSourcesProperties->OutputExistingName = TEXT("");
|
|
UpdateGizmoVisibility();
|
|
}
|
|
else
|
|
{
|
|
int32 Index = (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::FirstInputObject) ? 0 : Targets.Num() - 1;
|
|
HandleSourcesProperties->OutputExistingName = UE::Modeling::GetComponentAssetBaseName(UE::ToolTarget::GetTargetComponent(Targets[Index]), false);
|
|
|
|
// Reset the hidden gizmo to its initial position
|
|
const FTransform ComponentTransform = (FTransform) UE::ToolTarget::GetLocalToWorldTransform(Targets[Index]);
|
|
TransformGizmos[Index]->SetNewGizmoTransform(ComponentTransform, true);
|
|
UpdateGizmoVisibility();
|
|
}
|
|
});
|
|
|
|
Preview->InvalidateResult();
|
|
}
|
|
|
|
|
|
int32 UBaseCreateFromSelectedTool::GetHiddenGizmoIndex() const
|
|
{
|
|
if (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::NewObject)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::FirstInputObject) ? 0 : Targets.Num() - 1;
|
|
}
|
|
}
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::OnTick(float DeltaTime)
|
|
{
|
|
Preview->Tick(DeltaTime);
|
|
}
|
|
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::UpdateGizmoVisibility()
|
|
{
|
|
for (int32 GizmoIndex = 0; GizmoIndex < TransformGizmos.Num(); GizmoIndex++)
|
|
{
|
|
UCombinedTransformGizmo* Gizmo = TransformGizmos[GizmoIndex];
|
|
Gizmo->SetVisibility(TransformProperties->bShowTransformGizmo && GizmoIndex != GetHiddenGizmoIndex());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::SetTransformGizmos()
|
|
{
|
|
UInteractiveGizmoManager* GizmoManager = GetToolManager()->GetPairedGizmoManager();
|
|
|
|
for (int ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
|
|
{
|
|
UTransformProxy* Proxy = TransformProxies.Add_GetRef(NewObject<UTransformProxy>(this));
|
|
UCombinedTransformGizmo* Gizmo = TransformGizmos.Add_GetRef(UE::TransformGizmoUtil::Create3AxisTransformGizmo(GizmoManager, this));
|
|
Proxy->SetTransform((FTransform) UE::ToolTarget::GetLocalToWorldTransform(Targets[ComponentIdx]));
|
|
Gizmo->SetActiveTarget(Proxy, GetToolManager());
|
|
Proxy->OnTransformChanged.AddUObject(this, &UBaseCreateFromSelectedTool::TransformChanged);
|
|
}
|
|
UpdateGizmoVisibility();
|
|
}
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::TransformChanged(UTransformProxy* Proxy, FTransform Transform)
|
|
{
|
|
Preview->InvalidateResult();
|
|
}
|
|
|
|
|
|
FText UBaseCreateFromSelectedTool::GetActionName() const
|
|
{
|
|
return LOCTEXT("BaseCreateFromSelectedTool", "Generated Mesh");
|
|
}
|
|
|
|
|
|
TArray<UMaterialInterface*> UBaseCreateFromSelectedTool::GetOutputMaterials() const
|
|
{
|
|
return Preview->StandardMaterials;
|
|
}
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::GenerateAsset(const FDynamicMeshOpResult& OpResult)
|
|
{
|
|
if (OpResult.Mesh.Get() == nullptr) return;
|
|
|
|
FTransform3d NewTransform;
|
|
if (Targets.Num() == 1) // in the single-selection case, shove the result back into the original component space
|
|
{
|
|
FTransform3d ToSourceComponentSpace = UE::ToolTarget::GetLocalToWorldTransform(Targets[0]).Inverse();
|
|
MeshTransforms::ApplyTransform(*OpResult.Mesh, ToSourceComponentSpace);
|
|
NewTransform = UE::ToolTarget::GetLocalToWorldTransform(Targets[0]);
|
|
}
|
|
else // in the multi-selection case, center the pivot for the combined result
|
|
{
|
|
FVector3d Center = OpResult.Mesh->GetBounds().Center();
|
|
double Rescale = OpResult.Transform.GetScale().X;
|
|
FTransform3d LocalTransform(-Center * Rescale);
|
|
LocalTransform.SetScale(FVector3d(Rescale, Rescale, Rescale));
|
|
MeshTransforms::ApplyTransform(*OpResult.Mesh, LocalTransform);
|
|
NewTransform = OpResult.Transform;
|
|
NewTransform.SetScale(FVector3d::One());
|
|
NewTransform.SetTranslation(NewTransform.GetTranslation() + NewTransform.TransformVector(Center * Rescale));
|
|
}
|
|
|
|
// max len explicitly enforced here, would ideally notify user
|
|
FString UseBaseName = HandleSourcesProperties->OutputNewName.Left(250);
|
|
if (UseBaseName.IsEmpty())
|
|
{
|
|
UseBaseName = PrefixWithSourceNameIfSingleSelection(GetCreatedAssetName());
|
|
}
|
|
|
|
FCreateMeshObjectParams NewMeshObjectParams;
|
|
NewMeshObjectParams.TargetWorld = TargetWorld;
|
|
NewMeshObjectParams.Transform = (FTransform)NewTransform;
|
|
NewMeshObjectParams.BaseName = UseBaseName;
|
|
NewMeshObjectParams.Materials = GetOutputMaterials();
|
|
NewMeshObjectParams.SetMesh(OpResult.Mesh.Get());
|
|
if (OutputTypeProperties->OutputType == UCreateMeshObjectTypeProperties::AutoIdentifier)
|
|
{
|
|
UE::ToolTarget::ConfigureCreateMeshObjectParams(Targets[0], NewMeshObjectParams);
|
|
}
|
|
else
|
|
{
|
|
OutputTypeProperties->ConfigureCreateMeshObjectParams(NewMeshObjectParams);
|
|
}
|
|
FCreateMeshObjectResult Result = UE::Modeling::CreateMeshObject(GetToolManager(), MoveTemp(NewMeshObjectParams));
|
|
if (Result.IsOK() && Result.NewActor != nullptr)
|
|
{
|
|
ToolSelectionUtil::SetNewActorSelection(GetToolManager(), Result.NewActor);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::UpdateAsset(const FDynamicMeshOpResult& Result, UToolTarget* UpdateTarget)
|
|
{
|
|
check(Result.Mesh.Get() != nullptr);
|
|
|
|
FTransform3d TargetToWorld = UE::ToolTarget::GetLocalToWorldTransform(UpdateTarget);
|
|
|
|
FTransform3d ResultTransform = Result.Transform;
|
|
MeshTransforms::ApplyTransform(*Result.Mesh, ResultTransform);
|
|
MeshTransforms::ApplyTransformInverse(*Result.Mesh, TargetToWorld);
|
|
|
|
UE::ToolTarget::CommitMeshDescriptionUpdateViaDynamicMesh(UpdateTarget, *Result.Mesh, true);
|
|
|
|
FComponentMaterialSet MaterialSet;
|
|
MaterialSet.Materials = GetOutputMaterials();
|
|
Cast<IMaterialProvider>(UpdateTarget)->CommitMaterialSetUpdate(MaterialSet, true);
|
|
}
|
|
|
|
|
|
FString UBaseCreateFromSelectedTool::PrefixWithSourceNameIfSingleSelection(const FString& AssetName) const
|
|
{
|
|
if (Targets.Num() == 1)
|
|
{
|
|
FString CurName = UE::Modeling::GetComponentAssetBaseName(UE::ToolTarget::GetTargetComponent(Targets[0]));
|
|
return FString::Printf(TEXT("%s_%s"), *CurName, *AssetName);
|
|
}
|
|
else
|
|
{
|
|
return AssetName;
|
|
}
|
|
}
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::OnPropertyModified(UObject* PropertySet, FProperty* Property)
|
|
{
|
|
if (Property && (Property->GetFName() == GET_MEMBER_NAME_CHECKED(UTransformInputsToolProperties, bShowTransformGizmo)))
|
|
{
|
|
UpdateGizmoVisibility();
|
|
}
|
|
else if (Property &&
|
|
( PropertySet == HandleSourcesProperties
|
|
))
|
|
{
|
|
// nothing
|
|
}
|
|
else
|
|
{
|
|
Preview->InvalidateResult();
|
|
}
|
|
}
|
|
|
|
|
|
void UBaseCreateFromSelectedTool::Shutdown(EToolShutdownType ShutdownType)
|
|
{
|
|
SaveProperties();
|
|
HandleSourcesProperties->SaveProperties(this);
|
|
OutputTypeProperties->SaveProperties(this, TEXT("OutputTypeFromInputTool"));
|
|
TransformProperties->SaveProperties(this);
|
|
|
|
FDynamicMeshOpResult Result = Preview->Shutdown();
|
|
// Restore (unhide) the source meshes
|
|
for (int32 ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
|
|
{
|
|
UE::ToolTarget::ShowSourceObject(Targets[ComponentIdx]);
|
|
}
|
|
|
|
if (ShutdownType == EToolShutdownType::Accept)
|
|
{
|
|
GetToolManager()->BeginUndoTransaction(GetActionName());
|
|
|
|
// Generate the result
|
|
AActor* KeepActor = nullptr;
|
|
if (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::NewObject)
|
|
{
|
|
GenerateAsset(Result);
|
|
}
|
|
else
|
|
{
|
|
int32 TargetIndex = (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::FirstInputObject) ? 0 : (Targets.Num() - 1);
|
|
KeepActor = UE::ToolTarget::GetTargetActor(Targets[TargetIndex]);
|
|
|
|
UpdateAsset(Result, Targets[TargetIndex]);
|
|
}
|
|
|
|
TArray<AActor*> Actors;
|
|
for (int32 ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
|
|
{
|
|
AActor* Actor = UE::ToolTarget::GetTargetActor(Targets[ComponentIdx]);
|
|
Actors.Add(Actor);
|
|
}
|
|
HandleSourcesProperties->ApplyMethod(Actors, GetToolManager(), KeepActor);
|
|
|
|
if (KeepActor != nullptr)
|
|
{
|
|
// select the actor we kept
|
|
ToolSelectionUtil::SetNewActorSelection(GetToolManager(), KeepActor);
|
|
}
|
|
|
|
GetToolManager()->EndUndoTransaction();
|
|
}
|
|
|
|
UInteractiveGizmoManager* GizmoManager = GetToolManager()->GetPairedGizmoManager();
|
|
GizmoManager->DestroyAllGizmosByOwner(this);
|
|
}
|
|
|
|
|
|
bool UBaseCreateFromSelectedTool::CanAccept() const
|
|
{
|
|
return Super::CanAccept() && Preview->HaveValidNonEmptyResult();
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|