M2 Natur-Update t_7cf80244: Bibliothek 54 Objekte in Gruppen bäume/felsen/pflanzen/gras/pilze. library_browser: 39 deutsche Namen, alte Gruppe 'natur' thematisch aufgelöst (tree_pine->bäume, rock_large/boulder_small->felsen, bush_small->pflanzen). mesh_shapes: 'none' = flache Fußpunkt-Scheibe (Deko ohne Kollider bleibt sichtbar/wählbar). gen_thumbs: rendert jetzt ECHTE GLB-Meshes aus dem Mesh-Lager (Sibling-Repo, GLTFDocument ohne Import-System), Fallback weiter Platzhalter — alle 54 Thumbnails neu gerendert. test_library: 15->54 + Gruppen-Checks, Suite 56 Checks grün (alle 6 Editor-Suiten OK).

This commit is contained in:
Slyphax 2026-10-15 23:08:24 +00:00
parent 87e7a96fd5
commit 905edc021a
51 changed files with 301 additions and 7 deletions

View file

@ -16,6 +16,45 @@
"fass": { "poly": 128, "collision": { "shape": "cylinder", "radius": 0.31, "height": 0.88 } },
"bruecke_holz": { "poly": 228, "collision": { "shape": "compound", "parts": [{ "shape": "box", "pos": [0, 0.85, 0], "size": [2, 0.3, 3] }, { "shape": "box", "pos": [0, 0.361, -2.806], "size": [2, 0.3, 2.89], "rot_deg": [21.8, 0, 0] }, { "shape": "box", "pos": [0, 0.361, 2.806], "size": [2, 0.3, 2.89], "rot_deg": [-21.8, 0, 0] }, { "shape": "box", "pos": [-0.93, 1.5, 0], "size": [0.14, 0.12, 3] }, { "shape": "box", "pos": [-0.93, 0.964, -2.564], "size": [0.14, 0.12, 2.69], "rot_deg": [21.8, 0, 0] }, { "shape": "box", "pos": [-0.93, 0.964, 2.564], "size": [0.14, 0.12, 2.69], "rot_deg": [-21.8, 0, 0] }, { "shape": "box", "pos": [0.93, 1.5, 0], "size": [0.14, 0.12, 3] }, { "shape": "box", "pos": [0.93, 0.964, -2.564], "size": [0.14, 0.12, 2.69], "rot_deg": [21.8, 0, 0] }, { "shape": "box", "pos": [0.93, 0.964, 2.564], "size": [0.14, 0.12, 2.69], "rot_deg": [-21.8, 0, 0] }] } },
"hoehleneingang": { "poly": 204, "collision": { "shape": "compound", "parts": [{ "shape": "box", "pos": [-1.8, 1.6, 0], "size": [1.4, 3.2, 4] }, { "shape": "box", "pos": [1.8, 1.6, 0], "size": [1.4, 3.2, 4] }, { "shape": "box", "pos": [0, 2.8, 0], "size": [5, 0.8, 4] }, { "shape": "box", "pos": [0, 1.2, 1.8], "size": [2.2, 2.4, 0.4] }] } },
"felsbogen": { "poly": 156, "collision": { "shape": "compound", "parts": [{ "shape": "box", "pos": [-1.9, 1.3, 0], "size": [1.2, 2.6, 2.4] }, { "shape": "box", "pos": [1.9, 1.3, 0], "size": [1.2, 2.6, 2.4] }, { "shape": "box", "pos": [0, 3.1, 0], "size": [5, 1, 2.4] }] } }
"felsbogen": { "poly": 156, "collision": { "shape": "compound", "parts": [{ "shape": "box", "pos": [-1.9, 1.3, 0], "size": [1.2, 2.6, 2.4] }, { "shape": "box", "pos": [1.9, 1.3, 0], "size": [1.2, 2.6, 2.4] }, { "shape": "box", "pos": [0, 3.1, 0], "size": [5, 1, 2.4] }] } },
"stein_kiesel_1": { "poly": 136, "collision": { "shape": "none" } },
"baum_kiefer_1": { "poly": 728, "collision": { "shape": "cylinder", "radius": 0.4, "height": 8.489 } },
"baum_kiefer_2": { "poly": 655, "collision": { "shape": "cylinder", "radius": 0.4, "height": 7.082 } },
"baum_kiefer_3": { "poly": 1012, "collision": { "shape": "cylinder", "radius": 0.4, "height": 7.141 } },
"baum_kiefer_4": { "poly": 1006, "collision": { "shape": "cylinder", "radius": 0.4, "height": 10.001 } },
"baum_laub_1": { "poly": 857, "collision": { "shape": "cylinder", "radius": 0.4, "height": 7.022 } },
"baum_laub_2": { "poly": 802, "collision": { "shape": "cylinder", "radius": 0.4, "height": 7.4 } },
"baum_laub_3": { "poly": 723, "collision": { "shape": "cylinder", "radius": 0.4, "height": 9.182 } },
"baum_laub_4": { "poly": 668, "collision": { "shape": "cylinder", "radius": 0.4, "height": 6.763 } },
"baum_tot_1": { "poly": 761, "collision": { "shape": "cylinder", "radius": 0.4, "height": 9.16 } },
"fels_moos_block_gross": { "poly": 46, "collision": { "shape": "compound", "parts": [{ "shape": "box", "pos": [0, 0.4, 0], "size": [2, 0.8, 2] }, { "shape": "box", "pos": [0, 1.1, 0], "size": [1.2, 0.7, 1.2] }] } },
"fels_moos_block_hoch": { "poly": 64, "collision": { "shape": "compound", "parts": [{ "shape": "box", "pos": [0, 0.48, 0], "size": [1.4, 0.95, 1.4] }, { "shape": "box", "pos": [0, 1.35, 0], "size": [0.9, 0.95, 0.9] }] } },
"fels_trocken_block": { "poly": 36, "collision": { "shape": "compound", "parts": [{ "shape": "box", "pos": [0, 0.5, 0], "size": [2.18, 1, 1.63] }, { "shape": "box", "pos": [0, 1.5, 0], "size": [1.5, 1.15, 1] }] } },
"fels_moos_platte": { "poly": 32, "collision": { "shape": "box", "size": [2, 0.915, 2] } },
"fels_moos_scharte": { "poly": 48, "collision": { "shape": "box", "size": [0.968, 0.289, 1.823] } },
"fels_trocken_platte": { "poly": 48, "collision": { "shape": "box", "size": [3.821, 0.662, 2] } },
"fels_trocken_klein": { "poly": 20, "collision": { "shape": "box", "size": [0.894, 0.724, 0.851] } },
"stein_mittel_1": { "poly": 342, "collision": { "shape": "box", "size": [3.225, 1.989, 2.989] } },
"stein_mittel_2": { "poly": 522, "collision": { "shape": "box", "size": [3.42, 2.001, 3.476] } },
"strauch_gruen": { "poly": 900, "collision": { "shape": "none" } },
"strauch_blumen": { "poly": 1368, "collision": { "shape": "none" } },
"pflanze_farn": { "poly": 288, "collision": { "shape": "none" } },
"pflanze_klee": { "poly": 379, "collision": { "shape": "none" } },
"blume_gross_1": { "poly": 285, "collision": { "shape": "none" } },
"blume_gross_2": { "poly": 642, "collision": { "shape": "none" } },
"blumen_strauss": { "poly": 755, "collision": { "shape": "none" } },
"pflanze_niedrig": { "poly": 120, "collision": { "shape": "none" } },
"pflanze_teppich": { "poly": 48, "collision": { "shape": "none" } },
"pflanze_teppich_gross": { "poly": 112, "collision": { "shape": "none" } },
"gras_kurz": { "poly": 155, "collision": { "shape": "none" } },
"gras_hoch": { "poly": 326, "collision": { "shape": "none" } },
"gras_bueschel": { "poly": 494, "collision": { "shape": "none" } },
"gras_wispy_hoch": { "poly": 622, "collision": { "shape": "none" } },
"pilz_fliegenpilz": { "poly": 80, "collision": { "shape": "none" } },
"pilz_pfifferling": { "poly": 112, "collision": { "shape": "none" } },
"pilz_steinpilz": { "poly": 80, "collision": { "shape": "none" } },
"pilz_shiitake": { "poly": 80, "collision": { "shape": "none" } },
"pilz_morchel": { "poly": 80, "collision": { "shape": "none" } },
"pilz_austernseitling": { "poly": 112, "collision": { "shape": "none" } }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 751 B

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://du4ld5kl2rbyg"
path="res://.godot/imported/bruecke_holz.png-f770f1a2d554c7b92cef5575af6a53ae.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://library/thumbs/bruecke_holz.png"
dest_files=["res://.godot/imported/bruecke_holz.png-f770f1a2d554c7b92cef5575af6a53ae.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,003 B

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 941 B

After

Width:  |  Height:  |  Size: 725 B

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cp5cmqxmoar51"
path="res://.godot/imported/felsbogen.png-9d9bf75ae86d41c640de187ee24b258f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://library/thumbs/felsbogen.png"
dest_files=["res://.godot/imported/felsbogen.png-9d9bf75ae86d41c640de187ee24b258f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,001 B

After

Width:  |  Height:  |  Size: 733 B

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b2lyywg7e17o3"
path="res://.godot/imported/hoehleneingang.png-6c781859cfc4bd852de0b2e25697b38e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://library/thumbs/hoehleneingang.png"
dest_files=["res://.godot/imported/hoehleneingang.png-6c781859cfc4bd852de0b2e25697b38e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -25,21 +25,81 @@ const NAMES := {
"bruecke_holz": "Brücke (Holz)",
"hoehleneingang": "Höhleneingang",
"felsbogen": "Felsbogen",
# Natur-Update (Karte t_7cf80244): kuratierte CC0-Packs (Quaternius
# MegaKit, Kyle's Rock/Mushroom) — Namen aus stage/kuration.json.
"baum_kiefer_1": "Kiefer (schlank)",
"baum_kiefer_2": "Kiefer (kräftig)",
"baum_kiefer_3": "Kiefer (mittel)",
"baum_kiefer_4": "Kiefer (hoch)",
"baum_laub_1": "Laubbaum (rund)",
"baum_laub_2": "Laubbaum (breit)",
"baum_laub_3": "Laubbaum (schlank)",
"baum_laub_4": "Laubbaum (klein)",
"baum_tot_1": "Totholz-Baum",
"fels_moos_block_gross": "Moosfelsen (groß)",
"fels_moos_block_hoch": "Moosfelsen (hoch)",
"fels_moos_platte": "Moosfelsen (Platte)",
"fels_moos_scharte": "Moosfelsen (klein)",
"fels_trocken_block": "Trockenfelsen (hoch)",
"fels_trocken_platte": "Trockenfelsen (Platte)",
"fels_trocken_klein": "Trockenfelsen (klein)",
"stein_mittel_1": "Großer Stein 1",
"stein_mittel_2": "Großer Stein 2",
"stein_kiesel_1": "Kieselstein",
"strauch_gruen": "Strauch",
"strauch_blumen": "Blühender Strauch",
"pflanze_farn": "Farn",
"pflanze_klee": "Klee-Pflanze",
"blume_gross_1": "Blume (weiß)",
"blume_gross_2": "Blume (hoch)",
"blumen_strauss": "Blumenstrauß",
"pflanze_niedrig": "Bodendecker",
"pflanze_teppich": "Moospolster",
"pflanze_teppich_gross": "Moospolster (groß)",
"gras_kurz": "Kurzes Gras",
"gras_hoch": "Hohes Gras",
"gras_bueschel": "Grasbüschel",
"gras_wispy_hoch": "Wispy-Gras (hoch)",
"pilz_fliegenpilz": "Fliegenpilz",
"pilz_pfifferling": "Pfifferling",
"pilz_steinpilz": "Steinpilz",
"pilz_shiitake": "Shiitake",
"pilz_morchel": "Morchel",
"pilz_austernseitling": "Austernseitling",
}
## Gruppen für den Bibliothek-Browser (Anzeige-Reihenfolge = Reihenfolge hier).
const GROUP_ORDER := ["kisten", "bauwerke", "natur", "sonstiges"]
## Natur-Update (t_7cf80244): die alte Gruppe "natur" ist in thematische
## Gruppen aufgelöst (die 4 Alt-Objekte wanderten mit).
const GROUP_ORDER := ["kisten", "bauwerke", "bäume", "felsen", "pflanzen", "gras", "pilze", "sonstiges"]
const GROUP_LABELS := {
"kisten": "Kisten & Barrieren",
"bauwerke": "Bauwerke",
"natur": "Natur",
"bäume": "Bäume",
"felsen": "Felsen",
"pflanzen": "Pflanzen",
"gras": "Gras",
"pilze": "Pilze",
"sonstiges": "Sonstiges",
}
const GROUP_IDS := {
"kisten": ["crate_wood", "crate_metal", "barrier_sandbag", "wall_concrete"],
"bauwerke": ["bunker_concrete", "watchtower_wood", "fence_metal",
"bruecke_holz", "hoehleneingang", "felsbogen"],
"natur": ["tree_pine", "bush_small", "rock_large", "boulder_small"],
"bäume": ["tree_pine",
"baum_kiefer_1", "baum_kiefer_2", "baum_kiefer_3", "baum_kiefer_4",
"baum_laub_1", "baum_laub_2", "baum_laub_3", "baum_laub_4", "baum_tot_1"],
"felsen": ["rock_large", "boulder_small",
"fels_moos_block_gross", "fels_moos_block_hoch", "fels_moos_platte",
"fels_moos_scharte", "fels_trocken_block", "fels_trocken_platte",
"fels_trocken_klein", "stein_mittel_1", "stein_mittel_2", "stein_kiesel_1"],
"pflanzen": ["bush_small",
"strauch_gruen", "strauch_blumen", "pflanze_farn", "pflanze_klee",
"blume_gross_1", "blume_gross_2", "blumen_strauss", "pflanze_niedrig",
"pflanze_teppich", "pflanze_teppich_gross"],
"gras": ["gras_kurz", "gras_hoch", "gras_bueschel", "gras_wispy_hoch"],
"pilze": ["pilz_fliegenpilz", "pilz_pfifferling", "pilz_steinpilz",
"pilz_shiitake", "pilz_morchel", "pilz_austernseitling"],
}

View file

@ -8,10 +8,19 @@ const SHAPE_BOX := "box"
const SHAPE_SPHERE := "sphere"
const SHAPE_CYLINDER := "cylinder"
const SHAPE_COMPOUND := "compound"
const SHAPE_NONE := "none"
static func make_placeholder(shape: String, col: Dictionary, scale: float) -> Mesh:
match shape:
SHAPE_NONE:
# Rein dekorativ (Natur-Update, t_7cf80244): kein Kollider — aber
# im Editor trotzdem sichtbar/wählbar: flache Fußpunkt-Scheibe.
var d := CylinderMesh.new()
d.top_radius = 0.4 * scale
d.bottom_radius = d.top_radius
d.height = maxf(0.02, 0.02 * scale)
return d
SHAPE_SPHERE:
var s := SphereMesh.new()
var r := maxf(0.01, float(col.get("radius", 1.0)) * scale)

View file

@ -52,7 +52,7 @@ func _test_manifest_load() -> void:
var manifest := _load_manifest()
_check(not manifest.is_empty(), "Manifest lädt und ist ein Objekt")
var lib: Dictionary = manifest.get("objects", {})
_check(lib.size() == 15, "Katalog hat die 15 etablierten Objekte (ist %d)" % lib.size())
_check(lib.size() == 54, "Katalog hat die 54 Objekte (15 Basis + 39 Natur-Update, ist %d)" % lib.size())
var all_ok := true
for oid in lib.keys():
var entry: Dictionary = lib[oid]
@ -87,9 +87,24 @@ func _test_groups() -> void:
seen[oid] = true
_check(all_in, "keine ID in zwei Gruppen")
_check(seen.size() == lib.size(), "alle %d IDs landen in einer Gruppe (ist %d)" % [lib.size(), seen.size()])
_check(LibraryBrowser.group_of("tree_pine") == "natur", "group_of: tree_pine → natur")
_check(LibraryBrowser.group_of("tree_pine") == "bäume", "group_of: tree_pine → bäume (Natur-Update hat 'natur' aufgelöst)")
_check(LibraryBrowser.group_of("crate_wood") == "kisten", "group_of: crate_wood → kisten")
_check(LibraryBrowser.group_of("baum_kiefer_1") == "bäume", "group_of: baum_kiefer_1 → bäume")
_check(LibraryBrowser.group_of("fels_moos_platte") == "felsen", "group_of: fels_moos_platte → felsen")
_check(LibraryBrowser.group_of("gras_kurz") == "gras", "group_of: gras_kurz → gras")
_check(LibraryBrowser.group_of("pilz_morchel") == "pilze", "group_of: pilz_morchel → pilze")
_check(LibraryBrowser.group_of("fremdes_ding") == "sonstiges", "group_of: unbekannte ID → sonstiges")
var vorhanden := {}
for oid in lib.keys():
vorhanden[str(oid)] = true
var gruppen_komplett := true
for key in LibraryBrowser.GROUP_IDS:
if key == "sonstiges":
continue
for oid in (LibraryBrowser.GROUP_IDS[key] as Array):
if not vorhanden.has(str(oid)):
gruppen_komplett = false
_check(gruppen_komplett, "jede feste Gruppe listet nur IDs, die es im Katalog gibt")
# Gruppen, die im Katalog leer sind, werden nicht angezeigt (außer Sonstiges).
var labels: Array = []
for group in groups:

View file

@ -8,10 +8,18 @@ extends SceneTree
## xvfb-run -a godot4 --rendering-driver opengl3 --path . --script res://tools/gen_thumbs.gd
## (auf Slys PC auch ohne xvfb: godot4 --rendering-driver opengl3 --path . --script ...)
##
## Natur-Update (t_7cf80244): wird das echte Mesh im Mesh-Lager gefunden
## (Sibling-Repo scopedvr-match-server oder scopedvr-client, assets/objekte),
## wird das GLB direkt gerendert (GLTFDocument, ohne Import-System) — die
## Bibliothek zeigt dann die echten Bäume/Felsen/Pilze, nicht nur den
## Kollisions-Platzhalter. Ohne GLB: Platzhalter wie bisher.
##
## Exit 0 = alle Thumbnails geschrieben.
const SIZE := 128
const BG_COLOR := Color(0.16, 0.18, 0.21)
## Relative Quellen für echte GLB-Meshes (vom Editor-Projektordner aus).
const GLB_QUELLEN := ["../scopedvr-match-server/assets/objekte", "../scopedvr-client/assets/objekte"]
var manifest: Dictionary = {}
var ids: Array = []
@ -73,7 +81,7 @@ func _next() -> void:
var oid := str(ids[idx])
var entry: Dictionary = (manifest["objects"] as Dictionary)[oid]
var col: Dictionary = entry.get("collision", {})
var mesh := MeshShapes.make_placeholder(str(col.get("shape", "box")), col, 1.0)
var mesh := _mesh_fuer(oid, col)
mi.mesh = mesh
# Kamera diagonal aufs Objekt, passend zur Mesh-Größe (Kiste nah, Turm weit).
var aabb := mesh.get_aabb()
@ -98,3 +106,46 @@ func _process(_delta: float) -> bool:
print(" thumb: %s (%dx%d)" % [oid, img.get_width(), img.get_height()])
_next()
return false
# ---------------------------------------------------- echtes Mesh laden ------
## Mesh für ein Thumbnail: echtes GLB aus dem Mesh-Lager (Sibling-Repos),
## sonst Kollisions-Platzhalter (alte Fallback-Regel).
func _mesh_fuer(oid: String, col: Dictionary) -> Mesh:
var basis := ProjectSettings.globalize_path("res://")
for quelle in GLB_QUELLEN:
var pfad := basis.path_join(str(quelle)).path_join(oid + ".glb")
if FileAccess.file_exists(pfad):
var m := _glb_mesh(pfad)
if m != null:
return m
return MeshShapes.make_placeholder(str(col.get("shape", "box")), col, 1.0)
## GLB OHNE Import-System laden (GLTFDocument) und das erste Mesh liefern.
## null = Load-Fehlschlag → Aufrufer fällt auf den Platzhalter zurück.
func _glb_mesh(pfad: String) -> Mesh:
var gltf := GLTFDocument.new()
var state := GLTFState.new()
if gltf.append_from_file(pfad, state) != OK:
push_warning("gen_thumbs: GLB nicht ladbar: %s" % pfad)
return null
var szene: Node = gltf.generate_scene(state)
if szene == null:
return null
var m := _erstes_mesh(szene)
# Das Mesh ist eine Resource (RefCounted) — das Freigeben der Szene
# berührt die Referenz im Rückgabewert nicht.
szene.free()
return m
func _erstes_mesh(n: Node) -> Mesh:
if n is MeshInstance3D and (n as MeshInstance3D).mesh != null:
return (n as MeshInstance3D).mesh
for c in n.get_children():
var m := _erstes_mesh(c)
if m != null:
return m
return null