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>
This commit is contained in:
76
Source/OptimizerEditor/Public/OptimizerSubsystem.h
Normal file
76
Source/OptimizerEditor/Public/OptimizerSubsystem.h
Normal file
@ -0,0 +1,76 @@
|
||||
// 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;
|
||||
};
|
||||
Reference in New Issue
Block a user