Files
mesh-project-duplicate-remover/Source/OptimizerEditor/Public/OptimizerSubsystem.h
Bonchellon a95b299680 Mesh Optimizer: sibling StaticMesh duplicate remover (UE 5.7)
Editor plugin that detects geometrically-identical sibling StaticMeshes across a
level, rebases each placement onto one canonical mesh with a corrected transform
(W' = D * W, verified by exact vertex matching), and can collapse groups into HISM.
Native Slate tool panel + BlueprintCallable UOptimizerSubsystem.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 18:26:45 +03:00

77 lines
2.7 KiB
C++

// Copyright IHY.
#pragma once
#include "CoreMinimal.h"
#include "EditorSubsystem.h"
#include "OptimizerTypes.h"
#include "OptimizerSubsystem.generated.h"
class UStaticMesh;
class UStaticMeshComponent;
/**
* Editor subsystem driving the Mesh Optimizer pipeline. The Editor Utility Widget calls these:
* 1. ScanLevel -> dry-run plan (sibling groups + per-placement corrected transforms)
* 2. ApplyUnify -> reassign every sibling placement to its canonical mesh with the fixed transform
* 3. BuildHISM -> collapse each group into one HierarchicalInstancedStaticMesh
* Steps 2 and 3 each run inside a single undoable transaction. BuildHISM is independent of ApplyUnify
* (it uses the canonical mesh + planned transforms directly).
*/
UCLASS()
class OPTIMIZEREDITOR_API UOptimizerSubsystem : public UEditorSubsystem
{
GENERATED_BODY()
public:
/** Dry run: scan the level, group sibling meshes, plan corrected transforms. Mutates nothing. */
UFUNCTION(BlueprintCallable, Category = "Optimizer")
FOptimizerScanResult ScanLevel(const FOptimizerScanSettings& Settings);
/** Reassign all non-instanced sibling placements to their canonical mesh + corrected transform. Returns count changed. */
UFUNCTION(BlueprintCallable, Category = "Optimizer")
int32 ApplyUnify();
/** Build one HISM actor per group from the planned transforms. Returns number of HISM actors created. */
UFUNCTION(BlueprintCallable, Category = "Optimizer")
int32 BuildHISM(bool bDestroyOriginals = true);
/** Discard the current plan. */
UFUNCTION(BlueprintCallable, Category = "Optimizer")
void ClearPlan();
UFUNCTION(BlueprintCallable, Category = "Optimizer")
bool HasPlan() const;
private:
/** One placement of a mesh in the level (a component, or one instance inside an ISM/HISM). */
struct FPlacement
{
TWeakObjectPtr<UStaticMeshComponent> Component;
int32 InstanceIndex = INDEX_NONE; // >= 0 when this is an instance inside an ISM/HISM
TWeakObjectPtr<UStaticMesh> Mesh;
FTransform World = FTransform::Identity;
FTransform PlannedWorld = FTransform::Identity;
bool bNeedsTransformFix = false;
bool bShearRejected = false;
bool bInstanced = false; // inside an ISM/HISM -> ApplyUnify can't swap it (HISM-only)
};
/** A sibling group: distinct meshes that share geometry, collapsed onto one canonical. */
struct FGroup
{
TArray<TWeakObjectPtr<UStaticMesh>> Members;
TWeakObjectPtr<UStaticMesh> Canonical;
TArray<FPlacement> Placements;
float MaxDeviation = 0.0f;
bool bHasMirrored = false;
bool bHasScaled = false;
bool bMaterialMismatch = false;
int32 ShearRejected = 0;
};
TArray<FGroup> Groups;
FOptimizerScanSettings LastSettings;
FOptimizerScanResult BuildResultView() const;
};