D6 (t_31e800f2): Editor-Sync — 30 Fahrzeug-Thumbs + Map-Builder-Nachweis

- library/objects.json = 347 Objekte (Merge-Stand Match-Server)
- library/thumbs/: 30 neue Thumbs (tank/apc/air_defense/antenna), in
  Kategorie-Farbe Oliv (D0-Muster) — uebrige 317 Thumbs byte-identisch
- tests/probe_d6_mapbuilder.gd: 3 Fahrzeuge ueber den ECHTEN Map Builder
  platziert (Panzer + Turm exakt auf dem Turm-Ring 1,5929 m + Transportpanzer,
  dazu die Kanone auf 2,1273 m), Kollisionsboxen als Drahtgitter,
  PNG 1600x1000 — PROBE_D6_MAPBUILDER_OK
This commit is contained in:
Hermes (scopedvr-dev) 2026-10-19 18:25:15 +00:00
parent 8f598dc67d
commit e1e07e57b0
33 changed files with 591 additions and 0 deletions

View file

@ -2,6 +2,146 @@
"library_version": 1, "library_version": 1,
"note": "Editor-Kopie der offiziellen Bibliotheks-Registry (geschlossener Baukasten, PLAN Entscheidung 20). Quelle: scopedvr-match-server library/objects.json — beim Registrieren neuer Objekte DORT zuerst eintragen und hier synchron ziehen. 'poly' = Referenz-Dreieckszahl (Budget-Rechnung, map_format.md §4 V8); 'collision' = Approximation für Platzhalter-Darstellung im Viewport.", "note": "Editor-Kopie der offiziellen Bibliotheks-Registry (geschlossener Baukasten, PLAN Entscheidung 20). Quelle: scopedvr-match-server library/objects.json — beim Registrieren neuer Objekte DORT zuerst eintragen und hier synchron ziehen. 'poly' = Referenz-Dreieckszahl (Budget-Rechnung, map_format.md §4 V8); 'collision' = Approximation für Platzhalter-Darstellung im Viewport.",
"objects": { "objects": {
"air_defense_001": {
"poly": 520,
"collision": {
"shape": "box",
"size": [
2.653,
3.257,
7.567
]
},
"glb": "res://assets/objekte/military_desert/vehicles/air_defense_001.glb",
"kategorie": "vehicles",
"name_de": "Flugabwehr 001"
},
"air_defense_002": {
"poly": 520,
"collision": {
"shape": "box",
"size": [
2.653,
3.257,
7.567
]
},
"glb": "res://assets/objekte/military_desert/vehicles/air_defense_002.glb",
"kategorie": "vehicles",
"name_de": "Flugabwehr 002"
},
"air_defense_platform_001": {
"poly": 964,
"collision": {
"shape": "box",
"size": [
3.544,
3.947,
12.05
]
},
"glb": "res://assets/objekte/military_desert/vehicles/air_defense_platform_001.glb",
"kategorie": "vehicles",
"name_de": "Flak-Lafette 001"
},
"air_defense_platform_002": {
"poly": 964,
"collision": {
"shape": "box",
"size": [
3.544,
3.947,
12.05
]
},
"glb": "res://assets/objekte/military_desert/vehicles/air_defense_platform_002.glb",
"kategorie": "vehicles",
"name_de": "Flak-Lafette 002"
},
"antenna_001": {
"poly": 134,
"collision": {
"shape": "box",
"size": [
1.591,
4.491,
1.203
]
},
"glb": "res://assets/objekte/military_desert/vehicles/antenna_001.glb",
"kategorie": "vehicles",
"name_de": "Funkantenne 001"
},
"apc_001": {
"poly": 2460,
"collision": {
"shape": "box",
"size": [
3.732,
3.936,
6.939
]
},
"glb": "res://assets/objekte/military_desert/vehicles/apc_001.glb",
"kategorie": "vehicles",
"name_de": "Transportpanzer 001"
},
"apc_002": {
"poly": 1878,
"collision": {
"shape": "box",
"size": [
3.732,
3.936,
6.939
]
},
"glb": "res://assets/objekte/military_desert/vehicles/apc_002.glb",
"kategorie": "vehicles",
"name_de": "Transportpanzer 002"
},
"apc_cap": {
"poly": 84,
"collision": {
"shape": "box",
"size": [
0.799,
0.25,
0.799
]
},
"glb": "res://assets/objekte/military_desert/vehicles/apc_cap.glb",
"kategorie": "vehicles",
"name_de": "TPz-Luke"
},
"apc_cap_1": {
"poly": 84,
"collision": {
"shape": "box",
"size": [
0.799,
0.25,
0.799
]
},
"glb": "res://assets/objekte/military_desert/vehicles/apc_cap_1.glb",
"kategorie": "vehicles",
"name_de": "TPz-Luke 1"
},
"apc_weapon": {
"poly": 482,
"collision": {
"shape": "box",
"size": [
0.82,
1.163,
1.576
]
},
"glb": "res://assets/objekte/military_desert/vehicles/apc_weapon.glb",
"kategorie": "vehicles",
"name_de": "TPz-MG"
},
"barracks_001": { "barracks_001": {
"poly": 1139, "poly": 1139,
"collision": { "collision": {
@ -3272,6 +3412,286 @@
"shape": "none" "shape": "none"
} }
}, },
"tank_001": {
"poly": 3734,
"collision": {
"shape": "box",
"size": [
4.964,
2.27,
8.842
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_001.glb",
"kategorie": "vehicles",
"name_de": "Panzer 001"
},
"tank_002": {
"poly": 3734,
"collision": {
"shape": "box",
"size": [
4.964,
2.27,
8.842
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_002.glb",
"kategorie": "vehicles",
"name_de": "Panzer 002"
},
"tank_003": {
"poly": 3734,
"collision": {
"shape": "box",
"size": [
4.964,
2.27,
8.842
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_003.glb",
"kategorie": "vehicles",
"name_de": "Panzer 003"
},
"tank_004": {
"poly": 3734,
"collision": {
"shape": "box",
"size": [
4.964,
2.27,
8.842
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_004.glb",
"kategorie": "vehicles",
"name_de": "Panzer 004"
},
"tank_005": {
"poly": 3564,
"collision": {
"shape": "box",
"size": [
4.518,
2.309,
9.973
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_005.glb",
"kategorie": "vehicles",
"name_de": "Panzer 005"
},
"tank_006": {
"poly": 3560,
"collision": {
"shape": "box",
"size": [
4.518,
2.309,
9.973
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_006.glb",
"kategorie": "vehicles",
"name_de": "Panzer 006"
},
"tank_car_001": {
"poly": 778,
"collision": {
"shape": "box",
"size": [
2.766,
2.45,
6.548
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_car_001.glb",
"kategorie": "vehicles",
"name_de": "Radpanzer 001"
},
"tank_car_002": {
"poly": 778,
"collision": {
"shape": "box",
"size": [
2.766,
2.45,
6.548
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_car_002.glb",
"kategorie": "vehicles",
"name_de": "Radpanzer 002"
},
"tank_gun_001": {
"poly": 106,
"collision": {
"shape": "box",
"size": [
0.761,
0.761,
4.338
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_gun_001.glb",
"kategorie": "vehicles",
"name_de": "Panzerkanone 001"
},
"tank_gun_002": {
"poly": 106,
"collision": {
"shape": "box",
"size": [
0.761,
0.761,
4.338
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_gun_002.glb",
"kategorie": "vehicles",
"name_de": "Panzerkanone 002"
},
"tank_gun_003": {
"poly": 106,
"collision": {
"shape": "box",
"size": [
0.761,
0.761,
4.338
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_gun_003.glb",
"kategorie": "vehicles",
"name_de": "Panzerkanone 003"
},
"tank_gun_004": {
"poly": 106,
"collision": {
"shape": "box",
"size": [
0.761,
0.761,
4.338
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_gun_004.glb",
"kategorie": "vehicles",
"name_de": "Panzerkanone 004"
},
"tank_gun_005": {
"poly": 217,
"collision": {
"shape": "box",
"size": [
0.764,
1.005,
4.851
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_gun_005.glb",
"kategorie": "vehicles",
"name_de": "Panzerkanone 005"
},
"tank_gun_006": {
"poly": 217,
"collision": {
"shape": "box",
"size": [
0.764,
1.005,
4.851
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_gun_006.glb",
"kategorie": "vehicles",
"name_de": "Panzerkanone 006"
},
"tank_tower_001": {
"poly": 1456,
"collision": {
"shape": "box",
"size": [
4.411,
4.173,
4.502
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_tower_001.glb",
"kategorie": "vehicles",
"name_de": "Panzer-Turm 001"
},
"tank_tower_002": {
"poly": 1456,
"collision": {
"shape": "box",
"size": [
4.411,
4.173,
4.502
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_tower_002.glb",
"kategorie": "vehicles",
"name_de": "Panzer-Turm 002"
},
"tank_tower_003": {
"poly": 1456,
"collision": {
"shape": "box",
"size": [
4.411,
4.173,
4.502
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_tower_003.glb",
"kategorie": "vehicles",
"name_de": "Panzer-Turm 003"
},
"tank_tower_004": {
"poly": 1456,
"collision": {
"shape": "box",
"size": [
4.411,
4.173,
4.502
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_tower_004.glb",
"kategorie": "vehicles",
"name_de": "Panzer-Turm 004"
},
"tank_tower_005": {
"poly": 861,
"collision": {
"shape": "box",
"size": [
4.08,
3.147,
5.624
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_tower_005.glb",
"kategorie": "vehicles",
"name_de": "Panzer-Turm 005"
},
"tank_tower_006": {
"poly": 861,
"collision": {
"shape": "box",
"size": [
4.08,
3.147,
5.624
]
},
"glb": "res://assets/objekte/military_desert/vehicles/tank_tower_006.glb",
"kategorie": "vehicles",
"name_de": "Panzer-Turm 006"
},
"tent_001": { "tent_001": {
"poly": 1322, "poly": 1322,
"collision": { "collision": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 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.2 KiB

BIN
library/thumbs/apc_001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
library/thumbs/apc_002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
library/thumbs/apc_cap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
library/thumbs/tank_001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
library/thumbs/tank_002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
library/thumbs/tank_003.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
library/thumbs/tank_004.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
library/thumbs/tank_005.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
library/thumbs/tank_006.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,170 @@
extends SceneTree
## D6-Beweis (t_31e800f2): Map Builder platziert 3 Fahrzeuge (Panzer + Panzer-Turm
## aufgesetzt + Transportpanzer) und zeigt die Kollisionsboxen als Drahtgitter
## (Groesse aus registry `collision.size` — die Deckungsprobe als Bild).
## Zusaetzlich aufgesetzt: die Panzerkanone, damit sichtbar ist, dass Turm und
## Kanone an der richtigen Stelle sitzen (Pack-Prefab-Hoehen 1,5929 m / 0,5344 m).
##
## xvfb-run -a /opt/data/home/bin/godot4 --rendering-driver opengl3 --path . \
## -s res://tests/probe_d6_mapbuilder.gd
##
## Ausgabe: user://probe_d6_mapbuilder.png + Pruefzeilen
const AUSGABE := "user://probe_d6_mapbuilder.png"
const TURM_RING_Y := 1.5928574
const KANONE_Y := TURM_RING_Y + 0.53440094
const KANONE_Z := 1.4340973
const PLATZ := [
{"id": "tank_001", "pos": [0.0, 0.0, 0.0], "rot_y_deg": 0.0, "aufsatz": false},
{"id": "tank_tower_001", "pos": [0.0, TURM_RING_Y, 0.0], "rot_y_deg": 0.0, "aufsatz": true},
{"id": "tank_gun_001", "pos": [0.0, KANONE_Y, KANONE_Z], "rot_y_deg": 0.0, "aufsatz": true},
{"id": "apc_001", "pos": [9.5, 0.0, 0.0], "rot_y_deg": 0.0, "aufsatz": false},
]
const MapDocument := preload("res://src/svmap/map_document.gd")
var vp: SubViewport
var bauer: Node3D
var kamera: Camera3D
var rahmen := 0
var fehler: Array = []
func _initialize() -> void:
vp = SubViewport.new()
vp.size = Vector2i(1600, 1000)
vp.own_world_3d = true
vp.render_target_update_mode = SubViewport.UPDATE_ALWAYS
root.add_child(vp)
var env := Environment.new()
env.background_mode = Environment.BG_COLOR
env.background_color = Color(0.55, 0.62, 0.72)
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
env.ambient_light_color = Color(1, 1, 1)
env.ambient_light_energy = 0.85
var we := WorldEnvironment.new()
we.environment = env
vp.add_child(we)
var sonne := DirectionalLight3D.new()
sonne.rotation_degrees = Vector3(-48.0, 35.0, 0.0)
sonne.light_energy = 1.2
vp.add_child(sonne)
# Bodenplatte (Terrain-Ersatz): zeigt, dass die Fahrzeuge AUF dem Boden stehen.
# Bewusst ein flacher Kasten (nicht PlaneMesh) + unshaded: keine Z-Artefakte
# und keine Beleuchtungsflecken im llvmpipe-Renderer.
var boden := MeshInstance3D.new()
var bm_boden := BoxMesh.new()
bm_boden.size = Vector3(90.0, 0.4, 90.0)
boden.mesh = bm_boden
boden.position = Vector3(0.0, -0.19, 0.0) # Oberkante y=+0.01: Sand liegt 1 cm ueber der Builder-Bodenebene (kein Z-Kampf)
var bmat := StandardMaterial3D.new()
bmat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
bmat.albedo_color = Color(0.76, 0.66, 0.44)
boden.material_override = bmat
vp.add_child(boden)
# --- der ECHTE Map Builder (gleiche Datei wie der Editor benutzt) ---
var manifest: Dictionary = JSON.parse_string(
FileAccess.get_file_as_string("res://library/objects.json"))
var doc: Dictionary = MapDocument.create_new("D6-Beweis", 256.0, "mittag")
doc["objects"] = PLATZ
bauer = load("res://src/viewport/map_view_builder.gd").new()
vp.add_child(bauer)
await process_frame
bauer.rebuild(doc, manifest)
var lib: Dictionary = manifest.get("objects", {})
print("Bibliothek: %d Objekte" % lib.size())
for i in PLATZ.size():
var oid := str(PLATZ[i]["id"])
var marker: Node3D = bauer.object_markers[i]
if marker == null:
fehler.append("%s: kein Marker" % oid)
continue
var entry: Dictionary = lib.get(oid, {})
if entry.is_empty():
fehler.append("%s: nicht in der Bibliothek" % oid)
continue
var col: Dictionary = entry.get("collision", {})
var groesse: Array = col.get("size", [0.0, 0.0, 0.0])
# Kollisionsbox als Drahtgitter (Fusspunkt: Unterkante y=0 der Platzierung).
# 12 Kanten als PRIMITIVE_LINES — `wireframe` gibt es in der
# Compatibility-Pipeline nicht (Godot-3-Remap-Warnung).
var box := MeshInstance3D.new()
var im := ImmediateMesh.new()
var mat := StandardMaterial3D.new()
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
mat.albedo_color = Color(0.0, 1.0, 0.2)
im.surface_begin(Mesh.PRIMITIVE_LINES, mat)
var h := Vector3(float(groesse[0]), float(groesse[1]), float(groesse[2])) * 0.5
var ecken: Array = []
for sx in [-1.0, 1.0]:
for sy in [-1.0, 1.0]:
for sz in [-1.0, 1.0]:
ecken.append(Vector3(sx * h.x, sy * h.y, sz * h.z))
for a in ecken.size():
for b in range(a + 1, ecken.size()):
var d: Vector3 = ecken[a] - ecken[b]
# Kante = genau eine Achse unterschiedlich
var gleich := 0
if abs(d.x) < 1e-4:
gleich += 1
if abs(d.y) < 1e-4:
gleich += 1
if abs(d.z) < 1e-4:
gleich += 1
if gleich == 2:
im.surface_add_vertex(ecken[a])
im.surface_add_vertex(ecken[b])
im.surface_end()
box.mesh = im
box.material_override = mat
box.position = Vector3(0.0, float(groesse[1]) * 0.5, 0.0)
marker.add_child(box)
var echt := bool(marker.get_meta("glb"))
var mi := marker.get_child(0) as MeshInstance3D
var mesh_aabb := mi.mesh.get_aabb() if (mi != null and mi.mesh != null) else AABB()
print("%-16s echtesGLB=%-5s aufsatz=%-5s registry=%.3f/%.3f/%.3f mesh_aabb=%.3f/%.3f/%.3f mesh_min_y=%.3f box_fuss=%.3f"
% [oid, str(echt), str(PLATZ[i]["aufsatz"]),
float(groesse[0]), float(groesse[1]), float(groesse[2]),
mesh_aabb.size.x, mesh_aabb.size.y, mesh_aabb.size.z, mesh_aabb.position.y,
marker.position.y])
if not echt:
fehler.append("%s: rendert nur den Platzhalter (GLB fehlt)" % oid)
if abs(mesh_aabb.position.y) > 0.01:
fehler.append("%s: Mesh-Unterkante %.3f (soll 0)" % [oid, mesh_aabb.position.y])
# Turm muss exakt auf dem Turm-Ring des Panzers sitzen (Pack-Prefab-Wert).
var turm: Node3D = bauer.object_markers[1]
if turm != null and abs(turm.position.y - TURM_RING_Y) > 0.001:
fehler.append("Turm sitzt bei y=%.4f (Pack-Prefab: %.4f)" % [turm.position.y, TURM_RING_Y])
kamera = Camera3D.new()
kamera.fov = 42.0
kamera.current = true
vp.add_child(kamera)
func _process(_delta: float) -> bool:
rahmen += 1
if rahmen < 4:
return false
if rahmen == 4:
kamera.look_at_from_position(Vector3(16.0, 9.0, 20.0), Vector3(3.0, 2.4, 0.0), Vector3.UP)
return false
if rahmen == 8:
var pfad := ProjectSettings.globalize_path(AUSGABE)
var img := vp.get_texture().get_image()
img.save_png(pfad)
print("Bild: %s (%dx%d)" % [pfad, img.get_width(), img.get_height()])
for f in fehler:
print(" FEHLER: %s" % f)
print("PROBE_D6_MAPBUILDER_%s" % ("FAIL" if not fehler.is_empty() else "OK"))
quit(1 if not fehler.is_empty() else 0)
return true
return false

View file

@ -0,0 +1 @@
uid://c5ejo72vu5bw2