Files
UnrealEngineUWP/Engine/Plugins/Experimental/MeshModelingToolsetExp/Source/MeshModelingToolsExp/Private/MeshInspectorTool.cpp
lonnie li 4afd669dcb ModelingTools: Clear TargetWorld member during Shutdown of SingleSelectionMeshEditingTool and MultiSelectionMeshEditingTool
#rb ryan.schmidt michael.balzer
#rnx
#jira none
#preflight 61f435dd74510448a6865d14

#ROBOMERGE-AUTHOR: lonnie.li
#ROBOMERGE-SOURCE: CL 18777332 in //UE5/Release-5.0/... via CL 18780413 via CL 18780555
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v903-18687472)

[CL 18780558 by lonnie li in ue5-main branch]
2022-01-28 18:40:54 -05:00

420 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MeshInspectorTool.h"
#include "InteractiveToolManager.h"
#include "ToolBuilderUtil.h"
#include "DynamicMesh/DynamicMesh3.h"
#include "DynamicMesh/DynamicMeshAttributeSet.h"
#include "DynamicMesh/MeshNormals.h"
#include "Components/DynamicMeshComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Properties/MeshStatisticsProperties.h"
#include "Properties/MeshAnalysisProperties.h"
#include "Drawing/LineSetComponent.h"
#include "ToolDataVisualizer.h"
#include "SceneManagement.h" // for FPrimitiveDrawInterface
#include "ToolSetupUtil.h"
#include "AssetUtils/MeshDescriptionUtil.h"
#include "ModelingToolTargetUtil.h"
using namespace UE::Geometry;
#define LOCTEXT_NAMESPACE "UMeshInspectorTool"
/*
* ToolBuilder
*/
USingleSelectionMeshEditingTool* UMeshInspectorToolBuilder::CreateNewTool(const FToolBuilderState& SceneState) const
{
return NewObject<UMeshInspectorTool>(SceneState.ToolManager);
}
/*
* Tool
*/
UMeshInspectorTool::UMeshInspectorTool()
{
}
void UMeshInspectorTool::Setup()
{
UInteractiveTool::Setup();
PreviewMesh = NewObject<UPreviewMesh>(this);
PreviewMesh->bBuildSpatialDataStructure = false;
PreviewMesh->CreateInWorld(GetTargetWorld(), FTransform::Identity);
ToolSetupUtil::ApplyRenderingConfigurationToPreview(PreviewMesh, Target);
PreviewMesh->SetTransform((FTransform)UE::ToolTarget::GetLocalToWorldTransform(Target));
FComponentMaterialSet MaterialSet = UE::ToolTarget::GetMaterialSet(Target);
PreviewMesh->SetMaterials(MaterialSet.Materials);
DefaultMaterial = PreviewMesh->GetMaterial(0);
PreviewMesh->SetTangentsMode(EDynamicMeshComponentTangentsMode::ExternallyProvided);
FDynamicMesh3 InputMeshWithTangents = UE::ToolTarget::GetDynamicMeshCopy(Target, true);
PreviewMesh->ReplaceMesh(MoveTemp(InputMeshWithTangents));
DrawnLineSet = NewObject<ULineSetComponent>(PreviewMesh->GetRootComponent(), "MeshInspectorToolLineSet");
DrawnLineSet->SetupAttachment(PreviewMesh->GetRootComponent());
DrawnLineSet->SetLineMaterial(ToolSetupUtil::GetDefaultLineComponentMaterial(GetToolManager()));
DrawnLineSet->RegisterComponent();
Precompute();
UE::ToolTarget::HideSourceObject(Target);
// initialize our properties
Settings = NewObject<UMeshInspectorProperties>(this);
Settings->RestoreProperties(this);
AddToolPropertySource(Settings);
MaterialSettings = NewObject<UExistingMeshMaterialProperties>(this);
const FDynamicMesh3* TargetMesh = PreviewMesh->GetPreviewDynamicMesh();
TArray<FString> UVChannelNamesList;
for (int32 k = 0; k < TargetMesh->Attributes()->NumUVLayers(); ++k)
{
UVChannelNamesList.Add(FString::Printf(TEXT("UV %d"), k));
}
MaterialSettings->UpdateUVChannels(0, UVChannelNamesList);
MaterialSettings->RestoreProperties(this);
AddToolPropertySource(MaterialSettings);
PreviewMesh->EnableWireframe(Settings->bWireframe);
UMeshStatisticsProperties* Statistics = NewObject<UMeshStatisticsProperties>(this);
Statistics->Update(*PreviewMesh->GetPreviewDynamicMesh());
AddToolPropertySource(Statistics);
UMeshAnalysisProperties* MeshAnalysis = NewObject<UMeshAnalysisProperties>(this);
MeshAnalysis->Update(*PreviewMesh->GetPreviewDynamicMesh(), (FTransform)UE::ToolTarget::GetLocalToWorldTransform(Target));
AddToolPropertySource(MeshAnalysis);
UpdateVisualization();
SetToolDisplayName(LOCTEXT("ToolName", "Mesh Inspector"));
GetToolManager()->DisplayMessage(
LOCTEXT("OnStartTool", "Visualize various geometric properties and attributes of the Mesh"),
EToolMessageLevel::UserNotification);
}
void UMeshInspectorTool::OnShutdown(EToolShutdownType ShutdownType)
{
UE::ToolTarget::ShowSourceObject(Target);
if (PreviewMesh != nullptr)
{
PreviewMesh->SetVisible(false);
PreviewMesh->Disconnect();
PreviewMesh = nullptr;
}
Settings->SaveProperties(this);
MaterialSettings->SaveProperties(this);
}
void UMeshInspectorTool::Precompute()
{
BoundaryEdges.Reset();
BoundaryBowties.Reset();
UVSeamEdges.Reset();
UVBowties.Reset();
NormalSeamEdges.Reset();
GroupBoundaryEdges.Reset();
MissingUVTriangleEdges.Reset();
const FDynamicMesh3* TargetMesh = PreviewMesh->GetPreviewDynamicMesh();
const FDynamicMeshUVOverlay* UVOverlay =
TargetMesh->HasAttributes() ? TargetMesh->Attributes()->PrimaryUV() : nullptr;
const FDynamicMeshNormalOverlay* NormalOverlay =
TargetMesh->HasAttributes() ? TargetMesh->Attributes()->PrimaryNormals() : nullptr;
for (int eid : TargetMesh->EdgeIndicesItr())
{
if (TargetMesh->IsBoundaryEdge(eid))
{
BoundaryEdges.Add(eid);
}
if (UVOverlay != nullptr && UVOverlay->IsSeamEdge(eid))
{
UVSeamEdges.Add(eid);
}
if (NormalOverlay != nullptr && NormalOverlay->IsSeamEdge(eid))
{
NormalSeamEdges.Add(eid);
}
if (TargetMesh->IsGroupBoundaryEdge(eid))
{
GroupBoundaryEdges.Add(eid);
}
}
for (int vid : TargetMesh->VertexIndicesItr())
{
if (TargetMesh->IsBowtieVertex(vid))
{
BoundaryBowties.Add(vid);
}
if (UVOverlay != nullptr && UVOverlay->IsBowtieInOverlay(vid))
{
UVBowties.Add(vid);
}
}
for (int tid : TargetMesh->TriangleIndicesItr())
{
if (UVOverlay != nullptr && !UVOverlay->IsSetTriangle(tid))
{
const FIndex3i Edges = TargetMesh->GetTriEdges(tid);
MissingUVTriangleEdges.Add(Edges[0]);
MissingUVTriangleEdges.Add(Edges[1]);
MissingUVTriangleEdges.Add(Edges[2]);
}
}
}
void UMeshInspectorTool::Render(IToolsContextRenderAPI* RenderAPI)
{
const FDynamicMesh3* TargetMesh = PreviewMesh->GetPreviewDynamicMesh();
FTransform Transform = PreviewMesh->GetTransform();
if (BoundaryBowties.Num() > 0 && Settings->bBowtieVertices)
{
FToolDataVisualizer BowtieRenderer;
BowtieRenderer.PointColor = FColor(240, 15, 15);
BowtieRenderer.PointSize = 25.0;
BowtieRenderer.BeginFrame(RenderAPI);
BowtieRenderer.SetTransform(Transform);
for (int32 vid : BoundaryBowties)
{
BowtieRenderer.DrawPoint(TargetMesh->GetVertex(vid));
}
BowtieRenderer.EndFrame();
}
if (UVBowties.Num() > 0 && Settings->bUVBowties)
{
FToolDataVisualizer BowtieRenderer;
BowtieRenderer.PointColor = FColor(15, 240, 15);
BowtieRenderer.PointSize = 12.0;
BowtieRenderer.BeginFrame(RenderAPI);
BowtieRenderer.SetTransform(Transform);
for (int32 vid : UVBowties)
{
BowtieRenderer.DrawPoint(TargetMesh->GetVertex(vid));
}
BowtieRenderer.EndFrame();
}
}
void UMeshInspectorTool::OnPropertyModified(UObject* PropertySet, FProperty* Property)
{
GetToolManager()->PostInvalidation();
UpdateVisualization();
}
void UMeshInspectorTool::UpdateVisualization()
{
PreviewMesh->EnableWireframe(Settings->bWireframe);
MaterialSettings->UpdateMaterials();
UMaterialInterface* OverrideMaterial = MaterialSettings->GetActiveOverrideMaterial();
if (OverrideMaterial == nullptr)
{
PreviewMesh->ClearOverrideRenderMaterial();
}
else
{
PreviewMesh->SetOverrideRenderMaterial(OverrideMaterial);
}
FColor BoundaryEdgeColor(240, 15, 15);
float BoundaryEdgeThickness = LineWidthMultiplier * 4.0;
FColor UVSeamColor(15, 240, 15);
float UVSeamThickness = LineWidthMultiplier * 2.0;
const FColor MissingUVColor(240, 15, 15);
const float MissingUVThickness = LineWidthMultiplier * 2.0;
FColor NormalSeamColor(15, 240, 240);
float NormalSeamThickness = LineWidthMultiplier * 2.0;
FColor PolygonBorderColor(240, 15, 240);
float PolygonBorderThickness = LineWidthMultiplier * 2.0;
FColor NormalColor(15, 15, 240);
float NormalThickness = LineWidthMultiplier * 2.0f;
FColor TangentColor(240, 15, 15);
FColor BinormalColor(15, 240, 15);
float TangentThickness = LineWidthMultiplier * 2.0f;
float BoundaryEdgeDepthBias = 0.2f;
float UVSeamDepthBias = 0.3f;
const float MissingUVDepthBias = 0.3f;
float NormalSeamDepthBias = 0.3f;
float PolygonBorderDepthBias = 0.2f;
float NormalDepthBias = 0.0f;
float TangentDepthBias = 0.35f;
// Used to scale normals and tangents appropriately
FVector ComponentScale = DrawnLineSet->GetComponentTransform().GetScale3D();
FVector3f InverseScale(1 / ComponentScale.X, 1 / ComponentScale.Y, 1 / ComponentScale.Z);
const FDynamicMesh3* TargetMesh = PreviewMesh->GetPreviewDynamicMesh();
FVector3d A, B;
DrawnLineSet->Clear();
if (Settings->bBoundaryEdges)
{
for (int eid : BoundaryEdges)
{
TargetMesh->GetEdgeV(eid, A, B);
DrawnLineSet->AddLine((FVector)A, (FVector)B, BoundaryEdgeColor, BoundaryEdgeThickness, BoundaryEdgeDepthBias);
}
}
if (Settings->bUVSeams)
{
for (int eid : UVSeamEdges)
{
TargetMesh->GetEdgeV(eid, A, B);
DrawnLineSet->AddLine((FVector)A, (FVector)B, UVSeamColor, UVSeamThickness, UVSeamDepthBias);
}
}
if (Settings->bMissingUVs)
{
for (int eid : MissingUVTriangleEdges)
{
TargetMesh->GetEdgeV(eid, A, B);
DrawnLineSet->AddLine((FVector)A, (FVector)B, MissingUVColor, MissingUVThickness, UVSeamDepthBias);
}
}
if (Settings->bNormalSeams)
{
for (int eid : NormalSeamEdges)
{
TargetMesh->GetEdgeV(eid, A, B);
DrawnLineSet->AddLine((FVector)A, (FVector)B, NormalSeamColor, NormalSeamThickness, NormalSeamDepthBias);
}
}
if (Settings->bPolygonBorders)
{
for (int eid : GroupBoundaryEdges)
{
TargetMesh->GetEdgeV(eid, A, B);
DrawnLineSet->AddLine((FVector)A, (FVector)B, PolygonBorderColor, PolygonBorderThickness, PolygonBorderDepthBias);
}
}
if (Settings->bNormalVectors && TargetMesh->HasAttributes() && TargetMesh->Attributes()->PrimaryNormals() != nullptr)
{
// Note that for normals and tangent vectors, we want to allow the origin of the vector to undergo the full
// transform of the component, but the direction we travel along the vector has to be inversely scaled
// to end up with the original length in the end (and to reflect the fact that Unreal does not consider
// the scale transform when adjusting normals for an object).
FVector3f NormalScaling = Settings->NormalLength * InverseScale;
const FDynamicMeshNormalOverlay* NormalOverlay = TargetMesh->Attributes()->PrimaryNormals();
FVector3d TriV[3];
FVector3f TriN[3];
for (int tid : TargetMesh->TriangleIndicesItr())
{
if ( NormalOverlay->IsSetTriangle(tid) )
{
TargetMesh->GetTriVertices(tid, TriV[0], TriV[1], TriV[2]);
NormalOverlay->GetTriElements(tid, TriN[0], TriN[1], TriN[2]);
for (int j = 0; j < 3; ++j)
{
DrawnLineSet->AddLine((FVector)TriV[j], (FVector)((FVector3f)TriV[j] + NormalScaling * TriN[j]),
NormalColor, NormalThickness, NormalDepthBias);
}
}
}
}
if (Settings->bTangentVectors && PreviewMesh->GetMesh()->Attributes()->HasTangentSpace() )
{
// See note in normals about scaling
FVector3f TangentScaling = Settings->TangentLength * InverseScale;
FDynamicMeshTangents Tangents(PreviewMesh->GetMesh());
for (int TID : TargetMesh->TriangleIndicesItr())
{
FVector3d TriV[3];
TargetMesh->GetTriVertices(TID, TriV[0], TriV[1], TriV[2]);
for (int SubIdx = 0; SubIdx < 3; SubIdx++)
{
FVector3f Vert(TriV[SubIdx]);
FVector3f Tangent, Bitangent;
Tangents.GetTangentVectors(TID, SubIdx, Tangent, Bitangent);
DrawnLineSet->AddLine((FVector)Vert, (FVector)(Vert + TangentScaling * Tangent),
TangentColor, TangentThickness, TangentDepthBias);
DrawnLineSet->AddLine((FVector)Vert, (FVector)(Vert + TangentScaling * Bitangent),
BinormalColor, TangentThickness, TangentDepthBias);
}
}
}
}
bool UMeshInspectorTool::HasAccept() const
{
return false;
}
bool UMeshInspectorTool::CanAccept() const
{
return false;
}
void UMeshInspectorTool::RegisterActions(FInteractiveToolActionSet& ActionSet)
{
ActionSet.RegisterAction(this, (int32)EStandardToolActions::BaseClientDefinedActionID + 1,
TEXT("IncreaseLineWidth"),
LOCTEXT("IncreaseLineWidth", "Increase Line Width"),
LOCTEXT("IncreaseLineWidthTooltip", "Increase line width of rendering"),
EModifierKey::Shift, EKeys::Equals,
[this]() { IncreaseLineWidthAction(); });
ActionSet.RegisterAction(this, (int32)EStandardToolActions::BaseClientDefinedActionID + 2,
TEXT("DecreaseLineWidth"),
LOCTEXT("DecreaseLineWidth", "Decrease Line Width"),
LOCTEXT("DecreaseLineWidthTooltip", "Decrease line width of rendering"),
EModifierKey::None, EKeys::Equals,
[this]() { DecreaseLineWidthAction(); });
}
void UMeshInspectorTool::IncreaseLineWidthAction()
{
LineWidthMultiplier = LineWidthMultiplier * 1.25f;
GetToolManager()->PostInvalidation();
}
void UMeshInspectorTool::DecreaseLineWidthAction()
{
LineWidthMultiplier = LineWidthMultiplier * (1.0f / 1.25f);
GetToolManager()->PostInvalidation();
}
#undef LOCTEXT_NAMESPACE