# Mesh Optimizer — Sibling Duplicate Remover Editor-only Unreal Engine plugin that finds **geometrically identical StaticMesh assets** used across a level, rebases every placement onto a single **canonical** mesh with a corrected transform, and optionally collapses the group into a **Hierarchical Instanced Static Mesh (HISM)**. > UE 5.7 · Editor module `OptimizerEditor` · native Slate tool panel. --- ## The problem it solves Bought kits and **Kitbash3D**-style packs import the *same* geometry as many separate assets: `SM_Fence_01`, `SM_Fence_02`, … are literal twins — identical vertices, sometimes with a different **baked pivot or rotation**. That defeats instancing: the engine sees N different meshes, so it can't batch them, and you can't make one HISM out of them. Mesh Optimizer detects those "sibling" meshes, picks one to keep, and re-points every actor that used a sibling to the survivor — **fixing each actor's transform** so nothing moves on screen — leaving a set that is ready to become a single HISM. --- ## What it does 1. **Scan** (dry run — mutates nothing): walk the level's StaticMesh placements, fingerprint every unique mesh, group the geometric siblings, and report each group with a confidence figure (`maxDeviation`). 2. **Unify**: reassign every sibling placement to its group's canonical mesh and apply the corrected world transform. Undoable (`Ctrl+Z`). 3. **Build HISM**: create one `HierarchicalInstancedStaticMeshComponent` per group from the corrected transforms, optionally destroying the originals. Undoable. Every mutation runs inside a single editor transaction. --- ## How it works ``` extract geometry (LOD0 FMeshDescription) → fingerprint (welded vertex/tri counts, surface area, |volume|, covariance eigenvalues, radial histogram — all rotation-invariant) → bucket by (welded vertex count, triangle count) → recover the rigid delta between candidates (identity fast-path, then the 24/48 signed-permutation axis rotations) → verify by order-independent nearest-neighbour vertex match (spatial hash) → union-find into groups, pick a canonical → plan the corrected transform per placement ``` **The corrective transform.** With `D` = the recovered *canonical-local → sibling-local* delta and `W` = the sibling placement's current world transform, the canonical mesh must be placed at ``` W' = D * W (UE FTransform multiply order; matrix W'_mat = D_mat * W_mat) ``` built via `FMatrix` and reconstructed into an `FTransform`. Because a non-uniform actor scale combined with a rotational `D` can produce **shear** (which `FTransform` cannot represent), each result is checked at the bounding-box corners and any placement that would shear is **skipped and reported** rather than silently corrupted. Every candidate match is confirmed by an **exact vertex-set verification** before it is ever applied, so a bad transform is rejected, not shipped. --- ## Installation 1. Copy this folder into your project's `Plugins/` directory (so it lives at `Plugins/Optimizer/`). 2. Add it to your `.uproject` (editor-only): ```json { "Name": "Optimizer", "Enabled": true, "TargetAllowList": [ "Editor" ] } ``` 3. Regenerate project files and build the editor target (a new module needs a full build — Live Coding cannot register a brand-new module). Requires **Unreal Engine 5.7** and an editor build (`Editor Win64 Development`). --- ## Usage Open the panel from **Tools → Optimizer → Mesh Optimizer**. | Control | Effect | |---|---| | **Scan** | Dry-run analysis of the current level; fills the report. Changes nothing. | | **Unify** | Reassign sibling placements to the canonical mesh + corrected transform. | | **Build HISM** | Collapse each group into one HISM actor. | | ☐ Mirrored | Also treat negative-scale (mirrored) variants as siblings. | | ☐ Scaled | Also treat uniformly-scaled copies as siblings. | | ☐ Merge materials | Group siblings even if their material sets differ (the canonical's materials win). | | ☐ Destroy originals | When building HISM, delete the original actors/components. | Recommended flow: **Scan → review the report** (check `maxDev` and the flags) **→ Unify** (or **Build HISM**). Everything is undoable with `Ctrl+Z`. --- ## Detection modes - **Exact + rigid (default):** identical geometry up to a rigid transform (rotation and/or a baked pivot offset). Covers almost all Kitbash cases. - **+ Mirrored:** negative-scale reflections (kept as a separate canonical group, since HISM winding differs). - **+ Scaled:** uniform-scale copies (the instance carries the scale). Advanced tolerances (weld epsilon, accept tolerance, scalar relative tolerance, degenerate-eigenvalue epsilon) are exposed on the scan settings for tuning against specific content. --- ## Safety & limitations - **World Partition:** only *loaded* cells are visible to the scan — coverage is partial and the report says so. - **Shear:** non-uniform actor scale combined with a rotational delta is unrepresentable by `FTransform`; those placements are skipped and counted, never corrupted. - **ISM/HISM sources:** existing instanced components are out of scope in this version (only plain `StaticMeshActor`s / components are processed). - **Materials:** by default siblings with different material sets are kept in separate groups so each HISM keeps one material set. --- ## Architecture ``` Source/OptimizerEditor/ OptimizerEditor.Build.cs Public/ OptimizerEditorModule.h – module + Tools menu / nomad tab OptimizerSubsystem.h – UEditorSubsystem: ScanLevel / ApplyUnify / BuildHISM OptimizerTypes.h – settings + result structs/enums Private/ OptimizerEditorModule.cpp OptimizerGeometry.{h,cpp} – geometry extraction + fingerprint + 3x3 Jacobi eigensolver OptimizerMatcher.{h,cpp} – bucketing, transform recovery, spatial-hash verification OptimizerReconciler.{h,cpp}– W' = D * W + shear detection OptimizerSubsystem.cpp – enumeration, planning, transacted mutation, HISM build SOptimizerPanel.{h,cpp} – native Slate tool panel ``` The heavy logic is UI-agnostic C++ in `UOptimizerSubsystem` (`BlueprintCallable`); the Slate panel is a thin driver. --- ## License Internal tool. © IHY / ExbyteLabs.