// Copyright Epic Games, Inc. All Rights Reserved. #include "SmoothMeshTool.h" #include "InteractiveToolManager.h" #include "ToolBuilderUtil.h" #include "DynamicMesh/DynamicMesh3.h" #include "DynamicMesh/MeshNormals.h" // Smoothing operators #include "DynamicSubmesh3.h" #include "Selections/GeometrySelectionUtil.h" #include "SmoothingOps/IterativeSmoothingOp.h" #include "SmoothingOps/CotanSmoothingOp.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(SmoothMeshTool) using namespace UE::Geometry; #define LOCTEXT_NAMESPACE "USmoothMeshTool" /* * Tool Builder */ USingleTargetWithSelectionTool* USmoothMeshToolBuilder::CreateNewTool(const FToolBuilderState& SceneState) const { return NewObject(SceneState.ToolManager); } /* * Tool */ USmoothMeshTool::USmoothMeshTool() { SetToolDisplayName(LOCTEXT("ToolName", "Smooth")); } void USmoothMeshTool::InitializeProperties() { SmoothProperties = NewObject(this); AddToolPropertySource(SmoothProperties); SmoothProperties->RestoreProperties(this); SmoothProperties->WatchProperty(SmoothProperties->SmoothingType, [&](ESmoothMeshToolSmoothType) { UpdateOptionalPropertyVisibility(); InvalidateResult(); }); IterativeProperties = AddOptionalPropertySet( [&]() { return SmoothProperties->SmoothingType == ESmoothMeshToolSmoothType::Iterative; } ); DiffusionProperties = AddOptionalPropertySet( [&]() { return SmoothProperties->SmoothingType == ESmoothMeshToolSmoothType::Diffusion; }); ImplicitProperties = AddOptionalPropertySet( [&]() { return SmoothProperties->SmoothingType == ESmoothMeshToolSmoothType::Implicit; }); WeightMapProperties = AddWeightMapPropertySet( [&]() { return SmoothProperties->SmoothingType != ESmoothMeshToolSmoothType::Diffusion; }); WeightMapProperties->WatchProperty(WeightMapProperties->MinSmoothMultiplier, [&](float) { InvalidateResult(); }); } void USmoothMeshTool::OnShutdown(EToolShutdownType ShutdownType) { SmoothProperties->SaveProperties(this); } FText USmoothMeshTool::GetToolMessageString() const { return LOCTEXT("StartSmoothToolMessage", "Smooth the mesh vertex positions using various smoothing methods."); } FText USmoothMeshTool::GetAcceptTransactionName() const { return LOCTEXT("SmoothMeshToolTransactionName", "Smooth Mesh"); } bool USmoothMeshTool::HasMeshTopologyChanged() const { return false; } TUniquePtr USmoothMeshTool::MakeNewOperator() { TUniquePtr MeshOp; const FDynamicMesh3* Mesh = &GetInitialMesh(); bool bUsingSelection = false; UE::Geometry::FDynamicSubmesh3 SubmeshToSmooth; if (HasGeometrySelection()) { // retrieves all triangles in the current selected geometry TSet TrianglesSelected; const FGeometrySelection& InputSelection = GetGeometrySelection(); UE::Geometry::EnumerateSelectionTriangles(InputSelection, *Mesh, [&](int32 TriangleID){TrianglesSelected.Add(TriangleID); }); // creates a Submesh from the selection SubmeshToSmooth = FDynamicSubmesh3(Mesh,TrianglesSelected.Array()); bUsingSelection = true; } FSmoothingOpBase::FOptions Options; Options.BaseNormals = this->GetInitialVtxNormals(); if (HasActiveWeightMap()) { Options.bUseWeightMap = true; Options.WeightMap = GetActiveWeightMap(); Options.WeightMapMinMultiplier = WeightMapProperties->MinSmoothMultiplier; } switch (SmoothProperties->SmoothingType) { default: case ESmoothMeshToolSmoothType::Iterative: Options.SmoothAlpha = IterativeProperties->SmoothingPerStep; Options.BoundarySmoothAlpha = FMathd::Lerp(0.0, 0.9, IterativeProperties->SmoothingPerStep); Options.Iterations = IterativeProperties->Steps; Options.bSmoothBoundary = IterativeProperties->bSmoothBoundary; Options.bUniform = true; Options.bUseImplicit = false; if (bUsingSelection) { MeshOp = MakeUnique(Mesh, Options, SubmeshToSmooth); } else { MeshOp = MakeUnique(Mesh, Options); } break; case ESmoothMeshToolSmoothType::Diffusion: Options.SmoothAlpha = DiffusionProperties->SmoothingPerStep; Options.BoundarySmoothAlpha = FMathd::Lerp(0.0, 0.9, IterativeProperties->SmoothingPerStep); Options.Iterations = DiffusionProperties->Steps; Options.bUniform = DiffusionProperties->bPreserveUVs == false; Options.bUseImplicit = true; if (bUsingSelection) { MeshOp = MakeUnique(Mesh, Options, SubmeshToSmooth); } else { MeshOp = MakeUnique(Mesh, Options); } break; case ESmoothMeshToolSmoothType::Implicit: { Options.SmoothAlpha = ImplicitProperties->SmoothSpeed; Options.BoundarySmoothAlpha = 0.0; double NonlinearT = FMathd::Pow(ImplicitProperties->Smoothness, 2.0); // this is an empirically-determined hack that seems to work OK to normalize the smoothing result for variable vertex count... double ScaledPower = (NonlinearT/50.0) * Mesh->VertexCount(); Options.SmoothPower = ScaledPower; Options.bUniform = ImplicitProperties->bPreserveUVs == false; Options.bUseImplicit = true; Options.NormalOffset = ImplicitProperties->VolumeCorrection; if (bUsingSelection) { MeshOp = MakeUnique(Mesh, Options, SubmeshToSmooth); } else { MeshOp = MakeUnique(Mesh, Options); } } break; } FTransform3d XForm3d(GetPreviewTransform()); MeshOp->SetTransform(XForm3d); return MeshOp; } #undef LOCTEXT_NAMESPACE