Files
UnrealEngine/Engine/Plugins/Runtime/MeshModelingToolset/Source/ModelingComponents/Private/Drawing/PolyEditPreviewMesh.cpp
2025-05-18 13:04:45 +08:00

340 lines
9.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Drawing/PolyEditPreviewMesh.h"
#include "DynamicSubmesh3.h"
#include "DynamicMesh/MeshTransforms.h"
#include "Operations/ExtrudeMesh.h"
#include "Operations/InsetMeshRegion.h"
#include "Selections/MeshVertexSelection.h"
#include "DynamicMesh/MeshNormals.h"
#include "DynamicMeshEditor.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(PolyEditPreviewMesh)
using namespace UE::Geometry;
void UPolyEditPreviewMesh::InitializeExtrudeType(
const FDynamicMesh3* SourceMesh, const TArray<int32>& Triangles,
const FVector3d& TransformedOffsetDirection,
const FTransform3d* MeshTransformIn,
bool bDeleteExtrudeBaseFaces)
{
// extract submesh
ActiveSubmesh = MakeUnique<FDynamicSubmesh3>(SourceMesh, Triangles, (int32)(EMeshComponents::FaceGroups) | (int32)(EMeshComponents::VertexNormals), true);
FDynamicMesh3& EditPatch = ActiveSubmesh->GetSubmesh();
check(EditPatch.IsCompact());
// do we want to apply a transform?
bHaveMeshTransform = (MeshTransformIn != nullptr);
if (bHaveMeshTransform)
{
MeshTransform = *MeshTransformIn;
MeshTransforms::ApplyTransform(EditPatch, MeshTransform, true);
}
//FMeshNormals::QuickComputeVertexNormals(EditPatch);
// save copy of initial patch
InitialEditPatch = EditPatch;
// save initial tri normals
InitialTriNormals.SetNum(InitialEditPatch.MaxTriangleID());
for ( int32 tid = 0; tid < InitialEditPatch.MaxTriangleID(); ++tid)
{
InitialTriNormals[tid] = InitialEditPatch.GetTriNormal(tid);
}
// extrude initial patch by a tiny amount so that we get normals
FExtrudeMesh Extruder(&EditPatch);
Extruder.DefaultExtrudeDistance = 0.01;
Extruder.Apply();
// get set of extrude vertices
ExtrudeToInitialVerts.Reset();
EditVertices.Reset();
FMeshVertexSelection Vertices(&EditPatch);
for (const FExtrudeMesh::FExtrusionInfo& Extrusion : Extruder.Extrusions)
{
Vertices.SelectTriangleVertices(Extrusion.OffsetTriangles);
for (TPair<int32, int32> pair : Extrusion.InitialToOffsetMapV)
{
ExtrudeToInitialVerts.Add(pair.Value, pair.Key);
}
}
EditVertices = Vertices.AsArray();
// save initial extrude positions
InitialPositions.Reset();
InitialNormals.Reset();
for (int32 vid : EditVertices)
{
InitialPositions.Add(EditPatch.GetVertex(vid));
InitialNormals.Add((FVector3d)EditPatch.GetVertexNormal(vid));
}
if (bDeleteExtrudeBaseFaces)
{
FDynamicMeshEditor Editor(&EditPatch);
for (const FExtrudeMesh::FExtrusionInfo& Extrusion : Extruder.Extrusions)
{
Editor.RemoveTriangles(Extrusion.InitialTriangles, false);
}
}
InputDirection = TransformedOffsetDirection;
// initialize the preview mesh
UpdatePreview(&EditPatch);
}
void UPolyEditPreviewMesh::InitializeExtrudeType(FDynamicMesh3&& BaseMesh,
const FVector3d& TransformedOffsetDirection,
const FTransform3d* MeshTransformIn,
bool bDeleteExtrudeBaseFaces)
{
InitialEditPatch = MoveTemp(BaseMesh);
// do we want to apply a transform?
bHaveMeshTransform = (MeshTransformIn != nullptr);
if (bHaveMeshTransform)
{
MeshTransform = *MeshTransformIn;
MeshTransforms::ApplyTransform(InitialEditPatch, MeshTransform, true);
}
// save initial tri normals
InitialTriNormals.SetNum(InitialEditPatch.MaxTriangleID());
for ( int32 tid : InitialEditPatch.TriangleIndicesItr() )
{
InitialTriNormals[tid] = InitialEditPatch.GetTriNormal(tid);
}
// extrude initial patch by a tiny amount so that we get normals
FDynamicMesh3 EditPatch(InitialEditPatch);
FExtrudeMesh Extruder(&EditPatch);
Extruder.DefaultExtrudeDistance = 0.01;
Extruder.Apply();
// get set of extrude vertices
ExtrudeToInitialVerts.Reset();
EditVertices.Reset();
FMeshVertexSelection Vertices(&EditPatch);
for (const FExtrudeMesh::FExtrusionInfo& Extrusion : Extruder.Extrusions)
{
Vertices.SelectTriangleVertices(Extrusion.OffsetTriangles);
for (TPair<int32,int32> pair : Extrusion.InitialToOffsetMapV)
{
ExtrudeToInitialVerts.Add(pair.Value, pair.Key);
}
}
EditVertices = Vertices.AsArray();
// save initial extrude positions
InitialPositions.Reset();
InitialNormals.Reset();
for (int32 vid : EditVertices)
{
InitialPositions.Add(EditPatch.GetVertex(vid));
InitialNormals.Add((FVector3d)EditPatch.GetVertexNormal(vid));
}
if (bDeleteExtrudeBaseFaces)
{
FDynamicMeshEditor Editor(&EditPatch);
for (const FExtrudeMesh::FExtrusionInfo& Extrusion : Extruder.Extrusions)
{
Editor.RemoveTriangles(Extrusion.InitialTriangles, false);
}
}
InputDirection = TransformedOffsetDirection;
// initialize the preview mesh
UpdatePreview(&EditPatch);
}
void UPolyEditPreviewMesh::UpdateExtrudeType(double NewOffset, bool bUseNormalDirection)
{
EditMesh([&](FDynamicMesh3& Mesh)
{
int32 NumVertices = EditVertices.Num();
for (int32 k = 0; k < NumVertices; ++k)
{
int vid = EditVertices[k];
FVector3d InitialPos = InitialPositions[k];
FVector3d NewPos = InitialPos + NewOffset * (bUseNormalDirection ? InitialNormals[k] : InputDirection);
Mesh.SetVertex(vid, NewPos);
}
});
}
void UPolyEditPreviewMesh::UpdateExtrudeType_FaceNormalAvg(double NewOffset)
{
EditMesh([&](FDynamicMesh3& Mesh)
{
int32 NumVertices = EditVertices.Num();
TArray<FVector3d> NewPositions;
NewPositions.SetNum(NumVertices);
for (int32 k = 0; k < NumVertices; ++k)
{
int vid = EditVertices[k];
FVector3d InitialPos = InitialPositions[k];
FVector3d AccumV = FVector3d::Zero();
int32 Count = 0;
int32 InitialVID = ExtrudeToInitialVerts[vid];
InitialEditPatch.EnumerateVertexTriangles(InitialVID, [&](int32 InitialTID)
{
AccumV += (InitialPos + NewOffset * InitialTriNormals[InitialTID]);
Count++;
});
NewPositions[k] = (Count == 0) ? InitialPos : (AccumV / (double)Count);
}
for (int32 k = 0; k < NumVertices; ++k)
{
Mesh.SetVertex(EditVertices[k], NewPositions[k]);
}
});
}
void UPolyEditPreviewMesh::UpdateExtrudeType(TFunctionRef<void(FDynamicMesh3&)> UpdateMeshFunc, bool bFullRecalculate)
{
if (bFullRecalculate)
{
FDynamicMesh3 TempMesh(InitialEditPatch);
UpdateMeshFunc(TempMesh);
ReplaceMesh(MoveTemp(TempMesh));
}
else
{
EditMesh(UpdateMeshFunc);
}
}
void UPolyEditPreviewMesh::MakeExtrudeTypeHitTargetMesh(FDynamicMesh3& TargetMesh, bool bUseNormalDirection)
{
FVector3d ExtrudeDirection = InputDirection;
double Length = 99999.0;
TargetMesh = InitialEditPatch;
MeshTransforms::Translate(TargetMesh, -Length * ExtrudeDirection);
FExtrudeMesh Extruder(&TargetMesh);
Extruder.ExtrudedPositionFunc = [&](const FVector3d& Position, const FVector3f& Normal, int VertexID)
{
return Position + 2.0 * Length * (bUseNormalDirection ? (FVector3d)Normal : ExtrudeDirection);
};
Extruder.Apply();
}
void UPolyEditPreviewMesh::InitializeInsetType(const FDynamicMesh3* SourceMesh, const TArray<int32>& Triangles,
const FTransform3d* MeshTransformIn)
{
// extract submesh
ActiveSubmesh = MakeUnique<FDynamicSubmesh3>(SourceMesh, Triangles, (int32)EMeshComponents::FaceGroups, true);
FDynamicMesh3& EditPatch = ActiveSubmesh->GetSubmesh();
check(EditPatch.IsCompact());
// do we want to apply a transform?
bHaveMeshTransform = (MeshTransformIn != nullptr);
if (bHaveMeshTransform)
{
MeshTransform = *MeshTransformIn;
MeshTransforms::ApplyTransform(EditPatch, MeshTransform, true);
}
// save copy of initial patch
InitialEditPatch = EditPatch;
// initialize the preview mesh
UpdatePreview(&EditPatch);
}
void UPolyEditPreviewMesh::UpdateInsetType(double NewOffset, bool bReproject, double Softness, double AreaScaleT, bool bBoundaryOnly)
{
FDynamicMesh3 EditPatch(InitialEditPatch);
FInsetMeshRegion Inset(&EditPatch);
for (int32 tid : EditPatch.TriangleIndicesItr())
{
Inset.Triangles.Add(tid);
}
Inset.InsetDistance = NewOffset;
Inset.bReproject = bReproject;
Inset.Softness = Softness;
Inset.AreaCorrection = AreaScaleT;
Inset.bSolveRegionInteriors = !bBoundaryOnly;
Inset.Apply();
FMeshNormals::QuickRecomputeOverlayNormals(EditPatch);
UpdatePreview(&EditPatch);
}
void UPolyEditPreviewMesh::MakeInsetTypeTargetMesh(FDynamicMesh3& TargetMesh)
{
TargetMesh = InitialEditPatch;
MeshTransforms::ApplyTransform(TargetMesh, GetTransform());
}
void UPolyEditPreviewMesh::InitializeStaticType(const FDynamicMesh3* SourceMesh, const TArray<int32>& Triangles,
const FTransform3d* MeshTransformIn)
{
// extract submesh
ActiveSubmesh = MakeUnique<FDynamicSubmesh3>(SourceMesh, Triangles, (int32)EMeshComponents::FaceGroups, true);
FDynamicMesh3& EditPatch = ActiveSubmesh->GetSubmesh();
check(EditPatch.IsCompact());
// do we want to apply a transform?
bHaveMeshTransform = (MeshTransformIn != nullptr);
if (bHaveMeshTransform)
{
MeshTransform = *MeshTransformIn;
MeshTransforms::ApplyTransform(EditPatch, MeshTransform, true);
}
// save copy of initial patch
InitialEditPatch = EditPatch;
// initialize the preview mesh
UpdatePreview(&EditPatch);
}
void UPolyEditPreviewMesh::UpdateStaticType(TFunctionRef<void(FDynamicMesh3&)> UpdateMeshFunc, bool bFullRecalculate)
{
if (bFullRecalculate)
{
FDynamicMesh3 TempMesh(InitialEditPatch);
UpdateMeshFunc(TempMesh);
ReplaceMesh(MoveTemp(TempMesh));
}
else
{
EditMesh(UpdateMeshFunc);
}
}
void UPolyEditPreviewMesh::MakeStaticTypeTargetMesh(FDynamicMesh3& TargetMesh)
{
TargetMesh = InitialEditPatch;
}