U5.5 Lane-Fassung: LOD für den Meshy-Kohlenbeißer

Lane-Kopie mit 4.998 statt 20.714 Dreiecken aus dem Generator (Nähte
verschweißt, Collapse, Skin-Gewichte bleiben), LODGroup aus den Namen,
Wechsel unter rund 10 % Bildhöhe; Porträts erzwingen die volle Fassung.
Stresstest 35 Kohlenbeißer: Mid 109,8 -> 120,2 fps, Karte 93,9 -> 103,8
(starr 133,3 / 106,4). Tests grün, Fingerabdrücke unverändert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Martin Stickelbroeck 2026-10-09 16:17:28 +02:00
parent 1f2306f4e9
commit f0d1e9388c
48 changed files with 59224 additions and 58659 deletions

View file

@ -74,7 +74,7 @@
{ {
"check": "mesh_names_unique", "check": "mesh_names_unique",
"ok": true, "ok": true,
"detail": "['KohlenbeisserBody']" "detail": "['KohlenbeisserBody_LOD0', 'KohlenbeisserBody_LOD1']"
}, },
{ {
"check": "material_slots_filled", "check": "material_slots_filled",
@ -94,7 +94,7 @@
{ {
"check": "triangles_match_godot", "check": "triangles_match_godot",
"ok": true, "ok": true,
"detail": "20714 fbx / 20714 godot" "detail": "25712 fbx / 25712 godot"
}, },
{ {
"check": "one_armature", "check": "one_armature",
@ -144,7 +144,7 @@
{ {
"check": "roundtrip_triangles", "check": "roundtrip_triangles",
"ok": true, "ok": true,
"detail": "20714 / 20714" "detail": "25712 / 25712"
}, },
{ {
"check": "roundtrip_materials", "check": "roundtrip_materials",
@ -254,21 +254,28 @@
2048 2048
] ]
}, },
"unit": 0.009999999776482582 "unit": 0.009999999776482582,
"lod": {
"lod0_triangles": 20714,
"lod1_triangles": 4998,
"lod1_vertices": 2501,
"welded_triangles": 20714,
"lod0_screen": 0.2
}
}, },
"inputs_sha256": { "inputs_sha256": {
"tools/meshy/g01/figure.json": "858bf47dc277a8a3a9f280d3f51a156b575d8abd091b083abf0cf2a32dc2277c", "tools/meshy/g01/figure.json": "8e642064d739ba4ed94d18233037bb44ecbf023e08ccc076605a8059b8f13211",
"assets-source/meshy/g01/kohlenbeisser-skelett.glb": "f5379bc92f77f42235b45decc5dfab26428c6649ea3a17ca7b33809fe4dcd568", "assets-source/meshy/g01/kohlenbeisser-skelett.glb": "f5379bc92f77f42235b45decc5dfab26428c6649ea3a17ca7b33809fe4dcd568",
"assets-source/meshy/g01/kohlenbeisser-animationen.glb": "16ede0d7afb86a46d658265ed7df4d1b1b0c9c5171af6de9257e6c764a55cb48" "assets-source/meshy/g01/kohlenbeisser-animationen.glb": "16ede0d7afb86a46d658265ed7df4d1b1b0c9c5171af6de9257e6c764a55cb48"
}, },
"source_sha256": "124688e799e0508e58af53f5346857e5404d49875d6600cbb974afe1b1e5796e", "source_sha256": "9eb17a4e3dc7029b7031f3be85f6676877c521788835137eb199c352c5b35aa4",
"removed_modifiers": 0, "removed_modifiers": 0,
"kind": "skinned", "kind": "skinned",
"fps": 24.0, "fps": 24.0,
"objects": 2, "objects": 3,
"meshes": { "meshes": {
"KohlenbeisserBody": { "KohlenbeisserBody_LOD0": {
"mesh": "KohlenbeisserBody", "mesh": "KohlenbeisserBody_LOD0",
"triangles": 20714, "triangles": 20714,
"vertices": 22962, "vertices": 22962,
"ngons": 0, "ngons": 0,
@ -303,6 +310,43 @@
0.3833 0.3833
] ]
} }
},
"KohlenbeisserBody_LOD1": {
"mesh": "KohlenbeisserBody_LOD1",
"triangles": 4998,
"vertices": 2501,
"ngons": 0,
"materials": [
"AI_Kohlenbeisser"
],
"uv_layers": [
"UVMap"
],
"color_attributes": [],
"active_color": null,
"custom_normals": false,
"normals_unit_length": true,
"bad_normals": 0,
"degenerate_triangles": 0,
"shape_keys": 0,
"skinned": true,
"scale": [
1.0,
1.0,
1.0
],
"bounds_unity": {
"min": [
-0.8581,
0.0003,
-0.3892
],
"max": [
0.8593,
1.3498,
0.3856
]
}
} }
}, },
"armatures": { "armatures": {
@ -342,14 +386,14 @@
"empties": {}, "empties": {},
"bounds_unity": { "bounds_unity": {
"min": [ "min": [
-0.857, -0.8581,
0.0, 0.0,
-0.388 -0.3892
], ],
"max": [ "max": [
0.8576, 0.8593,
1.35, 1.35,
0.3833 0.3856
] ]
}, },
"clips": [ "clips": [
@ -425,7 +469,7 @@
} }
], ],
"expected_from_godot": { "expected_from_godot": {
"triangles": 20714, "triangles": 25712,
"bones": 25, "bones": 25,
"clips": [ "clips": [
"idle", "idle",
@ -439,8 +483,8 @@
}, },
"meshes_with_ngons": {}, "meshes_with_ngons": {},
"meshes_without_uv": [], "meshes_without_uv": [],
"triangles": 20714, "triangles": 25712,
"fbx": "Assets/Luneraria/Art/Characters/kohlenbeisser.fbx", "fbx": "Assets/Luneraria/Art/Characters/kohlenbeisser.fbx",
"fbx_bytes": 2936524, "fbx_bytes": 3262700,
"ok": true "ok": true
} }

View file

@ -257,7 +257,9 @@ ModelImporter:
additiveReferencePoseFrame: 0 additiveReferencePoseFrame: 0
isReadable: 1 isReadable: 1
meshes: meshes:
lODScreenPercentages: [] lODScreenPercentages:
- 0.25
- 0.01
globalScale: 1 globalScale: 1
meshCompression: 0 meshCompression: 0
addColliders: 0 addColliders: 0

View file

