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>
77 lines
2.7 KiB
C++
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;
|
|
};
|