// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "BaseTools/SingleSelectionMeshEditingTool.h" #include "MeshOpPreviewHelpers.h" #include "Properties/RemeshProperties.h" #include "CleaningOps/SimplifyMeshOp.h" // required in header for enum types #include "SimplifyMeshTool.generated.h" class UMeshStatisticsProperties; class UMeshElementsVisualizer; PREDECLARE_GEOMETRY(class FDynamicMesh3); PREDECLARE_GEOMETRY(typedef TMeshAABBTree3 FDynamicMeshAABBTree3); /** * */ UCLASS() class MESHMODELINGTOOLSEDITORONLY_API USimplifyMeshToolBuilder : public USingleSelectionMeshEditingToolBuilder { GENERATED_BODY() public: virtual USingleSelectionMeshEditingTool* CreateNewTool(const FToolBuilderState& SceneState) const override; }; /** * Standard properties of the Simplify operation */ UCLASS() class MESHMODELINGTOOLSEDITORONLY_API USimplifyMeshToolProperties : public UMeshConstraintProperties { GENERATED_BODY() public: USimplifyMeshToolProperties(); /** Simplification Scheme */ UPROPERTY(EditAnywhere, Category = Options) ESimplifyType SimplifierType; /** Simplification Target Type */ UPROPERTY(EditAnywhere, Category = Options, meta = (EditCondition = "SimplifierType != ESimplifyType::MinimalPlanar && SimplifierType != ESimplifyType::MinimalPolygroup && SimplifierType != ESimplifyType::ClusterBased")) ESimplifyTargetType TargetMode; /** Target percentage of original triangle count */ UPROPERTY(EditAnywhere, Category = Options, meta = (UIMin = "0", UIMax = "100", ClampMin = "0.0", ClampMax = "100.0", EditCondition = "SimplifierType != ESimplifyType::ClusterBased && SimplifierType != ESimplifyType::MinimalPolygroup && SimplifierType != ESimplifyType::MinimalPlanar && TargetMode == ESimplifyTargetType::Percentage")) int TargetPercentage; /** Target edge length */ UPROPERTY(EditAnywhere, Category = Options, meta = (UIMin = "3.0", UIMax = "10.0", ClampMin = "0.001", ClampMax = "1000.0", EditCondition = "SimplifierType == ESimplifyType::ClusterBased || (TargetMode == ESimplifyTargetType::EdgeLength && SimplifierType != ESimplifyType::UEStandard && SimplifierType != ESimplifyType::MinimalPlanar && SimplifierType != ESimplifyType::MinimalPolygroup)")) float TargetEdgeLength; /** Target triangle count */ UPROPERTY(EditAnywhere, Category = Options, meta = (UIMin = "4", UIMax = "10000", ClampMin = "1", ClampMax = "9999999999", EditCondition = "TargetMode == ESimplifyTargetType::TriangleCount && SimplifierType != ESimplifyType::MinimalPlanar && SimplifierType != ESimplifyType::MinimalPolygroup && SimplifierType != ESimplifyType::ClusterBased")) int TargetTriangleCount; /** Target vertex count */ UPROPERTY(EditAnywhere, Category = Options, meta = (UIMin = "4", UIMax = "10000", ClampMin = "1", ClampMax = "9999999999", EditCondition = "TargetMode == ESimplifyTargetType::VertexCount && SimplifierType != ESimplifyType::MinimalPlanar && SimplifierType != ESimplifyType::ClusterBased")) int TargetVertexCount; /** Angle threshold in degrees used for testing if two triangles should be considered coplanar, or two lines collinear */ UPROPERTY() float MinimalAngleThreshold = 0.01; //~ Note PolyEdgeAngleTolerance is very similar to MinimalAngleThreshold, but not redundant b/c the useful ranges are very different (MinimalAngleThreshold should generally be kept very small) /** Threshold angle change (in degrees) along a polygroup edge, above which a vertex must be added */ UPROPERTY(EditAnywhere, Category = Options, meta = (UIMin = "0.001", ClampMin = "0.0", UIMax = "90.0", ClampMax = "180.0", EditCondition = "SimplifierType == ESimplifyType::MinimalPolygroup")) float PolyEdgeAngleTolerance = .1; /** Threshold angle change (in degrees) between adjacent boundary edges, above which the common vertex must be preserved */ UPROPERTY(EditAnywhere, Category = Options, meta = (UIMin = "0.001", ClampMin = "0.0", UIMax = "90.0", ClampMax = "180.0", EditCondition = "SimplifierType == ESimplifyType::ClusterBased")) float BoundaryEdgeAngleTolerance = 30.0f; /** Discard UVs and existing normals, allowing the simplifier to ignore any UV and normal seams. New per-vertex normals are computed. */ UPROPERTY(EditAnywhere, Category = Options) bool bDiscardAttributes; /** If true, then simplification will consider geometric deviation with the input mesh */ UPROPERTY(EditAnywhere, Category = Options, meta = (EditCondition = "SimplifierType != ESimplifyType::MinimalPolygroup")) bool bGeometricConstraint; /** Geometric deviation tolerance used when bGeometricConstraint is enabled, to limit the geometric deviation between the simplified and original meshes */ UPROPERTY(EditAnywhere, Category = Options, meta = (UIMin = "0.0", UIMax = "10.0", ClampMin = "0.0", ClampMax = "10000000.0", EditCondition = "bGeometricConstraint && SimplifierType != ESimplifyType::UEStandard && SimplifierType != ESimplifyType::MinimalPolygroup")) float GeometricTolerance; /** Display colors corresponding to the mesh's polygon groups */ UPROPERTY(EditAnywhere, Category = Display) bool bShowGroupColors = false; /** Enable projection back to input mesh */ UPROPERTY(EditAnywhere, Category = Options, AdvancedDisplay) bool bReproject; protected: virtual bool IsPreventNormalFlipsEnabled() const override { return SimplifierType == ESimplifyType::QEM || SimplifierType == ESimplifyType::MinimalExistingVertex || SimplifierType == ESimplifyType::Attribute || SimplifierType == ESimplifyType::MinimalPlanar; } virtual bool IsPreventTinyTrianglesEnabled() const override { return SimplifierType == ESimplifyType::QEM || SimplifierType == ESimplifyType::MinimalExistingVertex || SimplifierType == ESimplifyType::Attribute || SimplifierType == ESimplifyType::MinimalPlanar; } }; /** * Simple Mesh Simplifying Tool */ UCLASS() class MESHMODELINGTOOLSEDITORONLY_API USimplifyMeshTool : public USingleSelectionMeshEditingTool, public UE::Geometry::IDynamicMeshOperatorFactory { GENERATED_BODY() public: virtual void Setup() override; virtual void OnShutdown(EToolShutdownType ShutdownType) override; virtual void OnTick(float DeltaTime) override; virtual bool HasCancel() const override { return true; } virtual bool HasAccept() const override { return true; } virtual bool CanAccept() const override; virtual void OnPropertyModified(UObject* PropertySet, FProperty* Property) override; // IDynamicMeshOperatorFactory API virtual TUniquePtr MakeNewOperator() override; private: UPROPERTY() TObjectPtr SimplifyProperties; UPROPERTY() TObjectPtr MeshStatisticsProperties; UPROPERTY() TObjectPtr Preview; UPROPERTY() TObjectPtr MeshElementsDisplay; TSharedPtr OriginalMeshDescription; // Dynamic Mesh versions precomputed in Setup (rather than recomputed for every simplify op) TSharedPtr OriginalMesh; TSharedPtr OriginalMeshSpatial; void UpdateVisualization(); };