Mesh-Optimierung für Unity
Shin Mesh Atlas Tool
Fasst beliebig viele Source-Meshes zu einem einzigen, atlas-texturierten Mesh zusammen — weniger Draw Calls, weniger Materialien, ein Prefab.
Überblick
Das Mesh-Tool kombiniert beliebig viele Kind-Meshes eines Source-Objekts zu einem einzigen Mesh mit einem einzigen Material. Texturen aller Quell-Materialien werden dafür automatisch in einen gemeinsamen Atlas gepackt.
| Komponente | Rolle |
|---|---|
SuraFix_ShinMeshPipelineBuilder |
Der eigentliche Build-Prozess: sammelt Meshes, packt den Atlas, kombiniert Geometrie, speichert Assets & Prefab. |
SuraFix_ShinMeshPipelineWindow |
Editor-Fenster zur Konfiguration eines Builds (siehe Pipeline-Fenster). |
ShinAtlasPacker |
Eigener Shelf-Pack-Algorithmus für das Texturatlas — Ersatz für Unitys PackTextures(). |
Shin_AtlasDebugWindow |
Visualisiert das fertige Atlas-Layout nach einem Build. |
SuraFix_ShinInteriorVolume |
Markiert Bereiche, deren Dreiecke beim Combine entfernt werden sollen (z.B. unsichtbare Innenflächen). |
SuraFix_ColliderGrouper |
Eigenständiges Hilfswerkzeug zum Vorsortieren von Szenen-Objekten vor dem Build. |
Workflow
Ein typischer Durchlauf läuft in dieser Reihenfolge:
- Objekte in der Szene gruppieren (optional, via Collider Grouper).
- Source-Root im Pipeline-Fenster auswählen.
- Optional Interior-Volumes platzieren, um unsichtbare Innengeometrie vor dem Build zu entfernen.
- Build-Settings einstellen (Atlasgröße, Padding, Mip-Maps, Lightmap-UV2).
- Build ausführen — Mesh, Material, Texturen und Prefab landen automatisch im Output-Ordner.
- Ergebnis im Atlas Debug Window prüfen.
Schnellstart
Fenster öffnen über:
SuraFix → ShinCore → Mesh Optimizer → Pipeline Builder
Minimal-Konfiguration für einen ersten Test-Build:
var settings = new SuraFix_ShinMeshPipelineBuilder.BuildSettings
{
SourceRoot = mySceneRoot,
OutputRootFolder = "Assets/ShinMeshTool",
AtlasSize = 2048,
AtlasPadding = 8,
GenerateLightmapUV2 = true
};
var result = SuraFix_ShinMeshPipelineBuilder.Build(settings);
// result.PrefabPath zeigt auf das fertige, kombinierte Prefab.
1. Sammeln & Vorbereiten
Der Builder durchläuft den SourceRoot rekursiv und sammelt jedes MeshFilter + MeshRenderer-Paar als SourceEntry, zusammen mit der Transform-Matrix relativ zum Root (ToRootLocal) — diese Matrix ist die Grundlage für alle nachfolgenden Positions-, Normalen- und Tangenten-Berechnungen.
2. Interior Cutting
Jedes SuraFix_ShinInteriorVolume in CutVolumes definiert eine Box. Liegen alle drei Eckpunkte eines Dreiecks innerhalb eines solchen Volumens, wird das Dreieck beim Combine komplett verworfen.
Das ist gedacht für Innenflächen, die nach dem Zusammenfügen mehrerer Module ohnehin nie sichtbar sind (z.B. doppelte Wandflächen zwischen zwei aneinanderstoßenden Raum-Prefabs) — weniger Dreiecke im Endergebnis, ohne manuell jedes einzelne löschen zu müssen.
3. Atlas Packing
ShinAtlasPacker ist ein selbst geschriebener Shelf-Pack-Algorithmus: Texturen werden zeilenweise ("Regal für Regal") in den Atlas gelegt. Im Gegensatz zu Unitys eigenem Texture2D.PackTextures() wird dabei keine Textur verworfen — passt etwas nicht, wird die Slot-Größe automatisch halbiert und der Pack-Versuch wiederholt, bis alles passt oder die Mindestgröße von 8px erreicht ist.
Ablauf
- Start-Slot-Größe wird aus Atlasgröße und Texturanzahl grob abgeschätzt.
TryPackversucht, alle Texturen bei dieser Slot-Größe unterzubringen.- Scheitert der Versuch, wird die Slot-Größe halbiert und erneut versucht.
- Bei Erfolg: Texturen werden per
Graphics.Blitauf die Zielgröße skaliert und in den Atlas kopiert.
InvalidOperationException mit der Empfehlung, die Atlasgröße zu erhöhen oder die Mesh-Anzahl zu reduzieren — der Build bricht dann bewusst ab, statt stillschweigend Texturen wegzulassen.4. Normalen & Tangenten
Beim Zusammenführen werden Positionen, Normalen und Tangenten jedes Source-Vertex korrekt in den Root-Raum transformiert:
| Datentyp | Transformation |
|---|---|
| Position | ToRootLocal.MultiplyPoint3x4(...) |
| Normale | ToRootLocal.inverse.transpose.MultiplyVector(...) — die inverse Transponierte, nicht die normale Matrix. |
| Tangente | Gleiche inverse Transponierte wie bei Normalen, plus erhaltenes w-Vorzeichen für die Bitangente. |
UV-Tiling-Split
Dreiecke, die über UV-Kachelgrenzen hinausragen (z.B. bei wiederholenden Texturen mit Tiling > 1), werden entlang dieser Grenzen automatisch aufgeschnitten, bevor sie ins Atlas-Koordinatensystem übertragen werden — sonst würde ein Dreieck versuchen, über mehrere Atlas-Kacheln gleichzeitig zu samplen.
5. Export & Prefab
Nach erfolgreichem Combine legt der Builder automatisch eine Ordnerstruktur unter OutputRootFolder an:
Assets/ShinMeshTool/
└── <ObjektName>/
├── Meshes/<Name>_Combined.asset
├── Materials/<Name>_Atlas.mat
├── Textures/<Name>_Atlas.png
├── Textures/<Name>_NormalAtlas.png (nur falls Normal Maps vorhanden)
└── Prefabs/<Name>.prefab
Das fertige Prefab wird automatisch instanziiert, an der ursprünglichen Position/Rotation/Skalierung des Source-Roots platziert und in der Hierarchie ausgewählt — zusammen mit einem automatisch geöffneten Atlas Debug Window zur Kontrolle.
Pipeline-Fenster
Zentrale Editor-UI für einen Build-Durchlauf. Erreichbar über SuraFix → ShinCore → Mesh Optimizer → Pipeline Builder. Stellt alle Felder aus BuildSettings als Inspector-UI bereit, inklusive Drag&Drop für CutVolumes und die SlotOverride-Liste pro Material-Key.
Atlas Debug Window
Öffnet sich automatisch nach einem Build und zeigt das gepackte Atlas-Bild mit eingezeichneten UV-Rects pro Quelltextur — nützlich, um zu prüfen, ob eine Textur unerwartet stark herunterskaliert wurde (sichtbar an einem ungewöhnlich kleinen Slot im Vergleich zu den anderen).
Collider Grouper
Eigenständiges Hilfswerkzeug, unabhängig von der eigentlichen Mesh-Pipeline. Erreichbar über SuraFix → ShinCore → Mesh Optimizer → Collider Grouper.
Findet alle Root-GameObjects einer Szene, deren Position innerhalb eines gewählten Colliders liegt, und verschiebt sie gesammelt unter ein neues Parent-Objekt — Position, Rotation und Skalierung bleiben dabei erhalten. Praktisch, um vor einem Mesh-Combine-Build schnell alle Teile eines Raums unter einen gemeinsamen Root zu sammeln.
previewOnly) — es zeigt nur, was gefunden wurde, ohne etwas zu verschieben, bis du das explizit deaktivierst.Interior Volume
SuraFix_ShinInteriorVolume ist eine simple Box-Marker-Komponente ([ExecuteAlways], mit Gizmo-Darstellung in Cyan zur Platzierung im Editor). Sie hat keine Laufzeit-Logik außer der Punkt-in-Box-Prüfung, die vom Mesh-Builder beim Interior Cutting genutzt wird.
Referenz: BuildSettings
| Feld | Beschreibung |
|---|---|
SourceRoot |
Wurzel-Objekt, dessen Kind-Meshes kombiniert werden. |
OutputRootFolder |
Basis-Pfad für alle erzeugten Assets. |
AtlasSize |
Maximale Kantenlänge des erzeugten Texturatlas in Pixeln. |
AtlasPadding |
Abstand zwischen gepackten Texturen, verhindert Bleeding an Slot-Grenzen. |
MaxBakeTextureSize |
Obergrenze für die Größe, auf die einzelne Texturen vor dem Packen herunterskaliert werden. |
UseMipMaps / FilterMode / AnisoLevel |
Texture-Import-Einstellungen für den fertigen Atlas. |
AtlasShaderOverride |
Optionaler Shader für das erzeugte Material, statt des Standard-Shaders. |
GenerateLightmapUV2 |
Erzeugt eine zweite UV-Kanal für Unitys Lightmap-Baking. |
CutVolumes |
Liste von SuraFix_ShinInteriorVolume-Objekten für das Interior Cutting. |
SlotOverrides |
Pro Material-Key manuell gesetztes Tiling/Offset für Albedo und Normal Map. |
Referenz: BuildResult
| Feld | Beschreibung |
|---|---|
PrefabPath / MeshPath / MaterialPath |
Pfade zu den erzeugten Assets. |
TexturePath / NormalTexturePath |
Pfade zum Albedo- bzw. Normal-Atlas (letzterer nur falls vorhanden). |
SourceMeshCount / SourceRendererCount |
Anzahl der eingesammelten Quell-Meshes bzw. Renderer. |
FinalVertexCount |
Vertexanzahl des kombinierten Meshes nach allen Splits/Cuts. |
RemovedTriangleCount |
Anzahl der durch Interior Cutting entfernten Dreiecke. |
FAQ
Mein Build wirft eine InvalidOperationException beim Packen.
Der Atlas konnte selbst bei 8px Slot-Größe nicht alle Texturen unterbringen. AtlasSize erhöhen oder die Anzahl der kombinierten Meshes/Materialien reduzieren.
Ein Innenraum-Dreieck wurde nicht entfernt, obwohl ein Interior Volume dort liegt.
Geprüft wird, ob alle drei Eckpunkte des Dreiecks innerhalb der Box liegen. Liegt nur ein Teil des Dreiecks im Volume, bleibt es vollständig erhalten — Volume entsprechend großzügiger platzieren.
Die Schattierung des kombinierten Meshes sieht anders aus als im Original.
Meist ein Hinweis auf eine fehlerhafte Normalen-Transformation bei nicht-uniform skalierten Source-Objekten. Stelle sicher, dass für Normalen und Tangenten konsequent die inverse Transponierte verwendet wird (siehe Normalen & Tangenten).