@ -18,7 +18,7 @@ namespace Luneraria.EditorTools
/// <summary>Raised on the figure at the hit frame of attack and ability clips.</summary> /// <summary>Raised on the figure at the hit frame of attack and ability clips.</summary>
public const string ContactEvent = "OnLuneContact"; public const string ContactEvent = "OnLuneContact";
public override uint GetVersion() { return 4; } public override uint GetVersion() { return 5; }
void OnPreprocessModel() void OnPreprocessModel()
{ {
@ -48,6 +48,28 @@ namespace Luneraria.EditorTools
importer.resampleCurves = false; importer.resampleCurves = false;
} }
/// <summary>
/// U5.5: a figure with a lane copy (meshes &lt;body&gt;_LOD0/_LOD1, Unity builds the LODGroup
/// from the names) switches to it below the screen height the generator names; the lane
/// copy is never culled, so a figure never vanishes at map zoom.
/// </summary>
void OnPostprocessModel(GameObject root)
{
if (!assetPath.StartsWith(ArtRoot) || !assetPath.EndsWith(".fbx"))
return;
LODGroup group = root.GetComponentInChildren<LODGroup>();
ExportReport report = ExportReport.ForModel(assetPath);
var lod = report?.Data["generator"]?["lod"];
if (group == null || lod == null)
return;
LOD[] lods = group.GetLODs();
if (lods.Length != 2)
return;
lods[0].screenRelativeTransitionHeight = (float)lod["lod0_screen"];
lods[1].screenRelativeTransitionHeight = 0f;
group.SetLODs(lods);
}
void OnPreprocessAnimation() void OnPreprocessAnimation()
{ {
if (!assetPath.StartsWith(ArtRoot) || !assetPath.EndsWith(".fbx")) if (!assetPath.StartsWith(ArtRoot) || !assetPath.EndsWith(".fbx"))

File diff suppressed because it is too large Load diff

View file

@ -196,6 +196,10 @@ namespace Luneraria.UI
foreach (Transform node in model.GetComponentsInChildren<Transform>(true)) foreach (Transform node in model.GetComponentsInChildren<Transform>(true))
node.gameObject.layer = Layer; node.gameObject.layer = Layer;
Library.Materials?.Dress(model, 2); Library.Materials?.Dress(model, 2);
// A figure with a lane copy (U5.5) shows its full mesh: the portrait is a close-up, and
// the LOD choice of a model rendered in the frame it was made in left the card empty.
foreach (LODGroup group in model.GetComponentsInChildren<LODGroup>(true))
group.ForceLOD(0);
ShowDetail(model); ShowDetail(model);
// Skinned figures stand in their idle pose (Godot preview("idle", .4)). // Skinned figures stand in their idle pose (Godot preview("idle", .4)).
if (entry.Controller != null) if (entry.Controller != null)

View file

@ -130,6 +130,17 @@ Hinweis: Die Projektdateien des .NET-Harness (`tools/dotnet/*/*.csproj`) fehlten
| Bekannte Unterschiede | keine im Verhalten. Geometrie und Textur der Figur wechseln (Meshy statt Phase-4); Anatomie/Gesicht/Haar aus dem generierten Modell, nicht aus Künstler-Sculpts. Lava-Glut pauschal (keine Emission-Map). Schatten der Figur nur mit Tiefen-Bias | | Bekannte Unterschiede | keine im Verhalten. Geometrie und Textur der Figur wechseln (Meshy statt Phase-4); Anatomie/Gesicht/Haar aus dem generierten Modell, nicht aus Künstler-Sculpts. Lava-Glut pauschal (keine Emission-Map). Schatten der Figur nur mit Tiefen-Bias |
| Commits | `luneraria/u5.5-pilot` = `c386206` | | Commits | `luneraria/u5.5-pilot` = `c386206` |
## U5.5 · Lane-Fassung (LOD)
| Punkt | Ergebnis |
| --- | --- |
| Tests | EditMode 29/29, PlayMode 14/14 (Verify A–I 718/0), Player-Selbsttest 30/30, Asset-Prüfung 20/0 |
| Parität | Fingerabdrücke unverändert (`DCE95C96556F3A1A`, `7B8E43AEFC0D60C5`) |
| Inhalt | Kohlenbeißer mit Lane-Fassung (4.998 statt 20.714 Dreiecke, LODGroup aus dem Export), Porträts in voller Fassung |
| Leistung | Stresstest 35 Kohlenbeißer: Mid 109,8 → 120,2 fps (starr 133,3), Karte 93,9 → 103,8 fps (starr 106,4). Rohdaten `logs/u5.5-lod/` |
| Bild | `screenshots/u5.5-lod/` (Figur, vier Spielmomente, 14 Kampfmomente) |
| Commits | `luneraria/u5.5-lod` |
## Ausblick ## Ausblick
Der Pilot entscheidet über eine Serie weiterer Meshy-Figuren (Kosten je Figur, Lizenz, Stilgleichheit). Offen bleiben außerdem Künstler-Sculpts für Anatomie/Gesicht/Haar, LOD und Material-Atlanten sowie die Build-Module für Windows und Linux. Der Pilot entscheidet über eine Serie weiterer Meshy-Figuren (Kosten je Figur, Lizenz, Stilgleichheit). Offen bleiben außerdem Künstler-Sculpts für Anatomie/Gesicht/Haar, LOD und Material-Atlanten sowie die Build-Module für Windows und Linux.

View file

@ -1,6 +1,6 @@
# Port-Status · Champions of Luneraria in Unity # Port-Status · Champions of Luneraria in Unity
Stand: 9. Oktober 2026 (U5.5-pilot). Stand: 9. Oktober 2026 (U5.5, Lane-Fassung).
Referenz ist der Godot-Stand `luneraria/g3` (`1b540f2`) in `../saumwacht-godot`; er wird nicht mehr verändert. Engine: Unity 6.3 LTS (6000.3.20f1), Renderer URP. HDRP ist ausgeschlossen, bis ein Vergleich mit einer echten Szene etwas anderes nahelegt. Referenz ist der Godot-Stand `luneraria/g3` (`1b540f2`) in `../saumwacht-godot`; er wird nicht mehr verändert. Engine: Unity 6.3 LTS (6000.3.20f1), Renderer URP. HDRP ist ausgeschlossen, bis ein Vergleich mit einer echten Szene etwas anderes nahelegt.
@ -13,7 +13,7 @@ Zielplattformen sind Fedora 44 und Windows 11; macOS ist die Entwicklungsplattfo
| U2 · Unity-Spielwelt | **fertig**: U2A Blender→FBX-Pipeline (9 Assets geprüft), U2B G1-Karte mit Materialsystem, U2C fester Takt und Ansichten (bildratenunabhängig nachgewiesen), U2D vollständige Bot-Partien sichtbar und gleich dem Kern; danach Batch-Import aller 86 Modelle, Einheiten mit eigenen Modellen | [U2-WORLD.md](U2-WORLD.md) | | U2 · Unity-Spielwelt | **fertig**: U2A Blender→FBX-Pipeline (9 Assets geprüft), U2B G1-Karte mit Materialsystem, U2C fester Takt und Ansichten (bildratenunabhängig nachgewiesen), U2D vollständige Bot-Partien sichtbar und gleich dem Kern; danach Batch-Import aller 86 Modelle, Einheiten mit eigenen Modellen | [U2-WORLD.md](U2-WORLD.md) |
| U3 · G3-HUD portieren | **fertig** (`luneraria/u3`): UI Toolkit, Sichtmodell mit Privatsphäre, menschlicher Sitz, alle HUD-Bereiche, Eingabe und Befehle, Prüfung 718/0, 14 G3-Motive, Spieltest, Leistung mit HUD | [U3-UI.md](U3-UI.md) | | U3 · G3-HUD portieren | **fertig** (`luneraria/u3`): UI Toolkit, Sichtmodell mit Privatsphäre, menschlicher Sitz, alle HUD-Bereiche, Eingabe und Befehle, Prüfung 718/0, 14 G3-Motive, Spieltest, Leistung mit HUD | [U3-UI.md](U3-UI.md) |
| U4 · Netzwerk | **fertig** (`luneraria/u4` = `769e622`): LuneSession (Protokoll 4), TCP-Transport, Startbildschirm Host/Join, 43+12 Prüfungen, Mindestumfang M4. Nachtrag (`luneraria/u4-nachtrag`, in U5.3 zusammengeführt): Startbildschirm in der Szene, „Menü“ führt dorthin zurück | [U4-NETWORK.md](U4-NETWORK.md) | | U4 · Netzwerk | **fertig** (`luneraria/u4` = `769e622`): LuneSession (Protokoll 4), TCP-Transport, Startbildschirm Host/Join, 43+12 Prüfungen, Mindestumfang M4. Nachtrag (`luneraria/u4-nachtrag`, in U5.3 zusammengeführt): Startbildschirm in der Szene, „Menü“ führt dorthin zurück | [U4-NETWORK.md](U4-NETWORK.md) |
| U5 · Visuelle Neuausrichtung (Vertical Slice Mid-Lane) | **fertig** (`luneraria/u5` = `2c1686b`, Stufen `luneraria/u5.2`): 6 PBR-Sätze, Surface-Shader mit Albedo/Normal/ORM, Stufen Lane/Rand, Hit- und Turm-VFX, 133/180 fps. **U5.3** (`luneraria/u5.3` = `07fa457`): Gebäude, Boss und Ringborkes Rinde auf PBR (11 Sätze); Bildfehler aus U5 behoben (doppelte Einfärbung, Datenkarten als sRGB, Streifen, bleichender Treffer-Flash, Nebel), Helligkeit und Grün wieder auf U3-Niveau **U5.4** (`luneraria/u5.4` = `4883d95`): Surface-Materialien für alle 146 Figurenmaterialien (Metalle metallisch, Randlicht, Struktur in den Porträts), SSAO (abschaltbar), Leistung −13 % Karte / −16 % Mid **U5.5-pilot** (`luneraria/u5.5-pilot` = `c386206`): Meshy-Figur für den Kohlenbeißer `g01` (Pipeline `tools/meshy/`, UV-Material mit Lava-Glut, Schatten ohne Normalen-Versatz), GPU-Batched-Skinning, Figuren-Stress −21 % Mid / −13 % Karte gegenüber Phase-4 | [U5-VISUAL.md](U5-VISUAL.md) | | U5 · Visuelle Neuausrichtung (Vertical Slice Mid-Lane) | **fertig** (`luneraria/u5` = `2c1686b`, Stufen `luneraria/u5.2`): 6 PBR-Sätze, Surface-Shader mit Albedo/Normal/ORM, Stufen Lane/Rand, Hit- und Turm-VFX, 133/180 fps. **U5.3** (`luneraria/u5.3` = `07fa457`): Gebäude, Boss und Ringborkes Rinde auf PBR (11 Sätze); Bildfehler aus U5 behoben (doppelte Einfärbung, Datenkarten als sRGB, Streifen, bleichender Treffer-Flash, Nebel), Helligkeit und Grün wieder auf U3-Niveau **U5.4** (`luneraria/u5.4` = `4883d95`): Surface-Materialien für alle 146 Figurenmaterialien (Metalle metallisch, Randlicht, Struktur in den Porträts), SSAO (abschaltbar), Leistung −13 % Karte / −16 % Mid **U5.5-pilot** (`luneraria/u5.5-pilot` = `c386206`): Meshy-Figur für den Kohlenbeißer `g01` (Pipeline `tools/meshy/`, UV-Material mit Lava-Glut, Schatten ohne Normalen-Versatz), GPU-Batched-Skinning, Figuren-Stress −21 % Mid / −13 % Karte gegenüber Phase-4; **Lane-Fassung** (`luneraria/u5.5-lod`): 5.000-Dreiecke-LOD, Abstand −10 % Mid / −2 % Karte | [U5-VISUAL.md](U5-VISUAL.md) |
QA je Meilenstein: [PORT-QA.md](PORT-QA.md). QA je Meilenstein: [PORT-QA.md](PORT-QA.md).

View file

@ -389,3 +389,42 @@ Wirkung: Der Kohlenbeißer zeigt gehämmerte Platten und glühende Lava in den F
- **UV-Nähte statt geteilter Schatten-Normalen.** `ShadowNormalScale 0` vermeidet die Lichtkanten, nimmt der Figur aber den Normalen-Versatz im Schattenwurf (Tiefen-Bias allein). - **UV-Nähte statt geteilter Schatten-Normalen.** `ShadowNormalScale 0` vermeidet die Lichtkanten, nimmt der Figur aber den Normalen-Versatz im Schattenwurf (Tiefen-Bias allein).
- **Geometrie ist teurer** als die starre Phase-4-Figur (−22 % Mid bei 35 Kopien mit GPU-Skinning). Abhilfe wäre LOD oder eine reduzierte Schattenkopie; beides ist offen. - **Geometrie ist teurer** als die starre Phase-4-Figur (−22 % Mid bei 35 Kopien mit GPU-Skinning). Abhilfe wäre LOD oder eine reduzierte Schattenkopie; beides ist offen.
- **Build-Module** für Windows und Linux fehlen weiterhin (PORT-STATUS). - **Build-Module** für Windows und Linux fehlen weiterhin (PORT-STATUS).
## U5.5 · Lane-Fassung des Kohlenbeißers (LOD)
Stand 9. Oktober 2026, Zweig `luneraria/u5.5-lod` (auf `luneraria/u5.5-pilot`). Antwort auf die offene Grenze oben: Die Meshy-Figur hat jetzt eine vereinfachte Fassung für Lane-Zoom und Karte.
### Umfang
- **Lane-Kopie im Generator** (`build_figure.py`, `lane_lod`, Regel `lod` in `figure.json`): Kopie des Körpers, die an den UV-Nähten getrennten Eckpunkte verschweißt, auf 5.000 Dreiecke reduziert (Collapse; UVs, Material und Skin-Gewichte bleiben), Normalen glatt mit harten Kanten ab 50°. Nach dem Reduzieren werden entartete und doppelt belegte Dreiecke entfernt; der FBX-Rückimport behielt von zwei Dreiecken auf denselben drei Ecken nur eines.
- `KohlenbeisserBody_LOD0` 20.714 Dreiecke / 22.962 Eckpunkte, `KohlenbeisserBody_LOD1` 4.998 / 2.501; Export 23 Prüfungen bestanden, zweiter Lauf bytegleich.
- **Unity:** Aus den Namen `_LOD0`/`_LOD1` baut der Import eine LODGroup. `LuneModelPostprocessor` (Version 5) setzt den Wechsel auf die Bildschirmhöhe aus dem Exportbericht (`generator.lod.lod0_screen` = 0,2; mit dem LOD-Bias 2 der Qualitätsstufe „Ultra“ wechselt die Figur unter rund 10 % Bildhöhe). Die Lane-Fassung wird nie ausgeblendet.
- Ein erster Wert von 0,1 ließ die Figur wegen des Bias bei Zoom 22 meist in voller Fassung; gemessen brachte er Mid nichts und auf der Karte 5 %.
- **HUD-Porträts** erzwingen die volle Fassung (`LunePortraits`, `ForceLOD(0)`). Ohne das blieben Karten und Porträts leer: Das Modell wird im selben Bild erzeugt und gerendert, die LOD-Wahl griff dabei nicht.
### Prüfung
| Test | Ergebnis |
| --- | --- |
| EditMode | 29/29 |
| PlayMode | 14/14 (6 Werkzeuge `Explicit`), Verify A–I 718/0 |
| Fingerabdrücke | `DCE95C96556F3A1A`, `7B8E43AEFC0D60C5`, unverändert, `same_as_core` |
| Asset-Prüfung Unity | `kohlenbeisser` 20 Prüfungen, 0 Fehler |
| Player-Selbsttest | 30/30, `logs/u5.5-lod/player-smoke.json` |
| FigureViewsTests | 1/1, Bilder `screenshots/u5.5-lod/spiel/` |
### Leistung
Figuren-Stresstest wie oben (`-luneBenchmarkRound 5 -luneBenchmarkArmy g01`, 35 Kohlenbeißer), GPU-Skinning, je vier Läufe abwechselnd, Deckel offen (`logs/u5.5-lod/player-benchmark-army-*.json`):
| Ansicht | Phase-4 (starr) | Meshy ohne LOD | Meshy mit LOD |
| --- | ---: | ---: | ---: |
| Mid-Lane nah (Zoom 22) | 133,3 | 109,8 (−18 %) | 120,2 (−10 %) |
| ganze Karte (Zoom 64) | 106,4 | 93,9 (−12 %) | 103,8 (−2 %) |
Die Lane-Fassung halbiert den Abstand in der Mid-Ansicht und schließt ihn auf der Karte fast. Der Rest liegt vor allem beim Animator (Hauptthread +0,5 ms gegenüber der starren Figur, die nicht animiert wird) und bei der GPU. Im Bild ist der Wechsel bei Lane-Zoom nicht zu sehen (Vergleich `screenshots/u5.5/spiel-nachher/04-kampf-lane.jpg` mit `u5.5-lod/spiel/04-kampf-lane.jpg`).
### Grenzen
- Der Wechsel ist hart (kein Überblenden); bei Zoom um die Schwelle kann man ihn an den Krallen sehen.
- Die Lane-Fassung trägt geglättete Normalen statt Meshys geteilter Normalen; die Normalkarte ist für die volle Fassung gebacken. Aus der Lane-Distanz fällt das nicht auf.

View file

@ -1300,6 +1300,173 @@
] ]
} }
}, },
{
"id": "kohlenbeisser",
"kind": "skinned",
"ok": true,
"checks": [
{
"check": "blender_checks_passed",
"ok": true,
"detail": ""
},
{
"check": "imported",
"ok": true,
"detail": "\"Assets/Luneraria/Art/Characters/kohlenbeisser.fbx\""
},
{
"check": "import_rules_applied",
"ok": true,
"detail": ""
},
{
"check": "root_transform_identity",
"ok": true,
"detail": "\"kohlenbeisser pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
},
{
"check": "node_transforms_axis_clean",
"ok": true,
"detail": "[]"
},
{
"check": "mesh_names",
"ok": true,
"detail": "[]"
},
{
"check": "triangles",
"ok": true,
"detail": "\"25712 unity / 25712 blender \""
},
{
"check": "material_slots",
"ok": true,
"detail": "[]"
},
{
"check": "normals_unit_length",
"ok": true,
"detail": "[]"
},
{
"check": "tangents_where_uv",
"ok": true,
"detail": "[]"
},
{
"check": "uvs_where_blender_has_uv",
"ok": true,
"detail": "[]"
},
{
"check": "vertex_colors",
"ok": true,
"detail": "[]"
},
{
"check": "bounds_axes_scale",
"ok": true,
"detail": "\"largest difference 0.00002 m; unity (-0.858, 0.000, -0.389) (0.859, 1.350, 0.386)\""
},
{
"check": "skinned_mesh",
"ok": true,
"detail": "2"
},
{
"check": "bone_names KohlenbeisserBody_LOD0",
"ok": true,
"detail": "[]"
},
{
"check": "root_bone KohlenbeisserBody_LOD0",
"ok": true,
"detail": "\"Root\""
},
{
"check": "bone_names KohlenbeisserBody_LOD1",
"ok": true,
"detail": "[]"
},
{
"check": "root_bone KohlenbeisserBody_LOD1",
"ok": true,
"detail": "\"Root\""
},
{
"check": "generic_avatar",
"ok": true,
"detail": "\"kohlenbeisserAvatar\""
},
{
"check": "clips",
"ok": true,
"detail": "[]"
}
],
"facts": {
"triangles": 25712,
"renderers": 2,
"meshes_without_uv_and_tangents": 0,
"degenerate_triangles_dropped": 0,
"bounds_min": [
-0.858105361,
7.834025E-08,
-0.389211059
],
"bounds_max": [
0.859303,
1.35000026,
0.385618329
],
"clips": [
{
"name": "ability",
"length": 1.20833337,
"loop": false,
"events": 1
},
{
"name": "attack_a",
"length": 1.04166663,
"loop": false,
"events": 1
},
{
"name": "attack_b",
"length": 1.0,
"loop": false,
"events": 1
},
{
"name": "death",
"length": 2.20833325,
"loop": false,
"events": 0
},
{
"name": "hit",
"length": 0.5,
"loop": false,
"events": 0
},
{
"name": "idle",
"length": 4.0,
"loop": true,
"events": 0
},
{
"name": "walk",
"length": 2.79166675,
"loop": true,
"events": 0
}
]
}
},
{ {
"id": "quellgeflecht", "id": "quellgeflecht",
"kind": "skinned", "kind": "skinned",

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 1884, "fps": 94.1, "frame_ms_avg": 10.63, "frame_ms_median": 3.90, "frame_ms_p95": 40.03, "frame_ms_p99": 54.34, "frame_ms_max": 75.40, "frames_over_16_7_ms": 408, "of_them_with_simulation_step": 35, "gc_collections": 21, "simulation_ms_per_frame": 0.096, "views_ms_per_frame": 0.227, "ui_ms_per_frame": 0.089, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.96 / median 2.65 / p95 4.59 ms, render thread avg 1.80 / median 1.77 / p95 2.20 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 7.66 / median 0.10 / p95 36.38 ms
{"view": "mid lane close (zoom 22)", "frames": 1102, "fps": 110.2, "frame_ms_avg": 9.07, "frame_ms_median": 3.42, "frame_ms_p95": 37.21, "frame_ms_p99": 46.70, "frame_ms_max": 60.00, "frames_over_16_7_ms": 201, "of_them_with_simulation_step": 19, "gc_collections": 9, "simulation_ms_per_frame": 0.056, "views_ms_per_frame": 0.189, "ui_ms_per_frame": 0.069, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.20 / median 2.10 / p95 3.19 ms, render thread avg 1.28 / median 1.26 / p95 1.52 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.91 / median 0.62 / p95 35.07 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 1825, "fps": 91.2, "frame_ms_avg": 10.97, "frame_ms_median": 4.30, "frame_ms_p95": 37.66, "frame_ms_p99": 54.32, "frame_ms_max": 90.51, "frames_over_16_7_ms": 441, "of_them_with_simulation_step": 42, "gc_collections": 21, "simulation_ms_per_frame": 0.110, "views_ms_per_frame": 0.245, "ui_ms_per_frame": 0.094, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 3.26 / median 2.84 / p95 5.24 ms, render thread avg 1.83 / median 1.81 / p95 2.20 ms, gpu avg 0.03 / median 0.00 / p95 0.00 ms, present wait avg 7.69 / median 0.01 / p95 33.91 ms
{"view": "mid lane close (zoom 22)", "frames": 1073, "fps": 107.3, "frame_ms_avg": 9.32, "frame_ms_median": 3.70, "frame_ms_p95": 38.07, "frame_ms_p99": 51.00, "frame_ms_max": 61.31, "frames_over_16_7_ms": 191, "of_them_with_simulation_step": 23, "gc_collections": 9, "simulation_ms_per_frame": 0.058, "views_ms_per_frame": 0.209, "ui_ms_per_frame": 0.078, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.44 / median 2.23 / p95 3.89 ms, render thread avg 1.32 / median 1.31 / p95 1.56 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.92 / median 0.12 / p95 35.70 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 1902, "fps": 95.0, "frame_ms_avg": 10.52, "frame_ms_median": 3.69, "frame_ms_p95": 41.10, "frame_ms_p99": 56.01, "frame_ms_max": 92.19, "frames_over_16_7_ms": 409, "of_them_with_simulation_step": 40, "gc_collections": 21, "simulation_ms_per_frame": 0.095, "views_ms_per_frame": 0.215, "ui_ms_per_frame": 0.079, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.78 / median 2.52 / p95 4.01 ms, render thread avg 1.75 / median 1.73 / p95 2.07 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 7.72 / median 0.13 / p95 37.86 ms
{"view": "mid lane close (zoom 22)", "frames": 1115, "fps": 111.5, "frame_ms_avg": 8.97, "frame_ms_median": 3.54, "frame_ms_p95": 38.53, "frame_ms_p99": 51.78, "frame_ms_max": 69.20, "frames_over_16_7_ms": 171, "of_them_with_simulation_step": 25, "gc_collections": 9, "simulation_ms_per_frame": 0.057, "views_ms_per_frame": 0.192, "ui_ms_per_frame": 0.067, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.22 / median 2.11 / p95 3.19 ms, render thread avg 1.26 / median 1.24 / p95 1.51 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.79 / median 1.07 / p95 36.51 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 1909, "fps": 95.4, "frame_ms_avg": 10.48, "frame_ms_median": 3.79, "frame_ms_p95": 39.82, "frame_ms_p99": 52.89, "frame_ms_max": 96.95, "frames_over_16_7_ms": 414, "of_them_with_simulation_step": 38, "gc_collections": 21, "simulation_ms_per_frame": 0.092, "views_ms_per_frame": 0.218, "ui_ms_per_frame": 0.079, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.74 / median 2.51 / p95 4.07 ms, render thread avg 1.75 / median 1.73 / p95 2.06 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 7.74 / median 0.19 / p95 37.33 ms
{"view": "mid lane close (zoom 22)", "frames": 1104, "fps": 110.3, "frame_ms_avg": 9.06, "frame_ms_median": 3.37, "frame_ms_p95": 38.57, "frame_ms_p99": 51.51, "frame_ms_max": 73.22, "frames_over_16_7_ms": 188, "of_them_with_simulation_step": 14, "gc_collections": 10, "simulation_ms_per_frame": 0.059, "views_ms_per_frame": 0.193, "ui_ms_per_frame": 0.067, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.22 / median 2.08 / p95 3.37 ms, render thread avg 1.28 / median 1.26 / p95 1.51 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.85 / median 0.13 / p95 36.51 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2066, "fps": 103.2, "frame_ms_avg": 9.69, "frame_ms_median": 3.60, "frame_ms_p95": 35.39, "frame_ms_p99": 46.69, "frame_ms_max": 111.10, "frames_over_16_7_ms": 434, "of_them_with_simulation_step": 44, "gc_collections": 21, "simulation_ms_per_frame": 0.085, "views_ms_per_frame": 0.220, "ui_ms_per_frame": 0.080, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.79 / median 2.55 / p95 4.18 ms, render thread avg 1.76 / median 1.74 / p95 2.07 ms, gpu avg 0.03 / median 0.00 / p95 0.00 ms, present wait avg 6.89 / median 0.13 / p95 32.61 ms
{"view": "mid lane close (zoom 22)", "frames": 1183, "fps": 118.2, "frame_ms_avg": 8.46, "frame_ms_median": 3.39, "frame_ms_p95": 31.41, "frame_ms_p99": 40.61, "frame_ms_max": 61.13, "frames_over_16_7_ms": 212, "of_them_with_simulation_step": 22, "gc_collections": 10, "simulation_ms_per_frame": 0.052, "views_ms_per_frame": 0.212, "ui_ms_per_frame": 0.079, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.50 / median 2.27 / p95 4.10 ms, render thread avg 1.33 / median 1.31 / p95 1.60 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.93 / median 0.00 / p95 28.87 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2073, "fps": 103.5, "frame_ms_avg": 9.66, "frame_ms_median": 3.50, "frame_ms_p95": 33.69, "frame_ms_p99": 44.40, "frame_ms_max": 65.71, "frames_over_16_7_ms": 456, "of_them_with_simulation_step": 39, "gc_collections": 22, "simulation_ms_per_frame": 0.087, "views_ms_per_frame": 0.219, "ui_ms_per_frame": 0.078, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.77 / median 2.56 / p95 3.99 ms, render thread avg 1.75 / median 1.73 / p95 2.07 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.88 / median 0.10 / p95 30.96 ms
{"view": "mid lane close (zoom 22)", "frames": 1207, "fps": 120.7, "frame_ms_avg": 8.29, "frame_ms_median": 3.47, "frame_ms_p95": 31.71, "frame_ms_p99": 41.91, "frame_ms_max": 57.88, "frames_over_16_7_ms": 207, "of_them_with_simulation_step": 16, "gc_collections": 9, "simulation_ms_per_frame": 0.056, "views_ms_per_frame": 0.216, "ui_ms_per_frame": 0.073, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.51 / median 2.26 / p95 4.16 ms, render thread avg 1.32 / median 1.30 / p95 1.58 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.82 / median 0.00 / p95 29.22 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2095, "fps": 104.7, "frame_ms_avg": 9.55, "frame_ms_median": 3.70, "frame_ms_p95": 36.68, "frame_ms_p99": 48.06, "frame_ms_max": 63.80, "frames_over_16_7_ms": 394, "of_them_with_simulation_step": 34, "gc_collections": 22, "simulation_ms_per_frame": 0.084, "views_ms_per_frame": 0.220, "ui_ms_per_frame": 0.081, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.76 / median 2.58 / p95 3.99 ms, render thread avg 1.75 / median 1.73 / p95 2.08 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.80 / median 0.13 / p95 33.85 ms
{"view": "mid lane close (zoom 22)", "frames": 1235, "fps": 123.4, "frame_ms_avg": 8.11, "frame_ms_median": 2.90, "frame_ms_p95": 31.70, "frame_ms_p99": 44.80, "frame_ms_max": 64.40, "frames_over_16_7_ms": 203, "of_them_with_simulation_step": 25, "gc_collections": 9, "simulation_ms_per_frame": 0.049, "views_ms_per_frame": 0.196, "ui_ms_per_frame": 0.067, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.24 / median 2.17 / p95 3.08 ms, render thread avg 1.27 / median 1.26 / p95 1.48 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.86 / median 0.00 / p95 29.51 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2083, "fps": 104.0, "frame_ms_avg": 9.61, "frame_ms_median": 3.51, "frame_ms_p95": 34.73, "frame_ms_p99": 45.15, "frame_ms_max": 70.06, "frames_over_16_7_ms": 445, "of_them_with_simulation_step": 35, "gc_collections": 21, "simulation_ms_per_frame": 0.089, "views_ms_per_frame": 0.224, "ui_ms_per_frame": 0.083, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.83 / median 2.59 / p95 4.30 ms, render thread avg 1.76 / median 1.74 / p95 2.07 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.79 / median 0.06 / p95 31.93 ms
{"view": "mid lane close (zoom 22)", "frames": 1187, "fps": 118.7, "frame_ms_avg": 8.43, "frame_ms_median": 3.61, "frame_ms_p95": 32.91, "frame_ms_p99": 42.81, "frame_ms_max": 54.39, "frames_over_16_7_ms": 202, "of_them_with_simulation_step": 23, "gc_collections": 10, "simulation_ms_per_frame": 0.055, "views_ms_per_frame": 0.222, "ui_ms_per_frame": 0.088, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.62 / median 2.29 / p95 5.11 ms, render thread avg 1.32 / median 1.29 / p95 1.62 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.81 / median 0.00 / p95 29.62 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2127, "fps": 106.3, "frame_ms_avg": 9.41, "frame_ms_median": 3.40, "frame_ms_p95": 37.95, "frame_ms_p99": 52.70, "frame_ms_max": 97.25, "frames_over_16_7_ms": 410, "of_them_with_simulation_step": 36, "gc_collections": 22, "simulation_ms_per_frame": 0.082, "views_ms_per_frame": 0.207, "ui_ms_per_frame": 0.077, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.49 / median 2.29 / p95 3.75 ms, render thread avg 1.68 / median 1.65 / p95 2.06 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.92 / median 0.29 / p95 35.59 ms
{"view": "mid lane close (zoom 22)", "frames": 1322, "fps": 132.2, "frame_ms_avg": 7.56, "frame_ms_median": 3.01, "frame_ms_p95": 31.41, "frame_ms_p99": 38.58, "frame_ms_max": 48.28, "frames_over_16_7_ms": 201, "of_them_with_simulation_step": 13, "gc_collections": 9, "simulation_ms_per_frame": 0.047, "views_ms_per_frame": 0.198, "ui_ms_per_frame": 0.067, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 2.08 / median 1.96 / p95 3.09 ms, render thread avg 1.20 / median 1.18 / p95 1.43 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.50 / median 0.18 / p95 28.86 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2132, "fps": 106.5, "frame_ms_avg": 9.39, "frame_ms_median": 3.41, "frame_ms_p95": 36.53, "frame_ms_p99": 49.22, "frame_ms_max": 74.49, "frames_over_16_7_ms": 406, "of_them_with_simulation_step": 38, "gc_collections": 21, "simulation_ms_per_frame": 0.083, "views_ms_per_frame": 0.210, "ui_ms_per_frame": 0.075, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.51 / median 2.29 / p95 3.77 ms, render thread avg 1.70 / median 1.67 / p95 2.08 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.87 / median 0.31 / p95 33.75 ms
{"view": "mid lane close (zoom 22)", "frames": 1337, "fps": 133.6, "frame_ms_avg": 7.48, "frame_ms_median": 3.00, "frame_ms_p95": 31.88, "frame_ms_p99": 40.00, "frame_ms_max": 53.01, "frames_over_16_7_ms": 194, "of_them_with_simulation_step": 15, "gc_collections": 10, "simulation_ms_per_frame": 0.045, "views_ms_per_frame": 0.190, "ui_ms_per_frame": 0.062, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 1.95 / median 1.85 / p95 2.91 ms, render thread avg 1.19 / median 1.17 / p95 1.40 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.54 / median 0.71 / p95 29.81 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2138, "fps": 106.8, "frame_ms_avg": 9.36, "frame_ms_median": 3.31, "frame_ms_p95": 35.77, "frame_ms_p99": 49.61, "frame_ms_max": 63.82, "frames_over_16_7_ms": 427, "of_them_with_simulation_step": 38, "gc_collections": 22, "simulation_ms_per_frame": 0.080, "views_ms_per_frame": 0.206, "ui_ms_per_frame": 0.077, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.45 / median 2.27 / p95 3.60 ms, render thread avg 1.69 / median 1.66 / p95 2.08 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.91 / median 0.26 / p95 33.23 ms
{"view": "mid lane close (zoom 22)", "frames": 1339, "fps": 133.9, "frame_ms_avg": 7.47, "frame_ms_median": 3.05, "frame_ms_p95": 31.39, "frame_ms_p99": 41.03, "frame_ms_max": 70.67, "frames_over_16_7_ms": 190, "of_them_with_simulation_step": 11, "gc_collections": 9, "simulation_ms_per_frame": 0.045, "views_ms_per_frame": 0.188, "ui_ms_per_frame": 0.062, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 1.96 / median 1.83 / p95 3.08 ms, render thread avg 1.18 / median 1.16 / p95 1.39 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.50 / median 0.28 / p95 29.34 ms
]
}

View file

@ -0,0 +1,15 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"vsync": 0,
"match": "seed 9 from round 5, army g01 x36, speed 1x, measured after 10 s of combat",
// moving units at the start of the first window: g01 35, w04 14, e04 12, w06 11, w02 7, e01 4, e02 4, w08 4, w10 4, g05 2
"windows": [
{"view": "overview (zoom 64)", "frames": 2123, "fps": 106.1, "frame_ms_avg": 9.43, "frame_ms_median": 3.46, "frame_ms_p95": 36.58, "frame_ms_p99": 51.40, "frame_ms_max": 75.82, "frames_over_16_7_ms": 405, "of_them_with_simulation_step": 33, "gc_collections": 21, "simulation_ms_per_frame": 0.082, "views_ms_per_frame": 0.214, "ui_ms_per_frame": 0.078, "units_alive_max": 97},
// timings overview (zoom 64): main thread avg 2.52 / median 2.33 / p95 3.77 ms, render thread avg 1.70 / median 1.66 / p95 2.10 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 6.90 / median 0.27 / p95 34.03 ms
{"view": "mid lane close (zoom 22)", "frames": 1337, "fps": 133.7, "frame_ms_avg": 7.48, "frame_ms_median": 3.00, "frame_ms_p95": 31.00, "frame_ms_p99": 40.70, "frame_ms_max": 65.49, "frames_over_16_7_ms": 188, "of_them_with_simulation_step": 11, "gc_collections": 10, "simulation_ms_per_frame": 0.049, "views_ms_per_frame": 0.189, "ui_ms_per_frame": 0.060, "units_alive_max": 44}
// timings mid lane close (zoom 22): main thread avg 1.95 / median 1.87 / p95 2.85 ms, render thread avg 1.18 / median 1.17 / p95 1.39 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 5.54 / median 0.54 / p95 29.05 ms
]
}

View file

@ -0,0 +1,11 @@
{
"build": "OSXPlayer player, 6000.3.20f1, release",
"device": "Mac17,2; Apple M5; Apple M5",
"graphics_api": "Metal",
"resolution": "1920x1080",
"seconds": 11.7,
"passed": ["Startbildschirm sichtbar", "Partie wartet: Spielcontroller und Treiber aus", "vor dem Start kein HUD", "„Allein spielen“ bedienbar", "Offline: Startbildschirm verborgen", "Offline: Spielcontroller und Treiber laufen", "Offline: HUD sichtbar", "Offline: neue Partie, Sitz 1 (Mid)", "Offline: Planung", "Offline: lokale Sitzung", "„Startaufstellung“ bedienbar", "Startaufstellung gekauft (3 Einheiten)", "„Bereit“ bedienbar", "Bereit: Kampf beginnt", "Kampf: Figuren im Feld", "„Menü“ bedienbar", "Verlassen-Dialog mit „Zum Menü“", "Zurück: Startbildschirm sichtbar", "Zurück: HUD verborgen", "Zurück: Spielcontroller und Treiber aus", "Zurück: Sitzung beendet", "Zurück: keine Figuren im Feld", "Zurück: Kamera ruht", "Zurück: „Allein spielen“ bedienbar", "Zweite Partie: Startbildschirm verborgen, HUD sichtbar", "Zweite Partie: neue Partie in der Planung", "SSAO folgt der Einstellung", "Option „Umgebungsverdeckung“ sichtbar", "Option schaltet SSAO um", "Option stellt SSAO zurück"],
"failed": [],
"photos": ["00-startbildschirm.jpg", "01-planung.jpg", "02-kampf.jpg", "03-verlassen.jpg", "04-zurueck-im-startbildschirm.jpg", "05-zweite-partie.jpg", "06-optionen.jpg"],
"result": "PASS"
}

View file

@ -0,0 +1,11 @@
{
"match": "seed 2, bots, speed 24x",
"core_hash": "DCE95C96556F3A1A",
"core_steps": 12690,
"runs": [
{"target": "30 fps", "frames": 816, "seconds": 27.183, "measured_fps": 30.018, "max_steps_per_frame": 17, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true},
{"target": "60 fps", "frames": 1626, "seconds": 27.089, "measured_fps": 60.024, "max_steps_per_frame": 11, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true},
{"target": "120 fps", "frames": 3224, "seconds": 26.906, "measured_fps": 119.824, "max_steps_per_frame": 7, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true},
{"target": "unlimited", "frames": 83299, "seconds": 26.851, "measured_fps": 3102.282, "max_steps_per_frame": 15, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true}
]
}

View file

@ -0,0 +1,16 @@
{
"runs": [
{"label": "match-seed2", "seed": 2, "start_round": 1, "extra_gold": 0, "speed": 6, "winner": 1, "end_note": "Ancient von Blau zerstört.", "steps": 12690, "hash": "DCE95C96556F3A1A", "core_hash": "DCE95C96556F3A1A", "same_as_core": true,
"units_alive_max": 84, "heroes_alive_max": 4, "boss_log": ["round 8: won team 1 ", "round 9: deployed team 1 bot"],
"rounds": [{"round": 1, "combat_seconds": 44.9, "lost": [], "boss": "none", "end": "cleared"}, {"round": 2, "combat_seconds": 57.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 3, "combat_seconds": 54.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 4, "combat_seconds": 62.9, "lost": [], "boss": "none", "end": "cleared"}, {"round": 5, "combat_seconds": 60.7, "lost": [], "boss": "none", "end": "cleared"}, {"round": 6, "combat_seconds": 62.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 7, "combat_seconds": 66.5, "lost": ["blau_bot_outer"], "boss": "none", "end": "cleared"}, {"round": 8, "combat_seconds": 89.65, "lost": ["rot_top_outer", "rot_top_inner"], "boss": "won", "end": "cleared"}, {"round": 9, "combat_seconds": 136.55, "lost": ["blau_bot_inner", "blau_base_2", "blau_base_1", "blau_ancient"], "boss": "deployed", "end": "core"}],
"events": ["round 7: blau_bot_outer destroyed", "round 8: rot_top_outer destroyed", "round 8: rot_top_inner destroyed", "round 8: grotto boss won", "round 9: blau_bot_inner destroyed", "round 9: blau_base_2 destroyed", "round 9: blau_base_1 destroyed", "round 9: blau_ancient destroyed", "round 9: grotto boss deployed"],
"shots": ["01-runde1-aufmarsch", "02-runde1-mid-kampf", "03-turm-faellt", "04-turm-ruine", "05-grotte-bosskampf", "06-held-kaempft", "07-boss-auf-der-lane", "08-ancient-faellt", "09-ancient-ruine", "10-ende-uebersicht"],
"performance": null},
{"label": "match-seed9-round21", "seed": 9, "start_round": 21, "extra_gold": 4000, "speed": 6, "winner": 0, "end_note": "Ancient von Rot zerstört.", "steps": 4195, "hash": "7B8E43AEFC0D60C5", "core_hash": "7B8E43AEFC0D60C5", "same_as_core": true,
"units_alive_max": 125, "heroes_alive_max": 6, "boss_log": [],
"rounds": [{"round": 21, "combat_seconds": 121.8, "lost": ["rot_mid_outer", "rot_top_outer", "rot_mid_inner"], "boss": "none", "end": "cleared"}, {"round": 22, "combat_seconds": 87.95, "lost": ["rot_top_inner", "rot_base_1", "blau_bot_outer", "rot_base_2", "rot_ancient"], "boss": "none", "end": "core"}],
"events": ["round 21: rot_mid_outer destroyed", "round 21: rot_top_outer destroyed", "round 21: rot_mid_inner destroyed", "round 22: rot_top_inner destroyed", "round 22: rot_base_1 destroyed", "round 22: blau_bot_outer destroyed", "round 22: rot_base_2 destroyed", "round 22: rot_ancient destroyed"],
"shots": ["11-welle21-uebersicht", "12-welle21-kampf", "13-ancient-rot-faellt", "14-welle-ende"],
"performance": {"window": "20 s real time at 1x speed, unlimited frame rate, round 21", "frames": 56103, "fps": 2805.12, "frame_ms_avg": 0.356, "frame_ms_p95": 0.413, "simulation_ms_per_frame": 0.003, "views_ms_per_frame": 0.124, "units_alive_max": 116}}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 KiB

View file

@ -1605,7 +1605,7 @@
}, },
"replaces": "g01", "replaces": "g01",
"expect": { "expect": {
"triangles": 20714, "triangles": 25712,
"bones": 25, "bones": 25,
"clips": [ "clips": [
"idle", "idle",

View file

@ -231,6 +231,62 @@ def textures(material, prefix, rule, colours):
return {'glow_share': round(float(mask.mean()), 4), 'palette_gains': gains, 'size': list(found['albedo'].size)} return {'glow_share': round(float(mask.mean()), 4), 'palette_gains': gains, 'size': list(found['albedo'].size)}
def lane_lod(body, rule):
"""The lane-distance copy (LOD1): the seam copies welded (Meshy splits the mesh along its UV
seams), decimated to the target triangle count, sharp edges from the angle instead of Meshy's
split normals. Decimation keeps UVs, material and vertex groups (the skin weights).
The meshes are named <body>_LOD0 / _LOD1, Unity builds the LODGroup from the names."""
import bmesh
lod = body.copy()
lod.data = body.data.copy()
body.users_collection[0].objects.link(lod)
mesh = lod.data
if mesh.has_custom_normals:
bpy.context.view_layer.objects.active = lod
with bpy.context.temp_override(object=lod, active_object=lod, selected_objects=[lod]):
bpy.ops.mesh.customdata_custom_splitnormals_clear()
bm = bmesh.new()
bm.from_mesh(mesh)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=rule.get('weld', 1e-4))
bm.to_mesh(mesh)
bm.free()
before = sum(len(poly.vertices) - 2 for poly in mesh.polygons)
decimate = lod.modifiers.new('LaneLod', 'DECIMATE')
decimate.decimate_type = 'COLLAPSE'
decimate.ratio = min(1.0, rule['triangles'] / max(before, 1))
decimate.use_collapse_triangulate = True
while lod.modifiers[0] != decimate:
lod.modifiers.move(lod.modifiers.find(decimate.name), 0)
with bpy.context.temp_override(object=lod, active_object=lod):
bpy.ops.object.modifier_apply(modifier=decimate.name)
# Collapsing can leave zero-area triangles; the FBX round trip drops them, so they go here ...
bm = bmesh.new()
bm.from_mesh(mesh)
bmesh.ops.dissolve_degenerate(bm, edges=bm.edges, dist=1e-6)
bmesh.ops.triangulate(bm, faces=[f for f in bm.faces if len(f.verts) > 3])
# ... and faces folded onto the same three vertices (the FBX import keeps only one).
seen = set()
twins = []
for face in bm.faces:
key = tuple(sorted(v.index for v in face.verts))
if key in seen:
twins.append(face)
seen.add(key)
bmesh.ops.delete(bm, geom=twins, context='FACES_ONLY')
bm.to_mesh(mesh)
bm.free()
for poly in mesh.polygons:
poly.use_smooth = True
mesh.set_sharp_from_angle(angle=math.radians(rule.get('sharp_degrees', 50)))
name = body.name
body.name = body.data.name = name + '_LOD0'
lod.name = lod.data.name = name + '_LOD1'
after = sum(len(poly.vertices) - 2 for poly in mesh.polygons)
return {'lod0_triangles': sum(len(poly.vertices) - 2 for poly in body.data.polygons),
'lod1_triangles': after, 'lod1_vertices': len(mesh.vertices), 'welded_triangles': before,
'lod0_screen': rule.get('lod0_screen', 0.1)}
def build(figure_path, source_root, unity_root): def build(figure_path, source_root, unity_root):
figure = json.loads(figure_path.read_text()) figure = json.loads(figure_path.read_text())
bpy.ops.wm.read_factory_settings(use_empty=True) bpy.ops.wm.read_factory_settings(use_empty=True)
@ -318,8 +374,9 @@ def build(figure_path, source_root, unity_root):
tree.nodes.remove(node) tree.nodes.remove(node)
for image in list(bpy.data.images): for image in list(bpy.data.images):
bpy.data.images.remove(image) bpy.data.images.remove(image)
lod = lane_lod(body, figure['lod']) if 'lod' in figure else None
scene.frame_set(0) scene.frame_set(0)
return {'clips': clips, 'textures': maps, 'unit': unit} return {'clips': clips, 'textures': maps, 'unit': unit, 'lod': lod}
figure_file, source_dir, unity_dir, save_to = options() figure_file, source_dir, unity_dir, save_to = options()

View file

@ -7,6 +7,7 @@
"textures": "Assets/Luneraria/Art/Textures/ai-kohlenbeisser", "textures": "Assets/Luneraria/Art/Textures/ai-kohlenbeisser",
"root_bone": "Root", "root_bone": "Root",
"glow": {"hue": [0, 42], "saturation": 0.6, "value": 0.5, "metal_below": 0.5}, "glow": {"hue": [0, 42], "saturation": 0.6, "value": 0.5, "metal_below": 0.5},
"lod": {"triangles": 5000, "sharp_degrees": 50, "lod0_screen": 0.2},
"palette": {"rock": {"color": "41434b", "strength": 0.8}, "metal": {"color": "c99645", "strength": 1.0}}, "palette": {"rock": {"color": "41434b", "strength": 0.8}, "metal": {"color": "c99645", "strength": 1.0}},
"clips": { "clips": {
"idle": {"source": "Idle", "loop": true}, "idle": {"source": "Idle", "loop": true},