Files
matija kecman 77a219bd26 Add a reusable geometry selection visualization system intended to be used in modeling tools with minimal boilerplate
This CL was reviewed here: https://p4-swarm.epicgames.net/reviews/26051575 but needs to be merged into //Fortnite/Release-26.00, not //Fortnite/Main

#jira UE-183457
#rb ryan.schmidt, nathan.mitchell

[CL 26180612 by matija kecman in 5.3 branch]
2023-06-22 09:26:09 -04:00

142 lines
5.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Selection/ToolSelectionUtil.h"
#include "InteractiveToolManager.h"
#include "GameFramework/Actor.h"
#include "TriangleTypes.h"
#include "SegmentTypes.h"
#include "GroupTopology.h"
#include "ToolDataVisualizer.h"
#include "DynamicMeshBuilder.h"
#include "DynamicMesh/DynamicMesh3.h"
#include "Selections/GeometrySelection.h"
#include "Selections/GeometrySelectionUtil.h"
// For debug drawing
#include "Engine/Engine.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "SceneManagement.h"
#include "SceneView.h"
using namespace UE::Geometry;
void ToolSelectionUtil::SetNewActorSelection(UInteractiveToolManager* ToolManager, AActor* Actor)
{
FSelectedOjectsChangeList NewSelection;
NewSelection.ModificationType = ESelectedObjectsModificationType::Replace;
NewSelection.Actors.Add(Actor);
ToolManager->RequestSelectionChange(NewSelection);
}
void ToolSelectionUtil::SetNewActorSelection(UInteractiveToolManager* ToolManager, const TArray<AActor*>& Actors)
{
FSelectedOjectsChangeList NewSelection;
NewSelection.ModificationType = ESelectedObjectsModificationType::Replace;
for (AActor* Actor : Actors)
{
NewSelection.Actors.Add(Actor);
}
ToolManager->RequestSelectionChange(NewSelection);
}
bool ToolSelectionUtil::AccumulateSelectionElements(
FGeometrySelectionElements& Elements,
const FGeometrySelection& Selection,
const FDynamicMesh3& SourceMesh,
const FGroupTopology* GroupTopology,
const FTransform* ApplyTransform,
bool bMapFacesToEdges)
{
auto AddPoint = [&Elements](uint32 Vid, const FVector3d& Point) { Elements.Points.Add(Point); };
auto AddSegment = [&Elements](uint32 Eid, const FSegment3d& Segment) { Elements.Segments.Add(Segment); };
auto AddTriangle = [&Elements](uint32 Tid, const FTriangle3d& Triangle) { Elements.Triangles.Add(Triangle); };
if (Selection.TopologyType == EGeometryTopologyType::Polygroup)
{
if (GroupTopology)
{
return EnumeratePolygroupSelectionElements(Selection, SourceMesh, GroupTopology,
AddPoint, AddSegment, AddTriangle, ApplyTransform, bMapFacesToEdges);
}
const FGroupTopology ComputedGroupTopology(&SourceMesh, true);
return EnumeratePolygroupSelectionElements(Selection, SourceMesh, &ComputedGroupTopology,
AddPoint, AddSegment, AddTriangle, ApplyTransform, bMapFacesToEdges);
}
return EnumerateTriangleSelectionElements(Selection, SourceMesh,
AddPoint, AddSegment, AddTriangle, ApplyTransform, bMapFacesToEdges);
}
void ToolSelectionUtil::DebugRenderGeometrySelectionElements(
IToolsContextRenderAPI* RenderAPI,
const FGeometrySelectionElements& Elements,
bool bIsPreview)
{
FPrimitiveDrawInterface* CurrentPDI = RenderAPI->GetPrimitiveDrawInterface();
// batch render all the triangles, vastly more efficient than drawing one by one!
FDynamicMeshBuilder MeshBuilder(CurrentPDI->View->GetFeatureLevel());
int32 DepthPriority = SDPG_World; // SDPG_Foreground; // SDPG_World
FVector2f UVs[3] = { FVector2f(0,0), FVector2f(0,1), FVector2f(1,1) };
FVector3f Normal = FVector3f(0, 0, 1);
FVector3f Tangent = FVector3f(1, 0, 0);
for (const FTriangle3d& Triangle : Elements.Triangles)
{
int32 V0 = MeshBuilder.AddVertex(FDynamicMeshVertex((FVector3f)Triangle.V[0], Tangent, Normal, UVs[0], FColor::White));
int32 V1 = MeshBuilder.AddVertex(FDynamicMeshVertex((FVector3f)Triangle.V[1], Tangent, Normal, UVs[1], FColor::White));
int32 V2 = MeshBuilder.AddVertex(FDynamicMeshVertex((FVector3f)Triangle.V[2], Tangent, Normal, UVs[2], FColor::White));
MeshBuilder.AddTriangle(V0, V1, V2);
}
//FMaterialRenderProxy* MaterialRenderProxy = TriangleMaterial->GetRenderProxy(); // currently does not work, material does not render
FMaterialRenderProxy* MaterialRenderProxy = GEngine->ConstraintLimitMaterialX->GetRenderProxy();
MeshBuilder.Draw(CurrentPDI, FMatrix::Identity, MaterialRenderProxy, DepthPriority, false, false);
FToolDataVisualizer Visualizer;
Visualizer.bDepthTested = false;
Visualizer.BeginFrame(RenderAPI);
if (bIsPreview)
{
Visualizer.SetLineParameters(FLinearColor(1, 1, 0, 1), 1.0f);
Visualizer.SetPointParameters(FLinearColor(1, 1, 0, 1), 5.0f);
}
else
{
Visualizer.SetLineParameters(FLinearColor(0,0.3f,0.95f,1), 3.0f);
Visualizer.SetPointParameters(FLinearColor(0,0.3f,0.95f,1), 10.0f);
}
for (const FSegment3d& Segment : Elements.Segments)
{
Visualizer.DrawLine(Segment.StartPoint(), Segment.EndPoint());
}
for (const FVector3d& Point : Elements.Points)
{
Visualizer.DrawPoint(Point);
}
Visualizer.EndFrame();
}
void FSelectionRenderHelper::Initialize(const FGeometrySelection& Selection,
const FDynamicMesh3& SourceMesh,
const FGroupTopology* Topology,
const FTransform* ApplyTransform)
{
bool bSuccess = ToolSelectionUtil::AccumulateSelectionElements(Elements, Selection, SourceMesh, Topology, ApplyTransform, false);
ensure(bSuccess);
}
void FSelectionRenderHelper::Render(IToolsContextRenderAPI* RenderAPI) const
{
// TODO Using PDI here does not scale well for large selections. We are going to have to reimplement this with
// something that uses (eg) a custom LineSetComponent / PointSetComponent / TriangleSetComponent depending on
// the selection type
ToolSelectionUtil::DebugRenderGeometrySelectionElements(RenderAPI, Elements, false);
}